gdkkeys-win32: Fix handling of SGCAPS

Contrary to what you can read on the internet, SGCAPS keys don't work
by having capslock toggle the KBDCTRL bit, they actually have two
consecutive table entries, the first of which is for the normal
version and the second of which is for the capslocked version.

Background: SGCAPS is short for Swiss German caps because Swiss German
was the first layout to use this feature. For keys with the SGCAPS flag,
capslock has a different effect than pressing shift. For example:
Shift + ü = è,  CapsLock + ü = Ü,  CapsLock + Shift + ü = È
This commit is contained in:
Philip Zander 2022-01-12 21:36:41 +01:00 committed by Luca Bacci
parent 438fad803e
commit db0234ecb4
No known key found for this signature in database
GPG Key ID: 8E3C8D989C98883D
3 changed files with 15 additions and 20 deletions

View File

@ -291,6 +291,7 @@ vk_to_char_fuzzy (GdkWin32KeymapLayoutInfo *info,
if (entry->VirtualKey == vk)
{
gboolean have_sgcaps = FALSE;
WCHAR best_char = WCH_NONE;
BYTE best_modifiers = 0;
int best_score = -1;
@ -316,10 +317,11 @@ vk_to_char_fuzzy (GdkWin32KeymapLayoutInfo *info,
mod_bits ^= KBDSHIFT;
/* In the Swiss German layout, CapsLock + key is different from Shift + key
* for some keys. For such keys, Capslock toggles the KBDCTRL bit. */
* for some keys. For such keys, the characters for active capslock are
* in the next entry. */
if ((entry->Attributes & SGCAPS) &&
(lock_bits & CAPLOK))
mod_bits ^= KBDCTRL;
have_sgcaps = TRUE;
/* I'm not totally sure how kanalok behaves, for now I assume that there
* aren't any special cases. */
@ -336,12 +338,12 @@ vk_to_char_fuzzy (GdkWin32KeymapLayoutInfo *info,
int score;
if (candidate_modbits & ~mod_bits)
continue;
continue;
c = entry->wch[level];
if (c == WCH_DEAD)
if (c == WCH_DEAD || have_sgcaps)
{
/* Next entry contains the undead keys */
/* Next entry contains the undead/capslocked keys */
PVK_TO_WCHARS next_entry;
next_entry = (PVK_TO_WCHARS) ((PBYTE) wch_table->pVkToWchars.ptr
+ entry_size * (entry_index + 1));
@ -458,8 +460,13 @@ init_vk_lookup_table (GdkWin32KeymapLayoutInfo *info)
/* Lookup table to find entry for a VK in O(1). */
info->vk_lookup_table[entry->VirtualKey].table = table_idx;
info->vk_lookup_table[entry->VirtualKey].index = entry_idx;
/* Only add the first entry, as some layouts (Swiss German) contain
* multiple successive entries for the same VK (SGCAPS). */
if (info->vk_lookup_table[entry->VirtualKey].table < 0)
{
info->vk_lookup_table[entry->VirtualKey].table = table_idx;
info->vk_lookup_table[entry->VirtualKey].index = entry_idx;
}
/* Create reverse lookup entries to find a VK+modifier combinations
* that results in a given character. */
@ -497,7 +504,7 @@ init_vk_lookup_table (GdkWin32KeymapLayoutInfo *info)
g_hash_table_insert (info->reverse_lookup_table,
GINT_TO_POINTER (c),
GINT_TO_POINTER (inserted_idx));
}
}
}
}
}

View File

@ -602,17 +602,6 @@ _gdk_win32_keymap_set_active_layout (GdkWin32Keymap *keymap,
}
}
gboolean
_gdk_win32_keymap_has_altgr (GdkWin32Keymap *keymap)
{
/* We just return FALSE, since it doesn't really matter because AltGr
* is the same as Ctrl + Alt. Hence, we will never get a GDK_MOD2_MASK,
* rather we will just get GDK_CONTROL_MASK | GDK_ALT_MASK. I don't
* think there is any clean way to distinguish <Ctrl + Alt> from
* <AltGr> on Windows. */
return FALSE;
}
guint8
_gdk_win32_keymap_get_active_group (GdkWin32Keymap *keymap)
{

View File

@ -351,7 +351,6 @@ GList *_gdk_win32_display_list_devices (GdkDisplay *dpy);
gboolean _gdk_win32_display_has_pending (GdkDisplay *display);
void _gdk_win32_display_queue_events (GdkDisplay *display);
gboolean _gdk_win32_keymap_has_altgr (GdkWin32Keymap *keymap);
guint8 _gdk_win32_keymap_get_active_group (GdkWin32Keymap *keymap);
guint8 _gdk_win32_keymap_get_rshift_scancode (GdkWin32Keymap *keymap);
void _gdk_win32_keymap_set_active_layout (GdkWin32Keymap *keymap,