@@ -350,45 +350,45 @@ void main() {
350
350
);
351
351
}, skip: isBrowser); // [intended] This is a GLFW-specific test.
352
352
353
+ Future <void > simulateGTKKeyEvent (bool keyDown, int scancode, int keycode, int modifiers) async {
354
+ final Map <String , dynamic > data = < String , dynamic > {
355
+ 'type' : keyDown ? 'keydown' : 'keyup' ,
356
+ 'keymap' : 'linux' ,
357
+ 'toolkit' : 'gtk' ,
358
+ 'scanCode' : scancode,
359
+ 'keyCode' : keycode,
360
+ 'modifiers' : modifiers,
361
+ };
362
+ // Dispatch an empty key data to disable HardwareKeyboard sanity check,
363
+ // since we're only testing if the raw keyboard can handle the message.
364
+ // In a real application, the embedder responder will send the correct key data
365
+ // (which is tested in the engine).
366
+ TestDefaultBinaryMessengerBinding .instance! .keyEventManager.handleKeyData (const ui.KeyData (
367
+ type: ui.KeyEventType .down,
368
+ timeStamp: Duration .zero,
369
+ logical: 0 ,
370
+ physical: 0 ,
371
+ character: null ,
372
+ synthesized: false ,
373
+ ));
374
+ await TestDefaultBinaryMessengerBinding .instance! .defaultBinaryMessenger.handlePlatformMessage (
375
+ SystemChannels .keyEvent.name,
376
+ SystemChannels .keyEvent.codec.encodeMessage (data),
377
+ (ByteData ? data) {},
378
+ );
379
+ }
353
380
354
381
// Regression test for https://github.com/flutter/flutter/issues/93278 .
355
382
//
356
383
// GTK has some weird behavior where the tested key event sequence will
357
384
// result in a AltRight down event without Alt bitmask.
358
385
testWidgets ('keysPressed modifiers are synchronized with key events on Linux GTK (down events)' , (WidgetTester tester) async {
359
386
expect (RawKeyboard .instance.keysPressed, isEmpty);
360
- Future <void > simulate (bool keyDown, int scancode, int keycode, int modifiers) async {
361
- final Map <String , dynamic > data = < String , dynamic > {
362
- 'type' : keyDown ? 'keydown' : 'keyup' ,
363
- 'keymap' : 'linux' ,
364
- 'toolkit' : 'gtk' ,
365
- 'scanCode' : scancode,
366
- 'keyCode' : keycode,
367
- 'modifiers' : modifiers,
368
- };
369
- // Dispatch an empty key data to disable HardwareKeyboard sanity check,
370
- // since we're only testing if the raw keyboard can handle the message.
371
- // In real application the embedder responder will send correct key data
372
- // (which is tested in the engine.)
373
- TestDefaultBinaryMessengerBinding .instance! .keyEventManager.handleKeyData (const ui.KeyData (
374
- type: ui.KeyEventType .down,
375
- timeStamp: Duration .zero,
376
- logical: 0 ,
377
- physical: 0 ,
378
- character: null ,
379
- synthesized: false ,
380
- ));
381
- await TestDefaultBinaryMessengerBinding .instance! .defaultBinaryMessenger.handlePlatformMessage (
382
- SystemChannels .keyEvent.name,
383
- SystemChannels .keyEvent.codec.encodeMessage (data),
384
- (ByteData ? data) {},
385
- );
386
- }
387
387
388
- await simulate (true , 0x6c /*AltRight*/ , 0xffea /*AltRight*/ , 0x2000000 );
389
- await simulate (true , 0x32 /*ShiftLeft*/ , 0xfe08 /*NextGroup*/ , 0x2000008 /*MOD3*/ );
390
- await simulate (false , 0x6c /*AltRight*/ , 0xfe03 /*AltRight*/ , 0x2002008 /*MOD3|Reserve14*/ );
391
- await simulate (true , 0x6c /*AltRight*/ , 0xfe03 /*AltRight*/ , 0x2002000 /*Reserve14*/ );
388
+ await simulateGTKKeyEvent (true , 0x6c /*AltRight*/ , 0xffea /*AltRight*/ , 0x2000000 );
389
+ await simulateGTKKeyEvent (true , 0x32 /*ShiftLeft*/ , 0xfe08 /*NextGroup*/ , 0x2000008 /*MOD3*/ );
390
+ await simulateGTKKeyEvent (false , 0x6c /*AltRight*/ , 0xfe03 /*AltRight*/ , 0x2002008 /*MOD3|Reserve14*/ );
391
+ await simulateGTKKeyEvent (true , 0x6c /*AltRight*/ , 0xfe03 /*AltRight*/ , 0x2002000 /*Reserve14*/ );
392
392
expect (
393
393
RawKeyboard .instance.keysPressed,
394
394
equals (
@@ -399,6 +399,56 @@ void main() {
399
399
);
400
400
}, skip: isBrowser); // [intended] This is a GTK-specific test.
401
401
402
+ // Regression test for https://github.com/flutter/flutter/issues/114591 .
403
+ //
404
+ // On Linux, CapsLock can be remapped to a non-modifier key.
405
+ testWidgets ('CapsLock should not be release when remapped on Linux' , (WidgetTester tester) async {
406
+ expect (RawKeyboard .instance.keysPressed, isEmpty);
407
+
408
+ await simulateGTKKeyEvent (true , 0x42 /*CapsLock*/ , 0xff08 /*Backspace*/ , 0x2000000 );
409
+ expect (
410
+ RawKeyboard .instance.keysPressed,
411
+ equals (
412
+ < LogicalKeyboardKey > {
413
+ LogicalKeyboardKey .backspace,
414
+ },
415
+ ),
416
+ );
417
+ }, skip: isBrowser); // [intended] This is a GTK-specific test.
418
+
419
+ // Regression test for https://github.com/flutter/flutter/issues/114591 .
420
+ //
421
+ // On Web, CapsLock can be remapped to a non-modifier key.
422
+ testWidgets ('CapsLock should not be release when remapped on Web' , (WidgetTester _) async {
423
+ final List <RawKeyEvent > events = < RawKeyEvent > [];
424
+ RawKeyboard .instance.addListener (events.add);
425
+ addTearDown (() {
426
+ RawKeyboard .instance.removeListener (events.add);
427
+ });
428
+ await TestDefaultBinaryMessengerBinding .instance! .defaultBinaryMessenger.handlePlatformMessage (
429
+ SystemChannels .keyEvent.name,
430
+ SystemChannels .keyEvent.codec.encodeMessage (const < String , dynamic > {
431
+ 'type' : 'keydown' ,
432
+ 'keymap' : 'web' ,
433
+ 'code' : 'CapsLock' ,
434
+ 'key' : 'Backspace' ,
435
+ 'location' : 0 ,
436
+ 'metaState' : 0 ,
437
+ 'keyCode' : 8 ,
438
+ }),
439
+ (ByteData ? data) { },
440
+ );
441
+
442
+ expect (
443
+ RawKeyboard .instance.keysPressed,
444
+ equals (
445
+ < LogicalKeyboardKey > {
446
+ LogicalKeyboardKey .backspace,
447
+ },
448
+ ),
449
+ );
450
+ }, skip: ! isBrowser); // [intended] This is a Browser-specific test.
451
+
402
452
testWidgets ('keysPressed modifiers are synchronized with key events on web' , (WidgetTester tester) async {
403
453
expect (RawKeyboard .instance.keysPressed, isEmpty);
404
454
// Generate the data for a regular key down event. Change the modifiers so
0 commit comments