Bug#1111485: Acknowledgement (orca: Incorrectly determines the active keyboard layout)
Samuel Thibault
sthibault at debian.org
Sun Aug 24 20:13:32 BST 2025
Hello,
Илья Пащук, le dim. 24 août 2025 13:35:58 +0300, a ecrit:
> +resolve_keysym_with_xkb (Display *dpy, KeyCode keycode, unsigned int state, unsigned int numlock_physical_mask)
> +{
> + /* Игнорируем Lock/NumLock при выборе уровня */
Could you translate these comments to english please?
Samuel
> + unsigned int cleaned = state & ~(numlock_physical_mask | LockMask);
> +
> + XkbStateRec st;
> + memset (&st, 0, sizeof (st));
> + XkbGetState (dpy, XkbUseCoreKbd, &st);
> +
> + /* Вычислим «флаги» модификаторов, а не индекс уровня напрямую */
> + unsigned int altgr_mask = XkbKeysymToModifiers (dpy, XK_ISO_Level3_Shift);
> + unsigned int level5_mask = XkbKeysymToModifiers (dpy, XK_ISO_Level5_Shift);
> +
> + gboolean shift_on = (cleaned & ShiftMask) != 0;
> + gboolean altgr_on = (altgr_mask && (cleaned & altgr_mask));
> + gboolean level5_on = (level5_mask && (cleaned & level5_mask));
> +
> + /* Приоритетная последовательность уровней для распространённых типов (2/4/8 level):
> + * - без Level5:
> + * (none) -> [0,1,2,3]
> + * (Shift) -> [1,0,3,2]
> + * (AltGr) -> [2,3,0,1]
> + * (Shift+AltGr) -> [3,2,1,0]
> + * - с Level5: аналогично, но сначала проверяем «высшие» уровни (4..7) при активном Level5
> + */
> + int candidates[8];
> + int n = 0;
> +
> + if (!level5_on)
> + {
> + if (!shift_on && !altgr_on) { int pref[] = {0,1,2,3}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> + else if (shift_on && !altgr_on) { int pref[] = {1,0,3,2}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> + else if (!shift_on && altgr_on) { int pref[] = {2,3,0,1}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> + else /* shift_on && altgr_on */ { int pref[] = {3,2,1,0}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> +
> + /* затем добиваем уровни 4..7 про запас */
> + for (int lvl = 4; lvl < 8; lvl++) candidates[n++] = lvl;
> + }
> + else
> + {
> + /* Level5 активен: сначала 4..7, по аналогичной логике */
> + if (!shift_on && !altgr_on) { int pref[] = {4,5,6,7}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> + else if (shift_on && !altgr_on) { int pref[] = {5,4,7,6}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> + else if (!shift_on && altgr_on) { int pref[] = {6,7,4,5}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> + else /* shift_on && altgr_on */ { int pref[] = {7,6,5,4}; memcpy(candidates, pref, sizeof(pref)); n = 4; }
> +
> + /* затем уровни 0..3 как запасной вариант */
> + for (int lvl = 0; lvl < 4; lvl++) candidates[n++] = lvl;
> + }
> +
> + /* 1) Пробуем кандидатов в текущей группе */
> + for (int i = 0; i < n; i++)
> + {
> + KeySym t = XkbKeycodeToKeysym (dpy, keycode, st.group, candidates[i]);
> + if (t != NoSymbol && t != 0)
> + return t;
> + }
> +
> + /* 2) Полный перебор уровней текущей группы на всякий случай */
> + for (int lvl = 0; lvl < 8; lvl++)
> + {
> + KeySym t = XkbKeycodeToKeysym (dpy, keycode, st.group, lvl);
> + if (t != NoSymbol && t != 0)
> + return t;
> + }
> +
> + /* 3) Последний шанс: группа 0, сначала по тем же кандидатам */
> + for (int i = 0; i < n; i++)
> + {
> + KeySym t = XkbKeycodeToKeysym (dpy, keycode, 0, candidates[i]);
> + if (t != NoSymbol && t != 0)
> + return t;
> + }
> +
> + /* 4) И полный перебор группы 0 */
> + for (int lvl = 0; lvl < 8; lvl++)
> + {
> + KeySym t = XkbKeycodeToKeysym (dpy, keycode, 0, lvl);
> + if (t != NoSymbol && t != 0)
> + return t;
> + }
> +
> + return NoSymbol;
> +}
> +
> static gboolean
> do_event_dispatch (gpointer user_data)
> {
> @@ -352,7 +444,6 @@ do_event_dispatch (gpointer user_data)
> XEvent xevent;
> char text[10];
> KeySym keysym;
> - XComposeStatus status;
> guint modifiers;
>
> g_object_ref (device);
> @@ -365,7 +456,14 @@ do_event_dispatch (gpointer user_data)
> {
> case KeyPress:
> case KeyRelease:
> - XLookupString (&xevent.xkey, text, sizeof (text), &keysym, &status);
> + /* Resolve keysym via XKB using current state; avoid stale text. */
> + {
> + keysym = resolve_keysym_with_xkb (priv->display,
> + xevent.xkey.keycode,
> + xevent.xkey.state,
> + priv->numlock_physical_mask);
> + text[0] = '\0';
> + }
> modifiers = xevent.xkey.state | priv->virtual_mods_enabled;
> if (modifiers & priv->numlock_physical_mask)
> {
> @@ -388,9 +486,14 @@ do_event_dispatch (gpointer user_data)
> case XI_KeyPress:
> case XI_KeyRelease:
> xi2keyevent (xiDevEv, &keyevent);
> - XLookupString ((XKeyEvent *) &keyevent, text, sizeof (text), &keysym, &status);
> - if (text[0] < ' ')
> + /* Resolve keysym via XKB using current state (XI2 path). */
> + {
> + keysym = resolve_keysym_with_xkb (priv->display,
> + xiDevEv->detail,
> + keyevent.xkey.state,
> + priv->numlock_physical_mask);
> text[0] = '\0';
> + }
> set_virtual_modifier (device, xiRawEv->detail, xevent.xcookie.evtype == XI_KeyPress);
> modifiers = keyevent.xkey.state | priv->virtual_mods_enabled;
> if (modifiers & priv->numlock_physical_mask)
> Index: at-spi2-core-2.56.2/registryd/deviceeventcontroller-x11.c
> ===================================================================
> --- at-spi2-core-2.56.2.orig/registryd/deviceeventcontroller-x11.c
> +++ at-spi2-core-2.56.2/registryd/deviceeventcontroller-x11.c
> @@ -720,6 +720,64 @@ spi_controller_register_with_devices (Sp
> x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
> }
>
> +/* Compute effective XKB level from modifier state:
> + * bit0: Shift, bit1: ISO_Level3_Shift (AltGr), bit2: ISO_Level5_Shift.
> + * Lock and NumLock do not affect level.
> + */
> +static unsigned int
> +get_level_from_state (Display *dpy, unsigned int state)
> +{
> + unsigned int level = 0;
> + unsigned int altgr_mask = XkbKeysymToModifiers (dpy, XK_ISO_Level3_Shift);
> + unsigned int level5_mask = XkbKeysymToModifiers (dpy, XK_ISO_Level5_Shift);
> +
> + if (state & ShiftMask)
> + level |= 1;
> + if (altgr_mask && (state & altgr_mask))
> + level |= 2;
> + if (level5_mask && (state & level5_mask))
> + level |= 4;
> +
> + return level;
> +}
> +
> +/* Resolve keysym using explicit current group (st.group) and effective level.
> + * Fallback: scan levels in current group, then group 0 for specials.
> + */
> +static KeySym
> +resolve_keysym_with_xkb (Display *dpy, KeyCode keycode, unsigned int state)
> +{
> + unsigned int cleaned = state & ~(_numlock_physical_mask | LockMask);
> +
> + XkbStateRec st;
> + memset (&st, 0, sizeof (st));
> + XkbGetState (dpy, XkbUseCoreKbd, &st);
> +
> + unsigned int level = get_level_from_state (dpy, cleaned);
> +
> + KeySym ks = XkbKeycodeToKeysym (dpy, keycode, st.group, level);
> + if (ks != NoSymbol && ks != 0)
> + return ks;
> +
> + /* Fallback 1: scan levels in current group */
> + for (int lvl = 0; lvl < 8; lvl++)
> + {
> + KeySym t = XkbKeycodeToKeysym (dpy, keycode, st.group, lvl);
> + if (t != NoSymbol && t != 0)
> + return t;
> + }
> +
> + /* Fallback 2: scan group 0 */
> + for (int lvl = 0; lvl < 8; lvl++)
> + {
> + KeySym t = XkbKeycodeToKeysym (dpy, keycode, 0, lvl);
> + if (t != NoSymbol && t != 0)
> + return t;
> + }
> +
> + return NoSymbol;
> +}
> +
> static Accessibility_DeviceEvent
> spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
> {
> @@ -729,7 +787,11 @@ spi_keystroke_from_x_key_event (XKeyEven
> char cbuf[21];
> int nbytes;
>
> - nbytes = XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL);
> + /* Resolve keysym via XKB using current state; honors group and effective modifiers. */
> + keysym = resolve_keysym_with_xkb (spi_get_display (),
> + x_key_event->keycode,
> + x_key_event->state);
> +
> key_event.id = (dbus_int32_t) (keysym);
> key_event.hw_code = (dbus_int16_t) x_key_event->keycode;
> if (((XEvent *) x_key_event)->type == KeyPress)
> @@ -820,22 +882,21 @@ spi_keystroke_from_x_key_event (XKeyEven
> key_event.event_string = g_strdup ("Right");
> break;
> default:
> - if (nbytes > 0)
> - {
> - gunichar c;
> - cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */
> - key_event.event_string = g_strdup (cbuf);
> - c = keysym2ucs (keysym);
> - if (c > 0 && !g_unichar_iscntrl (c))
> - {
> - key_event.is_text = TRUE;
> - /* incorrect for some composed chars? */
> - }
> - }
> - else
> - {
> - key_event.event_string = g_strdup ("");
> - }
> + {
> + gunichar uc = (gunichar) keysym2ucs (keysym);
> + if (uc > 0 && !g_unichar_iscntrl (uc))
> + {
> + char utf8[6];
> + int len = g_unichar_to_utf8 (uc, utf8);
> + utf8[len] = '\0';
> + key_event.event_string = g_strdup (utf8);
> + key_event.is_text = TRUE;
> + }
> + else
> + {
> + key_event.event_string = g_strdup ("");
> + }
> + }
> }
>
> key_event.timestamp = (dbus_uint32_t) x_key_event->time;
> _______________________________________________
> Pkg-a11y-devel mailing list
> Pkg-a11y-devel at alioth-lists.debian.net
> https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/pkg-a11y-devel
--
Samuel
Créer une hiérarchie supplementaire pour remedier à un problème (?) de
dispersion est d'une logique digne des Shadocks.
* BT in: Guide du Cabaliste Usenet - La Cabale vote oui (les Shadocks aussi) *
More information about the Pkg-a11y-devel
mailing list