summaryrefslogtreecommitdiff
path: root/include/keyboard.js
diff options
context:
space:
mode:
Diffstat (limited to 'include/keyboard.js')
-rw-r--r--include/keyboard.js131
1 files changed, 131 insertions, 0 deletions
diff --git a/include/keyboard.js b/include/keyboard.js
index 8667031..26543db 100644
--- a/include/keyboard.js
+++ b/include/keyboard.js
@@ -285,6 +285,137 @@ var kbdUtil = (function() {
};
})();
+function QEMUKeyEventDecoder(modifierState, next) {
+ "use strict";
+
+ function sendAll(evts) {
+ for (var i = 0; i < evts.length; ++i) {
+ next(evts[i]);
+ }
+ }
+
+ var numPadCodes = ["Numpad0", "Numpad1", "Numpad2",
+ "Numpad3", "Numpad4", "Numpad5", "Numpad6",
+ "Numpad7", "Numpad8", "Numpad9", "NumpadDecimal"];
+
+ var numLockOnKeySyms = {
+ "Numpad0": 0xffb0, "Numpad1": 0xffb1, "Numpad2": 0xffb2,
+ "Numpad3": 0xffb3, "Numpad4": 0xffb4, "Numpad5": 0xffb5,
+ "Numpad6": 0xffb6, "Numpad7": 0xffb7, "Numpad8": 0xffb8,
+ "Numpad9": 0xffb9, "NumpadDecimal": 0xffac
+ };
+
+ var numLockOnKeyCodes = [96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 108, 110];
+
+ function isNumPadMultiKey(evt) {
+ return (numPadCodes.indexOf(evt.code) !== -1);
+ }
+
+ function getNumPadKeySym(evt) {
+ if (numLockOnKeyCodes.indexOf(evt.keyCode) !== -1) {
+ return numLockOnKeySyms[evt.code];
+ }
+ return 0;
+ }
+
+ function process(evt, type) {
+ var result = {type: type};
+ result.code = evt.code;
+ result.keysym = 0;
+
+ if (isNumPadMultiKey(evt)) {
+ result.keysym = getNumPadKeySym(evt);
+ }
+
+ var hasModifier = modifierState.hasShortcutModifier() || !!modifierState.activeCharModifier();
+ var isShift = evt.keyCode === 0x10 || evt.key === 'Shift';
+
+ var suppress = !isShift && (type !== 'keydown' || modifierState.hasShortcutModifier() || !!kbdUtil.nonCharacterKey(evt));
+
+ next(result);
+ return suppress;
+ }
+ return {
+ keydown: function(evt) {
+ sendAll(modifierState.keydown(evt));
+ return process(evt, 'keydown');
+ },
+ keypress: function(evt) {
+ return true;
+ },
+ keyup: function(evt) {
+ sendAll(modifierState.keyup(evt));
+ return process(evt, 'keyup');
+ },
+ syncModifiers: function(evt) {
+ sendAll(modifierState.syncAny(evt));
+ },
+ releaseAll: function() { next({type: 'releaseall'}); }
+ };
+}
+
+function TrackQEMUKeyState(next) {
+ "use strict";
+ var state = [];
+
+ return function (evt) {
+ var last = state.length !== 0 ? state[state.length-1] : null;
+
+ switch (evt.type) {
+ case 'keydown':
+
+ if (!last || last.code !== evt.code) {
+ last = {code: evt.code};
+
+ if (state.length > 0 && state[state.length-1].code == 'ControlLeft') {
+ if (evt.code !== 'AltRight') {
+ next({code: 'ControlLeft', type: 'keydown', keysym: 0});
+ } else {
+ state.pop();
+ }
+ }
+ state.push(last);
+ }
+ if (evt.code !== 'ControlLeft') {
+ next(evt);
+ }
+ break;
+
+ case 'keyup':
+ if (state.length === 0) {
+ return;
+ }
+ var idx = null;
+ // do we have a matching key tracked as being down?
+ for (var i = 0; i !== state.length; ++i) {
+ if (state[i].code === evt.code) {
+ idx = i;
+ break;
+ }
+ }
+ // if we couldn't find a match (it happens), assume it was the last key pressed
+ if (idx === null) {
+ if (evt.code === 'ControlLeft') {
+ return;
+ }
+ idx = state.length - 1;
+ }
+
+ state.splice(idx, 1);
+ next(evt);
+ break;
+ case 'releaseall':
+ /* jshint shadow: true */
+ for (var i = 0; i < state.length; ++i) {
+ next({code: state[i].code, keysym: 0, type: 'keyup'});
+ }
+ /* jshint shadow: false */
+ state = [];
+ }
+ };
+}
+
// Takes a DOM keyboard event and:
// - determines which keysym it represents
// - determines a keyId identifying the key that was pressed (corresponding to the key/keyCode properties on the DOM event)