Можно ли программно моделировать события нажатия клавиш? - PullRequest
314 голосов
/ 27 февраля 2009

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

Ответы [ 18 ]

160 голосов
/ 30 августа 2012

Версия без 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);
68 голосов
/ 27 февраля 2009

Если вы можете использовать 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");
});
46 голосов
/ 10 ноября 2013

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

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

Подробное объяснение:

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

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

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

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

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

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

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

22 голосов
/ 08 мая 2009

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

21 голосов
/ 26 мая 2017

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

element.dispatchEvent(new KeyboardEvent('keypress',{'key':'a'}));
20 голосов
/ 04 июля 2013

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

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

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

$('input').val('123');
$('input').change();
13 голосов
/ 02 октября 2011

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

8 голосов
/ 23 ноября 2017

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

element.dispatchEvent(new KeyboardEvent('keydown',{'key':'Shift'}));
element.dispatchEvent(new KeyboardEvent('keyup',{'key':'Shift'}));
8 голосов
/ 31 мая 2014

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

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

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

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

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

Затем, по выбору, для большинства:

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

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

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

7 голосов
/ 22 мая 2013

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

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...