 cc47262ccb
			
		
	
	cc47262ccb
	
	
	
		
			
			For some users, GetKeyboardLayoutNameA() returns an alias instead of the fully resolved keyboard layout identifier. In that case, we have to query the registry to resolve the alias before we can look up the DLL path. See comments under #4610
		
			
				
	
	
		
			1152 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1152 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GDK - The GIMP Drawing Kit
 | |
|  * Copyright (C) 2000 Red Hat, Inc.
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public
 | |
|  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Modified by the GTK+ Team and others 1997-2020.  See the AUTHORS
 | |
|  * file for a list of people on the GTK+ Team.  See the ChangeLog
 | |
|  * files for a list of changes.  These files are distributed with
 | |
|  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
 | |
|  */
 | |
| #include "config.h"
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <limits.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #include "gdk.h"
 | |
| 
 | |
| #include "gdkprivate-win32.h"
 | |
| #include "gdkinternals.h"
 | |
| #include "gdkkeysyms.h"
 | |
| #include "gdkkeysprivate.h"
 | |
| #include "gdkwin32keys.h"
 | |
| 
 | |
| #include "gdkkeys-win32.h"
 | |
| 
 | |
| /* GdkWin32Keymap */
 | |
| 
 | |
| struct _GdkWin32KeymapClass
 | |
| {
 | |
|   GdkKeymapClass parent_class;
 | |
| };
 | |
| 
 | |
| struct _GdkWin32Keymap
 | |
| {
 | |
|   GdkKeymap parent_instance;
 | |
| 
 | |
|   /* Array of HKL */
 | |
|   GArray *layout_handles;
 | |
| 
 | |
|   /* Array of GdkWin32KeymapLayoutInfo */
 | |
|   GArray *layout_infos;
 | |
| 
 | |
|   /* Index of a handle in layout_handles,
 | |
|    * at any point it should be the same handle as GetKeyboardLayout(0) returns,
 | |
|    * but GDK caches it to avoid calling GetKeyboardLayout (0) every time.
 | |
|    */
 | |
|   guint8 active_layout;
 | |
| 
 | |
|   guint current_serial;
 | |
| 
 | |
|   /* Pointer to the implementation to be used. See comment in gdkkeys-win32.h.
 | |
|    * (we will dynamically choose at runtime for 32-bit builds based on whether
 | |
|    * we are running under WOW64)
 | |
|    */
 | |
|   const GdkWin32KeymapImpl *gdkwin32_keymap_impl;
 | |
| };
 | |
| 
 | |
| G_DEFINE_TYPE (GdkWin32Keymap, gdk_win32_keymap, GDK_TYPE_KEYMAP)
 | |
| 
 | |
| guint _gdk_keymap_serial = 0;
 | |
| static GdkKeymap *default_keymap = NULL;
 | |
| 
 | |
| static void update_keymap              (GdkWin32Keymap *gdk_keymap);
 | |
| static void clear_keyboard_layout_info (gpointer        data);
 | |
| 
 | |
| static void
 | |
| gdk_win32_keymap_init (GdkWin32Keymap *keymap)
 | |
| {
 | |
|   /* Regular implementation (32 bit & 64 bit) */
 | |
|   extern const GdkWin32KeymapImpl gdkwin32_keymap_impl;
 | |
|   /* Implementation for 32 bit applications running on a 64 bit host (WOW64). */
 | |
| #ifndef _WIN64
 | |
|   extern const GdkWin32KeymapImpl gdkwin32_keymap_impl_wow64;
 | |
| #endif
 | |
| 
 | |
|   keymap->layout_infos = g_array_new (FALSE, TRUE,
 | |
|                                       sizeof (GdkWin32KeymapLayoutInfo));
 | |
|   g_array_set_clear_func (keymap->layout_infos,
 | |
|                           clear_keyboard_layout_info);
 | |
| 
 | |
|   keymap->layout_handles = g_array_new (FALSE, FALSE,
 | |
|                                         sizeof (GdkWin32KeymapLayoutInfo));
 | |
| 
 | |
|   keymap->active_layout = 0;
 | |
| 
 | |
|   keymap->gdkwin32_keymap_impl = &gdkwin32_keymap_impl;
 | |
| #ifndef _WIN64
 | |
|   if (_gdk_win32_check_processor (GDK_WIN32_WOW64))
 | |
|     keymap->gdkwin32_keymap_impl = &gdkwin32_keymap_impl_wow64;
 | |
| #endif
 | |
| 
 | |
|   update_keymap (keymap);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_win32_keymap_finalize (GObject *object)
 | |
| {
 | |
|   GdkWin32Keymap *keymap = GDK_WIN32_KEYMAP (object);
 | |
| 
 | |
|   g_clear_pointer (&keymap->layout_handles, g_array_unref);
 | |
|   g_clear_pointer (&keymap->layout_infos, g_array_unref);
 | |
| 
 | |
|   G_OBJECT_CLASS (gdk_win32_keymap_parent_class)->finalize (object);
 | |
| }
 | |
| 
 | |
| /* Convenience wrapper functions */
 | |
| 
 | |
| static gboolean
 | |
| load_layout_dll (GdkWin32Keymap           *keymap,
 | |
|                  const char               *dll,
 | |
|                  GdkWin32KeymapLayoutInfo *info)
 | |
| {
 | |
|   return keymap->gdkwin32_keymap_impl->load_layout_dll (dll, info);
 | |
| }
 | |
| 
 | |
| static void
 | |
| init_vk_lookup_table (GdkWin32Keymap           *keymap,
 | |
|                       GdkWin32KeymapLayoutInfo *info)
 | |
| {
 | |
|   keymap->gdkwin32_keymap_impl->init_vk_lookup_table (info);
 | |
| }
 | |
| 
 | |
| static BYTE
 | |
| keystate_to_modbits (GdkWin32Keymap           *keymap,
 | |
|                      GdkWin32KeymapLayoutInfo *info,
 | |
|                      const BYTE                keystate[256])
 | |
| {
 | |
|   return keymap->gdkwin32_keymap_impl->keystate_to_modbits (info, keystate);
 | |
| }
 | |
| 
 | |
| static BYTE
 | |
| modbits_to_level (GdkWin32Keymap           *keymap,
 | |
|                   GdkWin32KeymapLayoutInfo *info,
 | |
|                   BYTE                      modbits)
 | |
| {
 | |
|   return keymap->gdkwin32_keymap_impl->modbits_to_level (info, modbits);
 | |
| }
 | |
| 
 | |
| static WCHAR
 | |
| vk_to_char_fuzzy (GdkWin32Keymap           *keymap,
 | |
|                   GdkWin32KeymapLayoutInfo *info,
 | |
|                   BYTE                      mod_bits,
 | |
|                   BYTE                      lock_bits,
 | |
|                   BYTE                     *consumed_mod_bits,
 | |
|                   gboolean                 *is_dead,
 | |
|                   BYTE                      vk)
 | |
| {
 | |
|   return keymap->gdkwin32_keymap_impl->vk_to_char_fuzzy (info, mod_bits, lock_bits,
 | |
|                                                          consumed_mod_bits, is_dead, vk);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return the keyboard layout according to the user's keyboard layout
 | |
|  * substitution preferences.
 | |
|  *
 | |
|  * The result is heap-allocated and should be freed with g_free().
 | |
|  */
 | |
| static char*
 | |
| get_keyboard_layout_substituted_name (const char *layout_name)
 | |
| {
 | |
|   HKEY     hkey     = 0;
 | |
|   DWORD    var_type = REG_SZ;
 | |
|   char    *result   = NULL;
 | |
|   DWORD    buf_len  = 0;
 | |
|   LSTATUS  status;
 | |
| 
 | |
|   static const char *substitute_path = "Keyboard Layout\\Substitutes";
 | |
| 
 | |
|   status = RegOpenKeyExA (HKEY_CURRENT_USER, substitute_path, 0,
 | |
|                           KEY_QUERY_VALUE, &hkey);
 | |
|   if (status != ERROR_SUCCESS)
 | |
|     {
 | |
|       /* No substitute set for this value, not sure if this is a normal case */
 | |
|       g_warning("Could not open registry key '%s'. Error code: %d",
 | |
|                 substitute_path, (int)status);
 | |
| 
 | |
|       goto fail1;
 | |
|     }
 | |
| 
 | |
|   status = RegQueryValueExA (hkey, layout_name, 0, &var_type, 0, &buf_len);
 | |
|   if (status != ERROR_SUCCESS)
 | |
|     {
 | |
|       g_debug("Could not query registry key '%s\\%s'. Error code: %d",
 | |
|               substitute_path, layout_name, (int)status);
 | |
|       goto fail2;
 | |
|     }
 | |
| 
 | |
|   /* Allocate buffer */
 | |
|   result = (char*) g_malloc (buf_len);
 | |
| 
 | |
|   /* Retrieve substitute name */
 | |
|   status = RegQueryValueExA (hkey, layout_name, 0, &var_type,
 | |
|                              (LPBYTE) result, &buf_len);
 | |
|   if (status != ERROR_SUCCESS)
 | |
|     {
 | |
|       g_warning("Could not obtain registry value at key '%s\\%s'. "
 | |
|                 "Error code: %d",
 | |
|                 substitute_path, layout_name, (int)status);
 | |
|       goto fail3;
 | |
|     }
 | |
| 
 | |
|   RegCloseKey (hkey);
 | |
|   return result;
 | |
| 
 | |
| fail3:
 | |
|   g_free (result);
 | |
| fail2:
 | |
|   RegCloseKey (hkey);
 | |
| fail1:
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /* 
 | |
|  * Get the file path of the keyboard layout dll.
 | |
|  * The result is heap-allocated and should be freed with g_free().
 | |
|  */
 | |
| static char*
 | |
| get_keyboard_layout_file (const char *layout_name)
 | |
| {
 | |
|   char    *final_layout_name = NULL;
 | |
|   HKEY     hkey              = 0;
 | |
|   DWORD    var_type          = REG_SZ;
 | |
|   char    *result            = NULL;
 | |
|   DWORD    file_name_len     = 0;
 | |
|   int      dir_len           = 0;
 | |
|   int      buf_len           = 0;
 | |
|   LSTATUS  status;
 | |
| 
 | |
|   static const char prefix[] = "SYSTEM\\CurrentControlSet\\Control\\"
 | |
|                                "Keyboard Layouts\\";
 | |
|   char kbdKeyPath[sizeof (prefix) + KL_NAMELENGTH];
 | |
| 
 | |
|   /* The user may have a keyboard substitute configured */
 | |
|   final_layout_name = get_keyboard_layout_substituted_name (layout_name);
 | |
|   if (final_layout_name != NULL)
 | |
|     {
 | |
|       g_debug ("Substituting keyboard layout name from '%s' to '%s'",
 | |
|                layout_name, final_layout_name);
 | |
|       g_snprintf (kbdKeyPath, sizeof (prefix) + KL_NAMELENGTH, "%s%s",
 | |
|                   prefix, final_layout_name);
 | |
|       g_free (final_layout_name);
 | |
|       final_layout_name = NULL;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_debug ("Could not get substitute keyboard layout name for '%s', "
 | |
|                "will use '%s' directly", layout_name, layout_name);
 | |
|       g_snprintf (kbdKeyPath, sizeof (prefix) + KL_NAMELENGTH, "%s%s",
 | |
|                   prefix, layout_name);
 | |
|     }
 | |
| 
 | |
|   status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, (LPCSTR) kbdKeyPath, 0,
 | |
|                           KEY_QUERY_VALUE, &hkey);
 | |
|   if (status != ERROR_SUCCESS)
 | |
|     {
 | |
|       g_warning("Could not open registry key '%s'. Error code: %d",
 | |
|                 kbdKeyPath, (int)status);
 | |
|       goto fail1;
 | |
|     }
 | |
| 
 | |
|   /* Get sizes */
 | |
|   status = RegQueryValueExA (hkey, "Layout File", 0, &var_type, 0,
 | |
|                              &file_name_len);
 | |
|   if (status != ERROR_SUCCESS)
 | |
|     {
 | |
|       g_warning("Could not query registry key '%s\\Layout File'. Error code: %d",
 | |
|                 kbdKeyPath, (int)status);
 | |
|       goto fail2;
 | |
|     }
 | |
| 
 | |
|   dir_len = GetSystemDirectoryA (0, 0); /* includes \0 */
 | |
|   if (dir_len == 0)
 | |
|     {
 | |
|       g_warning("GetSystemDirectoryA failed. Error: %d", (int)GetLastError());
 | |
|       goto fail2;
 | |
|     }
 | |
| 
 | |
|   /* Allocate buffer */
 | |
|   buf_len = dir_len + (int) strlen ("\\") + file_name_len;
 | |
|   result = (char*) g_malloc (buf_len);
 | |
| 
 | |
|   /* Append system directory. The -1 is because dir_len includes \0 */
 | |
|   if (GetSystemDirectoryA (&result[0], dir_len) != dir_len - 1)
 | |
|     goto fail3;
 | |
| 
 | |
|   /* Append directory separator */
 | |
|   result[dir_len - 1] = '\\';
 | |
| 
 | |
|   /* Append file name */
 | |
|   status = RegQueryValueExA (hkey, "Layout File", 0, &var_type,
 | |
|                              (LPBYTE) &result[dir_len], &file_name_len);
 | |
|   if (status != ERROR_SUCCESS)
 | |
|     {
 | |
|       goto fail3;
 | |
|     }
 | |
| 
 | |
|   result[dir_len + file_name_len] = '\0';
 | |
| 
 | |
|   RegCloseKey (hkey);
 | |
|   return result;
 | |
| 
 | |
| fail3:
 | |
|   g_free (result);
 | |
| fail2:
 | |
|   RegCloseKey (hkey);
 | |
| fail1:
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| clear_keyboard_layout_info (gpointer data)
 | |
| {
 | |
|   GdkWin32KeymapLayoutInfo *layout_info = (GdkWin32KeymapLayoutInfo*) data;
 | |
| 
 | |
|   g_free (layout_info->file);
 | |
| 
 | |
|   if (layout_info->key_entries != NULL)
 | |
|     g_array_unref (layout_info->key_entries);
 | |
| 
 | |
|   if (layout_info->reverse_lookup_table != NULL)
 | |
|     g_hash_table_destroy (layout_info->reverse_lookup_table);
 | |
| 
 | |
|   if (layout_info->lib != NULL)
 | |
|     FreeLibrary (layout_info->lib);
 | |
| 
 | |
|   memset (layout_info, 0, sizeof (GdkWin32KeymapLayoutInfo));
 | |
| }
 | |
| 
 | |
| #define DEFINE_SPECIAL(map)                 \
 | |
|   map (VK_CANCEL,     GDK_KEY_Cancel)       \
 | |
|   map (VK_BACK,       GDK_KEY_BackSpace)    \
 | |
|   map (VK_CLEAR,      GDK_KEY_Clear)        \
 | |
|   map (VK_RETURN,     GDK_KEY_Return)       \
 | |
|   map (VK_LSHIFT,     GDK_KEY_Shift_L)      \
 | |
|   map (VK_LCONTROL,   GDK_KEY_Control_L)    \
 | |
|   map (VK_LMENU,      GDK_KEY_Alt_L)        \
 | |
|   map (VK_PAUSE,      GDK_KEY_Pause)        \
 | |
|   map (VK_ESCAPE,     GDK_KEY_Escape)       \
 | |
|   map (VK_PRIOR,      GDK_KEY_Prior)        \
 | |
|   map (VK_NEXT,       GDK_KEY_Next)         \
 | |
|   map (VK_END,        GDK_KEY_End)          \
 | |
|   map (VK_HOME,       GDK_KEY_Home)         \
 | |
|   map (VK_LEFT,       GDK_KEY_Left)         \
 | |
|   map (VK_UP,         GDK_KEY_Up)           \
 | |
|   map (VK_RIGHT,      GDK_KEY_Right)        \
 | |
|   map (VK_DOWN,       GDK_KEY_Down)         \
 | |
|   map (VK_SELECT,     GDK_KEY_Select)       \
 | |
|   map (VK_PRINT,      GDK_KEY_Print)        \
 | |
|   map (VK_EXECUTE,    GDK_KEY_Execute)      \
 | |
|   map (VK_INSERT,     GDK_KEY_Insert)       \
 | |
|   map (VK_DELETE,     GDK_KEY_Delete)       \
 | |
|   map (VK_HELP,       GDK_KEY_Help)         \
 | |
|   map (VK_LWIN,       GDK_KEY_Meta_L)       \
 | |
|   map (VK_RWIN,       GDK_KEY_Meta_R)       \
 | |
|   map (VK_APPS,       GDK_KEY_Menu)         \
 | |
|   map (VK_DECIMAL,    GDK_KEY_KP_Decimal)   \
 | |
|   map (VK_MULTIPLY,   GDK_KEY_KP_Multiply)  \
 | |
|   map (VK_ADD,        GDK_KEY_KP_Add)       \
 | |
|   map (VK_SEPARATOR,  GDK_KEY_KP_Separator) \
 | |
|   map (VK_SUBTRACT,   GDK_KEY_KP_Subtract)  \
 | |
|   map (VK_DIVIDE,     GDK_KEY_KP_Divide)    \
 | |
|   map (VK_NUMPAD0,    GDK_KEY_KP_0)         \
 | |
|   map (VK_NUMPAD1,    GDK_KEY_KP_1)         \
 | |
|   map (VK_NUMPAD2,    GDK_KEY_KP_2)         \
 | |
|   map (VK_NUMPAD3,    GDK_KEY_KP_3)         \
 | |
|   map (VK_NUMPAD4,    GDK_KEY_KP_4)         \
 | |
|   map (VK_NUMPAD5,    GDK_KEY_KP_5)         \
 | |
|   map (VK_NUMPAD6,    GDK_KEY_KP_6)         \
 | |
|   map (VK_NUMPAD7,    GDK_KEY_KP_7)         \
 | |
|   map (VK_NUMPAD8,    GDK_KEY_KP_8)         \
 | |
|   map (VK_NUMPAD9,    GDK_KEY_KP_9)         \
 | |
|   map (VK_F1,         GDK_KEY_F1)           \
 | |
|   map (VK_F2,         GDK_KEY_F2)           \
 | |
|   map (VK_F3,         GDK_KEY_F3)           \
 | |
|   map (VK_F4,         GDK_KEY_F4)           \
 | |
|   map (VK_F5,         GDK_KEY_F5)           \
 | |
|   map (VK_F6,         GDK_KEY_F6)           \
 | |
|   map (VK_F7,         GDK_KEY_F7)           \
 | |
|   map (VK_F8,         GDK_KEY_F8)           \
 | |
|   map (VK_F9,         GDK_KEY_F9)           \
 | |
|   map (VK_F10,        GDK_KEY_F10)          \
 | |
|   map (VK_F11,        GDK_KEY_F11)          \
 | |
|   map (VK_F12,        GDK_KEY_F12)          \
 | |
|   map (VK_F13,        GDK_KEY_F13)          \
 | |
|   map (VK_F14,        GDK_KEY_F14)          \
 | |
|   map (VK_F15,        GDK_KEY_F15)          \
 | |
|   map (VK_F16,        GDK_KEY_F16)          \
 | |
|   map (VK_F17,        GDK_KEY_F17)          \
 | |
|   map (VK_F18,        GDK_KEY_F18)          \
 | |
|   map (VK_F19,        GDK_KEY_F19)          \
 | |
|   map (VK_F20,        GDK_KEY_F20)          \
 | |
|   map (VK_F21,        GDK_KEY_F21)          \
 | |
|   map (VK_F22,        GDK_KEY_F22)          \
 | |
|   map (VK_F23,        GDK_KEY_F23)          \
 | |
|   map (VK_F24,        GDK_KEY_F24)          \
 | |
|   map (VK_NUMLOCK,    GDK_KEY_Num_Lock)     \
 | |
|   map (VK_SCROLL,     GDK_KEY_Scroll_Lock)  \
 | |
|   map (VK_RSHIFT,     GDK_KEY_Shift_R)      \
 | |
|   map (VK_RCONTROL,   GDK_KEY_Control_R)    \
 | |
|   map (VK_RMENU,      GDK_KEY_Alt_R)        \
 | |
|   map (VK_CAPITAL,    GDK_KEY_Caps_Lock)
 | |
| 
 | |
| 
 | |
| #define DEFINE_DEAD(map)                                                      \
 | |
|   map ('"',                          /* 0x022 */ GDK_KEY_dead_diaeresis)      \
 | |
|   map ('\'',                         /* 0x027 */ GDK_KEY_dead_acute)          \
 | |
|   map (GDK_KEY_asciicircum,          /* 0x05e */ GDK_KEY_dead_circumflex)     \
 | |
|   map (GDK_KEY_grave,                /* 0x060 */ GDK_KEY_dead_grave)          \
 | |
|   map (GDK_KEY_asciitilde,           /* 0x07e */ GDK_KEY_dead_tilde)          \
 | |
|   map (GDK_KEY_diaeresis,            /* 0x0a8 */ GDK_KEY_dead_diaeresis)      \
 | |
|   map (GDK_KEY_degree,               /* 0x0b0 */ GDK_KEY_dead_abovering)      \
 | |
|   map (GDK_KEY_acute,                /* 0x0b4 */ GDK_KEY_dead_acute)          \
 | |
|   map (GDK_KEY_periodcentered,       /* 0x0b7 */ GDK_KEY_dead_abovedot)       \
 | |
|   map (GDK_KEY_cedilla,              /* 0x0b8 */ GDK_KEY_dead_cedilla)        \
 | |
|   map (GDK_KEY_breve,                /* 0x1a2 */ GDK_KEY_dead_breve)          \
 | |
|   map (GDK_KEY_ogonek,               /* 0x1b2 */ GDK_KEY_dead_ogonek)         \
 | |
|   map (GDK_KEY_caron,                /* 0x1b7 */ GDK_KEY_dead_caron)          \
 | |
|   map (GDK_KEY_doubleacute,          /* 0x1bd */ GDK_KEY_dead_doubleacute)    \
 | |
|   map (GDK_KEY_abovedot,             /* 0x1ff */ GDK_KEY_dead_abovedot)       \
 | |
|   map (0x1000384,              /* Greek tonos */ GDK_KEY_dead_acute)          \
 | |
|   map (GDK_KEY_Greek_accentdieresis, /* 0x7ae */ GDK_KEY_Greek_accentdieresis)
 | |
| 
 | |
| 
 | |
| static guint
 | |
| vk_and_mod_bits_to_gdk_keysym (GdkWin32Keymap     *keymap,
 | |
|                                GdkWin32KeymapLayoutInfo *info,
 | |
|                                guint               vk,
 | |
|                                BYTE                mod_bits,
 | |
|                                BYTE                lock_bits,
 | |
|                                BYTE               *consumed_mod_bits)
 | |
| 
 | |
| {
 | |
|   gboolean is_dead = FALSE;
 | |
|   gunichar c;
 | |
|   guint    sym;
 | |
| 
 | |
|   if (consumed_mod_bits)
 | |
|     *consumed_mod_bits = 0;
 | |
| 
 | |
|   /* Handle special key: Tab */
 | |
|   if (vk == VK_TAB)
 | |
|     {
 | |
|       if (consumed_mod_bits)
 | |
|         *consumed_mod_bits = mod_bits & KBDSHIFT;
 | |
|       return (mod_bits & KBDSHIFT) ? GDK_KEY_ISO_Left_Tab : GDK_KEY_Tab;
 | |
|     }
 | |
| 
 | |
|   /* Handle other special keys */
 | |
|   switch (vk)
 | |
|     {
 | |
|       #define MAP(a_vk, a_gdk) case a_vk: return a_gdk;
 | |
| 
 | |
|       DEFINE_SPECIAL (MAP)
 | |
| 
 | |
|       /* Non-bijective mappings: */
 | |
|       MAP (VK_SHIFT,    GDK_KEY_Shift_L)
 | |
|       MAP (VK_CONTROL,  GDK_KEY_Control_L)
 | |
|       MAP (VK_MENU,     GDK_KEY_Alt_L)
 | |
|       MAP (VK_SNAPSHOT, GDK_KEY_Print)
 | |
| 
 | |
|       #undef MAP
 | |
|     }
 | |
| 
 | |
|   /* Handle regular keys (including dead keys) */
 | |
|   c = vk_to_char_fuzzy (keymap, info, mod_bits, lock_bits,
 | |
|                         consumed_mod_bits, &is_dead, vk);
 | |
| 
 | |
|   if (c == WCH_NONE)
 | |
|     return GDK_KEY_VoidSymbol;
 | |
| 
 | |
|   sym = gdk_unicode_to_keyval (c);
 | |
| 
 | |
|   if (is_dead)
 | |
|     {
 | |
|       switch (sym)
 | |
| 	{
 | |
| 	  #define MAP(a_nondead, a_dead) case a_nondead: return a_dead;
 | |
| 	  DEFINE_DEAD (MAP)
 | |
| 	  #undef MAP
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return sym;
 | |
| }
 | |
| 
 | |
| static gint
 | |
| gdk_keysym_to_key_entry_index (GdkWin32KeymapLayoutInfo *info,
 | |
|                                guint               sym)
 | |
| {
 | |
|   gunichar c;
 | |
|   gintptr  index;
 | |
| 
 | |
|   if (info->reverse_lookup_table == NULL)
 | |
|     return -1;
 | |
| 
 | |
|   /* Special cases */
 | |
|   if (sym == GDK_KEY_Tab)
 | |
|     return VK_TAB;
 | |
|   if (sym == GDK_KEY_ISO_Left_Tab)
 | |
|     return 256;
 | |
| 
 | |
|   /* Generic non-printable keys */
 | |
|   switch (sym)
 | |
|     {
 | |
|       #define MAP(a_vk, a_gdk) case a_gdk: return a_vk;
 | |
|       DEFINE_SPECIAL (MAP)
 | |
|       #undef MAP
 | |
|     }
 | |
| 
 | |
|   /* Fix up dead keys */
 | |
|   #define MAP(a_nondead, a_dead) \
 | |
|     if (sym == a_dead)           \
 | |
|       sym = a_nondead;
 | |
|   DEFINE_DEAD (MAP)
 | |
|   #undef MAP
 | |
| 
 | |
|   /* Try converting to Unicode and back */
 | |
|   c = gdk_keyval_to_unicode (sym);
 | |
| 
 | |
|   index = -1;
 | |
|   if (g_hash_table_lookup_extended (info->reverse_lookup_table,
 | |
|                                     GINT_TO_POINTER (c),
 | |
|                                     NULL, (gpointer*) &index))
 | |
|     {
 | |
|       return index;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       return -1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static GdkModifierType
 | |
| mod_bits_to_gdk_mod_mask (BYTE mod_bits)
 | |
| {
 | |
|   GdkModifierType result = 0;
 | |
|   if (mod_bits & KBDSHIFT)
 | |
|     result |= GDK_SHIFT_MASK;
 | |
|   if (mod_bits & KBDCTRL)
 | |
|     result |= GDK_CONTROL_MASK;
 | |
|   if (mod_bits & KBDALT)
 | |
|     result |= GDK_MOD1_MASK;
 | |
|   if ((mod_bits & KBDALTGR) == KBDALTGR)
 | |
|     result |= GDK_MOD2_MASK;
 | |
|   if (mod_bits & KBDKANA)
 | |
|     result |= GDK_MOD3_MASK;
 | |
|   if (mod_bits & KBDROYA)
 | |
|     result |= GDK_MOD4_MASK;
 | |
|   if (mod_bits & KBDLOYA)
 | |
|     result |= GDK_MODIFIER_RESERVED_13_MASK;
 | |
|   if (mod_bits & KBDGRPSELTAP)
 | |
|     result |= GDK_MODIFIER_RESERVED_14_MASK;
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| static BYTE
 | |
| gdk_mod_mask_to_mod_bits (GdkModifierType mod_mask)
 | |
| {
 | |
|   BYTE result = 0;
 | |
|   if (mod_mask & GDK_SHIFT_MASK)
 | |
|     result |= KBDSHIFT;
 | |
|   if (mod_mask & GDK_CONTROL_MASK)
 | |
|     result |= KBDCTRL;
 | |
|   if (mod_mask & GDK_MOD1_MASK)
 | |
|     result |= KBDALT;
 | |
|   if (mod_mask & GDK_MOD2_MASK)
 | |
|     result |= KBDALTGR;
 | |
|   if (mod_mask & GDK_MOD3_MASK)
 | |
|     result |= KBDKANA;
 | |
|   if (mod_mask & GDK_MOD4_MASK)
 | |
|     result |= KBDROYA;
 | |
|   if (mod_mask & GDK_MODIFIER_RESERVED_13_MASK)
 | |
|     result |= KBDLOYA;
 | |
|   if (mod_mask & GDK_MODIFIER_RESERVED_14_MASK)
 | |
|     result |= KBDGRPSELTAP;
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* keypad decimal mark depends on active keyboard layout
 | |
|  * return current decimal mark as unicode character
 | |
|  */
 | |
| guint32
 | |
| _gdk_win32_keymap_get_decimal_mark (GdkWin32Keymap *keymap)
 | |
| {
 | |
|   guint32 c = MapVirtualKeyW (VK_DECIMAL, MAPVK_VK_TO_CHAR);
 | |
|   if (!c)
 | |
|     c = (guint32) '.';
 | |
|   return c;
 | |
| }
 | |
| 
 | |
| static void
 | |
| update_keymap (GdkWin32Keymap *keymap)
 | |
| {
 | |
|   HKL  current_layout;
 | |
|   BOOL changed = FALSE;
 | |
|   int  n_layouts;
 | |
|   int  i;
 | |
| 
 | |
|   if (keymap->current_serial == _gdk_keymap_serial &&
 | |
|       keymap->layout_handles->len > 0)
 | |
|     {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   n_layouts = GetKeyboardLayoutList (0, 0);
 | |
|   g_array_set_size (keymap->layout_handles, n_layouts);
 | |
|   n_layouts = GetKeyboardLayoutList (n_layouts,
 | |
| 		                     &g_array_index(keymap->layout_handles,
 | |
| 				                    HKL, 0));
 | |
| 
 | |
|   g_array_set_size (keymap->layout_infos, n_layouts);
 | |
| 
 | |
|   current_layout = GetKeyboardLayout (0);
 | |
| 
 | |
|   for (i = 0; i < n_layouts; ++i)
 | |
|     {
 | |
|       GdkWin32KeymapLayoutInfo *info = &g_array_index(keymap->layout_infos,
 | |
|                                                       GdkWin32KeymapLayoutInfo, i);
 | |
|       HKL hkl = g_array_index(keymap->layout_handles, HKL, i);
 | |
| 
 | |
|       if (info->handle != hkl)
 | |
|         {
 | |
|           changed = TRUE;
 | |
| 
 | |
|           /* Free old data */
 | |
|           clear_keyboard_layout_info (info);
 | |
| 
 | |
|           /* Load new data */
 | |
|           info->handle = hkl;
 | |
|           ActivateKeyboardLayout (hkl, 0);
 | |
|           GetKeyboardLayoutNameA (info->name);
 | |
| 
 | |
|           info->file = get_keyboard_layout_file (info->name);
 | |
| 
 | |
|           if (info->file != NULL && load_layout_dll (keymap, info->file, info))
 | |
|             {
 | |
|               info->key_entries = g_array_new (FALSE, FALSE,
 | |
|                                                sizeof (GdkWin32KeymapKeyEntry));
 | |
| 
 | |
|               info->reverse_lookup_table = g_hash_table_new (g_direct_hash,
 | |
|                                                              g_direct_equal);
 | |
|               init_vk_lookup_table (keymap, info);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               g_warning("Failed to load keyboard layout DLL for layout %s: %s",
 | |
|                         info->name, info->file);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       if (info->handle == current_layout)
 | |
|         keymap->active_layout = i;
 | |
|     }
 | |
| 
 | |
|   if (changed)
 | |
|     ActivateKeyboardLayout (current_layout, 0);
 | |
| 
 | |
|   keymap->current_serial = _gdk_keymap_serial;
 | |
| }
 | |
| 
 | |
| guint8
 | |
| _gdk_win32_keymap_get_rshift_scancode (GdkWin32Keymap *keymap)
 | |
| {
 | |
|   return MapVirtualKey (VK_RSHIFT, MAPVK_VK_TO_VSC);
 | |
| }
 | |
| 
 | |
| void
 | |
| _gdk_win32_keymap_set_active_layout (GdkWin32Keymap *keymap,
 | |
|                                      HKL             hkl)
 | |
| {
 | |
|   if (keymap != NULL &&
 | |
|       keymap->layout_handles->len > 0)
 | |
|     {
 | |
|       gint group;
 | |
| 
 | |
|       for (group = 0; group < keymap->layout_handles->len; group++)
 | |
|         if (g_array_index (keymap->layout_handles, HKL, group) == hkl)
 | |
|           keymap->active_layout = group;
 | |
|     }
 | |
| }
 | |
| 
 | |
| guint8
 | |
| _gdk_win32_keymap_get_active_group (GdkWin32Keymap *keymap)
 | |
| {
 | |
|   if (keymap != NULL &&
 | |
|       keymap->layout_handles->len > 0)
 | |
|     return keymap->active_layout;
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| GdkKeymap*
 | |
| _gdk_win32_display_get_keymap (GdkDisplay *display)
 | |
| {
 | |
|   g_return_val_if_fail (display == gdk_display_get_default (), NULL);
 | |
| 
 | |
|   if (default_keymap == NULL)
 | |
|     default_keymap = g_object_new (gdk_win32_keymap_get_type (), NULL);
 | |
| 
 | |
|   return default_keymap;
 | |
| }
 | |
| 
 | |
| 
 | |
| GdkModifierType
 | |
| _gdk_win32_keymap_get_mod_mask (GdkWin32Keymap *keymap)
 | |
| {
 | |
|   GdkWin32KeymapLayoutInfo *layout_info;
 | |
|   BYTE                      keystate[256] = {0};
 | |
|   BYTE                      mod_bits;
 | |
|     
 | |
|   update_keymap (keymap);
 | |
| 
 | |
|   layout_info = &g_array_index (keymap->layout_infos, GdkWin32KeymapLayoutInfo,
 | |
|                                 keymap->active_layout);
 | |
|     
 | |
|   GetKeyboardState (keystate);
 | |
|     
 | |
|   mod_bits = keystate_to_modbits (keymap, layout_info, keystate);
 | |
| 
 | |
|   return mod_bits_to_gdk_mod_mask (mod_bits);
 | |
| }
 | |
| 
 | |
| static PangoDirection
 | |
| get_hkl_direction (HKL hkl)
 | |
| {
 | |
|   switch (PRIMARYLANGID (LOWORD ((DWORD) (gintptr) hkl)))
 | |
|     {
 | |
|     case LANG_HEBREW:
 | |
|     case LANG_ARABIC:
 | |
| #ifdef LANG_URDU
 | |
|     case LANG_URDU:
 | |
| #endif
 | |
|     case LANG_FARSI:
 | |
|       /* Others? */
 | |
|       return PANGO_DIRECTION_RTL;
 | |
| 
 | |
|     default:
 | |
|       return PANGO_DIRECTION_LTR;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static PangoDirection
 | |
| gdk_win32_keymap_get_direction (GdkKeymap *gdk_keymap)
 | |
| {
 | |
|   GdkWin32Keymap *keymap;
 | |
|   HKL             active_hkl;
 | |
|   
 | |
|   g_return_val_if_fail (GDK_IS_KEYMAP (gdk_keymap), PANGO_DIRECTION_LTR);
 | |
| 
 | |
|   keymap = GDK_WIN32_KEYMAP (gdk_keymap);
 | |
| 
 | |
|   update_keymap (keymap);
 | |
| 
 | |
|   if (keymap->layout_handles->len <= 0)
 | |
|     active_hkl = GetKeyboardLayout (0);
 | |
|   else
 | |
|     active_hkl = g_array_index (keymap->layout_handles, HKL,
 | |
|                                 keymap->active_layout);
 | |
| 
 | |
|   return get_hkl_direction (active_hkl);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_have_bidi_layouts (GdkKeymap *gdk_keymap)
 | |
| {
 | |
|   GdkWin32Keymap *keymap;
 | |
|   gboolean        have_rtl = FALSE;
 | |
|   gboolean        have_ltr = FALSE;
 | |
|   gint            group;
 | |
|   
 | |
|   g_return_val_if_fail (GDK_IS_KEYMAP (gdk_keymap), FALSE);
 | |
| 
 | |
|   keymap = GDK_WIN32_KEYMAP (gdk_keymap);
 | |
| 
 | |
|   update_keymap (keymap);
 | |
| 
 | |
|   for (group = 0; group < keymap->layout_handles->len; group++)
 | |
|     {
 | |
|       if (get_hkl_direction (g_array_index (keymap->layout_handles, HKL,
 | |
|                              group)) == PANGO_DIRECTION_RTL)
 | |
|         have_rtl = TRUE;
 | |
|       else
 | |
|         have_ltr = TRUE;
 | |
|     }
 | |
| 
 | |
|   return have_ltr && have_rtl;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_get_caps_lock_state (GdkKeymap *keymap)
 | |
| {
 | |
|   (void) keymap;
 | |
| 
 | |
|   return ((GetKeyState (VK_CAPITAL) & 1) != 0);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_get_num_lock_state (GdkKeymap *keymap)
 | |
| {
 | |
|   (void) keymap;
 | |
| 
 | |
|   return ((GetKeyState (VK_NUMLOCK) & 1) != 0);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_get_scroll_lock_state (GdkKeymap *keymap)
 | |
| {
 | |
|   (void) keymap;
 | |
| 
 | |
|   return ((GetKeyState (VK_SCROLL) & 1) != 0);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_get_entries_for_keyval (GdkKeymap     *gdk_keymap,
 | |
|                                          guint          keyval,
 | |
|                                          GdkKeymapKey **keys,
 | |
|                                          gint          *n_keys)
 | |
| {
 | |
|   GdkWin32Keymap *keymap;
 | |
|   GArray         *retval;
 | |
|   gint            group;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_KEYMAP (gdk_keymap), FALSE);
 | |
|   g_return_val_if_fail (keys != NULL, FALSE);
 | |
|   g_return_val_if_fail (n_keys != NULL, FALSE);
 | |
|   g_return_val_if_fail (keyval != 0, FALSE);
 | |
| 
 | |
|   retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
 | |
| 
 | |
|   keymap = GDK_WIN32_KEYMAP (gdk_keymap);
 | |
| 
 | |
|   update_keymap (keymap);
 | |
| 
 | |
|   for (group = 0; group < keymap->layout_handles->len; group++)
 | |
|     {
 | |
|       GdkWin32KeymapLayoutInfo *info = &g_array_index (keymap->layout_infos,
 | |
|                                                        GdkWin32KeymapLayoutInfo,
 | |
|                                                        group);
 | |
|       gint entry_index = gdk_keysym_to_key_entry_index (info, keyval);
 | |
| 
 | |
|       while (entry_index >= 0)
 | |
|         {
 | |
|           GdkWin32KeymapKeyEntry  *entry        = &g_array_index (info->key_entries,
 | |
|                                                                   GdkWin32KeymapKeyEntry,
 | |
|                                                                   entry_index);
 | |
|           BYTE                     base_modbits = entry->mod_bits;
 | |
|           BYTE                     extra_modbits;
 | |
|           GdkKeymapKey             gdk_key      = {0};
 | |
| 
 | |
|           /* Add original key combination */
 | |
|           gdk_key.keycode = entry->vk;
 | |
|           gdk_key.level   = modbits_to_level (keymap, info, entry->mod_bits);
 | |
|           gdk_key.group   = group;
 | |
| 
 | |
|           g_array_append_val (retval, gdk_key);
 | |
| 
 | |
|           /* Add combinations with modifiers that do not affect the translation */
 | |
|           for (extra_modbits = 0;
 | |
|                extra_modbits <= info->max_modbit_value;
 | |
|                ++extra_modbits)
 | |
|             {
 | |
|               BYTE  modbits;
 | |
|               guint sym;
 | |
| 
 | |
|               /* We are only interested in masks which are orthogonal to the
 | |
|                * original mask. */
 | |
|               if ((extra_modbits | base_modbits) == base_modbits ||
 | |
|                   (extra_modbits & base_modbits) != 0)
 | |
|                 continue;
 | |
| 
 | |
|               modbits = base_modbits | extra_modbits;
 | |
| 
 | |
|               /* Check if the additional modifiers change the semantics.
 | |
|                * If they do not, add them. */
 | |
|               sym = vk_and_mod_bits_to_gdk_keysym (keymap, info, entry->vk,
 | |
|                                                    modbits, 0, NULL);
 | |
|               if (sym == keyval || sym == GDK_KEY_VoidSymbol)
 | |
|                 {
 | |
|                   gdk_key.keycode = entry->vk;
 | |
|                   gdk_key.level   = modbits_to_level (keymap, info, modbits);
 | |
|                   gdk_key.group   = group;
 | |
|                   g_array_append_val (retval, gdk_key);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|           entry_index = entry->next;
 | |
|         }
 | |
|    }
 | |
| 
 | |
|   if (retval->len > 0)
 | |
|     {
 | |
|       *keys = (GdkKeymapKey*) retval->data;
 | |
|       *n_keys = retval->len;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       *keys = NULL;
 | |
|       *n_keys = 0;
 | |
|     }
 | |
| 
 | |
|   g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
 | |
| 
 | |
|   return *n_keys > 0;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_get_entries_for_keycode (GdkKeymap     *gdk_keymap,
 | |
|                                           guint          hardware_keycode,
 | |
|                                           GdkKeymapKey **keys,
 | |
|                                           guint        **keyvals,
 | |
|                                           gint          *n_entries)
 | |
| {
 | |
|   GdkWin32Keymap *keymap;
 | |
|   GArray         *key_array;
 | |
|   GArray         *keyval_array;
 | |
|   gint            group;
 | |
|   BYTE            vk;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_KEYMAP (gdk_keymap), FALSE);
 | |
|   g_return_val_if_fail (n_entries != NULL, FALSE);
 | |
| 
 | |
|   *n_entries = 0;
 | |
| 
 | |
|   if (keys != NULL)
 | |
|     key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
 | |
|   else
 | |
|     key_array = NULL;
 | |
| 
 | |
|   if (keyvals != NULL)
 | |
|     keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
 | |
|   else
 | |
|     keyval_array = NULL;
 | |
| 
 | |
|   keymap = GDK_WIN32_KEYMAP (gdk_keymap);
 | |
|   update_keymap (keymap);
 | |
| 
 | |
|   vk = hardware_keycode;
 | |
| 
 | |
|   for (group = 0; group < keymap->layout_handles->len; group++)
 | |
|     {
 | |
|       GdkWin32KeymapLayoutInfo *info = &g_array_index (keymap->layout_infos,
 | |
|                                                        GdkWin32KeymapLayoutInfo,
 | |
|                                                        group);
 | |
|       int level;
 | |
| 
 | |
|       for (level = 0; level <= info->max_level; ++level)
 | |
|         {
 | |
|           BYTE         modbits          = info->level_to_modbits[level];
 | |
|           BYTE         consumed_modbits = 0;
 | |
|           GdkKeymapKey key              = {0};
 | |
|           guint        keyval;
 | |
| 
 | |
|           keyval = vk_and_mod_bits_to_gdk_keysym (keymap, info, vk, modbits, 0, &consumed_modbits);
 | |
| 
 | |
|           if (keyval == GDK_KEY_VoidSymbol || consumed_modbits != modbits)
 | |
|             continue;
 | |
| 
 | |
|           key.keycode = vk;
 | |
|           key.group = group;
 | |
|           key.level = level;
 | |
| 
 | |
|           if (key_array)
 | |
|             g_array_append_val (key_array, key);
 | |
| 
 | |
|           if (keyval_array)
 | |
|             g_array_append_val (keyval_array, keyval);
 | |
| 
 | |
|           ++(*n_entries);
 | |
|         }
 | |
|     }
 | |
|   
 | |
|   if (keys != NULL)
 | |
|     *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE);
 | |
| 
 | |
|   if (keyvals != NULL)
 | |
|     *keyvals = (guint*) g_array_free (keyval_array, FALSE);
 | |
| 
 | |
|   return *n_entries > 0;
 | |
| }
 | |
| 
 | |
| static guint
 | |
| gdk_win32_keymap_lookup_key (GdkKeymap          *gdk_keymap,
 | |
|                              const GdkKeymapKey *key)
 | |
| {
 | |
|   GdkWin32Keymap           *keymap;
 | |
|   GdkWin32KeymapLayoutInfo *info;
 | |
| 
 | |
|   BYTE                      modbits;
 | |
|   guint                     sym;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_KEYMAP (gdk_keymap), 0);
 | |
|   g_return_val_if_fail (key != NULL, 0);
 | |
| 
 | |
|   keymap = GDK_WIN32_KEYMAP (gdk_keymap);
 | |
|   update_keymap (keymap);
 | |
| 
 | |
|   info = &g_array_index (keymap->layout_infos, GdkWin32KeymapLayoutInfo, key->group);
 | |
| 
 | |
|   if (key->group < 0 || key->group >= keymap->layout_handles->len)
 | |
|     return 0;
 | |
|   if (key->level < 0 || key->level > info->max_level)
 | |
|     return 0;
 | |
|   
 | |
|   modbits = info->level_to_modbits[key->level];
 | |
|   sym = vk_and_mod_bits_to_gdk_keysym (keymap, info, key->keycode, modbits, 0, NULL);
 | |
| 
 | |
|   if (sym == GDK_KEY_VoidSymbol)
 | |
|     return 0;
 | |
|   else
 | |
|     return sym;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_translate_keyboard_state (GdkKeymap       *gdk_keymap,
 | |
|                                            guint            hardware_keycode,
 | |
|                                            GdkModifierType  state,
 | |
|                                            gint             group,
 | |
|                                            guint           *keyval,
 | |
|                                            gint            *effective_group,
 | |
|                                            gint            *level,
 | |
|                                            GdkModifierType *consumed_modifiers)
 | |
| {
 | |
|   GdkWin32Keymap           *keymap;
 | |
|   guint                     tmp_keyval;
 | |
|   gint                      tmp_effective_group;
 | |
|   gint                      tmp_level;
 | |
|   BYTE                      consumed_mod_bits;
 | |
| 
 | |
|   GdkWin32KeymapLayoutInfo *layout_info;
 | |
|   guint                     vk;
 | |
|   BYTE                      mod_bits;
 | |
|   BYTE                      lock_bits = 0;
 | |
| 
 | |
|   g_return_val_if_fail (GDK_IS_KEYMAP (gdk_keymap), FALSE);
 | |
| 
 | |
|   keymap = GDK_WIN32_KEYMAP (gdk_keymap);
 | |
|   update_keymap (keymap);
 | |
| 
 | |
|   g_return_val_if_fail (group >= 0 && group < keymap->layout_infos->len, FALSE);
 | |
| 
 | |
|   layout_info = &g_array_index (keymap->layout_infos, GdkWin32KeymapLayoutInfo,
 | |
|                                 group);
 | |
| 
 | |
|   vk = hardware_keycode;
 | |
|   mod_bits = gdk_mod_mask_to_mod_bits (state);
 | |
| 
 | |
|   if (vk == VK_SHIFT || vk == VK_LSHIFT || vk == VK_RSHIFT)
 | |
|     mod_bits &= ~KBDSHIFT;
 | |
|   if (vk == VK_CONTROL || vk == VK_LCONTROL || vk == VK_RCONTROL)
 | |
|     mod_bits &= ~KBDCTRL;
 | |
|   if (vk == VK_MENU || vk == VK_LMENU || vk == VK_RMENU)
 | |
|     mod_bits &= ~KBDALT;
 | |
|   if (vk == VK_RMENU)
 | |
|     mod_bits &= ~KBDALTGR;
 | |
| 
 | |
|   /* Translate lock state
 | |
|    *
 | |
|    * Right now the only locking modifier is CAPSLOCK. We don't handle KANALOK
 | |
|    * because GDK doesn't have an equivalent modifier mask to my knowledge (On
 | |
|    * X11, I believe the same effect is achieved by shifting to a different
 | |
|    * group. It's just a different concept, that doesn't translate to Windows).
 | |
|    * But since KANALOK is only used on far-eastern keyboards, which require IME
 | |
|    * anyway, this is probably fine. The IME input module has actually been the
 | |
|    * default for all languages (not just far-eastern) for a while now, which
 | |
|    * means that the keymap is now only used for things like accelerators and
 | |
|    * keybindings, where you probably don't even want KANALOK to affect the
 | |
|    * translation.
 | |
|    */
 | |
| 
 | |
|   if (state & GDK_LOCK_MASK)
 | |
|     lock_bits |= CAPLOK;
 | |
| 
 | |
|   tmp_keyval = vk_and_mod_bits_to_gdk_keysym (keymap, layout_info, vk, mod_bits,
 | |
|                                               lock_bits, &consumed_mod_bits);
 | |
|   tmp_effective_group = group;
 | |
|   tmp_level = modbits_to_level (keymap, layout_info, consumed_mod_bits);
 | |
| 
 | |
|   /* Determine consumed modifiers */
 | |
|   
 | |
|   if (keyval)
 | |
|     *keyval = tmp_keyval;
 | |
|   if (effective_group)
 | |
|     *effective_group = tmp_effective_group;
 | |
|   if (level)
 | |
|     *level = tmp_level;
 | |
|   if (consumed_modifiers)
 | |
|     *consumed_modifiers = mod_bits_to_gdk_mod_mask (consumed_mod_bits);
 | |
| 
 | |
|   /* Just a diagnostic message to inform the user why their keypresses aren't working.
 | |
|    * Shouldn't happen under normal circumstances. */
 | |
|   if (tmp_keyval == GDK_KEY_VoidSymbol && layout_info->tables == NULL)
 | |
|     g_warning("Failed to translate keypress (keycode: %u) for group %d (%s) because "
 | |
|               "we could not load the layout.",
 | |
|               hardware_keycode, group, layout_info->name);
 | |
| 
 | |
|   return tmp_keyval != GDK_KEY_VoidSymbol;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| gdk_win32_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
 | |
|                                         GdkModifierType *state)
 | |
| {
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| gdk_win32_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
 | |
|                                         GdkModifierType *state)
 | |
| {
 | |
|   /* FIXME: Is this the right thing to do? */
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| gdk_win32_keymap_class_init (GdkWin32KeymapClass *klass)
 | |
| {
 | |
|   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 | |
|   GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
 | |
| 
 | |
|   object_class->finalize = gdk_win32_keymap_finalize;
 | |
| 
 | |
|   keymap_class->get_direction = gdk_win32_keymap_get_direction;
 | |
|   keymap_class->have_bidi_layouts = gdk_win32_keymap_have_bidi_layouts;
 | |
|   keymap_class->get_caps_lock_state = gdk_win32_keymap_get_caps_lock_state;
 | |
|   keymap_class->get_num_lock_state = gdk_win32_keymap_get_num_lock_state;
 | |
|   keymap_class->get_scroll_lock_state = gdk_win32_keymap_get_scroll_lock_state;
 | |
|   keymap_class->get_entries_for_keyval = gdk_win32_keymap_get_entries_for_keyval;
 | |
|   keymap_class->get_entries_for_keycode = gdk_win32_keymap_get_entries_for_keycode;
 | |
|   keymap_class->lookup_key = gdk_win32_keymap_lookup_key;
 | |
|   keymap_class->translate_keyboard_state = gdk_win32_keymap_translate_keyboard_state;
 | |
|   keymap_class->add_virtual_modifiers = gdk_win32_keymap_add_virtual_modifiers;
 | |
|   keymap_class->map_virtual_modifiers = gdk_win32_keymap_map_virtual_modifiers;
 | |
| }
 |