emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master 5b464a9: Fix modifier key handling on macOS


From: Alan Third
Subject: [Emacs-diffs] master 5b464a9: Fix modifier key handling on macOS
Date: Sat, 17 Feb 2018 07:35:01 -0500 (EST)

branch: master
commit 5b464a9ceab6aa48138d0353669b426ff69e5365
Author: Alan Third <address@hidden>
Commit: Alan Third <address@hidden>

    Fix modifier key handling on macOS
    
    * configure.ac: Use the Carbon framework on macOS.
    * src/nsterm.m (ns_get_shifted_character) [NS_IMPL_COCOA]: New function.
    (EmacsView::keyDown) [NS_IMPL_COCOA]: Use ns_get_shifted_character
    when we have shift style modifiers.
---
 configure.ac |   2 +-
 src/nsterm.m | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 90 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index cb452e0..cf0347a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5269,7 +5269,7 @@ case "$opsys" in
    if test "$HAVE_NS" = "yes"; then
      libs_nsgui="-framework AppKit"
      if test "$NS_IMPL_COCOA" = "yes"; then
-        libs_nsgui="$libs_nsgui -framework IOKit"
+        libs_nsgui="$libs_nsgui -framework IOKit -framework Carbon"
      fi
    else
      libs_nsgui=
diff --git a/src/nsterm.m b/src/nsterm.m
index 627a61c..1919c6d 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -67,6 +67,7 @@ GNUstep port and post-20 update by Adrian Robert 
(address@hidden)
 
 #ifdef NS_IMPL_COCOA
 #include "macfont.h"
+#include <Carbon/Carbon.h>
 #endif
 
 static EmacsMenu *dockMenu;
@@ -2679,7 +2680,78 @@ x_get_keysym_name (int keysym)
   return value;
 }
 
+#ifdef NS_IMPL_COCOA
+static UniChar
+ns_get_shifted_character (NSEvent *event)
+/* Look up the character corresponding to the key pressed on the
+   current keyboard layout and the currently configured shift-like
+   modifiers.  This ignores the control-like modifiers that cause
+   [event characters] to give us the wrong result.
+
+   Although UCKeyTranslate doesn't require the Carbon framework, some
+   of the surrounding paraphernalia does, so this function makes
+   Carbon a requirement.  */
+{
+  static UInt32 dead_key_state;
+
+  /* UCKeyTranslate may return up to 255 characters.  If the buffer
+     isn't large enough then it produces an error.  What kind of
+     keyboard inputs 255 characters in a single keypress?  */
+  UniChar buf[255];
+  UniCharCount max_string_length = 255;
+  UniCharCount actual_string_length = 0;
+  OSStatus result;
+
+  CFDataRef layout_ref = (CFDataRef) TISGetInputSourceProperty
+    (TISCopyCurrentKeyboardLayoutInputSource (), 
kTISPropertyUnicodeKeyLayoutData);
+  UCKeyboardLayout* layout = (UCKeyboardLayout*) CFDataGetBytePtr (layout_ref);
+
+  UInt32 flags = [event modifierFlags];
+  UInt32 modifiers = (flags & NSEventModifierFlagShift) ? shiftKey : 0;
+
+  NSTRACE ("ns_get_shifted_character");
+
+  if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask
+      && (EQ (ns_right_alternate_modifier, Qnone)
+          || (EQ (ns_right_alternate_modifier, Qleft)
+              && EQ (ns_alternate_modifier, Qnone))))
+    modifiers |= rightOptionKey;
+
+  if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
+      && EQ (ns_alternate_modifier, Qnone))
+    modifiers |= optionKey;
+
+  if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask
+      && (EQ (ns_right_command_modifier, Qnone)
+          || (EQ (ns_right_command_modifier, Qleft)
+              && EQ (ns_command_modifier, Qnone))))
+    /* Carbon doesn't differentiate between left and right command
+       keys.  */
+    modifiers |= cmdKey;
+
+  if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
+      && EQ (ns_command_modifier, Qnone))
+    modifiers |= cmdKey;
+
+  result = UCKeyTranslate (layout, [event keyCode], kUCKeyActionDown,
+                           (modifiers >> 8) & 0xFF, LMGetKbdType (),
+                           kUCKeyTranslateNoDeadKeysBit, &dead_key_state,
+                           max_string_length, &actual_string_length, buf);
+
+  if (result != 0)
+    {
+      NSLog(@"Failed to translate character '%@' with modifiers %x",
+            [event characters], modifiers);
+      return 0;
+    }
+
+  /* FIXME: What do we do if more than one code unit is returned?  */
+  if (actual_string_length > 0)
+    return buf[0];
 
+  return 0;
+}
+#endif /* NS_IMPL_COCOA */
 
 /* ==========================================================================
 
@@ -6148,8 +6220,6 @@ not_in_argv (NSString *arg)
       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
 
-      /* (Carbon way: [theEvent keyCode]) */
-
       /* is it a "function key"? */
       /* Note: Sometimes a plain key will have the 
NSEventModifierFlagNumericPad
          flag set (this is probably a bug in the OS).
@@ -6191,8 +6261,8 @@ not_in_argv (NSString *arg)
          charactersIgnoringModifiers method).  An annoyance happens if
          we have both shift-like and control-like modifiers because
          the NSEvent API doesn’t let us ignore only some modifiers.
-         Therefore we ignore all shift-like modifiers in that
-         case.  */
+         In that case we use UCKeyTranslate (ns_get_shifted_character)
+         to look up the correct character.  */
 
       /* EV_MODIFIERS2 uses parse_solitary_modifier on all known
          modifier keys, which returns 0 for shift-like modifiers.
@@ -6218,7 +6288,6 @@ not_in_argv (NSString *arg)
       if (fnKeysym || (emacs_event->modifiers
                        && (emacs_event->modifiers != shift_modifier)
                        && [[theEvent charactersIgnoringModifiers] length] > 0))
-/*[[theEvent characters] length] */
         {
           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
           /* FIXME: What are the next four lines supposed to do?  */
@@ -6227,12 +6296,21 @@ not_in_argv (NSString *arg)
           else if (code == 0x7f)
             code |= (1<<28)|(3<<16);
           else if (!fnKeysym)
-            /* FIXME: This seems wrong, characters in the range
-               [0x80, 0xFF] are not ASCII characters.  Can’t we just
-               use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds
-               of characters?  */
-            emacs_event->kind = code > 0xFF
-              ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
+            {
+#ifdef NS_IMPL_COCOA
+              /* We potentially have both shift- and control-like
+                 modifiers in use, so find the correct character
+                 ignoring any control-like ones.  */
+              code = ns_get_shifted_character (theEvent);
+#endif
+
+              /* FIXME: This seems wrong, characters in the range
+                 [0x80, 0xFF] are not ASCII characters.  Can’t we just
+                 use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds
+                 of characters?  */
+              emacs_event->kind = code > 0xFF
+                ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
+            }
 
           emacs_event->code = code;
           EV_TRAILER (theEvent);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]