Javascript Chrome 中的 Keydown 模拟正常触发但不是正确的键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10455626/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 01:22:49  来源:igfitidea点击:

Keydown Simulation in Chrome fires normally but not the correct key

javascriptgoogle-chromejavascript-events

提问by fabricemarcelin

I want to simulate keydown events on a given textarea element in an html page. Since I am using chrome, I called initKeyboardEventon my variable and I passed the keyCode I want to type into the textarea. Here is what I tried:

我想在 html 页面中的给定 textarea 元素上模拟 keydown 事件。因为我使用的是 chrome,所以我调用initKeyboardEvent了我的变量,并将我想输入到 textarea 的 keyCode 传递给了我。这是我尝试过的:

var keyEvent = document.createEvent('KeyboardEvent');
keyEvent.initKeyboardEvent('keydown', true, false, null, 0, false, 0, false, 77, 0);
inputNode.dispatchEvent(keyEvent);

In this code I'm typing the letter mhowever the textarea is only getting the keyCode 13which is the Enterkey. So, I tried an override code I saw online that sets the value to keyCodeVal, but with no success

在这段代码中,我正在输入字母,m但是 textarea 只获取 keyCode13这是Enter关键。所以,我尝试了一个我在网上看到的将值设置为 keyCodeVal 的覆盖代码,但没有成功

var keyEvent = document.createEvent('KeyboardEvent');
Object.defineProperty(keyEvent, 'keyCode', { 
                         get : function() {
                                 return this.keyCodeVal;
                         }
                        });
keyEvent.initKeyboardEvent('keydown', true, false, null, 0, false, 0, false, 77, 0);
keyEvent.keyCodeVal = 77;
inputNode.dispatchEvent(keyEvent);

Does anyone have an idea how to set the keyCode value?

有谁知道如何设置 keyCode 值?

回答by Orwellophile

So very very close...

所以非常非常接近...

You just needed to override the 'which' property. Here's some sample code:

您只需要覆盖 'which' 属性。这是一些示例代码:

Podium = {};
Podium.keydown = function(k) {
    var oEvent = document.createEvent('KeyboardEvent');

    // Chromium Hack
    Object.defineProperty(oEvent, 'keyCode', {
                get : function() {
                    return this.keyCodeVal;
                }
    });     
    Object.defineProperty(oEvent, 'which', {
                get : function() {
                    return this.keyCodeVal;
                }
    });     

    if (oEvent.initKeyboardEvent) {
        oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, false, false, false, false, k, k);
    } else {
        oEvent.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, k, 0);
    }

    oEvent.keyCodeVal = k;

    if (oEvent.keyCode !== k) {
        alert("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ")");
    }

    document.dispatchEvent(oEvent);
}

Sample usage:

示例用法:

Podium.keydown(65);

Note: this code is not designed to work in IE, Safari, or other browsers. Well, maybe with Firefox. YMMV.

注意:此代码不适用于 IE、Safari 或其他浏览器。好吧,也许用 Firefox。天啊。

回答by termi

Orwellophile's solution does work.

Orwellophile 的解决方案确实有效。

  • First: 'keyCode', 'charCode' and 'which' is readonly in Safari and IE9+ (at least).
  • Second: initKeyboardEvent is kind of messy. All browsers implement it in a different way. Even in webkit's there are several different implementation of initKeyboardEvent. And there is no "good" way to initKeyboardEvent in Opera.
  • Third: initKeyboardEvent is deprecated. You need to use initKeyEvent or KeyboardEvent constructor.
  • 第一:'keyCode'、'charCode' 和 'which' 在 Safari 和 IE9+ 中是只读的(至少)。
  • 第二:initKeyboardEvent 有点乱。所有浏览器都以不同的方式实现它。即使在 webkit 中,initKeyboardEvent 也有几种不同的实现。在 Opera 中 initKeyboardEvent 没有“好”的方法。
  • 第三:不推荐使用 initKeyboardEvent。您需要使用 initKeyEvent 或 KeyboardEvent 构造函数。

Here I wrote a cross-browser initKeyboardEvent function(gist):

这里我写了一个跨浏览器的initKeyboardEvent函数(要点):

Example:

例子:

var a = window.crossBrowser_initKeyboardEvent("keypress", {"key": 1, "char": "!", shiftKey: true})
alert(a.type + " | " + a.key + " | " + a.char + " | " + a.shiftKey)

And here is my DOM Keyboard Event Level 3 polyfillwith cross-browser KeyboardEvent constructor.

这是我的DOM 键盘事件级别 3 polyfill,带有跨浏览器的 KeyboardEvent 构造函数。

Example:

例子:

var a = new KeyboardEvent("keypress", {"key": 1, "char": "!", shiftKey: true})
alert(a.type + " | " + a.key + " | " + a.char + " | " + a.shiftKey)

Example 2

示例 2

Example 3

示例 3

Important Note 1: charCode, keyCode and which properties is deprecated. So neither my crossBrowser_initKeyboardEvent no KeyboardEvent constructor is absolutely guaranteed right values of that properties in some browsers. You can using properties "key" and "char" instead or edit my gistto force using initEvent in browsers with read-only charCode, keyCode and which properties.

重要说明 1:不推荐使用 charCode、keyCode 和哪些属性。因此,我的 crossBrowser_initKeyboardEvent 和 KeyboardEvent 构造函数都不能绝对保证某些浏览器中该属性的正确值。您可以使用属性“key”和“char”来代替,或者编辑我的要点以强制在浏览器中使用只读 charCode、keyCode 和 which 属性使用 initEvent。

Important Note 2: keypress event is deprecated and for now unsupported in my Keyboard Event Level 3 polyfill. That's mean that key and char properties in keypress event can have random values. I am working to fix that problem to backward compatibility.

重要说明 2:keypress 事件已被弃用,目前在我的键盘事件级别 3 polyfill 中不受支持。这意味着 keypress 事件中的 key 和 char 属性可以具有随机值。我正在努力解决该问题以向后兼容。

回答by Dave Land

In order to get @Orwellophile's script to work on Google Chrome 26.0.1410.65 (on Mac OS X 10.7.5, if that matters), I had to change one line: his script appears to have the paramaters of initKeyboardEventin different order than the MDN documentation for initKeyboardEvent.

为了让@Orwellophile 的脚本在 Google Chrome 26.0.1410.65 上运行(在 Mac OS X 10.7.5 上,如果这很重要),我不得不更改一行:他的脚本的参数似乎initKeyboardEventMDN 的顺序不同initKeyboardEvent 的文档

The changed line looks like this:

更改后的行如下所示:

oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, k, k, "", "", false, "");

回答by Ankit

Well the above solutions did work, also thanks to @dland for the parameter tip. Here is something I found useful, if you are not able to get the events firing at the right place.

好吧,上述解决方案确实有效,还要感谢@dland 提供参数提示。如果您无法在正确的位置触发事件,我发现这里有一些有用的东西。

The @Orwellophile's script fires the event on document. It may be possible that the event listener is not always registered on document. I changed the last line to following and now it pretty much works every time.

@Orwellophile 的脚本在文档上触发事件。事件侦听器可能并不总是在 上注册document。我将最后一行更改为以下内容,现在几乎每次都有效。

document.activeElement.dispatchEvent(oEvent);

document.activeElement.dispatchEvent(oEvent);

The document.activeElementalways fires the event on the element where the user is currently focusing on.

document.activeElement始终激发了用户目前的重点是在元素上的事件。

回答by Fruch

All the solutions above are working, but I've found one case they won't.

上面的所有解决方案都有效,但我发现一种情况他们不会。

If Dart is being used, Dart code that uses KeyboardEvents won't work on a general Event.

如果正在使用 Dart,则使用 KeyboardEvents 的 Dart 代码将不适用于一般事件。

You'll get something like get$keyCode is undefined.

你会得到类似 get$keyCode 未定义的信息。

after banging my head for hours on this, I've found the following trick:

在为此敲了几个小时后,我发现了以下技巧:

function __triggerKeyboardEvent(el, keyCode)
{
   var eventObj = document.createEventObject ?
       document.createEventObject() : document.createEvent("Events");

   var tempKeyboardObj = document.createEvent("KeyboardEvents");

   if(eventObj.initEvent){
      eventObj.initEvent("keydown", true, true);
   }
   eventObj.___dart_dispatch_record_ZxYxX_0_ = tempKeyboardObj.___dart_dispatch_record_ZxYxX_0_
   eventObj.keyCode = keyCode;
   eventObj.which = keyCode;

   el.dispatchEvent ? el.dispatchEvent(eventObj) : el.fireEvent("onkeydown", eventObj);

} 

Fooling Dart interceptor to thing our Event is actually a KeyboardEvent, did the trick.

愚弄 Dart 拦截器认为我们的事件实际上是一个 KeyboardEvent,成功了。

Leaving it here, for the poor guy that is trying to test Dart app on a webkit based browser.

把它留在这里,对于试图在基于 webkit 的浏览器上测试 Dart 应用程序的可怜人。