Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gdkkeys-win32.c

  Sprache: 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-2000.  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 "gdkwin32keys.h"

#include "gdk.h"

#include "gdkprivate-win32.h"
#include "gdkdebugprivate.h"
#include "gdkdisplay-win32.h"
#include "gdkkeysyms.h"
#include "gdkkeysprivate.h"
#include "gdkkeys-win32.h"

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

#define GDK_MOD2_MASK (1 << 4)

/* 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)

/* forward declarations */
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 (FALSETRUE,
                                      sizeof (GdkWin32KeymapLayoutInfo));
  g_array_set_clear_func (keymap->layout_infos,
                          clear_keyboard_layout_info);

  keymap->layout_handles = g_array_new (FALSEFALSE,
                                        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
}

static void
gdk_win32_keymap_constructed (GObject *object)
{
  GdkWin32Keymap *keymap;

  G_OBJECT_CLASS (gdk_win32_keymap_parent_class)->constructed (object);

  keymap = GDK_WIN32_KEYMAP (object);
  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_FILE_NOT_FOUND)
    {
      return NULL;
    }
  else if (status != ERROR_SUCCESS)
    {
      g_warning("Could not open registry key '%s'. Error code: %d",
                kbdKeyPath, (int)status);
      return NULL;
    }

  /* 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 fail_close_key;
    }

  dir_len = GetSystemDirectoryA (00); /* includes \0 */
  if (dir_len == 0)
    {
      g_warning("GetSystemDirectoryA failed. Error: %d", (int)GetLastError());
      goto fail_close_key;
    }

  /* 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 fail_free_result;

  /* 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 fail_free_result;

  result[dir_len + file_name_len] = '\0';

  RegCloseKey (hkey);
  return result;

fail_free_result:
  g_free (result);
fail_close_key:
  RegCloseKey (hkey);
  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, 0sizeof (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 int
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_ALT_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_ALT_MASK)
    result |= KBDALT;
  return result;
}

static void
update_keymap (GdkWin32Keymap *keymap)
{
  HKL  current_layout;
  BOOL changed = FALSE;
  int  n_layouts;
  int  i;
  GdkWin32Display *display = GDK_WIN32_DISPLAY (GDK_KEYMAP (keymap)->display);


  if (keymap->current_serial == gdk_win32_display_get_keymap_serial (display) &&
      keymap->layout_handles->len > 0)
    {
      return;
    }

  n_layouts = GetKeyboardLayoutList (00);
  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 (FALSEFALSE,
                                               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)
    {
      GdkSeat *seat;
      GdkDevice *device;

      ActivateKeyboardLayout (current_layout, 0);

      seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
      device = gdk_seat_get_keyboard (seat);
      g_object_notify (G_OBJECT (device), "active-layout-index");
      g_object_notify (G_OBJECT (device), "layout-names");
    }

  keymap->current_serial = gdk_win32_display_get_keymap_serial (display);
}

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)
    {
      int group;

      for (group = 0; group < keymap->layout_handles->len; group++)
        if (g_array_index (keymap->layout_handles, HKL, group) == hkl)
          if (keymap->active_layout != group)
            {
              GdkSeat *seat;
              GdkDevice *device;

              keymap->active_layout = group;

              seat = gdk_display_get_default_seat (GDK_KEYMAP (keymap)->display);
              device = gdk_seat_get_keyboard (seat);
              g_object_notify (G_OBJECT (device), "active-layout-index");
            }
    }
}

guint8
_gdk_win32_keymap_get_active_group (GdkWin32Keymap *keymap)
{
  if (keymap != NULL &&
      keymap->layout_handles->len > 0)
    return keymap->active_layout;

  return 0;
}

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;
  int             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,
                                         GArray        *retval)
{
  GdkWin32Keymap *keymap;
  int             group;
  guint           len = retval->len;

  g_return_val_if_fail (GDK_IS_KEYMAP (gdk_keymap), FALSE);
  g_return_val_if_fail (keyval != 0FALSE);

  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);
      int 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;
        }
   }

  return retval->len > len;
}

static gboolean
gdk_win32_keymap_get_entries_for_keycode (GdkKeymap     *gdk_keymap,
                                          guint          hardware_keycode,
                                          GdkKeymapKey **keys,
                                          guint        **keyvals,
                                          int           *n_entries)
{
  GdkWin32Keymap *keymap;
  GArray         *key_array;
  GArray         *keyval_array;
  int             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 (FALSEFALSEsizeof (GdkKeymapKey));
  else
    key_array = NULL;

  if (keyvals != NULL)
    keyval_array = g_array_new (FALSEFALSEsizeof (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,
                                           int              group,
                                           guint           *keyval,
                                           int             *effective_group,
                                           int             *level,
                                           GdkModifierType *consumed_modifiers)
{
  GdkWin32Keymap           *keymap;
  guint                     tmp_keyval;
  int                       tmp_effective_group;
  int                       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 char **
gdk_win32_keymap_get_layout_names (GdkKeymap *gdk_keymap)
{
  GdkWin32Keymap *keymap = GDK_WIN32_KEYMAP (gdk_keymap);

  update_keymap (keymap);

  if (keymap->layout_infos)
    {
      GStrvBuilder *names_builder;
      char **layout_names;
      int i;

      names_builder = g_strv_builder_new ();

      for (i = 0; i < keymap->layout_infos->len; ++i)
        {
          LCID lcid;
          char *endptr;
          GdkWin32KeymapLayoutInfo *info;

          info = &g_array_index (keymap->layout_infos, GdkWin32KeymapLayoutInfo, i);
          lcid = strtoul (info->name, &endptr, 16);

          if (info->name != endptr)
            {
              wchar_t *locale_name_w;
              int locale_size = GetLocaleInfoW (lcid, LOCALE_SLOCALIZEDDISPLAYNAME, NULL, 0);

              locale_name_w = g_new0 (wchar_t, locale_size);

              if (GetLocaleInfoW (lcid, LOCALE_SLOCALIZEDDISPLAYNAME, locale_name_w, locale_size))
                {
                  gchar *locale_name = g_utf16_to_utf8 (locale_name_w, -1, NULL, NULL, NULL);
                  g_strv_builder_add (names_builder, locale_name);
                }

              g_free (locale_name_w);
            }
        }

      layout_names = g_strv_builder_end (names_builder);
      g_strv_builder_unref (names_builder);

      return layout_names;
    }

  return NULL;
}

static int
gdk_win32_keymap_get_active_layout_index (GdkKeymap *gdk_keymap)
{
  GdkWin32Keymap *keymap = GDK_WIN32_KEYMAP (gdk_keymap);

  update_keymap (keymap);

  if (keymap->layout_infos)
    return (int) keymap->active_layout;

  return -1;
}

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->constructed = gdk_win32_keymap_constructed;
  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->get_active_layout_index = gdk_win32_keymap_get_active_layout_index;
  keymap_class->get_layout_names = gdk_win32_keymap_get_layout_names;
}

Messung V0.5 in Prozent
C=98 H=95 G=96

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik