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

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

Ответов (23)

Версия без 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, // view: should be window
  false, // ctrlKey
  false, // altKey
  false, // shiftKey
  false, // metaKey
  40, // keyCode: unsigned long - the virtual key code, else 0
  0, // charCode: unsigned long - the Unicode character associated with the depressed key, else 0
);
document.dispatchEvent(keyboardEvent);

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

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

Самая простая форма:

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

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

Ниже приведен пример того, как это сделать в стандарте 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 для программного доступа к удаленному контенту.

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

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

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

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

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

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

  • фокус (отправляется в DOM с целевым набором)

Затем для каждого персонажа:

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

Затем, по желанию для большинства:

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

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

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

Вот библиотека, которая действительно помогает: 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 .

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

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

просто используйте 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 ex хочу смоделировать 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})

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

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);
    }
<input type="button" onclick="KeySimulation();" value=" Key Simulation " />
<textarea id="MyTextArea" rows="15" cols="30"></textarea>

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

В некоторых случаях keypress событие не может обеспечить требуемую функциональность. Из документации Mozilla видно, что эта функция устарела:

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

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

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

Один раз он был однострочным из-за простоты использования в контексте консоли. Но, вероятно, все же пригодится.

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

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

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

Пример

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

По состоянию на 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 нужный элемент.

Я хотел смоделировать нажатие «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>

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

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

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

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

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

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

Если вы можете использовать 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");
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>

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

Основываясь на ответе 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 .

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

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

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

Однако dispatchEvent может не обновлять значение поля ввода.


Пример:

let element = document.querySelector('input');
element.onkeydown = e => alert(e.key);
element.dispatchEvent(new KeyboardEvent('keydown',{'key':'a'}));
  
<input/>


При необходимости вы можете добавить к событию дополнительные свойства, например этот ответ

  element.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 + keyup, например

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

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

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

var keyboardEvent = new KeyboardEvent("keypress", { bubbles: true });
// you can try charCode or keyCode but they are deprecated
Object.defineProperty(keyboardEvent, "key", {
  get() {
    return "Enter";
  },
});
x.dispatchEvent(keyboardEvent);

{
  // example
  document.querySelector('input').addEventListener("keypress", e => console.log("keypress", e.key))
  // unfortunatelly doesn't trigger submit
  document.querySelector('form').addEventListener("submit", e => {
    e.preventDefault();
    console.log("submit")
  })
}

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

var keyboardEvent = new KeyboardEvent("keypress", { bubbles: true });
// you can try charCode or keyCode but they are deprecated
Object.defineProperty(keyboardEvent, "key", {
  get() {
    return "Enter";
  },
});
x.dispatchEvent(keyboardEvent);
<form>
  <input>
</form>