4

I have found lots of info online about how to use the initEvent and dispatchEvent functions, but I can't for the life of me get them to work in practice.

I'm trying to get a script to press the Enter key every 5 seconds. My userscript code (minus irrelevant metadata) is below:

// ==UserScript==
// @namespace      http://userscripts.org/scripts/show/153134
// @require        https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js
//
// @grant          unsafeWindow
//
// ==/UserScript==

$(function(){
window.setInterval(function(){
    var ev = document.createEvent("KeyboardEvent");
    ev.initKeyEvent("keypress", true, false, window, 0, 0, 0, 0, 13, 13);
        window.dispatchEvent(evt);
}, 5000);
});

Checkout my script on userscript to see how poorly it works (add a user include domain and test it on any <textarea>). Is Greasemonkey just not letting it through, or do I need to do something differently?

NH.
  • 2,240
  • 2
  • 23
  • 37
  • Did you ever get it to work? – G. Bach Apr 20 '17 at 15:31
  • nah, I ended up doing it with AutoHotKey instead. Maybe Python would have been a better solution for cross-platform compatibility, though. – NH. Apr 24 '17 at 19:29
  • Does autohotkey do it in the background while you do other stuff? And where would you have looked at with python? Any advice appreciated. – G. Bach Apr 24 '17 at 20:15
  • No, my AHK script didn't work in the background. What are you trying to do? – NH. Apr 24 '17 at 20:50
  • These answers didn't work for me in Firefox. But there is a library that does. You can find more information about it here: https://stackoverflow.com/a/75749283/61624 – Daniel Kaplan Mar 15 '23 at 20:43

2 Answers2

4

There is a copy-paste error in that code.
Don't use window.dispatchEvent(evt);;
use window.dispatchEvent(ev);

Sending the event to window may not be what you need either. (Or it could be. Link to the target page.)

Maybe send the event to the document:

document.body.dispatchEvent(ev);

Or send it to a specific node:

var targetNode  = document.querySelector ("#content textarea"); // Etc.
targetNode.dispatchEvent (ev);


Or, since you are using jQuery:

var ev = $.Event('keypress');
ev.which = 13; // Carriage-return (Enter)
$('body').trigger(ev);
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • So, what is the difference between sending it to the window or the document? Pressing enter is pressing enter. – NH. Dec 01 '12 at 20:22
  • The document is the entire webpage that you see and can interact with. The window is browser controls/trim, etc. As a rule, javascript is allowed little control of browser controls -- for security. Most (¿all?) browsers will ignore artificial key events targeted to `window`. – Brock Adams Dec 01 '12 at 22:07
  • 2
    So, this still doesn't work. I tried both the JQuery method and actually sending the event to the specific page element (document.querySelector("#UserProfileMain embed") ). It might be the problem that it is a flash object that I'm trying to send keypress events to, or maybe it is because keypress is only for actual letters, and not for other keys like arrows or enter? – NH. Dec 04 '12 at 18:39
  • 1
    Yes, sending it to a flash element may not be possible. Also, you can try sending keydown, keypress, keyup, in sequence. – Brock Adams Dec 04 '12 at 21:32
3

The only way I've been able to send keystrokes to the document and have them bubble properly is by creating an additional script insertion within the GM script. This example uses jQuery to simulate the keystroke event, it detects when the key "x" is pressed and sends "enter" to the document.

var script = document.createElement("script");
script.setAttribute("type", "application/javascript");

script.textContent = "(" + function(){
    $(document).keypress(function(e) {
        if(e.which == 120) {
            var p = jQuery.Event('keydown');
            p.which = 13;
            p.keyCode = 13;
            $('body').trigger(p);
        }
    });
} + ")()";

document.body.appendChild(script);
document.body.removeChild(script);

(edit: fixed equals/equivalency error)

Chris Like
  • 280
  • 1
  • 8
  • 1
    so why the removeChild line? – NH. Dec 08 '12 at 19:29
  • It's only necessary if you're only running the initiator script once, clearing up resources, but it's not that important. I usually keep the script there for debugging. This approach makes setting breakpoints much easier. – Chris Like Dec 08 '12 at 20:33
  • Did this answer the question for you, @NH.? – Chris Like Dec 12 '12 at 02:48
  • I'm not going to check mark an answer until I get a working script. but thanks for the explanation. – NH. Dec 12 '12 at 16:38
  • Do you know why adding a `script` element is necessary? Or why this works, but directly `dispatchEvent` doesn't? I debugged for a long time, and your answer works like a charm. Running `dispatchEvent` works in the console, but not in GM. In GM, the event is fired but not processed. I printed out the events, they look almost the same. Any idea? Thanks. – Kirk Jun 03 '19 at 16:20