491

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

4

24 回答 24

220

适用于 webkit 和 gecko 的非 jquery 版本:

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);

于 2012-08-29T22:18:11.157 回答
89

您可以像这样在EventTarget(元素、窗口、文档等)上分派键盘事件:

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

但是,dispatchEvent可能不会更新输入字段值,并且可能不会触发常规键盘按下的行为,可能是因为Event.isTrusted属性,我不知道是否有办法绕过

但是您也可以通过设置输入来更改输入value

element.value += "a";

例子:

let element = document.querySelector('input');
element.onkeydown = e => alert(e.key);
changeValButton.onclick = () => element.value += "a";
dispatchButton.onclick = () => {
   element.dispatchEvent(new KeyboardEvent('keydown', {'key': 'a'}));
}
<input/>
<button id="dispatchButton">Press to dispatch event </button>
<button id="changeValButton">Press to change value </button>


您可以根据需要向事件添加更多属性,如本答案所示。查看KeyboardEvent 文档

element.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.
}));

    

此外,由于keypress弃用,您可以使用keydown+ keyup,例如:

element.dispatchEvent(new KeyboardEvent('keydown', {'key':'Shift'} ));
element.dispatchEvent(new KeyboardEvent( 'keyup' , {'key':'Shift'} ));
于 2017-05-25T22:40:29.213 回答
79

如果您可以使用 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");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.3.1/jquery.min.js">
</script>

于 2009-02-27T20:36:55.923 回答
59

您可以做的是通过触发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...
  }
}

本示例改编自: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*/)      
   });

但是直到最近,还没有 [DOM] 方法可以真正触发离开浏览器沙箱的键事件。所有主要的浏览器供应商都将坚持这一安全理念。

至于像 Adob​​e Flash 这样基于 NPAPI 并允许绕过沙箱的插件:这些是逐步淘汰的火狐

详细说明:

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

有关替代方案和更多详细信息,请参阅此帖子。总是有基于闪存的复制和粘贴。这是一个优雅的 例子。同时,这也证明了网络正在远离插件供应商的原因。

在选择加入 CORS 策略以编程方式访问远程内容的情况下,应用了类似的安全思维方式。

答案是:
一般情况下,沙盒浏览器环境下是没有办法通过编程方式触发输入键的

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

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

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

于 2013-11-09T22:20:29.583 回答
39

截至 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.
  })
);

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

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

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

于 2019-11-30T04:20:59.747 回答
29

您可以使用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");
  }
}

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

于 2009-05-08T12:44:24.403 回答
27

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

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

最简单的形式是:

$('input').val('123');
$('input').change();
于 2013-07-04T17:28:48.227 回答
17

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

不再推荐此功能。尽管某些浏览器可能仍然支持它,但它可能已经从相关的 Web 标准中删除,可能正在被删除,或者可能仅出于兼容性目的而保留。避免使用它,并尽可能更新现有代码;请参阅本页底部的兼容性表以指导您的决定。请注意,此功能可能随时停止工作。

因此,由于该keypress事件是由两个因此触发的事件组合而成,并且对于相同的键keydown跟随它,因此只需一个接一个地生成事件:keyup

element.dispatchEvent(new KeyboardEvent('keydown',{'key':'Shift'}));
element.dispatchEvent(new KeyboardEvent('keyup',{'key':'Shift'}));
于 2017-11-23T11:55:24.270 回答
15

基于 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');
});

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

于 2011-10-02T15:11:25.297 回答
13

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

模型应该做:

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

然后对于每个字符:

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

然后,对于大多数人来说,可选:

  • 模糊(在带有目标集的 DOM 上调度)

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

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

于 2014-05-30T22:40:40.870 回答
8

只需使用 CustomEvent

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

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})
于 2015-12-04T19:00:05.020 回答
7

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

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);
于 2013-05-22T07:32:03.427 回答
5

我想模拟“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);

    setTimeout(function() {
      /*  event.keyCode = 13;  event.target.value += 'b';  */

      theKey = 'Tab';
      var e = new window.KeyboardEvent('focus', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keydown', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('beforeinput', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keypress', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('input', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('change', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keyup', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
    }, 4);

    setTimeout(function() {
      theKey = 'Tab';
      var e = new window.KeyboardEvent('focus', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keydown', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('beforeinput', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keypress', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('input', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('change', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keyup', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      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);
  }

});
<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>

于 2020-03-17T23:13:21.283 回答
5

这对我有用,它确实为我的 textaera 模拟了一个键盘。如果你想要它用于整个页面,只需KeySimulation()<body>这样<body onmousemove="KeySimulation()">或者如果不是onmousemove那么onmouseover或者onload也可以工作。

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>

于 2017-03-13T02:33:21.260 回答
4

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

我不知道它是从哪里来的,但它很有帮助。它向 中添加了一个.simulate()方法window.KeyEvent,因此您可以简单地使用它KeyEvent.simulate(0, 13)来模拟 aenterKeyEvent.simulate(81, 81)a 'Q'

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

于 2014-09-10T23:18:48.477 回答
4

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

只要您使用非弃用方法访问按键事件,例如key,您应该可以。

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

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

于 2019-08-12T17:26:35.010 回答
4

由于在控制台上下文中易于使用,它曾经是单排的。但可能仍然有用。

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);

于 2018-05-21T08:24:51.797 回答
2

支持 TypeScript 的原生 JavaScript 解决方案:

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

例子

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

于 2019-07-15T22:14:09.093 回答
2

这就是我在 chrome 中使用 js/typescript 所尝试的。感谢 这个答案的灵感。

var x = document.querySelector('input');

var keyboardEvent = new KeyboardEvent("keypress", { bubbles: true });
// you can try charCode or keyCode but they are deprecated
Object.defineProperty(keyboardEvent, "key", {
  get() {
    return "Enter";
  },
});
x.dispatchEvent(keyboardEvent);

{
  // example
  document.querySelector('input').addEventListener("keypress", e => console.log("keypress", e.key))
  // unfortunatelly doesn't trigger submit
  document.querySelector('form').addEventListener("submit", e => {
    e.preventDefault();
    console.log("submit")
  })
}

var x = document.querySelector('input');

var keyboardEvent = new KeyboardEvent("keypress", { bubbles: true });
// you can try charCode or keyCode but they are deprecated
Object.defineProperty(keyboardEvent, "key", {
  get() {
    return "Enter";
  },
});
x.dispatchEvent(keyboardEvent);
<form>
  <input>
</form>

于 2020-02-26T19:13:00.313 回答
2

这是适用于 Chrome 和 Chromium 的解决方案(仅测试过这些平台)。似乎 Chrome 有一些错误或自己的方法来处理键码,所以这个属性必须单独添加到 KeyboardEvent。

    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);
    }
    simulateKeydown(39, false, false, false);

于 2018-03-31T16:57:28.687 回答
1

我知道这个问题要求一种模拟按键的javascript方式。但对于那些正在寻找 jQuery 做事方式的人来说:

var e = jQuery.Event("keypress");
e.which = 13 //or e.keyCode = 13 that simulates an <ENTER>
$("#element_id").trigger(e); 
于 2019-03-11T13:30:53.830 回答
0

这是我设法找到的:

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)

于 2018-09-25T07:56:30.433 回答
0

只要用户按下有问题的键,您就可以存储对该键的引用并将其用于任何 HTML 其他元素:

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)">
<script>
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();
  }
}
</script>

如果您创建自己的事件,则可以设置 keyCode,您可以从任何真实的键盘事件中复制现有参数(忽略目标,因为它的 dispatchEvent 的工作)和:

ta = new KeyboardEvent('keypress',{ctrlKey:true,key:'Escape'})
于 2018-03-25T06:55:28.610 回答
0

基于@aljgom 的回答:

这对我很有用。与其将事件分派给 aljgom 建议的元素,不如将其分派给文档。

document.dispatchEvent(new KeyboardEvent("keydown", { key: "c" }));
于 2021-08-13T16:52:01.333 回答