是否有可能以编程方式模拟按键事件?

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

742471 次浏览

如果你可以使用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>

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

在alex2k8的基础上,这里有一个修订版,可以在jQuery支持的所有浏览器中工作(问题是缺少jQuery.event的参数。触发器,在使用内部函数时很容易忘记它)。

// 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

一个非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);

这种方法支持跨浏览器更改关键代码的值。 # EYZ0 < / p >
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);

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

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

最简单的形式是:

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

您可以通过编程方式触发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*/)
});

所有主要的浏览器供应商都将遵守这一安全概念。

至于像Adobe Flash这样的基于NPAPI的插件,并允许绕过沙盒:这些是逐步淘汰;# EYZ1。

详细解释:

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

有关替代方案和更多细节,请参阅帖子。总是有基于flash的复制粘贴。这是一个优雅的例子。同时,它也证明了为什么网络正在远离插件供应商。

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

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

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

在KeyCodes的上下文中,工具和keycode映射将派上用场。

答案基于答案在这里

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

该模型应该做到:

  • 焦点(使用目标设置在DOM上分派)

然后对于每个字符:

  • keydown(在DOM上分派)
  • Beforeinput(如果它是一个文本区域或输入,在目标分派)
  • 按键(在DOM上分派)
  • 输入(如果是文本区域或输入,则在目标处分派)
  • 改变(如果它是一个选择,在目标分派)
  • keyup(在DOM上分派)

然后,可选的大多数:

  • 模糊(随目标设置在DOM上分派)

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

不幸的是,代码是为雇主写的保密协议,所以我不能分享它,但这是绝对可能的,但你必须重新创建整个关键输入“堆栈”;每个元素的正确顺序。


编辑:我不是这个答案的原始海报,但我已经测试过了,我不能让它更新输入字段。下面是一个代码片段,其中的代码供其他人尝试或查看

let element = document.querySelector('input');
element.onkeydown = e => console.log('keydown on element: ' +  e.key);
document.onkeydown = e => console.log('keydown on document: ' + e.key + " " + e.target);
dispatchButton.onclick = () => dispatchKey(element, 'a')


dispatchKey = (target, key) => {
let dom = document;
// focus (dispatched on the DOM with the target set)
let ev = new Event('focus', {target: target});
// this part seems to not work? when logging the
// target in the onkeypress function it shows `document` instead of `input`
// I also tried these and got the same behavior
//    ev.target = target;
// and
//    Object.defineProperty(ev, 'target', {writable: false, value: target});
dom.dispatchEvent(ev);
// keydown (dispatched on the DOM)
dom.dispatchEvent(new KeyboardEvent('keydown', {'key': key, target: target}));
// beforeinput (dispatched at the target if it's a textarea or input)
target.dispatchEvent(new Event('beforeinput'));
// keypress (dispatched on the DOM)
dom.dispatchEvent(new KeyboardEvent('keypress', {'key': key}));
// input (dispatched at the target if it's a textarea or input)
target.dispatchEvent(new Event('input'));
// change (dispatched at the target if it's a select)


// keyup (dispatched on the DOM)
dom.dispatchEvent(new KeyboardEvent('keyup', {'key': key}));
// Then, optionally for most:
// blur (dispatched on the DOM with the target set)
dom.dispatchEvent(new Event('blur', {target: target}));
console.log('dispatched');
}
<input/>
<button id="dispatchButton">Press to dispatch events </button>

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

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

我在https://github.com/ccampbell/mousetrap/tree/master/tests买的。

只需使用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})

这对我来说是有效的,它确实为我的textaera模拟了一个按键。如果你想在整个页面中使用它,只需将KeySimulation()放在<body>上,比如<body onmousemove="KeySimulation()">,如果不是onmousemove,那么onmouseoveronload也可以。

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>

你可以在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'} ));

对于使用ReactJS的页面,这是一个线程,用于尝试模拟键盘行为

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

不再推荐使用此特性。虽然一些浏览器可能仍然支持它,但它可能已经从相关的网络标准中删除了,可能正在被删除的过程中,或者可能只是为了兼容性的目的而保留。避免使用它,并尽可能更新现有代码;请参阅本页底部的兼容性表,以指导您的决定。请注意,此功能可能在任何时候停止工作。

因此,由于keypress事件是由两个随后触发的事件keydown和下面的事件keyup组合而成的,对于同一个键,只需要一个一个地生成事件:

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

只要用户按下有问题的键,你就可以存储对该even的引用,并将其用于任何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'})

下面是一个在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);

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

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

这是我找到的:

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)

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

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

本地JavaScript与TypeScript支持的解决方案:

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

例子

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

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

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

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

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

截至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事件,也可以通过在代码片段中将"keydown"更改为"keyup"来模拟keyup事件。

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

这就是我在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>

我想模拟按Tab键……在特雷弗的回答上展开,我们可以看到像'tab'这样的特殊键确实被按下了,但我们看不到'tab'按下的实际结果……

尝试与调度这些事件的'activeElement'以及全局文档对象都-代码添加下面;

# EYZ0如下:

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


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

基于@aljgom的回答:

这对我来说很有效。而不是像aljgom建议的那样将事件分派给元素,而是将它分派给文档。

document.dispatchEvent(new KeyboardEvent("keydown", { key: "c" }));

你可以用下面的代码模拟输入密码:

铬测试 100%工作

DoCustomEvent('password', '#loginpin');






function DoCustomEvent(ct, elem){
var key;
var pressEvent = document.createEvent("CustomEvent");
pressEvent.initCustomEvent("keypress", true, false);


for (var i =0; i < ct.length; ++i)
{
key                     = ct.charCodeAt(i);
pressEvent.bubbles      = true;
pressEvent.cancelBubble = false;
pressEvent.returnValue  = true;
pressEvent.key          = ct.charAt(i);
pressEvent.keyCode      = key;
pressEvent.which        = key;
pressEvent.charCode     = key;
pressEvent.shiftKey     = false;
pressEvent.ctrlKey      = false;
pressEvent.metaKey      = false;


document.querySelector(elem).focus();


//keypress //beforeinput //input //sendkeys //select
setTimeout(function() {
var e = new window.KeyboardEvent('keypress', pressEvent);
document.activeElement.dispatchEvent(e);
e = new window.KeyboardEvent('input', pressEvent);
document.activeElement.dispatchEvent(e);


}, 0);


document.querySelector(elem).value = document.querySelector(elem).value + ct.charAt(i);
}