]> git.proxmox.com Git - mirror_novnc.git/blame - tests/test.keyboard.js
Merge branch 'png_cursor' of https://github.com/CendioOssman/noVNC
[mirror_novnc.git] / tests / test.keyboard.js
CommitLineData
f00b6fb6 1var assert = chai.assert;
2var expect = chai.expect;
3
f7363fd2 4import { Keyboard } from '../core/input/devices.js';
dfae3209
SR
5import keysyms from '../core/input/keysymdef.js';
6import * as KeyboardUtil from '../core/input/util.js';
7
31f169e8 8/* jshint newcap: false, expr: true */
f7363fd2 9describe('Key Event Handling', function() {
f00b6fb6 10 "use strict";
f00b6fb6 11
f7363fd2
PO
12 // The real KeyboardEvent constructor might not work everywhere we
13 // want to run these tests
14 function keyevent(typeArg, KeyboardEventInit) {
15 var e = { type: typeArg };
16 for (var key in KeyboardEventInit) {
17 e[key] = KeyboardEventInit[key];
18 }
19 e.stopPropagation = sinon.spy();
20 e.preventDefault = sinon.spy();
21 return e;
22 };
f00b6fb6 23
f7363fd2
PO
24 describe('Decode Keyboard Events', function() {
25 it('should decode keydown events', function(done) {
26 var kbd = new Keyboard({
27 onKeyEvent: function(keysym, code, down) {
28 expect(keysym).to.be.equal(0x61);
29 expect(code).to.be.equal('KeyA');
30 expect(down).to.be.equal(true);
31 done();
32 }});
33 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
34 });
35 it('should decode keyup events', function(done) {
36 var calls = 0;
37 var kbd = new Keyboard({
38 onKeyEvent: function(keysym, code, down) {
39 expect(keysym).to.be.equal(0x61);
40 expect(code).to.be.equal('KeyA');
41 if (calls++ === 1) {
42 expect(down).to.be.equal(false);
43 done();
44 }
45 }});
46 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
47 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
48 });
49
50 describe('Legacy keypress Events', function() {
51 it('should wait for keypress when needed', function() {
52 var callback = sinon.spy();
53 var kbd = new Keyboard({onKeyEvent: callback});
54 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
55 expect(callback).to.not.have.been.called;
56 });
57 it('should decode keypress events', function(done) {
58 var kbd = new Keyboard({
59 onKeyEvent: function(keysym, code, down) {
60 expect(keysym).to.be.equal(0x61);
61 expect(code).to.be.equal('KeyA');
62 expect(down).to.be.equal(true);
63 done();
64 }});
65 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
66 kbd._handleKeyPress(keyevent('keypress', {code: 'KeyA', charCode: 0x61}));
f00b6fb6 67 });
9fce233d
PO
68 it('should ignore keypress with different code', function() {
69 var callback = sinon.spy();
70 var kbd = new Keyboard({onKeyEvent: callback});
71 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
72 kbd._handleKeyPress(keyevent('keypress', {code: 'KeyB', charCode: 0x61}));
73 expect(callback).to.not.have.been.called;
74 });
75 it('should handle keypress with missing code', function(done) {
76 var kbd = new Keyboard({
77 onKeyEvent: function(keysym, code, down) {
78 expect(keysym).to.be.equal(0x61);
79 expect(code).to.be.equal('KeyA');
80 expect(down).to.be.equal(true);
81 done();
82 }});
83 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
84 kbd._handleKeyPress(keyevent('keypress', {charCode: 0x61}));
85 });
f00b6fb6 86 });
f00b6fb6 87
f7363fd2
PO
88 describe('suppress the right events at the right time', function() {
89 it('should suppress anything with a valid key', function() {
90 var kbd = new Keyboard({});
91 var evt = keyevent('keydown', {code: 'KeyA', key: 'a'});
92 kbd._handleKeyDown(evt);
93 expect(evt.preventDefault).to.have.been.called;
94 evt = keyevent('keyup', {code: 'KeyA', key: 'a'});
95 kbd._handleKeyUp(evt);
96 expect(evt.preventDefault).to.have.been.called;
97 });
98 it('should not suppress keys without key', function() {
99 var kbd = new Keyboard({});
100 var evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41});
101 kbd._handleKeyDown(evt);
102 expect(evt.preventDefault).to.not.have.been.called;
103 });
104 it('should suppress the following keypress event', function() {
105 var kbd = new Keyboard({});
106 var evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41});
107 kbd._handleKeyDown(evt);
108 var evt = keyevent('keypress', {code: 'KeyA', charCode: 0x41});
109 kbd._handleKeyPress(evt);
110 expect(evt.preventDefault).to.have.been.called;
f00b6fb6 111 });
112 });
f00b6fb6 113 });
114
f00b6fb6 115 describe('Track Key State', function() {
f7363fd2
PO
116 it('should send release using the same keysym as the press', function(done) {
117 var kbd = new Keyboard({
118 onKeyEvent: function(keysym, code, down) {
119 expect(keysym).to.be.equal(0x61);
120 expect(code).to.be.equal('KeyA');
121 if (!down) {
122 done();
123 }
124 }});
125 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
126 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'b'}));
f00b6fb6 127 });
ae820533
PO
128 it('should send the same keysym for multiple presses', function() {
129 var count = 0;
130 var kbd = new Keyboard({
131 onKeyEvent: function(keysym, code, down) {
132 expect(keysym).to.be.equal(0x61);
133 expect(code).to.be.equal('KeyA');
134 expect(down).to.be.equal(true);
135 count++;
136 }});
137 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
138 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'b'}));
139 expect(count).to.be.equal(2);
140 });
f7363fd2
PO
141 it('should do nothing on keyup events if no keys are down', function() {
142 var callback = sinon.spy();
143 var kbd = new Keyboard({onKeyEvent: callback});
144 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
145 expect(callback).to.not.have.been.called;
146 });
f7363fd2 147 });
f00b6fb6 148
bf43c263
PO
149 describe('Shuffle modifiers on macOS', function() {
150 var origNavigator;
151 beforeEach(function () {
152 // window.navigator is a protected read-only property in many
153 // environments, so we need to redefine it whilst running these
154 // tests.
155 origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
156 if (origNavigator === undefined) {
157 // Object.getOwnPropertyDescriptor() doesn't work
158 // properly in any version of IE
159 this.skip();
160 }
161
162 Object.defineProperty(window, "navigator", {value: {}});
163 if (window.navigator.platform !== undefined) {
164 // Object.defineProperty() doesn't work properly in old
165 // versions of Chrome
166 this.skip();
167 }
168
169 window.navigator.platform = "Mac x86_64";
170 });
171 afterEach(function () {
172 Object.defineProperty(window, "navigator", origNavigator);
173 });
174
175 it('should change Alt to AltGraph', function() {
176 var count = 0;
177 var kbd = new Keyboard({
178 onKeyEvent: function(keysym, code, down) {
179 switch (count++) {
180 case 0:
181 expect(keysym).to.be.equal(0xFF7E);
182 expect(code).to.be.equal('AltLeft');
183 break;
184 case 1:
185 expect(keysym).to.be.equal(0xFE03);
186 expect(code).to.be.equal('AltRight');
187 break;
188 }
189 }});
9782d4a3
PO
190 kbd._handleKeyDown(keyevent('keydown', {code: 'AltLeft', key: 'Alt', location: 1}));
191 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2}));
bf43c263
PO
192 expect(count).to.be.equal(2);
193 });
194 it('should change left Super to Alt', function(done) {
195 var kbd = new Keyboard({
196 onKeyEvent: function(keysym, code, down) {
197 expect(keysym).to.be.equal(0xFFE9);
198 expect(code).to.be.equal('MetaLeft');
199 done();
200 }});
9782d4a3 201 kbd._handleKeyDown(keyevent('keydown', {code: 'MetaLeft', key: 'Meta', location: 1}));
bf43c263
PO
202 });
203 it('should change right Super to left Super', function(done) {
204 var kbd = new Keyboard({
205 onKeyEvent: function(keysym, code, down) {
206 expect(keysym).to.be.equal(0xFFEB);
207 expect(code).to.be.equal('MetaRight');
208 done();
209 }});
9782d4a3 210 kbd._handleKeyDown(keyevent('keydown', {code: 'MetaRight', key: 'Meta', location: 2}));
bf43c263
PO
211 });
212 });
213
214 describe('Escape AltGraph on Windows', function() {
f7363fd2
PO
215 var origNavigator;
216 beforeEach(function () {
217 // window.navigator is a protected read-only property in many
218 // environments, so we need to redefine it whilst running these
219 // tests.
220 origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
221 if (origNavigator === undefined) {
222 // Object.getOwnPropertyDescriptor() doesn't work
223 // properly in any version of IE
224 this.skip();
225 }
226
227 Object.defineProperty(window, "navigator", {value: {}});
228 if (window.navigator.platform !== undefined) {
229 // Object.defineProperty() doesn't work properly in old
230 // versions of Chrome
231 this.skip();
232 }
233
234 window.navigator.platform = "Windows x86_64";
235 });
236 afterEach(function () {
237 Object.defineProperty(window, "navigator", origNavigator);
238 });
239
bf43c263 240 it('should generate fake undo/redo events on press when AltGraph is down', function() {
f00b6fb6 241 var times_called = 0;
f7363fd2
PO
242 var kbd = new Keyboard({
243 onKeyEvent: function(keysym, code, down) {
244 switch(times_called++) {
245 case 0:
246 expect(keysym).to.be.equal(0xFFE3);
247 expect(code).to.be.equal('ControlLeft');
248 expect(down).to.be.equal(true);
249 break;
250 case 1:
bf43c263
PO
251 expect(keysym).to.be.equal(0xFFEA);
252 expect(code).to.be.equal('AltRight');
f7363fd2
PO
253 expect(down).to.be.equal(true);
254 break;
255 case 2:
bf43c263
PO
256 expect(keysym).to.be.equal(0xFFEA);
257 expect(code).to.be.equal('AltRight');
f7363fd2
PO
258 expect(down).to.be.equal(false);
259 break;
260 case 3:
261 expect(keysym).to.be.equal(0xFFE3);
bf43c263 262 expect(code).to.be.equal('ControlLeft');
f7363fd2
PO
263 expect(down).to.be.equal(false);
264 break;
265 case 4:
266 expect(keysym).to.be.equal(0x61);
267 expect(code).to.be.equal('KeyA');
268 expect(down).to.be.equal(true);
269 break;
270 case 5:
bf43c263
PO
271 expect(keysym).to.be.equal(0xFFE3);
272 expect(code).to.be.equal('ControlLeft');
f7363fd2
PO
273 expect(down).to.be.equal(true);
274 break;
275 case 6:
bf43c263
PO
276 expect(keysym).to.be.equal(0xFFEA);
277 expect(code).to.be.equal('AltRight');
f7363fd2
PO
278 expect(down).to.be.equal(true);
279 break;
280 }
281 }});
282 // First the modifier combo
9782d4a3
PO
283 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
284 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2}));
f7363fd2
PO
285 // Next a normal character
286 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
287 expect(times_called).to.be.equal(7);
288 });
289 it('should no do anything on key release', function() {
f00b6fb6 290 var times_called = 0;
f7363fd2
PO
291 var kbd = new Keyboard({
292 onKeyEvent: function(keysym, code, down) {
293 switch(times_called++) {
294 case 7:
295 expect(keysym).to.be.equal(0x61);
296 expect(code).to.be.equal('KeyA');
297 expect(down).to.be.equal(false);
298 break;
299 }
300 }});
301 // First the modifier combo
9782d4a3
PO
302 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
303 kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2}));
f7363fd2
PO
304 // Next a normal character
305 kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
306 kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
307 expect(times_called).to.be.equal(8);
308 });
309 it('should not consider a char modifier to be down on the modifier key itself', function() {
f00b6fb6 310 var times_called = 0;
f7363fd2
PO
311 var kbd = new Keyboard({
312 onKeyEvent: function(keysym, code, down) {
313 switch(times_called++) {
314 case 0:
315 expect(keysym).to.be.equal(0xFFE3);
316 expect(code).to.be.equal('ControlLeft');
317 expect(down).to.be.equal(true);
318 break;
319 case 1:
320 expect(keysym).to.be.equal(0xFFE9);
321 expect(code).to.be.equal('AltLeft');
322 expect(down).to.be.equal(true);
323 break;
324 case 2:
325 expect(keysym).to.be.equal(0xFFE3);
326 expect(code).to.be.equal('ControlLeft');
327 expect(down).to.be.equal(true);
328 break;
329 }
330 }});
331 // First the modifier combo
9782d4a3
PO
332 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
333 kbd._handleKeyDown(keyevent('keydown', {code: 'AltLeft', key: 'Alt', location: 1}));
f7363fd2 334 // Then one of the keys again
9782d4a3 335 kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
f00b6fb6 336 expect(times_called).to.be.equal(3);
f00b6fb6 337 });
338 });
339});