@@ -374,6 +374,82 @@ test_explicit_actions(struct xkb_context *ctx)
374374 }
375375}
376376
377+ static void
378+ test_simultaneous_modifier_clear (struct xkb_context * context )
379+ {
380+ struct xkb_keymap * keymap ;
381+
382+ keymap = test_compile_rules (context , "evdev" , "pc104" ,
383+ "simultaneous-mods-latches" , "" , "" );
384+ assert (keymap );
385+
386+ /*
387+ * Github issue #583: simultaneous latches of *different* modifiers should
388+ * not affect each other when clearing their mods.
389+ */
390+
391+ /* Original key sequence reported in the issue */
392+ assert (test_key_seq (keymap ,
393+ KEY_LEFTCTRL , DOWN , XKB_KEY_Control_L , NEXT , /* Set Control */
394+ KEY_RIGHTALT , BOTH , XKB_KEY_ISO_Level5_Latch , NEXT , /* Latch Level5 */
395+ KEY_LEFTCTRL , UP , XKB_KEY_Control_L , NEXT , /* Unset Control */
396+ KEY_RIGHTALT , BOTH , XKB_KEY_ISO_Level3_Latch , NEXT , /* Latch Level3 */
397+ KEY_Z , BOTH , XKB_KEY_ydiaeresis , NEXT , /* Unlatch Level3, unlatch Level5 */
398+ KEY_Z , BOTH , XKB_KEY_z , NEXT ,
399+ KEY_Z , BOTH , XKB_KEY_z , FINISH
400+ ));
401+
402+ /* Alternative key sequence with only mod latches */
403+ assert (test_key_seq (keymap ,
404+ KEY_RIGHTCTRL , BOTH , XKB_KEY_Control_R , NEXT , /* Latch Control */
405+ KEY_RIGHTALT , BOTH , XKB_KEY_ISO_Level5_Latch , NEXT , /* Latch Level5 */
406+ KEY_LEFTMETA , BOTH , XKB_KEY_ISO_Level3_Latch , NEXT , /* Latch Level3 */
407+ KEY_Z , BOTH , XKB_KEY_ydiaeresis , NEXT , /* Unlatch Control, Level3 and Level5 */
408+ KEY_Z , BOTH , XKB_KEY_z , NEXT ,
409+ KEY_Z , BOTH , XKB_KEY_z , NEXT ,
410+ KEY_X , BOTH , XKB_KEY_x , FINISH
411+ ));
412+
413+ /* Alternative simplier key sequence */
414+ assert (test_key_seq (keymap ,
415+ KEY_LEFTMETA , BOTH , XKB_KEY_ISO_Level3_Latch , NEXT , /* Latch Level3 */
416+ KEY_RIGHTMETA , BOTH , XKB_KEY_ISO_Level5_Latch , NEXT , /* Latch Level5 */
417+ KEY_Z , BOTH , XKB_KEY_ydiaeresis , NEXT , /* Unlatch Level3, unlatch Level5 */
418+ KEY_Z , BOTH , XKB_KEY_z , NEXT ,
419+ KEY_Z , BOTH , XKB_KEY_z , FINISH
420+ ));
421+
422+ /*
423+ * Test same modifier latch but on a different key
424+ */
425+
426+ /* Level 3 */
427+ assert (test_key_seq (keymap ,
428+ KEY_LEFTMETA , BOTH , XKB_KEY_ISO_Level3_Latch , NEXT , /* Latch Level3 */
429+ KEY_RIGHTALT , BOTH , XKB_KEY_ISO_Level3_Latch , NEXT , /* Lock Level3 via latch */
430+ KEY_Z , BOTH , XKB_KEY_y , NEXT , /* Locked Level3 */
431+ KEY_Z , BOTH , XKB_KEY_y , NEXT ,
432+ KEY_RIGHTALT , BOTH , XKB_KEY_ISO_Level3_Latch , NEXT , /* Unlock Level3 via latch */
433+ KEY_Z , BOTH , XKB_KEY_z , NEXT ,
434+ KEY_Z , BOTH , XKB_KEY_z , FINISH
435+ ));
436+
437+ /* Level 5, via Control latch */
438+ assert (test_key_seq (keymap ,
439+ KEY_RIGHTCTRL , BOTH , XKB_KEY_Control_R , NEXT , /* Latch Control */
440+ KEY_RIGHTALT , BOTH , XKB_KEY_ISO_Level5_Latch , NEXT , /* Lock Level5 via latch */
441+ KEY_RIGHTMETA , BOTH , XKB_KEY_ISO_Level5_Latch , NEXT , /* Latch Level5 */
442+ KEY_Z , BOTH , XKB_KEY_ezh , NEXT , /* Locked Level5 */
443+ KEY_Z , BOTH , XKB_KEY_ezh , NEXT ,
444+ KEY_RIGHTMETA , BOTH , XKB_KEY_ISO_Level5_Latch , NEXT , /* Unlock Level5 via latch */
445+ KEY_Z , BOTH , XKB_KEY_z , NEXT ,
446+ KEY_Z , BOTH , XKB_KEY_z , NEXT ,
447+ KEY_X , BOTH , XKB_KEY_x , FINISH
448+ ));
449+
450+ xkb_keymap_unref (keymap );
451+ }
452+
377453int
378454main (void )
379455{
@@ -384,6 +460,7 @@ main(void)
384460
385461 assert (ctx );
386462
463+ test_simultaneous_modifier_clear (ctx );
387464 test_group_latch (ctx );
388465 test_explicit_actions (ctx );
389466
@@ -839,5 +916,5 @@ main(void)
839916
840917 xkb_keymap_unref (keymap );
841918 xkb_context_unref (ctx );
842- return 0 ;
919+ return EXIT_SUCCESS ;
843920}
0 commit comments