Можно ли программно моделировать события нажатия клавиш?

Можно ли программно моделировать события нажатия клавиш в JavaScript?

28 ответов

Версия без 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, // viewArg: should be window
                    false, // ctrlKeyArg
                    false, // altKeyArg
                    false, // shiftKeyArg
                    false, // metaKeyArg
                    40, // keyCodeArg : unsigned long the virtual key code, else 0
                    0 // charCodeArgs : unsigned long the Unicode character associated with the depressed key, else 0
);
document.dispatchEvent(keyboardEvent);

Вы можете отправлять события клавиатуры на элемент, подобный этому

element.dispatchEvent(new KeyboardEvent('keypress',{'key':'a'}));

Если вы в порядке использовать 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");
});

То, что вы можете сделать, это программно запускать слушатели ключевых событий путем запуска ключевых событий. Имеет смысл разрешить это с точки зрения безопасности. Используя эту способность, вы можете применить типичный шаблон наблюдателя. Вы можете назвать этот метод "имитацией".

Ниже приведен пример того, как этого добиться в стандарте 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*/)      
   });

Но с недавнего времени [DOM] не существует способа вызвать события, оставляющие браузер-песочницу. И все основные производители браузеров будут придерживаться этой концепции безопасности.

Что касается плагинов, таких как Adobe Flash, которые основаны на NPAPI и позволяют обходить песочницу: это постепенный отказ; Firefox.

Детальное объяснение:

Вы не можете и не должны по соображениям безопасности (как уже указывал Пекка). Вы всегда будете требовать взаимодействия пользователя между ними. Кроме того, представьте, что пользователи браузеров могут подать в суд на пользователей, поскольку различные программные события на клавиатуре приведут к подделке атак.

Смотрите этот пост для альтернатив и более подробной информации. Всегда есть флэш на основе копирования и вставки. Вот элегантный пример. В то же время это свидетельство того, почему Интернет отходит от поставщиков плагинов.

В случае применения политики CORS opt-in для аналогичного доступа к удаленному контенту применяется аналогичный подход к безопасности.

Ответ:
В нормальных условиях нет возможности программно запускать клавиши ввода в изолированной среде браузера.

Итог: я не говорю, что это не будет возможно в будущем, при специальных режимах браузера и / или привилегиях для достижения конечной цели игры или подобного пользовательского опыта. Однако до входа в такие режимы у пользователя будут запрашиваться разрешения и риски, аналогичные модели полноэкранного API.

Полезно: в контексте KeyCodes этот инструмент и сопоставление кодов ключей пригодятся.

Раскрытие: ответ основан на ответе здесь.

По состоянию на 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 события тоже можно смоделировать keyup события путем изменения "keydown" к "keyup" во фрагменте кода.

Это также отправляет событие на всю веб-страницу, поэтому document. Если вы хотите, чтобы событие получал только определенный элемент, вы можете заменитьdocument для желаемого элемента.

Ты можешь использовать 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().

Вы можете создавать и отправлять события клавиатуры, и они будут запускать соответствующие зарегистрированные обработчики событий, однако они не будут генерировать никакого текста, если отправлены, например, в элемент ввода.

Чтобы полностью имитировать ввод текста, необходимо создать последовательность событий клавиатуры и явно указать текст элемента ввода. Последовательность событий зависит от того, насколько тщательно вы хотите смоделировать ввод текста.

Простейшая форма будет:

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

В некоторых случаях keypress событие не может обеспечить требуемую функциональность, как правило, события объединяются из двух последовательно инициируемых событий keydownи следующий за ним keyup для того же ключа. Так что просто генерируйте события один за другим:

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

Для тех, кто заинтересован, вы можете надежно воссоздать события ввода с клавиатуры. Чтобы изменить текст в области ввода (перемещать курсоры или страницу с помощью вводимого символа), необходимо внимательно следовать модели событий DOM: http://www.w3.org/TR/DOM-Level-3-Events/

Модель должна делать:

  • focus (отправляется на DOM с установленной целью)

Тогда для каждого персонажа:

  • keydown (отправляется на DOM)
  • beforeinput (отправляется на цель, если это текстовое поле или вход)
  • нажатие клавиши (отправлено на DOM)
  • input (отправляется на цель, если это textarea или input)
  • изменить (отправляется на цель, если его выбор)
  • keyup (отправляется на DOM)

Тогда, по выбору, для большинства:

  • размытие (отправляется на DOM с установленной целью)

Это фактически изменяет текст на странице через javascript (без изменения операторов значений) и соответственно отключает любые прослушиватели / обработчики javascript. Если вы ошибетесь в последовательности, javascript не будет запущен в соответствующем порядке, текст в поле ввода не изменится, выбор не изменится или курсор не переместится на следующий пробел в текстовой области.

К сожалению, код был написан для работодателя под NDA, поэтому я не могу поделиться им, но это определенно возможно, но вы должны воссоздать весь "стек" ввода ключа для каждого элемента в правильном порядке.

Основываясь на ответе alex2k8, вот пересмотренная версия, которая работает во всех браузерах, которые поддерживает jQuery (проблема заключалась в отсутствии аргументов в jQuery.event.trigger, что легко забыть при использовании этой внутренней функции).

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

Просто используйте 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 бывших хотят симулировать 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})

Я хотел смоделировать нажатие "Tab"... Расширяя ответ Тревора, мы видим, что специальная клавиша, такая как "tab", действительно нажимается, но мы не видим фактического результата, который имел бы нажатие "tab"...

попытался отправить эти события как для "activeElement", так и для глобального объекта документа - код для обоих добавлен ниже;

фрагмент ниже:

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

    setTimeout(function() {
      /*  event.keyCode = 13;  event.target.value += 'b';  */

      theKey = 'Tab';
      var e = new window.KeyboardEvent('focus', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keydown', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('beforeinput', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keypress', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('input', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('change', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
      e = new window.KeyboardEvent('keyup', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.activeElement.dispatchEvent(e);
    }, 4);

    setTimeout(function() {
      theKey = 'Tab';
      var e = new window.KeyboardEvent('focus', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keydown', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('beforeinput', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keypress', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('input', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('change', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      document.dispatchEvent(e);
      e = new window.KeyboardEvent('keyup', {
        bubbles: true,
        key: theKey,
        keyCode: 9,
        charCode: 0,
      });
      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>

Этот подход поддерживает кросс-браузерное изменение значения кода ключа. Источник

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

Единственный ванильный парень веб-инспектора Javascript, готовый для консоли в копировании + вставке (этот парень уже привлекателен для большинства разработчиков, так что не пытайтесь его приукрашивать - он должен быть одиноким.. гребным)

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

Важнейшая часть того, чтобы это работало, - это осознать, что charCode, keyCode а также whichявляются все устаревшие методы. Следовательно, если код, обрабатывающий событие нажатия клавиши, использует любой из этих трех, то он получит ложный ответ (например, значение по умолчанию - 0).

Пока вы получаете доступ к событию нажатия клавиши нерекомендуемым методом, например key, все должно быть в порядке.

Для завершения я добавил базовый код Javascript для запуска события:

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

Это сработало для меня, и это имитирует keyup для моей textaera. если вы хотите это для всей страницы, просто поставьте KeySimulation() на <body> как это <body onmousemove="KeySimulation()"> или если нет onmousemove затем onmouseover или же onload тоже работает

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

<input type="button" onclick="KeySimulation();" value=" Key Simulation " />
<textarea id="MyTextArea" rows="15" cols="30"></textarea>

Вот библиотека, которая действительно помогает: https://cdn.rawgit.com/ccampbell/mousetrap/2e5c2a8adbe80a89050aaf4e02c45f02f1cc12d4/tests/libs/key-event.js

Я не знаю, откуда это взялось, но это полезно. Добавляет .simulate() метод для window.KeyEventтак что вы используете его просто с KeyEvent.simulate(0, 13) для моделирования enter или же KeyEvent.simulate(81, 81) для 'Q',

Я получил его по адресу https://github.com/ccampbell/mousetrap/tree/master/tests.

вы можете имитировать ввод пароля с помощью этого кода:

проверено на хроме 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);
}

Собственный JavaScript с решением, поддерживаемым TypeScript:

Введите keyCode или любое другое свойство, которое вы используете, и приведите его к KeyboardEventInit.

пример

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

Вот решение, которое работает в 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);
}

Это то, что я пробовал с js/typescript в chrome. Спасибо этому ответу за вдохновение.

const x = document.querySelector('input');

const keyboardEvent = new KeyboardEvent("keypress", { bubbles: true });
Object.defineProperty(keyboardEvent, "charCode", {
  get() {
    return 13;
  },
});
x.dispatchEvent(keyboardEvent);

Каждые несколько лет я натыкаюсь на этот вопрос и трачу час проб и ошибок в поисках ответа, который работает в Firefox. К сожалению, я пока не нашел здесь ни одного. Может быть, эти ответы сработали в какой-то момент, но больше не работают?

Единственное, что я нашел, это работающая библиотека под названием bililiteRange. У него есть функция sendkeys (обратите внимание, все написано строчными буквами).sendkeysможет вводить ввод и отображать введенные символы на экране. Его API также намного удобнее/высокоуровневый, чемKeyEvent. Вот пример, показывающий, как его использовать:

      const input = element.querySelector('.form-group.row .react-select__input');
bililiteRange(input).sendkeys('I typed this{enter}');

К сожалению, исходный код слишком абстрактен для меня; Я не уверен, какое ключевое отличие отсутствует во всех других ответах.

На предложение библиотеки обычно смотрят свысока, особенно потому, что внешние ссылки могут внезапно получить ошибку 404, но чего бы это ни стоило, я записал код bililiteRange на машине обратного пути и на случай непредвиденных обстоятельств создал вставку с неограниченным сроком действия.

Я знаю, что этот ответ сэкономит мне в будущем час+, и я подозреваю, что он сделает то же самое для других.

Основываясь на ответе @aljgom:

Это отлично сработало для меня. Вместо отправки события элементу, как предлагал aljgom, просто отправьте его в документ.

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

Вот что мне удалось найти:

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

Как только пользователь нажимает на нужный ключ, вы можете сохранить ссылку на него и использовать ее в любом другом 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'})

Лучший способ js для полноэкранного переключения:

      function toggleFullScreen() {
      if (!document.fullscreenElement) {
        document.documentElement.requestFullscreen();
      } else if (document.exitFullscreen) {
        document.exitFullscreen();
      }
}

Вы должны использовать JS-библиотеку с поддержкой переноса модели событий DOM. Оттуда вы можете выстрелить и проверить своих обработчиков.

Другие вопросы по тегам