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

Is it possible to simulate key press events programmatically?

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


在webkit和gecko中都可以使用的非jquery版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);


如果可以使用jQuery 1.3.1:

1
2
3
4
5
6
7
8
9
10
11
function simulateKeyPress(character) {
  jQuery.event.trigger({ type : 'keypress', which : character.charCodeAt(0) });
}

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

  simulateKeyPress("e");
});


您可以做的是通过触发关键事件以编程方式触发关键事件侦听器。从沙盒安全角度允许这样做是有意义的。使用此功能,然后可以应用典型的观察者模式。您可以将此方法称为"模拟"。

下面是一个如何在W3C DOM标准以及jQuery中完成此操作的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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...
  }
}

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

在jQuery中:

1
2
3
4
5
jQuery('input[type=submit][name=btnK]')
  .trigger({
    type: 'keypress',
    which: character.charCodeAt(0 /*the key to trigger*/)      
   });

但是从最近开始,还没有[DOM]方法来实际触发离开浏览器沙盒的键盘事件。所有主要的浏览器供应商都将遵守该安全概念。

至于基于NPAPI的Adobe Flash之类的插件,并允许绕过沙箱:这些插件正在逐步淘汰;火狐浏览器。

详细说明:

您不能也一定不能出于安全原因(正如Pekka已经指出的那样)。您之间总是需要用户交互。此外,想象一下浏览器供应商受到用户起诉的机会,因为各种编程性键盘事件将导致欺骗攻击。

有关替代方法和更多详细信息,请参见这篇文章。始终存在基于Flash的复制和粘贴。这是一个优雅的例子。同时,这也证明了为什么网络正在远离插件供应商。

在选择加入CORS策略的情况下,有一种类似的安全性思维方式适用于以编程方式访问远程内容。

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

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

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

披露:答案基于此处的答案。


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

1
element.dispatchEvent(new KeyboardEvent('keypress',{'key':'a'}));


您可以使用dispatchEvent()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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");
  }
}

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


您可以创建和调度键盘事件,它们将触发适当的注册事件处理程序,但是,例如,如果调度到输入元素,它们将不会产生任何文本。

要完全模拟文本输入,您需要产生一系列键盘事件,并显式设置输入元素的文本。事件的顺序取决于您要模拟文本输入的程度。

最简单的形式是:

1
2
$('input').val('123');
$('input').change();

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 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');
});

您甚至可以进一步推动它,让它不仅模拟事件,而且实际上插入字符(如果它是输入元素),但是尝试执行此操作时有很多跨浏览器的陷阱。最好使用更复杂的插件,例如SendKeys。


在某些情况下,keypress事件无法提供所需的功能。从mozilla文档中,我们可以看到该功能已被弃用:

This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time.

因此,由于keypress事件是由两个因此触发的事件keydown组合而成的,并且随后的keyup是相同的键,因此只需逐个生成事件:

1
2
element.dispatchEvent(new KeyboardEvent('keydown',{'key':'Shift'}));
element.dispatchEvent(new KeyboardEvent('keyup',{'key':'Shift'}));

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

该模型应执行以下操作:

  • 焦点(在设置了目标的DOM上调度)

然后,对于每个字符:

  • keydown(在DOM上调度)
  • beforeinput(如果目标是文本区域或输入,则在目标上调度)
  • 按键(在DOM上调度)
  • 输入(如果目标是文本区域或输入,则在目标上调度)
  • 更改(如果选择,则在目标上调度)
  • keyup(在DOM上调度)

然后,对于大多数情况(可选):

  • 模糊(在设置了目标的DOM上调度)

实际上,这会通过javascript更改页面中的文本(无需修改value语句),并适当地关闭所有javascript侦听器/处理程序。如果您弄乱了序列,则javascript不会以适当的顺序触发,输入框中的文本不会更改,选择内容也不会更改,或者光标不会移动到文本区域的下一个空格。

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


只需使用CustomEvent

1
2
3
4
5
6
7
Node.prototype.fire=function(type,options){
     var event=new CustomEvent(type);
     for(var p in options){
         event[p]=options[p];
     }
     this.dispatchEvent(event);
}

4前要模拟ctrl + z

1
2
3
4
5
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})


这种方法支持跨浏览器更改键码的值。
资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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);

这对我有用,它确实为我的textaera模拟了键盘输入。如果您希望整个页面都使用它,只需将KeySimulation()放在上,例如,否则将onmouseoveronload都可以。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}


<input type="button" onclick="KeySimulation();" value=" Key Simulation" />
<textarea id="MyTextArea" rows="15" cols="30"></textarea>


这是一个真正有用的库:https://cdn.rawgit.com/ccampbell/mousetrap/2e5c2a8adbe80a89050aaf4e02c45f02f1cc12d4/tests/libs/key-event.js

我不知道它是从哪里来的,但这很有帮助。它将.simulate()方法添加到window.KeyEvent,因此您可以将其与KeyEvent.simulate(0, 13)一起使用,以模拟enterKeyEvent.simulate(81, 81)来模拟'Q'

我在https://github.com/ccampbell/mousetrap/tree/master/tests获得了它。


这是可在Chrome和Chromium中使用的解决方案(仅测试了这些平台)。 Chrome似乎有一些Bug或自己的方法来处理键代码,因此必须将此属性单独添加到KeyboardEvent。

1
2
3
4
5
6
function simulateKeydown (keycode,isCtrl,isAlt,isShift){
    var e = new KeyboardEvent("keydown", { bubbles:true, cancelable:true, char:String.fromCharCode(keycode), key:String.fromCharCode(keycode), shiftKey:isShift, ctrlKey:isCtrl, altKey:isAlt } );
    Object.defineProperty(e, 'keyCode', {get : function() { return this.keyCodeVal; } });    
    e.keyCodeVal = keycode;
    document.dispatchEvent(e);
}


单行香草Java Web检查员准备在控制台中进行复制+粘贴(此家伙已经对大多数开发人员有吸引力,因此请不要假装他-他应该是单身。。。)

1
2
3
4
5
6
7
8
9
10
11
    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);

这是我设法找到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function createKeyboardEvent(name, key, altKey, ctrlKey, shiftKey, metaKey, bubbles) {
  var e = new Event(name)
  e.key = key
  e.keyCode = e.key.charCodeAt(0)
  e.which = e.keyCode
  e.altKey = altKey
  e.ctrlKey = ctrlKey
  e.shiftKey = shiftKey
  e.metaKey =  metaKey
  e.bubbles = bubbles
  return e
}

var name = 'keydown'
var key = 'a'

var event = createKeyboardEvent(name, key, false, false, false, false, true)

document.addEventListener(name, () => {})
document.dispatchEvent(event)

具有TypeScript支持的本机JavaScript解决方案:

输入keyCode或您正在使用的任何属性,并将其强制转换为KeyboardEventInit

1
2
3
const event = new KeyboardEvent("keydown", {
          keyCode: 38,
        } as KeyboardEventInit);

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

只要您使用不推荐使用的方法(例如key)访问按键事件,就可以了。

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

1
2
3
const rightArrowKey = 39
const event = new KeyboardEvent('keydown',{'key':rightArrowKey})
document.dispatchEvent(event)

用户按下相关键后,您甚至可以存储对该键的引用,并将其用于任何其他HTML元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
EnterKeyPressToEmulate<input class="lineEditInput" id="addr333_1" type="text" style="width:60%;right:0%;float:right" onkeydown="keyPressRecorder(event)"></input>
TypeHereToEmulateKeyPress<input class="lineEditInput" id="addr333_2" type="text" style="width:60%;right:0%;float:right" onkeydown="triggerKeyPressOnNextSiblingFromWithinKeyPress(event)">
Itappears Here Too<input class="lineEditInput" id="addr333_3" type="text" style="width:60%;right:0%;float:right;" onkeydown="keyPressHandler(event)">

var gZeroEvent;
function keyPressRecorder(e)
{
  gZeroEvent = e;
}
function triggerKeyPressOnNextSiblingFromWithinKeyPress(TTT)
{
  if(typeof(gZeroEvent) != 'undefined')  {
TTT.currentTarget.nextElementSibling.dispatchEvent(gZeroEvent);
keyPressHandler(TTT);
  }
}
function keyPressHandler(TTT)
{
  if(typeof(gZeroEvent) != 'undefined')  {
TTT.currentTarget.value+= gZeroEvent.key;
event.preventDefault();
event.stopPropagation();
  }
}

您可以在创建自己的事件时设置keyCode,也可以从任何真实的键盘事件中复制现有参数(由于它是dispatchEvent的工作而忽略目标),并且:

1
ta = new KeyboardEvent('keypress',{ctrlKey:true,key:'Escape'})


我知道这个问题需要一种模拟按键的JavaScript方法。但是对于那些正在寻找jQuery的工作方式的人:

1
2
3
var e = jQuery.Event("keypress");
e.which = 13 //or e.keyCode = 13 that simulates an <ENTER>
$("#element_id").trigger(e);