gtk/gdk/win32/gdkkeys-win32.h
Philip Zander b0818f9535
gdkkeys-win32: Fix capslock handling
Previously, we treated CapsLock and KanaLock as part of the global
keyboard state, much like NumLock and ScrollLock, rather than using
the supplied modifier mask. This was because GDK does not have a
modifier mask for KanaLock, only for CapsLock, so it would not have been
possible to properly support it.

However, this approach ended up causing problems, with certain keyboard
shortcuts not registering when capslock was active. This was first
observed in Inkscape [0] and appears to affect shortcuts consisting of a
single key (like 'a') with no additional modifiers (wheareas shortcuts
like 'ctrl+a' work).

So now we are using the supplied GDK_LOCK_MASK instead, and dropped
support for KanaLock, which we probably don't need anyway (since regular
text input should be handled by the IME input module -- the keymap is
mainly for shortcuts and keybindings, where you don't really want
KanaLock).

[0] https://gitlab.com/inkscape/inkscape/-/issues/3082
2022-01-12 21:43:53 +01:00

169 lines
5.8 KiB
C

/*
* Copyright (c) 2021 Philip Zander
* Copyright (c) 2018 Microsoft
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <glib.h>
#include <windows.h>
/* For lookup table VK -> chars */
typedef struct
{
int table;
int index;
} GdkWin32KeymapTableAndIndex;
/* For reverse lookup char -> VKs */
typedef struct
{
BYTE mod_bits;
BYTE vk;
/* Index of next KeyEntry. -1 if there is no next entry. */
int next;
} GdkWin32KeymapKeyEntry;
typedef struct
{
HKL handle;
/* Keyboard layout identifier */
char name[KL_NAMELENGTH];
/* Path of the layout DLL */
char *file;
/* Handle of the layout DLL */
HINSTANCE lib;
/* The actual conversion tables provided by the layout DLL.
*
* This is a pointer to a KBDTABLES structure. The exact definition
* of this structure depends on the kernel on which the executable
* run and can in general only be determined at runtime. That's why
* we have to use a generic gpointer instead of the actual type here.
*
* See comment on GdkWin32KeymapImpl below for more information. */
gpointer tables;
/* VK -> chars lookup table so we don't have to do a linear scan
* every time we look up a key. */
GdkWin32KeymapTableAndIndex vk_lookup_table[256];
/* List of entries for reverse (char ->VKs) lookup. */
GArray *key_entries;
/* Reverse lookup table (char -> VKs). Key: Unichar. Value: int.
* The value is used to index into the key_entries array. The key_entries
* array can contain multiple consecutive entries for a given char.
* The end of the list for the char is marked by a key entry that has
* mod_bits and vk set to 0xFF. */
GHashTable *reverse_lookup_table;
/* Map level to modbits */
BYTE level_to_modbits[256];
/* Max Number of levels */
BYTE max_level;
/* Maximum possible value of a modbits bitset. */
BYTE max_modbit_value;
} GdkWin32KeymapLayoutInfo;
/* Some keyboard driver constants
* See https://github.com/microsoft/windows-rs/blob/0.28.0/crates/deps/sys/src/Windows/Win32/UI/Input/KeyboardAndMouse/mod.rs
*/
/* Modifier bits */
#define KBDBASE 0x00
#define KBDSHIFT 0x01
#define KBDCTRL 0x02
#define KBDALT 0x04
#define KBDKANA 0x08
#define KBDROYA 0x10
#define KBDLOYA 0x20
#define KBDGRPSELTAP 0x80
#define KBDALTGR (KBDCTRL| KBDALT)
/* */
#define SHFT_INVALID 0x0F
/* Char table constants */
#define WCH_NONE 0xF000
#define WCH_DEAD 0xF001
#define WCH_LGTR 0xF002
/* Char table flags */
#define CAPLOK 0x01
#define SGCAPS 0x02
#define CAPLOKALTGR 0x04
#define KANALOK 0x08
#define GRPSELTAP 0x80
/* IMPORTANT:
*
* Keyboard layout DLLs are dependent on the host architecture.
*
* - 32 bit systems have just one 32 bit DLL in System32.
* - 64 bit systems contain two versions of each layout DLL: One in System32
* for 64-bit applications, and one in SysWOW64 for 32-bit applications.
*
* Here comes the tricky part:
*
* The 32-bit DLL in SysWOW64 is *not* identical to the DLL you would find
* on a true 32 bit system, because all the pointers there are declared with
* the attribute `__ptr64` (which means they are 64 bits wide, but only the
* lower 32 bits are used).
*
* This leads to the following problems:
*
* (1) GCC does not support `__ptr64`
* (2) When compiling the 32-bit library, we need two versions of the same code
* and decide at run-time which one to execute, because we can't know at
* compile time whether we will be running on a true 32-bit system, or on
* WOW64.
*
* To solve this problem, we generate code for both cases (see
* gdkkeys-win32-impl.c + gdkkeys-win32-impl-wow64.c) and encapsulate
* the resulting functions in a struct of type GdkWin32KeymapImpl,
* allowing us to select the correct implementation at runtime.
*
*/
typedef struct
{
gboolean (*load_layout_dll) (const char *dll,
GdkWin32KeymapLayoutInfo *info);
void (*init_vk_lookup_table) (GdkWin32KeymapLayoutInfo *info);
BYTE (*keystate_to_modbits) (GdkWin32KeymapLayoutInfo *info,
const BYTE keystate[256]);
BYTE (*modbits_to_level) (GdkWin32KeymapLayoutInfo *info,
BYTE modbits);
WCHAR (*vk_to_char_fuzzy) (GdkWin32KeymapLayoutInfo *info,
BYTE mod_bits,
BYTE lock_bits,
BYTE *consumed_mod_bits,
gboolean *is_dead,
BYTE vk);
} GdkWin32KeymapImpl;