Use standard DOM identifiers for physical keys
This commit is contained in:
parent
a5c8a755e8
commit
80cb8ffddd
|
@ -1,5 +1,6 @@
|
|||
import KeyTable from "./keysym.js";
|
||||
import keysyms from "./keysymdef.js";
|
||||
import vkeys from "./vkeys.js";
|
||||
|
||||
function isMac() {
|
||||
return navigator && !!(/mac/i).exec(navigator.platform);
|
||||
|
@ -131,18 +132,64 @@ export function ModifierSync(charModifier) {
|
|||
};
|
||||
}
|
||||
|
||||
// Get a key ID from a keyboard event
|
||||
// May be a string or an integer depending on the available properties
|
||||
export function getKey(evt){
|
||||
if ('keyCode' in evt && 'key' in evt) {
|
||||
return evt.key + ':' + evt.keyCode;
|
||||
// Get 'KeyboardEvent.code', handling legacy browsers
|
||||
export function getKeycode(evt){
|
||||
// Are we getting proper key identifiers?
|
||||
// (unfortunately Firefox and Chrome are crappy here and gives
|
||||
// us an empty string on some platforms, rather than leaving it
|
||||
// undefined)
|
||||
if (evt.code) {
|
||||
// Mozilla isn't fully in sync with the spec yet
|
||||
switch (evt.code) {
|
||||
case 'OSLeft': return 'MetaLeft';
|
||||
case 'OSRight': return 'MetaRight';
|
||||
}
|
||||
|
||||
return evt.code;
|
||||
}
|
||||
else if ('keyCode' in evt) {
|
||||
return evt.keyCode;
|
||||
}
|
||||
else {
|
||||
return evt.key;
|
||||
|
||||
// The de-facto standard is to use Windows Virtual-Key codes
|
||||
// in the 'keyCode' field for non-printable characters. However
|
||||
// Webkit sets it to the same as charCode in 'keypress' events.
|
||||
if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) {
|
||||
var code = vkeys[evt.keyCode];
|
||||
|
||||
// macOS has messed up this code for some reason
|
||||
if (isMac() && (code === 'ContextMenu')) {
|
||||
code = 'MetaRight';
|
||||
}
|
||||
|
||||
// The keyCode doesn't distinguish between left and right
|
||||
// for the standard modifiers
|
||||
if (evt.location === 2) {
|
||||
switch (code) {
|
||||
case 'ShiftLeft': return 'ShiftRight';
|
||||
case 'ControlLeft': return 'ControlRight';
|
||||
case 'AltLeft': return 'AltRight';
|
||||
}
|
||||
}
|
||||
|
||||
// Nor a bunch of the numpad keys
|
||||
if (evt.location === 3) {
|
||||
switch (code) {
|
||||
case 'Delete': return 'NumpadDecimal';
|
||||
case 'Insert': return 'Numpad0';
|
||||
case 'End': return 'Numpad1';
|
||||
case 'ArrowDown': return 'Numpad2';
|
||||
case 'PageDown': return 'Numpad3';
|
||||
case 'ArrowLeft': return 'Numpad4';
|
||||
case 'ArrowRight': return 'Numpad6';
|
||||
case 'Home': return 'Numpad7';
|
||||
case 'ArrowUp': return 'Numpad8';
|
||||
case 'PageUp': return 'Numpad9';
|
||||
case 'Enter': return 'NumpadEnter';
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
return 'Unidentified';
|
||||
}
|
||||
|
||||
// Get the most reliable keysym value we can get from a key event
|
||||
|
@ -290,7 +337,7 @@ export function QEMUKeyEventDecoder (modifierState, next) {
|
|||
|
||||
function process(evt, type) {
|
||||
var result = {type: type};
|
||||
result.code = evt.code;
|
||||
result.code = getKeycode(evt);
|
||||
result.keysym = 0;
|
||||
|
||||
if (isNumPadMultiKey(evt)) {
|
||||
|
@ -298,7 +345,7 @@ export function QEMUKeyEventDecoder (modifierState, next) {
|
|||
}
|
||||
|
||||
var hasModifier = modifierState.hasShortcutModifier() || !!modifierState.activeCharModifier();
|
||||
var isShift = evt.keyCode === 0x10 || evt.key === 'Shift';
|
||||
var isShift = result.code === 'ShiftLeft' || result.code === 'ShiftRight';
|
||||
|
||||
var suppress = !isShift && (type !== 'keydown' || modifierState.hasShortcutModifier() || !!nonCharacterKey(evt));
|
||||
|
||||
|
@ -387,7 +434,7 @@ export function TrackQEMUKeyState (next) {
|
|||
|
||||
// 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)
|
||||
// - determines a code identifying the key that was pressed (corresponding to the code/keyCode properties on the DOM event)
|
||||
// - synthesizes events to synchronize modifier key state between which modifiers are actually down, and which we thought were down
|
||||
// - marks each event with an 'escape' property if a modifier was down which should be "escaped"
|
||||
// - generates a "stall" event in cases where it might be necessary to wait and see if a keypress event follows a keydown
|
||||
|
@ -401,10 +448,16 @@ export function KeyEventDecoder (modifierState, next) {
|
|||
}
|
||||
function process(evt, type) {
|
||||
var result = {type: type};
|
||||
var keyId = getKey(evt);
|
||||
if (keyId) {
|
||||
result.keyId = keyId;
|
||||
var code = getKeycode(evt);
|
||||
if (code === 'Unidentified') {
|
||||
// Unstable, but we don't have anything else to go on
|
||||
// (don't use it for 'keypress' events thought since
|
||||
// WebKit sets it to the same as charCode)
|
||||
if (evt.keyCode && (evt.type !== 'keypress')) {
|
||||
code = 'Platform' + evt.keyCode;
|
||||
}
|
||||
}
|
||||
result.code = code;
|
||||
|
||||
var keysym = getKeysym(evt);
|
||||
|
||||
|
@ -416,7 +469,7 @@ export function KeyEventDecoder (modifierState, next) {
|
|||
result.keysym = keysym;
|
||||
}
|
||||
|
||||
var isShift = evt.keyCode === 0x10 || evt.key === 'Shift';
|
||||
var isShift = code === 'ShiftLeft' || code === 'ShiftRight';
|
||||
|
||||
// Should we prevent the browser from handling the event?
|
||||
// Doing so on a keydown (in most browsers) prevents keypress from being generated
|
||||
|
@ -546,8 +599,8 @@ export function TrackKeyState (next) {
|
|||
switch (evt.type) {
|
||||
case 'keydown':
|
||||
// insert a new entry if last seen key was different.
|
||||
if (!last || !evt.keyId || last.keyId !== evt.keyId) {
|
||||
last = {keyId: evt.keyId, keysyms: {}};
|
||||
if (!last || evt.code === 'Unidentified' || last.code !== evt.code) {
|
||||
last = {code: evt.code, keysyms: {}};
|
||||
state.push(last);
|
||||
}
|
||||
if (evt.keysym) {
|
||||
|
@ -560,7 +613,7 @@ export function TrackKeyState (next) {
|
|||
break;
|
||||
case 'keypress':
|
||||
if (!last) {
|
||||
last = {keyId: evt.keyId, keysyms: {}};
|
||||
last = {code: evt.code, keysyms: {}};
|
||||
state.push(last);
|
||||
}
|
||||
if (!evt.keysym) {
|
||||
|
@ -582,7 +635,7 @@ export function TrackKeyState (next) {
|
|||
var idx = null;
|
||||
// do we have a matching key tracked as being down?
|
||||
for (var i = 0; i !== state.length; ++i) {
|
||||
if (state[i].keyId === evt.keyId) {
|
||||
if (state[i].code === evt.code) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
|
@ -609,7 +662,7 @@ export function TrackKeyState (next) {
|
|||
for (var i = 0; i < state.length; ++i) {
|
||||
for (var key in state[i].keysyms) {
|
||||
var keysym = state[i].keysyms[key];
|
||||
next({keyId: 0, keysym: keysym, type: 'keyup'});
|
||||
next({code: 'Unidentified', keysym: keysym, type: 'keyup'});
|
||||
}
|
||||
}
|
||||
/* jshint shadow: false */
|
||||
|
@ -629,14 +682,14 @@ export function EscapeModifiers (next) {
|
|||
}
|
||||
// undo modifiers
|
||||
for (var i = 0; i < evt.escape.length; ++i) {
|
||||
next({type: 'keyup', keyId: 0, keysym: evt.escape[i]});
|
||||
next({type: 'keyup', code: 'Unidentified', keysym: evt.escape[i]});
|
||||
}
|
||||
// send the character event
|
||||
next(evt);
|
||||
// redo modifiers
|
||||
/* jshint shadow: true */
|
||||
for (var i = 0; i < evt.escape.length; ++i) {
|
||||
next({type: 'keydown', keyId: 0, keysym: evt.escape[i]});
|
||||
next({type: 'keydown', code: 'Unidentified', keysym: evt.escape[i]});
|
||||
}
|
||||
/* jshint shadow: false */
|
||||
};
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mapping between Microsoft® Windows® Virtual-Key codes and
|
||||
* HTML key codes.
|
||||
*/
|
||||
|
||||
export default {
|
||||
0x08: 'Backspace',
|
||||
0x09: 'Tab',
|
||||
0x0a: 'NumpadClear',
|
||||
0x0d: 'Enter',
|
||||
0x10: 'ShiftLeft',
|
||||
0x11: 'ControlLeft',
|
||||
0x12: 'AltLeft',
|
||||
0x13: 'Pause',
|
||||
0x14: 'CapsLock',
|
||||
0x15: 'Lang1',
|
||||
0x19: 'Lang2',
|
||||
0x1b: 'Escape',
|
||||
0x1c: 'Convert',
|
||||
0x1d: 'NonConvert',
|
||||
0x20: 'Space',
|
||||
0x21: 'PageUp',
|
||||
0x22: 'PageDown',
|
||||
0x23: 'End',
|
||||
0x24: 'Home',
|
||||
0x25: 'ArrowLeft',
|
||||
0x26: 'ArrowUp',
|
||||
0x27: 'ArrowRight',
|
||||
0x28: 'ArrowDown',
|
||||
0x29: 'Select',
|
||||
0x2c: 'PrintScreen',
|
||||
0x2d: 'Insert',
|
||||
0x2e: 'Delete',
|
||||
0x2f: 'Help',
|
||||
0x30: 'Digit0',
|
||||
0x31: 'Digit1',
|
||||
0x32: 'Digit2',
|
||||
0x33: 'Digit3',
|
||||
0x34: 'Digit4',
|
||||
0x35: 'Digit5',
|
||||
0x36: 'Digit6',
|
||||
0x37: 'Digit7',
|
||||
0x38: 'Digit8',
|
||||
0x39: 'Digit9',
|
||||
0x5b: 'MetaLeft',
|
||||
0x5c: 'MetaRight',
|
||||
0x5d: 'ContextMenu',
|
||||
0x5f: 'Sleep',
|
||||
0x60: 'Numpad0',
|
||||
0x61: 'Numpad1',
|
||||
0x62: 'Numpad2',
|
||||
0x63: 'Numpad3',
|
||||
0x64: 'Numpad4',
|
||||
0x65: 'Numpad5',
|
||||
0x66: 'Numpad6',
|
||||
0x67: 'Numpad7',
|
||||
0x68: 'Numpad8',
|
||||
0x69: 'Numpad9',
|
||||
0x6a: 'NumpadMultiply',
|
||||
0x6b: 'NumpadAdd',
|
||||
0x6c: 'NumpadDecimal',
|
||||
0x6d: 'NumpadSubtract',
|
||||
0x6e: 'NumpadDecimal', // Duplicate, because buggy on Windows
|
||||
0x6f: 'NumpadDivide',
|
||||
0x70: 'F1',
|
||||
0x71: 'F2',
|
||||
0x72: 'F3',
|
||||
0x73: 'F4',
|
||||
0x74: 'F5',
|
||||
0x75: 'F6',
|
||||
0x76: 'F7',
|
||||
0x77: 'F8',
|
||||
0x78: 'F9',
|
||||
0x79: 'F10',
|
||||
0x7a: 'F11',
|
||||
0x7b: 'F12',
|
||||
0x7c: 'F13',
|
||||
0x7d: 'F14',
|
||||
0x7e: 'F15',
|
||||
0x7f: 'F16',
|
||||
0x80: 'F17',
|
||||
0x81: 'F18',
|
||||
0x82: 'F19',
|
||||
0x83: 'F20',
|
||||
0x84: 'F21',
|
||||
0x85: 'F22',
|
||||
0x86: 'F23',
|
||||
0x87: 'F24',
|
||||
0x90: 'NumLock',
|
||||
0x91: 'ScrollLock',
|
||||
0xa6: 'BrowserBack',
|
||||
0xa7: 'BrowserForward',
|
||||
0xa8: 'BrowserRefresh',
|
||||
0xa9: 'BrowserStop',
|
||||
0xaa: 'BrowserSearch',
|
||||
0xab: 'BrowserFavorites',
|
||||
0xac: 'BrowserHome',
|
||||
0xad: 'AudioVolumeMute',
|
||||
0xae: 'AudioVolumeDown',
|
||||
0xaf: 'AudioVolumeUp',
|
||||
0xb0: 'MediaTrackNext',
|
||||
0xb1: 'MediaTrackPrevious',
|
||||
0xb2: 'MediaStop',
|
||||
0xb3: 'MediaPlayPause',
|
||||
0xb4: 'LaunchMail',
|
||||
0xb5: 'MediaSelect',
|
||||
0xb6: 'LaunchApp1',
|
||||
0xb7: 'LaunchApp2',
|
||||
0xe1: 'AltRight', // Only when it is AltGraph
|
||||
};
|
|
@ -112,8 +112,6 @@ export default {
|
|||
"Delete": 0xE053,
|
||||
"MetaLeft": 0xE05B,
|
||||
"MetaRight": 0xE05C,
|
||||
"OSLeft": 0xE05B, // OSLeft and OSRight are kept for compatability since
|
||||
"OSRight": 0xE05C, // Firefox haven't updated to MetaLeft and MetaRight yet
|
||||
"ContextMenu": 0xE05D,
|
||||
"BrowserSearch": 0xE065,
|
||||
"BrowserFavorites": 0xE066,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
<script src="../core/input/keysym.js"></script>
|
||||
<script src="../core/input/keysymdef.js"></script>
|
||||
<script src="../core/input/xtscancodes.js"></script>
|
||||
<script src="../core/input/vkeys.js"></script>
|
||||
<script src="../core/input/util.js"></script>
|
||||
<script src="../core/input/devices.js"></script>
|
||||
<script src="../core/display.js"></script>
|
||||
|
|
|
@ -33,6 +33,71 @@ describe('Helpers', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getKeycode', function() {
|
||||
it('should pass through proper code', function() {
|
||||
expect(KeyboardUtil.getKeycode({code: 'Semicolon'})).to.be.equal('Semicolon');
|
||||
});
|
||||
it('should map legacy values', function() {
|
||||
expect(KeyboardUtil.getKeycode({code: ''})).to.be.equal('Unidentified');
|
||||
expect(KeyboardUtil.getKeycode({code: 'OSLeft'})).to.be.equal('MetaLeft');
|
||||
});
|
||||
it('should map keyCode to code when possible', function() {
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x14})).to.be.equal('CapsLock');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x5b})).to.be.equal('MetaLeft');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x35})).to.be.equal('Digit5');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x65})).to.be.equal('Numpad5');
|
||||
});
|
||||
it('should map keyCode left/right side', function() {
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x10, location: 1})).to.be.equal('ShiftLeft');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x10, location: 2})).to.be.equal('ShiftRight');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x11, location: 1})).to.be.equal('ControlLeft');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x11, location: 2})).to.be.equal('ControlRight');
|
||||
});
|
||||
it('should map keyCode on numpad', function() {
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x0d, location: 0})).to.be.equal('Enter');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x0d, location: 3})).to.be.equal('NumpadEnter');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x23, location: 0})).to.be.equal('End');
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x23, location: 3})).to.be.equal('Numpad1');
|
||||
});
|
||||
it('should return Unidentified when it cannot map the keyCode', function() {
|
||||
expect(KeyboardUtil.getKeycode({keycode: 0x42})).to.be.equal('Unidentified');
|
||||
});
|
||||
|
||||
describe('Fix Meta on macOS', function() {
|
||||
var origNavigator;
|
||||
beforeEach(function () {
|
||||
// window.navigator is a protected read-only property in many
|
||||
// environments, so we need to redefine it whilst running these
|
||||
// tests.
|
||||
origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
|
||||
if (origNavigator === undefined) {
|
||||
// Object.getOwnPropertyDescriptor() doesn't work
|
||||
// properly in any version of IE
|
||||
this.skip();
|
||||
}
|
||||
|
||||
Object.defineProperty(window, "navigator", {value: {}});
|
||||
if (window.navigator.platform !== undefined) {
|
||||
// Object.defineProperty() doesn't work properly in old
|
||||
// versions of Chrome
|
||||
this.skip();
|
||||
}
|
||||
|
||||
window.navigator.platform = "Mac x86_64";
|
||||
});
|
||||
afterEach(function () {
|
||||
Object.defineProperty(window, "navigator", origNavigator);
|
||||
});
|
||||
|
||||
it('should respect ContextMenu on modern browser', function() {
|
||||
expect(KeyboardUtil.getKeycode({code: 'ContextMenu', keyCode: 0x5d})).to.be.equal('ContextMenu');
|
||||
});
|
||||
it('should translate legacy ContextMenu to MetaRight', function() {
|
||||
expect(KeyboardUtil.getKeycode({keyCode: 0x5d})).to.be.equal('MetaRight');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getKeysym', function() {
|
||||
it('should prefer char', function() {
|
||||
expect(KeyboardUtil.getKeysym({char : 'a', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal(0x61);
|
||||
|
|
|
@ -12,26 +12,26 @@ describe('Key Event Pipeline Stages', function() {
|
|||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.be.an.object;
|
||||
done();
|
||||
}).keydown({keyCode: 0x41});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should pass the right keysym through', function(done) {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt.keysym).to.be.deep.equal(0x61);
|
||||
done();
|
||||
}).keypress({keyCode: 0x41});
|
||||
}).keypress({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should pass the right keyid through', function(done) {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.have.property('keyId', 0x41);
|
||||
expect(evt).to.have.property('code', 'KeyA');
|
||||
done();
|
||||
}).keydown({keyCode: 0x41});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should not sync modifiers on a keypress', function() {
|
||||
// Firefox provides unreliable modifier state on keypress events
|
||||
var count = 0;
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
++count;
|
||||
}).keypress({keyCode: 0x41, ctrlKey: true});
|
||||
}).keypress({code: 'KeyA', keyCode: 0x41, ctrlKey: true});
|
||||
expect(count).to.be.equal(1);
|
||||
});
|
||||
it('should sync modifiers if necessary', function(done) {
|
||||
|
@ -43,29 +43,29 @@ describe('Key Event Pipeline Stages', function() {
|
|||
++count;
|
||||
break;
|
||||
case 1:
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown', keysym: 0x61});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', type: 'keydown', keysym: 0x61});
|
||||
done();
|
||||
break;
|
||||
}
|
||||
}).keydown({keyCode: 0x41, ctrlKey: true});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41, ctrlKey: true});
|
||||
});
|
||||
it('should forward keydown events with the right type', function(done) {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', type: 'keydown'});
|
||||
done();
|
||||
}).keydown({keyCode: 0x41});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should forward keyup events with the right type', function(done) {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: 0x61, type: 'keyup'});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keyup'});
|
||||
done();
|
||||
}).keyup({keyCode: 0x41});
|
||||
}).keyup({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should forward keypress events with the right type', function(done) {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: 0x61, type: 'keypress'});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keypress'});
|
||||
done();
|
||||
}).keypress({keyCode: 0x41});
|
||||
}).keypress({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should generate stalls if a char modifier is down while a key is pressed', function(done) {
|
||||
var count = 0;
|
||||
|
@ -82,14 +82,14 @@ describe('Key Event Pipeline Stages', function() {
|
|||
case 2: // 'a'
|
||||
expect(evt).to.be.deep.equal({
|
||||
type: 'keydown',
|
||||
keyId: 0x41,
|
||||
code: 'KeyA',
|
||||
keysym: 0x61
|
||||
});
|
||||
|
||||
done();
|
||||
break;
|
||||
}
|
||||
}).keydown({keyCode: 0x41, altGraphKey: true});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41, altGraphKey: true});
|
||||
|
||||
});
|
||||
describe('suppress the right events at the right time', function() {
|
||||
|
@ -184,7 +184,7 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
obj.keydown({keyCode: 0xe1}); // press altgr
|
||||
obj.keydown({keyCode: 'A'.charCodeAt()});
|
||||
obj.keydown({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
|
||||
it('should indicate on events if a single-key char modifier is down', function(done) {
|
||||
|
@ -196,8 +196,8 @@ describe('Key Event Pipeline Stages', function() {
|
|||
case 1: // 'a'
|
||||
expect(evt).to.be.deep.equal({
|
||||
type: 'keypress',
|
||||
keyId: 'A'.charCodeAt(),
|
||||
keysym: 'a'.charCodeAt(),
|
||||
code: 'KeyA',
|
||||
keysym: 0x61,
|
||||
escape: [0xfe03]
|
||||
});
|
||||
done();
|
||||
|
@ -206,7 +206,7 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
obj.keydown({keyCode: 0xe1}); // press altgr
|
||||
obj.keypress({keyCode: 'A'.charCodeAt()});
|
||||
obj.keypress({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should indicate on events if a multi-key char modifier is down', function(done) {
|
||||
var times_called = 0;
|
||||
|
@ -219,8 +219,8 @@ describe('Key Event Pipeline Stages', function() {
|
|||
case 2: // 'a'
|
||||
expect(evt).to.be.deep.equal({
|
||||
type: 'keypress',
|
||||
keyId: 'A'.charCodeAt(),
|
||||
keysym: 'a'.charCodeAt(),
|
||||
code: 'KeyA',
|
||||
keysym: 0x61,
|
||||
escape: [0xffe9, 0xffe3]
|
||||
});
|
||||
done();
|
||||
|
@ -230,7 +230,7 @@ describe('Key Event Pipeline Stages', function() {
|
|||
|
||||
obj.keydown({keyCode: 0x11}); // press ctrl
|
||||
obj.keydown({keyCode: 0x12}); // press alt
|
||||
obj.keypress({keyCode: 'A'.charCodeAt()});
|
||||
obj.keypress({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should not consider a char modifier to be down on the modifier key itself', function() {
|
||||
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
|
||||
|
@ -244,18 +244,18 @@ describe('Key Event Pipeline Stages', function() {
|
|||
describe('add/remove keysym', function() {
|
||||
it('should remove keysym from keydown if a char key and no modifier', function() {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'});
|
||||
}).keydown({keyCode: 0x41});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', type: 'keydown'});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should not remove keysym from keydown if a shortcut modifier is down', function() {
|
||||
var times_called = 0;
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
switch (times_called++) {
|
||||
case 1:
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: 0x61, type: 'keydown'});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keydown'});
|
||||
break;
|
||||
}
|
||||
}).keydown({keyCode: 0x41, ctrlKey: true});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41, ctrlKey: true});
|
||||
expect(times_called).to.be.equal(2);
|
||||
});
|
||||
it('should not remove keysym from keydown if a char modifier is down', function() {
|
||||
|
@ -263,30 +263,30 @@ describe('Key Event Pipeline Stages', function() {
|
|||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
|
||||
switch (times_called++) {
|
||||
case 2:
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: 0x61, type: 'keydown'});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keydown'});
|
||||
break;
|
||||
}
|
||||
}).keydown({keyCode: 0x41, altGraphKey: true});
|
||||
}).keydown({code: 'KeyA', keyCode: 0x41, altGraphKey: true});
|
||||
expect(times_called).to.be.equal(3);
|
||||
});
|
||||
it('should not remove keysym from keydown if key is noncharacter', function() {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt, 'bacobjpace').to.be.deep.equal({keyId: 0x09, keysym: 0xff09, type: 'keydown'});
|
||||
expect(evt, 'tab').to.be.deep.equal({code: 'Tab', keysym: 0xff09, type: 'keydown'});
|
||||
}).keydown({keyCode: 0x09});
|
||||
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt, 'ctrl').to.be.deep.equal({keyId: 0x11, keysym: 0xffe3, type: 'keydown'});
|
||||
expect(evt, 'ctrl').to.be.deep.equal({code: 'ControlLeft', keysym: 0xffe3, type: 'keydown'});
|
||||
}).keydown({keyCode: 0x11});
|
||||
});
|
||||
it('should never remove keysym from keypress', function() {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: 0x61, type: 'keypress'});
|
||||
}).keypress({keyCode: 0x41});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keypress'});
|
||||
}).keypress({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
it('should never remove keysym from keyup', function() {
|
||||
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
|
||||
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: 0x61, type: 'keyup'});
|
||||
}).keyup({keyCode: 0x41});
|
||||
expect(evt).to.be.deep.equal({code: 'KeyA', keysym: 0x61, type: 'keyup'});
|
||||
}).keyup({code: 'KeyA', keyCode: 0x41});
|
||||
});
|
||||
});
|
||||
// on keypress, keyup(?), always set keysym
|
||||
|
@ -296,31 +296,31 @@ describe('Key Event Pipeline Stages', function() {
|
|||
describe('Verify that char modifiers are active', function() {
|
||||
it('should pass keydown events through if there is no stall', function(done) {
|
||||
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
|
||||
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x41});
|
||||
expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x41});
|
||||
done();
|
||||
})({type: 'keydown', keyId: 0x41, keysym: 0x41});
|
||||
})({type: 'keydown', code: 'KeyA', keysym: 0x41});
|
||||
});
|
||||
it('should pass keyup events through if there is no stall', function(done) {
|
||||
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
|
||||
expect(evt).to.deep.equal({type: 'keyup', keyId: 0x41, keysym: 0x41});
|
||||
expect(evt).to.deep.equal({type: 'keyup', code: 'KeyA', keysym: 0x41});
|
||||
done();
|
||||
})({type: 'keyup', keyId: 0x41, keysym: 0x41});
|
||||
})({type: 'keyup', code: 'KeyA', keysym: 0x41});
|
||||
});
|
||||
it('should pass keypress events through if there is no stall', function(done) {
|
||||
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
|
||||
expect(evt).to.deep.equal({type: 'keypress', keyId: 0x41, keysym: 0x41});
|
||||
expect(evt).to.deep.equal({type: 'keypress', code: 'KeyA', keysym: 0x41});
|
||||
done();
|
||||
})({type: 'keypress', keyId: 0x41, keysym: 0x41});
|
||||
})({type: 'keypress', code: 'KeyA', keysym: 0x41});
|
||||
});
|
||||
it('should not pass stall events through', function(done){
|
||||
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
|
||||
// should only be called once, for the keydown
|
||||
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x41});
|
||||
expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x41});
|
||||
done();
|
||||
});
|
||||
|
||||
obj({type: 'stall'});
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x41});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x41});
|
||||
});
|
||||
it('should merge keydown and keypress events if they come after a stall', function(done) {
|
||||
var next_called = false;
|
||||
|
@ -328,13 +328,13 @@ describe('Key Event Pipeline Stages', function() {
|
|||
// should only be called once, for the keydown
|
||||
expect(next_called).to.be.false;
|
||||
next_called = true;
|
||||
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x44});
|
||||
expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x44});
|
||||
done();
|
||||
});
|
||||
|
||||
obj({type: 'stall'});
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
obj({type: 'keypress', keyId: 0x43, keysym: 0x44});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
obj({type: 'keypress', code: 'KeyC', keysym: 0x44});
|
||||
expect(next_called).to.be.false;
|
||||
});
|
||||
it('should preserve modifier attribute when merging if keysyms differ', function(done) {
|
||||
|
@ -343,13 +343,13 @@ describe('Key Event Pipeline Stages', function() {
|
|||
// should only be called once, for the keydown
|
||||
expect(next_called).to.be.false;
|
||||
next_called = true;
|
||||
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x44, escape: [0xffe3]});
|
||||
expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x44, escape: [0xffe3]});
|
||||
done();
|
||||
});
|
||||
|
||||
obj({type: 'stall'});
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
obj({type: 'keypress', keyId: 0x43, keysym: 0x44, escape: [0xffe3]});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
obj({type: 'keypress', code: 'KeyC', keysym: 0x44, escape: [0xffe3]});
|
||||
expect(next_called).to.be.false;
|
||||
});
|
||||
it('should not preserve modifier attribute when merging if keysyms are the same', function() {
|
||||
|
@ -358,18 +358,18 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
obj({type: 'stall'});
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
obj({type: 'keypress', keyId: 0x43, keysym: 0x42, escape: [0xffe3]});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
obj({type: 'keypress', code: 'KeyC', keysym: 0x42, escape: [0xffe3]});
|
||||
});
|
||||
it('should not merge keydown and keypress events if there is no stall', function(done) {
|
||||
var times_called = 0;
|
||||
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
|
||||
switch(times_called) {
|
||||
case 0:
|
||||
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
expect(evt).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
break;
|
||||
case 1:
|
||||
expect(evt).to.deep.equal({type: 'keypress', keyId: 0x43, keysym: 0x44});
|
||||
expect(evt).to.deep.equal({type: 'keypress', code: 'KeyC', keysym: 0x44});
|
||||
done();
|
||||
break;
|
||||
}
|
||||
|
@ -377,21 +377,21 @@ describe('Key Event Pipeline Stages', function() {
|
|||
++times_called;
|
||||
});
|
||||
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
obj({type: 'keypress', keyId: 0x43, keysym: 0x44});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
obj({type: 'keypress', code: 'KeyC', keysym: 0x44});
|
||||
});
|
||||
it('should not merge keydown and keypress events if separated by another event', function(done) {
|
||||
var times_called = 0;
|
||||
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
|
||||
switch(times_called) {
|
||||
case 0:
|
||||
expect(evt,1).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
expect(evt,1).to.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
break;
|
||||
case 1:
|
||||
expect(evt,2).to.deep.equal({type: 'keyup', keyId: 0x43, keysym: 0x44});
|
||||
expect(evt,2).to.deep.equal({type: 'keyup', code: 'KeyC', keysym: 0x44});
|
||||
break;
|
||||
case 2:
|
||||
expect(evt,3).to.deep.equal({type: 'keypress', keyId: 0x45, keysym: 0x46});
|
||||
expect(evt,3).to.deep.equal({type: 'keypress', code: 'KeyE', keysym: 0x46});
|
||||
done();
|
||||
break;
|
||||
}
|
||||
|
@ -400,9 +400,9 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
obj({type: 'stall'});
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
obj({type: 'keyup', keyId: 0x43, keysym: 0x44});
|
||||
obj({type: 'keypress', keyId: 0x45, keysym: 0x46});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
obj({type: 'keyup', code: 'KeyC', keysym: 0x44});
|
||||
obj({type: 'keypress', code: 'KeyE', keysym: 0x46});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -411,7 +411,7 @@ describe('Key Event Pipeline Stages', function() {
|
|||
var obj = KeyboardUtil.TrackKeyState(function(evt) {
|
||||
expect(true).to.be.false;
|
||||
});
|
||||
obj({type: 'keyup', keyId: 0x41});
|
||||
obj({type: 'keyup', code: 'KeyA'});
|
||||
});
|
||||
it('should insert into the queue on keydown if no keys are down', function() {
|
||||
var times_called = 0;
|
||||
|
@ -432,11 +432,11 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0x41, keysym: 0x42};
|
||||
elem = {type: 'keydown', code: 'KeyA', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keyup', keyId: 0x41};
|
||||
elem = {type: 'keyup', code: 'KeyA'};
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
expect(times_called).to.be.equal(2);
|
||||
|
@ -460,16 +460,16 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keypress', keyId: 0x41, keysym: 0x42};
|
||||
elem = {type: 'keypress', code: 'KeyA', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keyup', keyId: 0x41};
|
||||
elem = {type: 'keyup', code: 'KeyA'};
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
expect(times_called).to.be.equal(2);
|
||||
});
|
||||
it('should add keysym to last key entry if keyId matches', function() {
|
||||
it('should add keysym to last key entry if code matches', function() {
|
||||
// this implies that a single keyup will release both keysyms
|
||||
var times_called = 0;
|
||||
var elem = null;
|
||||
|
@ -489,19 +489,19 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keypress', keyId: 0x41, keysym: 0x42};
|
||||
elem = {type: 'keypress', code: 'KeyA', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keypress', keyId: 0x41, keysym: 0x43};
|
||||
elem = {type: 'keypress', code: 'KeyA', keysym: 0x43};
|
||||
keysymsdown[0x43] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keyup', keyId: 0x41};
|
||||
elem = {type: 'keyup', code: 'KeyA'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(4);
|
||||
});
|
||||
it('should create new key entry if keyId matches and keysym does not', function() {
|
||||
it('should create new key entry if code matches and keysym does not', function() {
|
||||
// this implies that a single keyup will release both keysyms
|
||||
var times_called = 0;
|
||||
var elem = null;
|
||||
|
@ -521,23 +521,23 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0, keysym: 0x42};
|
||||
elem = {type: 'keydown', code: 'Unidentified', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0, keysym: 0x43};
|
||||
elem = {type: 'keydown', code: 'Unidentified', keysym: 0x43};
|
||||
keysymsdown[0x43] = true;
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(2);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keyup', keyId: 0};
|
||||
elem = {type: 'keyup', code: 'Unidentified'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(3);
|
||||
elem = {type: 'keyup', keyId: 0};
|
||||
elem = {type: 'keyup', code: 'Unidentified'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(4);
|
||||
});
|
||||
it('should merge key entry if keyIds are zero and keysyms match', function() {
|
||||
it('should merge key entry if codes are zero and keysyms match', function() {
|
||||
// this implies that a single keyup will release both keysyms
|
||||
var times_called = 0;
|
||||
var elem = null;
|
||||
|
@ -557,20 +557,20 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0, keysym: 0x42};
|
||||
elem = {type: 'keydown', code: 'Unidentified', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0, keysym: 0x42};
|
||||
elem = {type: 'keydown', code: 'Unidentified', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(2);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keyup', keyId: 0};
|
||||
elem = {type: 'keyup', code: 'Unidentified'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(3);
|
||||
});
|
||||
it('should add keysym as separate entry if keyId does not match last event', function() {
|
||||
it('should add keysym as separate entry if code does not match last event', function() {
|
||||
// this implies that separate keyups are required
|
||||
var times_called = 0;
|
||||
var elem = null;
|
||||
|
@ -590,22 +590,22 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keypress', keyId: 0x41, keysym: 0x42};
|
||||
elem = {type: 'keypress', code: 'KeyA', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keypress', keyId: 0x42, keysym: 0x43};
|
||||
elem = {type: 'keypress', code: 'KeyB', keysym: 0x43};
|
||||
keysymsdown[0x43] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keyup', keyId: 0x41};
|
||||
elem = {type: 'keyup', code: 'KeyA'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(4);
|
||||
elem = {type: 'keyup', keyId: 0x42};
|
||||
elem = {type: 'keyup', code: 'KeyB'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(4);
|
||||
});
|
||||
it('should add keysym as separate entry if keyId does not match last event and first is zero', function() {
|
||||
it('should add keysym as separate entry if code does not match last event and first is zero', function() {
|
||||
// this implies that separate keyups are required
|
||||
var times_called = 0;
|
||||
var elem = null;
|
||||
|
@ -625,23 +625,23 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0, keysym: 0x42};
|
||||
elem = {type: 'keydown', code: 'Unidentified', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0x42, keysym: 0x43};
|
||||
elem = {type: 'keydown', code: 'KeyB', keysym: 0x43};
|
||||
keysymsdown[0x43] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
expect(times_called).to.be.equal(2);
|
||||
elem = {type: 'keyup', keyId: 0};
|
||||
elem = {type: 'keyup', code: 'Unidentified'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(3);
|
||||
elem = {type: 'keyup', keyId: 0x42};
|
||||
elem = {type: 'keyup', code: 'KeyB'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(4);
|
||||
});
|
||||
it('should add keysym as separate entry if keyId does not match last event and second is zero', function() {
|
||||
it('should add keysym as separate entry if code does not match last event and second is zero', function() {
|
||||
// this implies that a separate keyups are required
|
||||
var times_called = 0;
|
||||
var elem = null;
|
||||
|
@ -661,18 +661,18 @@ describe('Key Event Pipeline Stages', function() {
|
|||
});
|
||||
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0x41, keysym: 0x42};
|
||||
elem = {type: 'keydown', code: 'KeyA', keysym: 0x42};
|
||||
keysymsdown[0x42] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keydown', keyId: 0, keysym: 0x43};
|
||||
elem = {type: 'keydown', code: 'Unidentified', keysym: 0x43};
|
||||
keysymsdown[0x43] = true;
|
||||
obj(elem);
|
||||
expect(elem).to.be.null;
|
||||
elem = {type: 'keyup', keyId: 0x41};
|
||||
elem = {type: 'keyup', code: 'KeyA'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(3);
|
||||
elem = {type: 'keyup', keyId: 0};
|
||||
elem = {type: 'keyup', code: 'Unidentified'};
|
||||
obj(elem);
|
||||
expect(times_called).to.be.equal(4);
|
||||
});
|
||||
|
@ -686,18 +686,18 @@ describe('Key Event Pipeline Stages', function() {
|
|||
expect(evt.type).to.be.equal('keydown');
|
||||
break;
|
||||
case 3:
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x42, keysym: 0x62});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'KeyB', keysym: 0x62});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x61});
|
||||
obj({type: 'keydown', keyId: 0x42, keysym: 0x62});
|
||||
obj({type: 'keydown', keyId: 0x43, keysym: 0x63});
|
||||
obj({type: 'keyup', keyId: 0x42});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x61});
|
||||
obj({type: 'keydown', code: 'KeyB', keysym: 0x62});
|
||||
obj({type: 'keydown', code: 'KeyC', keysym: 0x63});
|
||||
obj({type: 'keyup', code: 'KeyB'});
|
||||
expect(times_called).to.equal(4);
|
||||
});
|
||||
it('should pop the first zero keyevent on keyup with zero keyId', function() {
|
||||
it('should pop the first zero keyevent on keyup with zero code', function() {
|
||||
var times_called = 0;
|
||||
var obj = KeyboardUtil.TrackKeyState(function(evt) {
|
||||
switch (times_called++) {
|
||||
|
@ -707,18 +707,18 @@ describe('Key Event Pipeline Stages', function() {
|
|||
expect(evt.type).to.be.equal('keydown');
|
||||
break;
|
||||
case 3:
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: 0x61});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'Unidentified', keysym: 0x61});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
obj({type: 'keydown', keyId: 0, keysym: 0x61});
|
||||
obj({type: 'keydown', keyId: 0, keysym: 0x62});
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x63});
|
||||
obj({type: 'keyup', keyId: 0x0});
|
||||
obj({type: 'keydown', code: 'Unidentified', keysym: 0x61});
|
||||
obj({type: 'keydown', code: 'Unidentified', keysym: 0x62});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x63});
|
||||
obj({type: 'keyup', code: 'Unidentified'});
|
||||
expect(times_called).to.equal(4);
|
||||
});
|
||||
it('should pop the last keyevents keysym if no match is found for keyId', function() {
|
||||
it('should pop the last keyevents keysym if no match is found for code', function() {
|
||||
var times_called = 0;
|
||||
var obj = KeyboardUtil.TrackKeyState(function(evt) {
|
||||
switch (times_called++) {
|
||||
|
@ -728,15 +728,15 @@ describe('Key Event Pipeline Stages', function() {
|
|||
expect(evt.type).to.be.equal('keydown');
|
||||
break;
|
||||
case 3:
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x44, keysym: 0x63});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'KeyD', keysym: 0x63});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x61});
|
||||
obj({type: 'keydown', keyId: 0x42, keysym: 0x62});
|
||||
obj({type: 'keydown', keyId: 0x43, keysym: 0x63});
|
||||
obj({type: 'keyup', keyId: 0x44});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x61});
|
||||
obj({type: 'keydown', code: 'KeyB', keysym: 0x62});
|
||||
obj({type: 'keydown', code: 'KeyC', keysym: 0x63});
|
||||
obj({type: 'keyup', code: 'KeyD'});
|
||||
expect(times_called).to.equal(4);
|
||||
});
|
||||
describe('Firefox sends keypress even when keydown is suppressed', function() {
|
||||
|
@ -747,9 +747,9 @@ describe('Key Event Pipeline Stages', function() {
|
|||
++times_called;
|
||||
});
|
||||
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
expect(times_called).to.be.equal(1);
|
||||
obj({type: 'keypress', keyId: 0x41, keysym: 0x43});
|
||||
obj({type: 'keypress', code: 'KeyA', keysym: 0x43});
|
||||
});
|
||||
});
|
||||
describe('releaseAll', function() {
|
||||
|
@ -766,15 +766,15 @@ describe('Key Event Pipeline Stages', function() {
|
|||
var obj = KeyboardUtil.TrackKeyState(function(evt) {
|
||||
switch (times_called++) {
|
||||
case 2:
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: 0x41});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'Unidentified', keysym: 0x41});
|
||||
break;
|
||||
case 3:
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: 0x42});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'Unidentified', keysym: 0x42});
|
||||
break;
|
||||
}
|
||||
});
|
||||
obj({type: 'keydown', keyId: 0x41, keysym: 0x41});
|
||||
obj({type: 'keydown', keyId: 0x42, keysym: 0x42});
|
||||
obj({type: 'keydown', code: 'KeyA', keysym: 0x41});
|
||||
obj({type: 'keydown', code: 'KeyB', keysym: 0x42});
|
||||
expect(times_called).to.be.equal(2);
|
||||
obj({type: 'releaseall'});
|
||||
expect(times_called).to.be.equal(4);
|
||||
|
@ -792,8 +792,8 @@ describe('Key Event Pipeline Stages', function() {
|
|||
KeyboardUtil.EscapeModifiers(function(evt) {
|
||||
expect(times_called).to.be.equal(0);
|
||||
++times_called;
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
})({type: 'keydown', keyId: 0x41, keysym: 0x42});
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
})({type: 'keydown', code: 'KeyA', keysym: 0x42});
|
||||
expect(times_called).to.be.equal(1);
|
||||
});
|
||||
it('should generate fake undo/redo events when a char modifier is down', function() {
|
||||
|
@ -801,22 +801,22 @@ describe('Key Event Pipeline Stages', function() {
|
|||
KeyboardUtil.EscapeModifiers(function(evt) {
|
||||
switch(times_called++) {
|
||||
case 0:
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: 0xffe9});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'Unidentified', keysym: 0xffe9});
|
||||
break;
|
||||
case 1:
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: 0xffe3});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'Unidentified', keysym: 0xffe3});
|
||||
break;
|
||||
case 2:
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0x41, keysym: 0x42, escape: [0xffe9, 0xffe3]});
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', code: 'KeyA', keysym: 0x42, escape: [0xffe9, 0xffe3]});
|
||||
break;
|
||||
case 3:
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0, keysym: 0xffe9});
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', code: 'Unidentified', keysym: 0xffe9});
|
||||
break;
|
||||
case 4:
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0, keysym: 0xffe3});
|
||||
expect(evt).to.be.deep.equal({type: 'keydown', code: 'Unidentified', keysym: 0xffe3});
|
||||
break;
|
||||
}
|
||||
})({type: 'keydown', keyId: 0x41, keysym: 0x42, escape: [0xffe9, 0xffe3]});
|
||||
})({type: 'keydown', code: 'KeyA', keysym: 0x42, escape: [0xffe9, 0xffe3]});
|
||||
expect(times_called).to.be.equal(5);
|
||||
});
|
||||
});
|
||||
|
@ -826,8 +826,8 @@ describe('Key Event Pipeline Stages', function() {
|
|||
KeyboardUtil.EscapeModifiers(function(evt) {
|
||||
expect(times_called).to.be.equal(0);
|
||||
++times_called;
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: 0x42, escape: [0xfe03]});
|
||||
})({type: 'keyup', keyId: 0x41, keysym: 0x42, escape: [0xfe03]});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'KeyA', keysym: 0x42, escape: [0xfe03]});
|
||||
})({type: 'keyup', code: 'KeyA', keysym: 0x42, escape: [0xfe03]});
|
||||
expect(times_called).to.be.equal(1);
|
||||
});
|
||||
it('should pass through when a char modifier is not down', function() {
|
||||
|
@ -835,8 +835,8 @@ describe('Key Event Pipeline Stages', function() {
|
|||
KeyboardUtil.EscapeModifiers(function(evt) {
|
||||
expect(times_called).to.be.equal(0);
|
||||
++times_called;
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: 0x42});
|
||||
})({type: 'keyup', keyId: 0x41, keysym: 0x42});
|
||||
expect(evt).to.be.deep.equal({type: 'keyup', code: 'KeyA', keysym: 0x42});
|
||||
})({type: 'keyup', code: 'KeyA', keysym: 0x42});
|
||||
expect(times_called).to.be.equal(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -50,7 +50,8 @@
|
|||
WebUtil.load_scripts({
|
||||
'core': ["base64.js", "websock.js", "des.js", "input/keysym.js",
|
||||
"input/keysymdef.js", "input/xtscancodes.js", "input/util.js",
|
||||
"input/devices.js", "display.js", "rfb.js", "inflator.js"],
|
||||
"input/devices.js", "display.js", "rfb.js", "inflator.js",
|
||||
"input/vkeys.js"],
|
||||
'tests': ["playback.js"],
|
||||
'recordings': [fname]});
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue