I\'m developing a Google Chrome extension which simulates keyboard events on a web-page.
I found that event.initKeyboardEvent()
does not work properly b
Because Chrome does not preserve custom properties when you initiate an event from a Content script to the page (and vice versa), inject a script in the page to take over this job. Here's a basic example which shows the idea. It is usable, although the key
and keyCode
properties are not correctly handled (those shouldn't be used anyway).
// Example: Say, you've got a reference to a DOM element...
var elem = document.body;
// And you want to "type" "A"
var charCode = 65;
// Now, you want to generate a key event...
triggerKeyEvent(elem, charCode);
// triggerKeyEvent is implemented as follows:
function triggerKeyEvent(element, charCode) {
// We cannot pass object references, so generate an unique selector
var attribute = 'robw_' + Date.now();
element.setAttribute(attribute, '');
var selector = element.tagName + '[' + attribute + ']';
var s = document.createElement('script');
s.textContent = '(' + function(charCode, attribute, selector) {
// Get reference to element...
var element = document.querySelector(selector);
element.removeAttribute(attribute);
// Create KeyboardEvent instance
var event = document.createEvent('KeyboardEvents');
event.initKeyboardEvent(
/* type */ 'keypress',
/* bubbles */ true,
/* cancelable */ false,
/* view */ window,
/* keyIdentifier*/ '',
/* keyLocation */ 0,
/* ctrlKey */ false,
/* altKey */ false,
/* shiftKey */ false,
/* metaKey */ false,
/* altGraphKey */ false
);
// Define custom values
// This part requires the script to be run in the page's context
var getterCode = {get: function() {return charCode}};
var getterChar = {get: function() {return String.fromCharCode(charCode)}};
Object.defineProperties(event, {
charCode: getterCode,
which: getterCode,
keyCode: getterCode, // Not fully correct
key: getterChar, // Not fully correct
char: getterChar
});
element.dispatchEvent(event);
} + ')(' + charCode + ', "' + attribute + '", "' + selector + '")';
(document.head||document.documentElement).appendChild(s);
s.parentNode.removeChild(s);
// The script should have removed the attribute already.
// Remove the attribute in case the script fails to run.
s.removeAttribute(attribute);
}
This is a simple example which triggers the keypress
event for char "A". If you want to trigger more relevant key events, do not use triggerKeyEvent
three times (because it has a slight overhead). Instead, modify the triggerKeyEvent
function such that it fires all events (keydown
, keypress
, keyup
and/or input
) with the correct parameters.
If you need to be able to change altKey
, shiftKey
, etc., just modify the function.
Bottom line: The example I've shown is very basic and can be tweaked to suit your needs.
If you want to change the implementation to match the specification, read these sources:
If you want to know more about the concept of Script injection in a content script, see:
Incase anyone has the issue I faced with triggering a keyup with a specific keycode. This is one way.
First off I tried @RobW's answer above with no luck. No Keycode passed, always undefined.
So then I looked into @disya2's answer, which did work.
So here's some code:-
Manifest
"permissions": [
"debugger"
],
ContentScript.js
chrome.runtime.sendMessage({ pressEnter: true });
Background.js
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
if(message.pressEnter){
chrome.tabs.query({active: true}, function(tabs) {
chrome.debugger.attach({ tabId: tabs[0].id }, "1.0");
chrome.debugger.sendCommand({ tabId: tabs[0].id }, 'Input.dispatchKeyEvent', { type: 'keyUp', windowsVirtualKeyCode:13, nativeVirtualKeyCode : 13, macCharCode: 13 });
chrome.debugger.sendCommand({ tabId: tabs[0].id }, 'Input.dispatchKeyEvent', { type: 'keyDown', windowsVirtualKeyCode:13, nativeVirtualKeyCode : 13, macCharCode: 13 });
chrome.debugger.detach({ tabId: tabs[0].id });
});
}
});
I found that chrome debugger protocol v1.1 is the definite answer to simulating key and mouse events from a Google Chrome extension. Part of the protocol is accessible through chrome.debugger API.