是否可以通过编程方式模拟按键事件?

tan*_*tan 342 javascript dom-events

是否可以在JavaScript中以编程方式模拟按键事件?

Phi*_*nyy 169

一个非jquery版本,适用于webkit和gecko:

var keyboardEvent = document.createEvent("KeyboardEvent");
var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";

keyboardEvent[initMethod](
  "keydown", // event type: keydown, keyup, keypress
  true,      // bubbles
  true,      // cancelable
  window,    // view: should be window
  false,     // ctrlKey
  false,     // altKey
  false,     // shiftKey
  false,     // metaKey
  40,        // keyCode: unsigned long - the virtual key code, else 0
  0          // charCode: unsigned long - the Unicode character associated with the depressed key, else 0
);
document.dispatchEvent(keyboardEvent);
Run Code Online (Sandbox Code Playgroud)

  • `keyCode`始终为0,我无法更改它. (22认同)
  • 看来Chromium中存在一个错误,当使用`document.createEvent("KeyboardEvent")时,会导致`event.which`始终为'0`.@lluft在这个[评论](http://stackoverflow.com/questions/961532/firing-a-keyboard-event-in-javascript#comment-44022523)上分享了详细信息和解决方法,这对我有用.不同的线程.基本上,你需要使用`document.createEvent('Event')`来创建一个通用事件,然后将类型设置为`keydown`并给出一个等于key的charcode的`keyCode`属性. (8认同)
  • Philip,这看起来像我需要的代码,但我需要将keypress事件发送到textarea.我试图修改你的代码发送到textarea,但它似乎没有工作,至少铬,任何想法可能是错的?这是我演示的jsfiddle:http://jsfiddle.net/szmJu/ (7认同)
  • 现在似乎已删除此功能.不过,MDN已经考虑过它已经弃用了很长一段时间. (5认同)
  • 事实证明Chromium中存在一个带有KeyboardEvent调度的错误.有关更多详细信息,请查看此主题:http://stackoverflow.com/questions/10455626/keydown-simulation-in-chrome-fires-normally-but-not-the-correct-key/12522769#12522769. (4认同)
  • 注意:MDN上的KeyboardEvent.initKeyboardEvent()的上述链接是错误的.正确的链接:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/initKeyboardEvent (3认同)

ale*_*2k8 70

如果你可以使用jQuery 1.3.1:

function simulateKeyPress(character) {
  jQuery.event.trigger({ type : 'keypress', which : character.charCodeAt(0) });
}

$(function() {
  $('body').keypress(function(e) {
    alert(e.which);
  });

  simulateKeyPress("e");
});
Run Code Online (Sandbox Code Playgroud)

  • 它在Chrome中无法正常运行,抱歉.jQuery创建了Event,但是没有重要的属性 - charCode,keyCode. (9认同)
  • @tan这是不可能的.请参阅我的答案,了解其背后的原因. (4认同)
  • 请注意,“触发” [无法用于模仿本机浏览器事件](http://stackoverflow.com/questions/32428993/why-doesnt-simulating-a-tab-keypress-change-focus-of-input-字段)。 (2认同)

Lor*_*uer 49

你可以做的是通过触发keyevents以编程方式触发keyevent监听.从沙盒安全角度来看,允许这样做是有意义的.使用此功能,您可以应用典型的观察者模式.您可以将此方法称为"模拟".

下面是如何在W3C DOM标准和jQuery中实现此目的的示例:

function triggerClick() {
  var event = new MouseEvent('click', {
    'view': window,
    'bubbles': true,
    'cancelable': true
  });
  var cb = document.querySelector('input[type=submit][name=btnK]'); 
  var canceled = !cb.dispatchEvent(event);
  if (canceled) {
    // preventDefault was called and the event cancelled
  } else {
    // insert your event-logic here...
  }
}
Run Code Online (Sandbox Code Playgroud)

此示例改编自:https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events

在jQuery中:

jQuery('input[type=submit][name=btnK]')
  .trigger({
    type: 'keypress',
    which: character.charCodeAt(0 /*the key to trigger*/)      
   });
Run Code Online (Sandbox Code Playgroud)

但截至最近,没有[DOM]方法实际触发离开浏览器沙箱的关键事件.所有主要的浏览器供应商都将遵循这一安全概念.

对于基于NPAPI的Adobe Flash等插件,允许绕过沙箱:这些都是逐步淘汰的 ; 火狐.

详细说明:

你不能也不能出于安全原因(正如Pekka已经指出的那样).您将始终需要用户之间的互动.此外,想象一下浏览器供应商被用户起诉的可能性,因为各种程序化键盘事件将导致欺骗攻击.

有关替代品和更多详细信息,请参阅此帖 总有基于闪存的复制粘贴.这是一个优雅的 例子.与此同时,它证明了为什么网络正在远离插件供应商.

如果选择加入CORS策略以编程方式访问远程内容,则应用类似的安全思维模式.

答案是:
在正常情况下,无法以编程方式触发沙盒浏览器环境中的输入键.

底线:我并不是说将来,在特殊的浏览器模式和/或特权用于游戏的最终目标或类似的用户体验下,它是不可能的.但是,在进入此类模式之前,将要求用户提供权限和风险,类似于Fullscreen API模型.

有用:在KeyCodes的上下文中,工具和键码映射将派上用场.

披露:答案是基于这里的答案.


hal*_*ley 36

截至 2019 年,此解决方案对我有用:

document.dispatchEvent(
  new KeyboardEvent("keydown", {
    key: "e",
    keyCode: 69, // example values.
    code: "KeyE", // put everything you need in this object.
    which: 69,
    shiftKey: false, // you don't need to include values
    ctrlKey: false,  // if you aren't going to use them.
    metaKey: false   // these are here for example's sake.
  })
);
Run Code Online (Sandbox Code Playgroud)

我在我的浏览器游戏中使用了它,以支持带有模拟键盘的移动设备。

说明:此代码调度单个keydown事件,而真正的按键按下将触发一个keydown事件(如果按住时间更长,则会触发多个事件),然后keyup在您释放该键时触发一个事件。如果您也需要keyup事件,也可以keyup通过在代码片段中更改"keydown"为来模拟事件"keyup"

这也会将事件发送到整个网页,因此document. 如果您只希望特定元素接收事件,则可以替换document所需元素。

  • @hanshenrik - 说实话,如果您在 2020 年使用 Flash,您确实需要重新考虑哪些工具最适合您的目的。 (10认同)
  • 请让Flash死掉吧 (6认同)
  • 这是 Qt QWebEngine runJavascript 函数中唯一对我有用的解决方案。谢谢 (2认同)

alj*_*gom 26

您可以在像这样的元素上调度键盘事件

element.dispatchEvent(new KeyboardEvent('keypress',{'key':'a'}));
Run Code Online (Sandbox Code Playgroud)

  • 我认为答案应该提到在js事件中调度的事实不会更新输入内容. (8认同)
  • 最新的Firefox不是现代的吗? (5认同)
  • 似乎`keypress` 已贬值,而是使用`keydown` -> https://developer.mozilla.org/en-US/docs/Web/Events/keypress (3认同)
  • 它没有填充文本框,为什么? (3认同)

Plu*_*tor 22

你可以使用dispatchEvent():

function simulateKeyPress() {
  var evt = document.createEvent("KeyboardEvent");
  evt.initKeyboardEvent("keypress", true, true, window,
                    0, 0, 0, 0,
                    0, "e".charCodeAt(0))
  var body = document.body;
  var canceled = !body.dispatchEvent(evt);
  if(canceled) {
    // A handler called preventDefault
    alert("canceled");
  } else {
    // None of the handlers called preventDefault
    alert("not canceled");
  }
}
Run Code Online (Sandbox Code Playgroud)

我没有对此进行测试,但它是根据dispatchEvent()文档中的代码改编.您可能想要阅读它,以及createEvent()和initKeyEvent()的文档.

  • 注意:仅Gecko浏览器支持此功能. (15认同)
  • Gecko 和其他浏览器在是否使用 `initKeyEvent` 或 `initKeyboardEvent()` 上存在分歧。两者都被弃用,以支持使用 [KeyboardEvent()](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent) 构造函数。 (5认同)

Ale*_*sev 21

您可以创建和分派键盘事件,它们将触发相应的已注册事件处理程序,但是如果调度到输入元素,它们将不会生成任何文本.

要完全模拟文本输入,您需要生成一系列键盘事件,并显式设置input元素的文本.事件序列取决于您想要模拟文本输入的彻底程度.

最简单的形式是:

$('input').val('123');
$('input').change();
Run Code Online (Sandbox Code Playgroud)


Tim*_*hof 13

基于alex2k8的答案,这是一个修订版本,适用于jQuery支持的所有浏览器(问题在于缺少jQuery.event.trigger的参数,在使用该内部函数时很容易忘记).

// jQuery plugin. Called on a jQuery object, not directly.
jQuery.fn.simulateKeyPress = function (character) {
  // Internally calls jQuery.event.trigger with arguments (Event, data, elem).
  // That last argument, 'elem', is very important!
  jQuery(this).trigger({ type: 'keypress', which: character.charCodeAt(0) });
};

jQuery(function ($) {
  // Bind event handler
  $('body').keypress(function (e) {
    alert(String.fromCharCode(e.which));
    console.log(e);
  });
  // Simulate the key press
  $('body').simulateKeyPress('x');
});
Run Code Online (Sandbox Code Playgroud)

你甚至可以进一步推动它,让它不仅模拟事件,而且实际插入角色(如果它是一个输入元素),但是在尝试这样做时有许多跨浏览器的问题.更好地使用像SendKeys这样更精细的插件.

  • 不模拟硬件按键,只需调用binded按键功能. (2认同)

Мал*_*евъ 12

在某些情况下,keypress事件无法提供所需的功能,通常情况下,事件是由两个因此触发的事件组合而来的keypress,并且后面的事件是keydown相同的键.所以只需逐个生成事件:

element.dispatchEvent(new KeyboardEvent('keydown',{'key':'Shift'}));
element.dispatchEvent(new KeyboardEvent('keyup',{'key':'Shift'}));
Run Code Online (Sandbox Code Playgroud)


小智 8

对于那些感兴趣的人,您可以实际上可靠地重新创建键盘输入事件.为了更改输入区域中的文本(移动游标,或通过输入字符移动页面),您必须密切关注DOM事件模型:http://www.w3.org/TR/DOM-Level-3-Events/ #h4_events-inputevents

该模型应该:

  • focus(在具有目标集的DOM上调度)

然后为每个角色:

  • keydown(在DOM上发送)
  • beforeinput(如果是textarea或输入,则在目标处调度)
  • keypress(在DOM上发送)
  • 输入(如果是textarea或输入,则在目标处调度)
  • 更改(如果选择,则在目标处调度)
  • keyup(在DOM上调度)

然后,可选择大多数:

  • 模糊(使用目标集在DOM上调度)

这实际上通过javascript更改页面中的文本(不修改值语句)并适当地设置任何javascript侦听器/处理程序.如果你弄乱了序列javascript将不会以适当的顺序触发,输入框中的文本将不会改变,选择不会改变或光标不会移动到文本区域中的下一个空格.

不幸的是,代码是根据NDA为雇主编写的,因此我无法共享它,但它绝对可以,但您必须以正确的顺序为每个元素重新创建整个键输入"堆栈".

  • 适用于JavaScript的NDA?真?,无论如何,对于你的算法错误的每个角色,模拟"输入"事件无论如何添加文本而不经历整个keydown,keyup事件或任何其他事件.问题是如何处理多个按键事件等,如按下"a"按钮并多次期待"aaaaaaa". (7认同)
  • 我试过这个但它似乎没有完全起作用:我可以触发Enter,Backspace或箭头键的事件,但不能触发字符.例如,虽然我密切关注您的事件顺序,但我无法通过此方法输入文本. (3认同)
  • 我尝试过这个,没有运气。 (2认同)
  • 出于安全原因,这是不可能的:手动触发事件不会生成与该事件关联的默认操作。例如,手动触发按键事件不会导致该字母出现在焦点文本输入中。对于 UI 事件,出于安全原因,这很重要,因为它可以防止脚本模拟与浏览器本身交互的用户操作。来源 MDN https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Auto-repeat_handling_prior_to_Gecko_5.0 (2认同)

Akb*_*bal 8

我想模拟按“Tab”键...扩展Trevor 的答案,我们可以看到像“Tab”这样的特殊键确实被按下,但我们看不到按“Tab”键会产生的实际结果。 。

尝试为“activeElement”以及全局文档对象分派这些事件 - 下面添加了两者的代码;

下面的片段

var element = document.getElementById("firstInput");

document.addEventListener("keydown", function(event) {

  console.log('we got key:', event.key, '  keyCode:', event.keyCode, '  charCode:', event.charCode);

  /* enter is pressed */
  if (event.keyCode == 13) {
    console.log('enter pressed:', event);
    theKey = 'Tab';
    attributes = {
      bubbles: true,
      key: theKey,
      keyCode: 9,
      charCode: 0,
    };
    setTimeout(function() {
      /*  event.keyCode = 13;  event.target.value += 'b';  */
      var e = new window.KeyboardEvent('focus', attributes);
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keydown', attributes);
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('beforeinput', attributes);
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keypress', attributes);
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('input', attributes);
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('change', attributes);
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keyup', attributes);
      document.activeElement.dispatchEvent(e);
    }, 4);

    setTimeout(function() {
      var e = new window.KeyboardEvent('focus', attributes);
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keydown', attributes);
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('beforeinput', attributes);
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keypress', attributes);
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('input', attributes);
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('change', attributes);
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keyup', attributes);
      document.dispatchEvent(e);
    }, 100);



  } else if (event.keyCode != 0) {
    console.log('we got a non-enter press...: :', event.key, '  keyCode:', event.keyCode, '  charCode:', event.charCode);
  }

});
Run Code Online (Sandbox Code Playgroud)
<h2>convert each enter to a tab in JavaScript... check console for output</h2>
<h3>we dispatchEvents on the activeElement... and the global element as well</h3>

<input type='text' id='firstInput' />
<input type='text' id='secondInput' />

<button type="button" onclick="document.getElementById('demo').innerHTML = Date()">
    Click me to display Date and Time.</button>
<p id="demo"></p>
Run Code Online (Sandbox Code Playgroud)


Ata*_*ani 7

这种方法支持跨浏览器更改密钥代码的值. 资源

var $textBox = $("#myTextBox");

var press = jQuery.Event("keypress");
press.altGraphKey = false;
press.altKey = false;
press.bubbles = true;
press.cancelBubble = false;
press.cancelable = true;
press.charCode = 13;
press.clipboardData = undefined;
press.ctrlKey = false;
press.currentTarget = $textBox[0];
press.defaultPrevented = false;
press.detail = 0;
press.eventPhase = 2;
press.keyCode = 13;
press.keyIdentifier = "";
press.keyLocation = 0;
press.layerX = 0;
press.layerY = 0;
press.metaKey = false;
press.pageX = 0;
press.pageY = 0;
press.returnValue = true;
press.shiftKey = false;
press.srcElement = $textBox[0];
press.target = $textBox[0];
press.type = "keypress";
press.view = Window;
press.which = 13;

$textBox.trigger(press);
Run Code Online (Sandbox Code Playgroud)


bor*_*nac 7

只需使用CustomEvent

Node.prototype.fire=function(type,options){
     var event=new CustomEvent(type);
     for(var p in options){
         event[p]=options[p];
     }
     this.dispatchEvent(event);
}
Run Code Online (Sandbox Code Playgroud)

4 ex想要模拟ctrl + z

window.addEventListener("keyup",function(ev){
     if(ev.ctrlKey && ev.keyCode === 90) console.log(ev); // or do smth
     })

 document.fire("keyup",{ctrlKey:true,keyCode:90,bubbles:true})
Run Code Online (Sandbox Code Playgroud)


See*_*oad 5

这对我有用,它确实为我的 textaera 模拟了一个键盘。如果您想要整个页面都使用它,只需像这样KeySimulation()打开,或者如果没有,则也可以使用。<body><body onmousemove="KeySimulation()">onmousemoveonmouseoveronload

function KeySimulation()
    {
    var e = document.createEvent("KeyboardEvent");
    if (e.initKeyboardEvent) {  // Chrome, IE
        e.initKeyboardEvent("keyup", true, true, document.defaultView, "Enter", 0, "", false, "");
    } else { // FireFox
        e.initKeyEvent("keyup", true, true, document.defaultView, false, false, false, false, 13, 0);
    }
    document.getElementById("MyTextArea").dispatchEvent(e);
    }
Run Code Online (Sandbox Code Playgroud)
<input type="button" onclick="KeySimulation();" value=" Key Simulation " />
<textarea id="MyTextArea" rows="15" cols="30"></textarea>
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`initKeyboardEvent` 已被弃用。([来源](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/initKeyboardEvent)) (2认同)

K. *_*erg 5

由于在控制台上下文中易于使用,它被单排一次。但可能仍然有用。

var pressthiskey = "q"/* <-- q for example */;
var e = new Event("keydown");
e.key = pressthiskey;
e.keyCode = e.key.charCodeAt(0);
e.which = e.keyCode;
e.altKey = false;
e.ctrlKey = true;
e.shiftKey = false;
e.metaKey = false;
e.bubbles = true;
document.dispatchEvent(e);
Run Code Online (Sandbox Code Playgroud)


Jac*_*lla 5

使其发挥作用的关键部分是要认识到这一点charCodekeyCodewhich都是已弃用的方法因此,如果处理按键事件的代码使用这三个中的任何一个,那么它将收到一个虚假的答案(例如默认值0)。

只要您使用未弃用的方法(例如 )访问按键事件,key就应该没问题。

为了完成,我添加了用于触发事件的基本 Javascript 代码:

const rightArrowKey = 39
const event = new KeyboardEvent('keydown',{'key':rightArrowKey})
document.dispatchEvent(event)
Run Code Online (Sandbox Code Playgroud)