【问题标题】:Firing a keyboard event on Chrome在 Chrome 上触发键盘事件
【发布时间】:2010-12-26 05:20:06
【问题描述】:

我正在尝试在 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。尽管如此,我仍然无法让它工作。

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

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

【问题讨论】:

  • 我已经从问题中删除了一条评论并作为答案,因为我认为即使它并不能真正解决问题,它可能对和我有同样问题的人真的很有帮助做了。
  • 嘿,你是怎么解决这个问题的?我还面临在 chrome/safari 上模拟左右按键的问题。但是没有成功,你是怎么做到的?
  • 您尝试过我发布的解决方案吗?它对我有用,可能会帮助你实现目标,所以我很奇怪你接受了自己的“这是一个错误”的答案。

标签: javascript google-chrome webkit


【解决方案1】:

我只是想把这个基本的 sn-p 扔出去。它可以在 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);

【讨论】:

    【解决方案2】:

    如果您想以正确的方式进行操作,可以使用 DOM Keyboard Event Level 4 KeyboardEvent 构造和 key 属性。

    在最新的浏览器或DOM Keyboard Event Level 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})
    

    Example

    "map event.key to character values of a normal QUERTY (en-US) layout" proposal demo

    请注意,keyCodecharCode 在最新规范 (www.w3.org/TR/DOM-Level-3-Events/) 中已弃用。因此,Chrome 没有机会在 keyCode 支持下实现 initKeyEvent。但是你总是可以覆盖这个值: 更新:错误的方法:

    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事件原型:UPDATE:坏方法:

    // 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 中,我以某种方式检测到它(gist):

    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 从未真正被调用过。
    • "第一次失败,因为 keyCode 属性不可配置。"我正在更新我的 polyfill 以修复各种错误和浏览器兼容性
    【解决方案3】:

    您可以使用createEvent('Event') 而不是createEvent('KeyboardEvent') 解决Webkit 错误,然后分配keyCode 属性。见this answerthis example

    【讨论】:

    • 两者有一个区别。如果您在 WebKit 中使用 createEvent("Events") 并将带有 keyCode 13 的事件发送到表单元素,它实际上并没有模仿返回键。如果有一个监听器在监听 keyCode 13,它会触发它,但与 Firefox 相比,它确实模仿键盘上的返回键并提交表单。只处理这个问题一天左右,并认为我会分享。 :)
    【解决方案4】:

    根据您的需要,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);
    

    【讨论】:

    【解决方案5】:

    我已将其追踪到 bug on Webkit,其中创建的事件仅包含 KeyIdentifier,但没有 keyCode/charCode,如 browser source code 所示。似乎有一个补丁正在解决这个问题。所以我想这不再是一个合适的问题了......

    【讨论】:

    • 人们在这里报告了这个漂亮的 hack 的成功:stackoverflow.com/a/10520017/89484
    • 此后发生了两件事: 1. 去年我加入了 Chrome 团队,并将这个 bug 分配给了自己; 2. 我放弃了修复这个问题,因为新标准似乎弃用了这个功能(而且在所有平台上修复这个错误都非常困难)。
    猜你喜欢
    • 2011-03-06
    • 2013-09-22
    • 2013-03-12
    • 2012-09-09
    • 2016-08-30
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    • 2013-10-23
    相关资源
    最近更新 更多