[gtk/wip/chergert/quartz4u] macos: implement some keyevents



commit 568a936c3fa297a6e2d2005c90e58a89971ed198
Author: Christian Hergert <chergert redhat com>
Date:   Wed May 6 14:09:02 2020 -0700

    macos: implement some keyevents
    
    This still doesn't seem to be complete enough, I can't seem to get
    option to work for alternate text input. So something else still needs
    to be done.

 gdk/macos/gdkmacosdisplay-translate.c | 111 +++++++++++-
 gdk/macos/gdkmacoskeymap-private.h    |   1 +
 gdk/macos/gdkmacoskeymap.c            | 307 ++++++++++------------------------
 3 files changed, 193 insertions(+), 226 deletions(-)
---
diff --git a/gdk/macos/gdkmacosdisplay-translate.c b/gdk/macos/gdkmacosdisplay-translate.c
index 033036acc6..ff9837b52a 100644
--- a/gdk/macos/gdkmacosdisplay-translate.c
+++ b/gdk/macos/gdkmacosdisplay-translate.c
@@ -27,6 +27,7 @@
 #include "gdkmacoskeymap-private.h"
 #include "gdkmacossurface-private.h"
 
+#define GDK_MOD2_MASK (1 << 4)
 #define GRIP_WIDTH 15
 #define GRIP_HEIGHT 15
 #define GDK_LION_RESIZE 5
@@ -169,7 +170,7 @@ get_keyboard_modifiers_from_ns_flags (NSUInteger nsflags)
   if (nsflags & NSEventModifierFlagOption)
     modifiers |= GDK_ALT_MASK;
   if (nsflags & NSEventModifierFlagCommand)
-    modifiers |= GDK_SUPER_MASK;
+    modifiers |= GDK_MOD2_MASK;
 
   return modifiers;
 }
@@ -284,27 +285,120 @@ synthesize_crossing_event (GdkMacosDisplay *display,
                                  GDK_NOTIFY_NONLINEAR);
 }
 
+static inline guint
+get_group_from_ns_event (NSEvent *nsevent)
+{
+  return ([nsevent modifierFlags] & NSEventModifierFlagOption) ? 1 : 0;
+}
+
+static void
+add_virtual_modifiers (GdkModifierType *state)
+{
+  if (*state & GDK_MOD2_MASK)
+    *state |= GDK_META_MASK;
+}
+
 static GdkEvent *
 fill_key_event (GdkMacosDisplay *display,
                 GdkMacosSurface *surface,
                 NSEvent         *nsevent,
                 GdkEventType     type)
 {
-#if 1
-  return NULL;
-#else
-  GdkTranslatedKey translated;
-  GdkTranslatedKey no_lock;
-  GdkModifierType modifiers;
+  GdkTranslatedKey translated = {0};
+  GdkTranslatedKey no_lock = {0};
+  GdkModifierType consumed;
+  GdkModifierType state;
+  GdkKeymap *keymap;
   gboolean is_modifier;
   GdkSeat *seat;
   guint keycode;
+  guint keyval;
+  guint group;
+  gint layout;
+  gint level;
 
   g_assert (GDK_IS_MACOS_DISPLAY (display));
   g_assert (GDK_IS_MACOS_SURFACE (surface));
   g_assert (nsevent != NULL);
 
   seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
+  keymap = gdk_display_get_keymap (GDK_DISPLAY (display));
+  keycode = [nsevent keyCode];
+  keyval = GDK_KEY_VoidSymbol;
+  state = get_keyboard_modifiers_from_ns_event (nsevent);
+  group = get_group_from_ns_event (nsevent);
+  is_modifier = _gdk_macos_keymap_is_modifier (keycode);
+
+  gdk_keymap_translate_keyboard_state (keymap, keycode, state, group,
+                                       &keyval, &layout, &level, &consumed);
+
+  /* If the key press is a modifier, the state should include the mask for
+   * that modifier but only for releases, not presses. This matches the
+   * X11 backend behavior.
+   */
+  if (is_modifier)
+    {
+      guint mask = 0;
+
+      switch (keyval)
+        {
+        case GDK_KEY_Meta_R:
+        case GDK_KEY_Meta_L:
+          mask = GDK_MOD2_MASK;
+          break;
+        case GDK_KEY_Shift_R:
+        case GDK_KEY_Shift_L:
+          mask = GDK_SHIFT_MASK;
+          break;
+        case GDK_KEY_Caps_Lock:
+          mask = GDK_LOCK_MASK;
+          break;
+        case GDK_KEY_Alt_R:
+        case GDK_KEY_Alt_L:
+          mask = GDK_ALT_MASK;
+          break;
+        case GDK_KEY_Control_R:
+        case GDK_KEY_Control_L:
+          mask = GDK_CONTROL_MASK;
+          break;
+        default:
+          mask = 0;
+        }
+
+      if (type == GDK_KEY_PRESS)
+        state &= ~mask;
+      else if (type == GDK_KEY_RELEASE)
+        state |= mask;
+    }
+
+  state |= _gdk_macos_display_get_current_mouse_modifiers (display);
+  add_virtual_modifiers (&state);
+
+  translated.keyval = keyval;
+  translated.consumed = consumed;
+  translated.layout = layout;
+  translated.level = level;
+
+  if (state & GDK_LOCK_MASK)
+    {
+      gdk_keymap_translate_keyboard_state (keymap,
+                                           keycode,
+                                           state & ~GDK_LOCK_MASK,
+                                           group,
+                                           &keyval,
+                                           &layout,
+                                           &level,
+                                           &consumed);
+
+      no_lock.keyval = keycode;
+      no_lock.consumed = consumed;
+      no_lock.layout = layout;
+      no_lock.level = level;
+    }
+  else
+    {
+      no_lock = translated;
+    }
 
   return gdk_key_event_new (type,
                             GDK_SURFACE (surface),
@@ -312,11 +406,10 @@ fill_key_event (GdkMacosDisplay *display,
                             NULL,
                             get_time_from_ns_event (nsevent),
                             [nsevent keyCode],
-                            modifiers,
+                            state,
                             is_modifier,
                             &translated,
                             &no_lock);
-#endif
 }
 
 static GdkEvent *
diff --git a/gdk/macos/gdkmacoskeymap-private.h b/gdk/macos/gdkmacoskeymap-private.h
index 28eaa091ac..34ff21b225 100644
--- a/gdk/macos/gdkmacoskeymap-private.h
+++ b/gdk/macos/gdkmacoskeymap-private.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
 
 GdkMacosKeymap *_gdk_macos_keymap_new            (GdkMacosDisplay *display);
 GdkEventType    _gdk_macos_keymap_get_event_type (NSEvent         *event);
+gboolean        _gdk_macos_keymap_is_modifier    (guint            keycode);
 
 G_END_DECLS
 
diff --git a/gdk/macos/gdkmacoskeymap.c b/gdk/macos/gdkmacoskeymap.c
index 26899a7f6e..c638c75179 100644
--- a/gdk/macos/gdkmacoskeymap.c
+++ b/gdk/macos/gdkmacoskeymap.c
@@ -80,55 +80,21 @@ static guint *keyval_array = NULL;
 #define GET_KEYVAL(keycode, group, level) \
   (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
 
-static inline UniChar
-macroman2ucs (unsigned char c)
-{
-  /* Precalculated table mapping MacRoman-128 to Unicode. Generated
-     by creating single element CFStringRefs then extracting the
-     first character. */
-
-  static const unsigned short table[128] = {
-    0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
-    0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
-    0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
-    0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
-    0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
-    0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
-    0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
-    0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
-    0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
-    0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
-    0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
-    0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
-    0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
-    0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
-    0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
-    0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7
-  };
-
-  if (c < 128)
-    return c;
-  else
-    return table[c - 128];
-}
-
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
 const static struct {
   guint keycode;
   guint keyval;
   unsigned int modmask; /* So we can tell when a mod key is pressed/released */
 } modifier_keys[] = {
-  {  54, GDK_KEY_Meta_R,    NSCommandKeyMask },
-  {  55, GDK_KEY_Meta_L,    NSCommandKeyMask },
-  {  56, GDK_KEY_Shift_L,   NSShiftKeyMask },
-  {  57, GDK_KEY_Caps_Lock, NSAlphaShiftKeyMask },
-  {  58, GDK_KEY_Alt_L,     NSAlternateKeyMask },
-  {  59, GDK_KEY_Control_L, NSControlKeyMask },
-  {  60, GDK_KEY_Shift_R,   NSShiftKeyMask },
-  {  61, GDK_KEY_Alt_R,     NSAlternateKeyMask },
-  {  62, GDK_KEY_Control_R, NSControlKeyMask }
+  {  54, GDK_KEY_Meta_R,    NSEventModifierFlagCommand },
+  {  55, GDK_KEY_Meta_L,    NSEventModifierFlagCommand },
+  {  56, GDK_KEY_Shift_L,   NSEventModifierFlagShift },
+  {  57, GDK_KEY_Caps_Lock, NSEventModifierFlagCapsLock },
+  {  58, GDK_KEY_Alt_L,     NSEventModifierFlagOption },
+  {  59, GDK_KEY_Control_L, NSEventModifierFlagControl },
+  {  60, GDK_KEY_Shift_R,   NSEventModifierFlagShift },
+  {  61, GDK_KEY_Alt_R,     NSEventModifierFlagOption },
+  {  62, GDK_KEY_Control_R, NSEventModifierFlagControl }
 };
-G_GNUC_END_IGNORE_DEPRECATIONS
 
 const static struct {
   guint keycode;
@@ -257,28 +223,13 @@ gdk_macos_keymap_update (GdkMacosKeymap *self)
   guint *p;
   int i;
 
-  /* Note: we could check only if building against the 10.5 SDK instead, but
-   * that would make non-xml layouts not work in 32-bit which would be a quite
-   * bad regression. This way, old unsupported layouts will just not work in
-   * 64-bit.
-   */
-#ifdef __LP64__
   TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
   CFDataRef layout_data_ref;
 
-#else
-  KeyboardLayoutRef new_layout;
-  KeyboardLayoutKind layout_kind;
-
-  KLGetCurrentKeyboardLayout (&new_layout);
-#endif
-
   g_free (keyval_array);
   keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
 
-#ifdef __LP64__
-  layout_data_ref = (CFDataRef) TISGetInputSourceProperty
-    (new_layout, kTISPropertyUnicodeKeyLayoutData);
+  layout_data_ref = (CFDataRef)TISGetInputSourceProperty (new_layout, kTISPropertyUnicodeKeyLayoutData);
 
   if (layout_data_ref)
     chr_data = CFDataGetBytePtr (layout_data_ref);
@@ -288,179 +239,88 @@ gdk_macos_keymap_update (GdkMacosKeymap *self)
       g_error ("cannot get keyboard layout data");
       return;
     }
-#else
-
-  /* Get the layout kind */
-  KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
 
-  /* 8-bit-only keyabord layout */
-  if (layout_kind == kKLKCHRKind)
+  for (i = 0; i < NUM_KEYCODES; i++)
     {
-      /* Get chr data */
-      KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
+      int j;
+      UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
+      UniChar chars[4];
+      UniCharCount nChars;
 
-      for (i = 0; i < NUM_KEYCODES; i++)
-        {
-          int j;
-          UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
-
-          p = keyval_array + i * KEYVALS_PER_KEYCODE;
+      p = keyval_array + i * KEYVALS_PER_KEYCODE;
 
-          for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
+      for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
+        {
+          UInt32 state = 0;
+          OSStatus err;
+          UInt16 key_code;
+          UniChar uc;
+
+          key_code = modifiers[j] | i;
+          err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
+                                (modifiers[j] >> 8) & 0xFF,
+                                LMGetKbdType(),
+                                0,
+                                &state, 4, &nChars, chars);
+
+          /* FIXME: Theoretically, we can get multiple UTF-16
+           * values; we should convert them to proper unicode and
+           * figure out whether there are really keyboard layouts
+           * that give us more than one character for one
+           * keypress.
+           */
+          if (err == noErr && nChars == 1)
             {
-              UInt32 c, state = 0;
-              UInt16 key_code;
-              UniChar uc;
-
-              key_code = modifiers[j] | i;
-              c = KeyTranslate (chr_data, key_code, &state);
-
+              int k;
+              gboolean found = FALSE;
+
+              /* A few <Shift><Option>keys return two characters,
+               * the first of which is U+00a0, which isn't
+               * interesting; so we return the second. More
+               * sophisticated handling is the job of a
+               * GtkIMContext.
+               *
+               * If state isn't zero, it means that it's a dead
+               * key of some sort. Some of those are enumerated in
+               * the special_ucs_table with the high nibble set to
+               * f to push it into the private use range. Here we
+               * do the same.
+               */
               if (state != 0)
-                {
-                  UInt32 state2 = 0;
-                  c = KeyTranslate (chr_data, key_code | 128, &state2);
-                }
+                chars[nChars - 1] |= 0xf000;
+              uc = chars[nChars - 1];
 
-              if (c != 0 && c != 0x10)
+              for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
                 {
-                  int k;
-                  gboolean found = FALSE;
-
-                  /* FIXME: some keyboard layouts (e.g. Russian) use a
-                   * different 8-bit character set. We should check
-                   * for this. Not a serious problem, because most
-                   * (all?) of these layouts also have a uchr version.
-                   */
-                  uc = macroman2ucs (c);
-
-                  for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
+                  if (special_ucs_table[k].ucs_value == uc)
                     {
-                      if (special_ucs_table[k].ucs_value == uc)
-                        {
-                          p[j] = special_ucs_table[k].keyval;
-                          found = TRUE;
-                          break;
-                        }
+                      p[j] = special_ucs_table[k].keyval;
+                      found = TRUE;
+                      break;
                     }
-
-                  /* Special-case shift-tab since GTK+ expects
-                   * GDK_KEY_ISO_Left_Tab for that.
-                   */
-                  if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
-                    p[j] = GDK_KEY_ISO_Left_Tab;
-
-                  if (!found)
-                    p[j] = gdk_unicode_to_keyval (uc);
                 }
-            }
-
-          if (p[3] == p[2])
-            p[3] = 0;
-          if (p[2] == p[1])
-            p[2] = 0;
-          if (p[1] == p[0])
-            p[1] = 0;
-          if (p[0] == p[2] &&
-              p[1] == p[3])
-            p[2] = p[3] = 0;
-        }
-    }
-  /* unicode keyboard layout */
-  else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
-    {
-      /* Get chr data */
-      KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
-#endif
 
-      for (i = 0; i < NUM_KEYCODES; i++)
-        {
-          int j;
-          UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
-          UniChar chars[4];
-          UniCharCount nChars;
-
-          p = keyval_array + i * KEYVALS_PER_KEYCODE;
-
-          for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
-            {
-              UInt32 state = 0;
-              OSStatus err;
-              UInt16 key_code;
-              UniChar uc;
-
-              key_code = modifiers[j] | i;
-              err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
-                                    (modifiers[j] >> 8) & 0xFF,
-                                    LMGetKbdType(),
-                                    0,
-                                    &state, 4, &nChars, chars);
-
-              /* FIXME: Theoretically, we can get multiple UTF-16
-               * values; we should convert them to proper unicode and
-               * figure out whether there are really keyboard layouts
-               * that give us more than one character for one
-               * keypress.
+              /* Special-case shift-tab since GTK+ expects
+               * GDK_KEY_ISO_Left_Tab for that.
                */
-              if (err == noErr && nChars == 1)
-                {
-                  int k;
-                  gboolean found = FALSE;
-
-                  /* A few <Shift><Option>keys return two characters,
-                   * the first of which is U+00a0, which isn't
-                   * interesting; so we return the second. More
-                   * sophisticated handling is the job of a
-                   * GtkIMContext.
-                   *
-                   * If state isn't zero, it means that it's a dead
-                   * key of some sort. Some of those are enumerated in
-                   * the special_ucs_table with the high nibble set to
-                   * f to push it into the private use range. Here we
-                   * do the same.
-                   */
-                  if (state != 0)
-                    chars[nChars - 1] |= 0xf000;
-                  uc = chars[nChars - 1];
-
-                  for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
-                    {
-                      if (special_ucs_table[k].ucs_value == uc)
-                        {
-                          p[j] = special_ucs_table[k].keyval;
-                          found = TRUE;
-                          break;
-                        }
-                    }
+              if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
+                p[j] = GDK_KEY_ISO_Left_Tab;
 
-                  /* Special-case shift-tab since GTK+ expects
-                   * GDK_KEY_ISO_Left_Tab for that.
-                   */
-                  if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
-                    p[j] = GDK_KEY_ISO_Left_Tab;
-
-                  if (!found)
-                    p[j] = gdk_unicode_to_keyval (uc);
-                }
+              if (!found)
+                p[j] = gdk_unicode_to_keyval (uc);
             }
-
-          if (p[3] == p[2])
-            p[3] = 0;
-          if (p[2] == p[1])
-            p[2] = 0;
-          if (p[1] == p[0])
-            p[1] = 0;
-          if (p[0] == p[2] &&
-              p[1] == p[3])
-            p[2] = p[3] = 0;
         }
-#ifndef __LP64__
-    }
-  else
-    {
-      g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
-               " - not supported right now");
+
+      if (p[3] == p[2])
+        p[3] = 0;
+      if (p[2] == p[1])
+        p[2] = 0;
+      if (p[1] == p[0])
+        p[1] = 0;
+      if (p[0] == p[2] &&
+          p[1] == p[3])
+        p[2] = p[3] = 0;
     }
-#endif
 
   for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
     {
@@ -611,11 +471,9 @@ gdk_macos_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
   guint i;
 
   g_assert (GDK_IS_MACOS_KEYMAP (keymap));
-  g_assert (keys != NULL);
   g_assert (keyvals != NULL);
   g_assert (n_entries != NULL);
 
-  *keys = NULL;
   *keyvals = NULL;
   *n_entries = 0;
 
@@ -823,3 +681,18 @@ _gdk_macos_keymap_get_event_type (NSEvent *event)
    * events for no good reason. Ignore them! */
   return 0;
 }
+
+gboolean
+_gdk_macos_keymap_is_modifier (guint keycode)
+{
+  for (guint i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
+    {
+      if (modifier_keys[i].modmask == 0)
+        break;
+
+      if (modifier_keys[i].keycode == keycode)
+        return TRUE;
+    }
+
+  return FALSE;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]