在 Chrome 上触发键盘事件

IT技术 javascript google-chrome webkit
2021-01-26 09:25:14

我正在尝试在 Chrome 上使用 javascript 向页面触发键盘事件。我有一种曾经在 Firefox 上工作的方法:

pressKey = function(key, shift) {
  var evt = document.createEvent('KeyboardEvent');
  evt.initKeyEvent("keypress", false, true, null, false, false,
                   shift, false, keyCode(key), key.charCodeAt(0));
  document.dispatchEvent(evt);
}

其中 key 是所需的键,keyCode 将小写字母更改为大写字母并调用 charCodeAt()。

我的问题是 Safari/Chrome 上的事件没有 initKeyEvent,而是 initKeyboardEvent。我注意到的主要区别是您必须将密钥作为 keyIdentifier(看起来像一个 unicode 字符)传递,而不是传递 keycode 和 keychar。尽管如此,我仍然无法使其工作。

我也尝试过这里描述的 JQuery 方法但没有成功。

编辑: 我进一步调试了这一点,似乎 Chrome 上的事件确实触发了侦听器,但 keyCode/charCode 始终为 0。我尝试设置 evt.keyCode 或 evt.charCode 也没有成功。

5个回答

我已经将此追溯到Webkit上的一个错误,其中创建的事件仅包含 KeyIdentifier 但没有在浏览器源代码上可以看到的 keyCode/charCode 似乎有一个补丁正在解决这个问题。所以我想这不再是一个合适的问题了......

人们在这里报告了这个漂亮的黑客成功:stackoverflow.com/a/10520017/89484
2021-04-01 09:25:14
此后发生了两件事: 1. 去年我加入了 Chrome 团队,并将这个 bug 分配给了自己;2. 我放弃了修复这个问题,因为新标准似乎不赞成这个功能(而且很难在所有平台上修复这个错误)。
2021-04-08 09:25:14

如果您想以正确的方式进行操作,您可以使用 DOM键盘事件级别 4 KeyboardEvent 构造和属性。

在最新的浏览器或DOM 键盘事件级别 3/4 polyfill 中,您可以执行以下操作:

element.addEventListener(function(e){ console.log(e.key, e.char, e.keyCode) })

var e = new KeyboardEvent("keydown", {bubbles : true, cancelable : true, key : "Q", char : "Q", shiftKey : true});
element.dispatchEvent(e);

//If you need legacy property "keyCode".
// Note: In some browsers you can't overwrite "keyCode" property. (At least in Safari)
delete e.keyCode;
Object.defineProperty(e, "keyCode", {"value" : 666})

例子

“将 event.key 映射到普通 QUERTY(en-US)布局的字符值”提案演示

请注意,最新的规范 (www.w3.org/TR/DOM-Level-3-Events/) 中不推荐使用keyCodecharCode所以 Chrome 没有机会实现带有keyCode支持的initKeyEvent但是你总是可以覆盖这个值: UPDATE : bad method:

var evt = document.createEvent('KeyboardEvent');
evt.initKeyEvent("keypress", false, true, null, false, false,
               shift, false, keyCode(key), key.charCodeAt(0));
if(evt.keyCode != keyCode(key)) {
    delete evt.keyCode;
    // Note: In some browsers you can't overwrite "keyCode" property. (At least in Safari)
    Object.defineProperty(evt, "keyCode", { keyCode(key) });
}

或者你可以更新事件原型:UPDATE : bad method:

// Note: In some browsers you can't overwrite "keyCode" property. (At least in Safari)
var _native_keyCode_getter = Object.getOwnPropertyDescriptor(KeyboardEvent.prototype, "keyCode");
Object.defineProperty(KeyboardEvent.prototype, "keyCode", {
    "enumerable" : true,
    "configurable" : true,
    "get" : function() {
        if("__keyCode" in this)return this["__keyCode"];

        return _native_keyCode_getter.call(this);
    },
    "set" : function(newValue) {
        return this["__keyCode"] = isNaN(newValue) ? 0 : newValue;
    }
});    

更新 initKeyboardEvent 有多种实现。在我的 KeyboardEvent polyfill 中,我以某种方式检测到它(要点):

var _initKeyboardEvent_type = (function( e ) {
    try {
        e.initKeyboardEvent(
            "keyup" // in DOMString typeArg
            , false // in boolean canBubbleArg
            , false // in boolean cancelableArg
            , global // in views::AbstractView viewArg
            , "+" // [test]in DOMString keyIdentifierArg | webkit event.keyIdentifier | IE9 event.key
            , 3 // [test]in unsigned long keyLocationArg | webkit event.keyIdentifier | IE9 event.location
            , true // [test]in boolean ctrlKeyArg | webkit event.shiftKey | old webkit event.ctrlKey | IE9 event.modifiersList
            , false // [test]shift | alt
            , true // [test]shift | alt
            , false // meta
            , false // altGraphKey
        );
        return ((e["keyIdentifier"] || e["key"]) == "+" && (e["keyLocation"] || e["location"]) == 3) && (
            e.ctrlKey ?
                e.altKey ? // webkit
                    1
                    :
                    3
                :
                e.shiftKey ?
                    2 // webkit
                    :
                    4 // IE9
            ) || 9 // FireFox|w3c
            ;
    }
    catch ( __e__ ) { alert("browser do not support KeyboardEvent") }
})( document.createEvent( "KeyboardEvent" ) );

var e = document.createEvent( "KeyboardEvent" );
...
if( "initKeyEvent" in e ) {//FF
    //https://developer.mozilla.org/en/DOM/event.initKeyEvent
    e.initKeyEvent( type, _bubbles, _cancelable, _view, _ctrlKey, _altKey, _shiftKey, _metaKey, _keyCode, _keyCode );
}
else if( "initKeyboardEvent" in e ) {//https://developer.mozilla.org/en/DOM/KeyboardEvent#initKeyboardEvent()
    if( _try_initKeyboardEvent ) {
        if( _initKeyboardEvent_type == 1 ) { // webkit
            //http://stackoverflow.com/a/8490774/1437207
            //https://bugs.webkit.org/show_bug.cgi?id=13368
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _key, _location, _ctrlKey, _shiftKey, _altKey, _metaKey, _altGraphKey );
        }
        else if( _initKeyboardEvent_type == 2 ) { // old webkit
            //http://code.google.com/p/chromium/issues/detail?id=52408
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _ctrlKey, _altKey, _shiftKey, _metaKey, _keyCode, _keyCode );
        }
        else if( _initKeyboardEvent_type == 3 ) { // webkit
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _key, _location, _ctrlKey, _altKey, _shiftKey, _metaKey, _altGraphKey );
        }
        else if( _initKeyboardEvent_type == 4 ) { // IE9
            //http://msdn.microsoft.com/en-us/library/ie/ff975297(v=vs.85).aspx
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _key, _location, _modifiersListArg, _repeat, _locale );
        }
        else { // FireFox|w3c
            //http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent-initKeyboardEvent
            //https://developer.mozilla.org/en/DOM/KeyboardEvent#initKeyboardEvent()
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _char, _key, _location, _modifiersListArg, _repeat, _locale );
        }
    }
}
您建议的解决方法都不起作用。第一个失败,因为该keyCode属性不可配置。第二个是因为get从未实际调用属性描述符
2021-03-20 09:25:14
“第一个失败,因为 keyCode 属性不可配置。” 我正在更新我的 polyfill 以修复各种错误和浏览器兼容性
2021-04-11 09:25:14

我只想把这个基本的片段放在那里。它适用于 Chrome,基于 Paul Irish 提到的 hack。
它使用 charCode 而不是 keyCode(在某些情况下很有用),但如果您愿意,可以适应 keyCode。

var keyboardEvent = new KeyboardEvent('keypress', {bubbles:true}); 
Object.defineProperty(keyboardEvent, 'charCode', {get:function(){return this.charCodeVal;}}); 
keyboardEvent.charCodeVal = [your char code];
document.body.dispatchEvent(keyboardEvent);

根据您的需要,TextEvent 可能会起作用。(它对我的需求有用 - 对于 chrome。这不是跨浏览器测试的,但是,问题是专门关于 chrome 的。)

// get a reference to the DOM element you want to affect
var input = document.getElementsByTagName('input')[0];
// create a TextEvent
var textEvent = document.createEvent('TextEvent');
// initialize the TextEvent
textEvent.initTextEvent('textInput', true, true, null, String.fromCharCode(13)+"\r\n", 9, "en-US");
// dispatch ('fire') the TextEvent
input.dispatchEvent(textEvent);
尽管这会触发事件,但它实际上并未插入文本。Chrome 61 中的安全“功能”?- 试试这个,它不起作用gist.github.com/flying19880517/3180456
2021-04-03 09:25:14

您可以使用createEvent('Event')而不是createEvent('KeyboardEvent'),然后分配keyCode属性来解决 Webkit 错误请参阅此答案此示例

两者之间有一个区别。如果您在 WebKit 中使用 createEvent("Events") 并将带有 keyCode 13 的事件发送到表单元素,它实际上并不会模仿返回键。如果有一个侦听器监听 keyCode 13,它会触发它,但与 Firefox 相比,它实际上模仿了键盘上返回键的按下并提交了表单。已经处理了一天左右的这个问题,并认为我会分享。:)
2021-03-31 09:25:14