@@ -350,45 +350,45 @@ void main() {
350350 );
351351 }, skip: isBrowser); // [intended] This is a GLFW-specific test.
352352
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+ }
353380
354381 // Regression test for https://github.com/flutter/flutter/issues/93278 .
355382 //
356383 // GTK has some weird behavior where the tested key event sequence will
357384 // result in a AltRight down event without Alt bitmask.
358385 testWidgets ('keysPressed modifiers are synchronized with key events on Linux GTK (down events)' , (WidgetTester tester) async {
359386 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- }
387387
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*/ );
392392 expect (
393393 RawKeyboard .instance.keysPressed,
394394 equals (
@@ -399,6 +399,56 @@ void main() {
399399 );
400400 }, skip: isBrowser); // [intended] This is a GTK-specific test.
401401
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+
402452 testWidgets ('keysPressed modifiers are synchronized with key events on web' , (WidgetTester tester) async {
403453 expect (RawKeyboard .instance.keysPressed, isEmpty);
404454 // Generate the data for a regular key down event. Change the modifiers so
0 commit comments