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


380

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


2
您可以澄清“模拟”吗?您的目标是测试您的网站,还是制定给定链接的onclick,onmousedown等功能?
Paulo

Answers:


180

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

8
菲利普,这看起来像我需要的代码,但我需要将keypress事件调度到文本区域。我试图修改您的代码以发送到textarea,但至少在chrome中,它似乎不起作用,任何想法可能出什么问题?这是我演示的jsfiddle
user280109 2012年

4
事实证明,使用KeyboardEvent分派在Chromium中存在一个错误。请查看此线程以获取更多详细信息:stackoverflow.com/questions/10455626/…
菲利普·努

26
keyCode始终为0,我无法更改。
Ata Iravani

9
似乎Chromium中存在一个错误,导致使用时该错误event.which始终存在。@lluft 在其他线程上的此评论中分享了详细信息和变通办法,这对我有用。基本上,您需要使用创建一个通用事件,然后将类型设置为,并赋予一个等于键的字符码的属性。0document.createEvent("KeyboardEvent")document.createEvent('Event')keydownkeyCode
A-Diddy

8
似乎此功能已被删除。MDN认为它已经过时了一段时间。
Tacticus

72

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

你好我的意思是:1,注册的关键事件(字母e执行一些JS)2.我希望通过编程按字母e)一另一种方法

9
抱歉,它无法在Chrome中正常运行。jQuery创建Event,但没有重要属性-其中的charCode,keyCode。
hamczu 2011年

4
@tan这是不可能的。请参阅我的答案以了解其背后的原因。
洛伦兹·洛绍尔


51

您可以做的是通过触发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]方法可以实际触发离开浏览器沙盒的键盘事件。所有主要的浏览器供应商都将遵守该安全概念。

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

详细说明:

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

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

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

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

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

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

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


因此,使用JavaScript KeyboardEvent API(developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent),您可以模拟按键事件,例如说按键被按下,但是不可能产生按键效果,就像写字符“ a”,“ b”,“ c”一样?如果可能的话,写这些基本字符不是安全问题,但我知道应该禁止使用特殊键(例如“ F12”或组合键“ Alt + F4”)。
baptx '16

1
这就是我在Chrome中运行jQuery时得到的信息:未捕获的ReferenceError:未定义字符
Jayden Lawson

29

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

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

12
我认为答案应该提到一个事实,即在js事件中调度不会更新输入内容。
基里尔·雷兹尼科夫

5
最新的Firefox不是现代的吗?
emix

似乎keypress已贬值,keydown改为使用-> developer.mozilla.org/zh-CN/docs/Web/Events/keypress
JMT2080AD

根据需要,它可以与Chrome Embedded完美配合。
PauloFrançaLacerda

25

您可以使用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()的文档。


15
注意:仅Gecko浏览器支持此功能。
lhunath

3
Gecko和其他浏览器不同意使用initKeyEvent还是initKeyboardEvent()。不推荐使用两者,而推荐使用KeyboardEvent()构造函数。
jkmartindale

21

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

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

最简单的形式是:

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

15

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

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

因此,由于该keypress事件是由两个随后触发的事件组合而成的keydown,并且keyup针对相同的密钥进行后续处理,因此只需一个一个地生成事件:

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

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

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


1
SendKeys不会模拟按键,它只是将值注入到目标元素中。
艾哈迈德·马苏德

2
不模拟硬件按键,仅调用绑定的按键功能。
Codebeat

8

对于感兴趣的人,您可以可靠地重新创建键盘输入事件。为了更改输入区域中的文本(通过输入字符移动光标或页面),您必须紧密遵循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为雇主编写的,因此我不能共享它,但是绝对有可能,但是您必须以正确的顺序为每个元素重新创建整个键输入“堆栈”。


8
NDA for JavaScript?真?,无论如何,对于您的算法错误的每个字符,模拟“输入”事件无论如何都会添加文本,而无需经历整个keydown,keyup事件或任何其他事件。问题是如何处理多个按键事件等,例如按下“ a”按钮并期望多次“ aaaaaaa”。
Akash Kava

1
诀窍是触发键盘按下,输入然后按下键盘。如果要多个“ aaaaaa”,请继续触发输入事件。而且不要告诉任何人。
特雷弗2014年

4
我尝试了一下,但是它似乎无法完全起作用:我可以触发Enter,Backspace或箭头键的事件,但不能触发字符。例如,尽管我严格遵循事件的顺序,但是我无法通过此方法输入文本。
Tacticus

@Tacticus偶然您仍然有根据此答案触发Enter的代码示例吗?
锡瓦斯(Siavas),

1
我尝试了这个,没有运气。
梅森

8

截至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所需元素。


1
这是在Qt QWebEngine runJavascript函数中对我有用的唯一解决方案。谢谢
Maxx

由于某些原因Flash游戏完全忽略了它(也许Flash忽略了所有不是Trusted?)
hanshenrik

@hanshenrik-坦白地说,如果您在2020年使用Flash,则确实需要重新考虑哪种工具最适合您的目的。
海莉

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

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

4前要模拟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})

我正在尝试您的代码。如果按一个键,我确实会进入侦听器,但是document.fire无效。
标记

“(”不是一个问题,我固定它的时候了它只是没有进入它document.fire后顺便说一句,我通过点击图标触发它。。
马克

我的代码是这样的:<img src =“ settings.svg” height =“ 22” width =“ 24” style =“ cursor:pointer;” ng-click =“ openAdminConsole()”>在openAdminConsole()中,我正在执行document.fire。那不正确吗?
标记


4

这对我有用,它确实为我的textaera模拟了键盘输入。如果你想整个页面只是把KeySimulation()<body>这样<body onmousemove="KeySimulation()">如果还是不行onmousemove,然后onmouseover还是onload作品了。

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

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

2
警告,initKeyboardEvent已弃用。(来源
射线影像

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

2

这是可在Chrome和Chromium中使用的解决方案(仅测试了这些平台)。Chrome似乎有一些bug或自己的方法来处理键码,因此必须将此属性单独添加到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);
}

1

这是我设法找到的:

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)

1

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

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

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

1

这就是我在chrome中使用js / typescript尝试过的方法。感谢 这个答案的启发。

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

const keyboardEvent = new KeyboardEvent("keypress", { bubbles: true });
Object.defineProperty(keyboardEvent, "charCode", {
  get() {
    return 13;
  },
});
x.dispatchEvent(keyboardEvent);

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

0

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

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

0

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

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

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

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

0

我想模拟一个“ 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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.