 99a816c361
			
		
	
	99a816c361
	
	
	
		
			
			On Windows with certain keyboard layout combinations you can get a benign terminal warning like this: Could not open registry key 'SYSTEM\CurrentControlSet\Control\Keyboard Layouts\D0010413' When using a lot of plug-ins, like GIMP does, this warning can show up a lot of times. The code after this warning, still has another last check, that, when it fails, will show a warning. We change the first g_warning to a g_debug statement, to reduce the amount of warning messages. Closes #5109
		
			
				
	
	
		
			1153 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1153 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;
 | |
| }
 | |
| 
 | |
| static char*
 | |
| _get_keyboard_layout_file (const char *layout_name)
 | |
| {
 | |
|   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];
 | |
| 
 | |
|   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_debug("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;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * 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 *result = _get_keyboard_layout_file (layout_name);
 | |
| 
 | |
|   /* If we could not retrieve a path, it may be that we need to perform layout
 | |
|    * substitution
 | |
|    */
 | |
|   if (result == NULL)
 | |
|     {
 | |
|       char *substituted = get_keyboard_layout_substituted_name (layout_name);
 | |
|       result = _get_keyboard_layout_file (substituted);
 | |
|       g_free (substituted);
 | |
|     }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 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;
 | |
| }
 |