Включение события клавиатуры в Chrome

Я пытаюсь запустить событие клавиатуры на странице, используя JavaScript в Chrome. У меня был подход, который раньше работал на 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);
}

где ключ - это требуемый ключ, а keyCode заменяет строчные буквы на строчные, а также вызывает charCodeAt().

Моя проблема в том, что события в Safari / Chrome имеют не initKeyEvent, а initKeyboardEvent. Основное отличие, которое я мог заметить, заключалось в том, что вы должны передавать ключ как keyIdentifier (который выглядит как символ Юникода) вместо передачи кода ключа и ключевого символа. Тем не менее, я все еще не могу заставить это работать.

Я также попробовал описанный здесь подход JQuery, но безуспешно.

РЕДАКТИРОВАТЬ: я отладил это немного дальше, и кажется, что событие в Chrome действительно вызывает слушателей, но keyCode/charCode всегда 0. Я пытался установить evt.keyCode или evt.charCode, но безуспешно.

5 ответов

Решение

Я просто хочу выбросить этот базовый фрагмент. Он работает в Chrome и основан на взломе, упомянутом Полом Айришем.
Он использует 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);

Я проследил это до ошибки в Webkit, когда созданные события содержат только KeyIdentifier, но не содержат keyCode/charCode, как это видно в исходном коде браузера. Кажется, есть патч, чтобы решить эту проблему. Так что я думаю, что это не правильный вопрос больше...

Если вы хотите сделать это правильно, вы можете использовать конструкцию и ключ Keyboard Event Event уровня 4 уровня Keyboard.

В последних браузерах или с полифилом DOM Keyboard Event Level 3/4 вы можете сделать что-то вроде этого:

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

Обратите внимание, что keyCode и charCode устарели в последней спецификации (www.w3.org/TR/DOM-Level-3-Events/). Таким образом, у Chrome нет шансов реализовать initKeyEvent с поддержкой keyCode. Но вы всегда можете переопределить это значение: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: плохой метод:

// 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. В моем polyfill KeyboardEvent я обнаруживаю это как-то так ( суть):

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://stackru.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 );
        }
    }
}

Вы можете обойти ошибку Webkit, используя createEvent('Event') скорее, чем createEvent('KeyboardEvent'), а затем присваивая keyCode имущество. Смотрите этот ответ и этот пример.

В зависимости от ваших потребностей, 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);
Другие вопросы по тегам