aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPhilipp Stephani2016-03-30 19:22:56 +0200
committerPhilipp Stephani2018-02-04 20:44:45 +0100
commit8fbf28536ee1169f59206523e2af050916befbf6 (patch)
tree3bb3e08efc13ba21fbedb4bafe17b8023fb48ca7 /src
parentd2630e456923d2bd70fdd59267fe6e3d8eeb69ca (diff)
downloademacs-8fbf28536ee1169f59206523e2af050916befbf6.tar.gz
emacs-8fbf28536ee1169f59206523e2af050916befbf6.zip
Fix handling of modifier keys on macOS
* src/nsterm.m (keyDown:): Distinguish between shift-like and control-like modifier keys. Allow treating ⌘ as shift-like modifier (e.g. for the Gujarati – QUERTY input method, where ⌘ switches to QUERTY.) * lisp/cus-start.el (standard): Change nil to none for ns-command-modifier; update description. * etc/NEWS: Add NEWS entry.
Diffstat (limited to 'src')
-rw-r--r--src/nsterm.m174
1 files changed, 54 insertions, 120 deletions
diff --git a/src/nsterm.m b/src/nsterm.m
index 4b81ad2a6c9..b7f5a32c098 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -37,6 +37,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
37#include <time.h> 37#include <time.h>
38#include <signal.h> 38#include <signal.h>
39#include <unistd.h> 39#include <unistd.h>
40#include <stdbool.h>
40 41
41#include <c-ctype.h> 42#include <c-ctype.h>
42#include <c-strcase.h> 43#include <c-strcase.h>
@@ -5944,7 +5945,6 @@ not_in_argv (NSString *arg)
5944@end /* EmacsApp */ 5945@end /* EmacsApp */
5945 5946
5946 5947
5947
5948/* ========================================================================== 5948/* ==========================================================================
5949 5949
5950 EmacsView implementation 5950 EmacsView implementation
@@ -6050,7 +6050,6 @@ not_in_argv (NSString *arg)
6050 int code; 6050 int code;
6051 unsigned fnKeysym = 0; 6051 unsigned fnKeysym = 0;
6052 static NSMutableArray *nsEvArray; 6052 static NSMutableArray *nsEvArray;
6053 int left_is_none;
6054 unsigned int flags = [theEvent modifierFlags]; 6053 unsigned int flags = [theEvent modifierFlags];
6055 6054
6056 NSTRACE ("[EmacsView keyDown:]"); 6055 NSTRACE ("[EmacsView keyDown:]");
@@ -6092,10 +6091,8 @@ not_in_argv (NSString *arg)
6092 6091
6093 if (!processingCompose) 6092 if (!processingCompose)
6094 { 6093 {
6095 /* When using screen sharing, no left or right information is sent, 6094 /* FIXME: What should happen for key sequences with more than
6096 so use Left key in those cases. */ 6095 one character? */
6097 int is_left_key, is_right_key;
6098
6099 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ? 6096 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6100 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0]; 6097 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6101 6098
@@ -6142,131 +6139,47 @@ not_in_argv (NSString *arg)
6142 if (flags & NSEventModifierFlagShift) 6139 if (flags & NSEventModifierFlagShift)
6143 emacs_event->modifiers |= shift_modifier; 6140 emacs_event->modifiers |= shift_modifier;
6144 6141
6145 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask; 6142 /* The ⌘ and ⌥ modifiers can be either shift-like (for alternate
6146 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask 6143 character input) or control-like (as command prefix). If we
6147 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand); 6144 have only shift-like modifiers, then we should use the
6148 6145 translated characters (returned by the characters method); if
6149 if (is_right_key) 6146 we have only control-like modifiers, then we should use the
6150 emacs_event->modifiers |= parse_solitary_modifier 6147 untranslated characters (returned by the
6151 (EQ (ns_right_command_modifier, Qleft) 6148 charactersIgnoringModifiers method). An annoyance happens if
6152 ? ns_command_modifier 6149 we have both shift-like and control-like modifiers because
6153 : ns_right_command_modifier); 6150 the NSEvent API doesn’t let us ignore only some modifiers.
6154 6151 Therefore we ignore all shift-like modifiers in that
6155 if (is_left_key) 6152 case. */
6156 { 6153
6157 emacs_event->modifiers |= parse_solitary_modifier 6154 /* EV_MODIFIERS2 uses parse_solitary_modifier on all known
6158 (ns_command_modifier); 6155 modifier keys, which returns 0 for shift-like modifiers.
6159 6156 Therefore its return value is the set of control-like
6160 /* if super (default), take input manager's word so things like 6157 modifiers. */
6161 dvorak / qwerty layout work */ 6158 unsigned int control_modifiers = EV_MODIFIERS2 (flags);
6162 if (EQ (ns_command_modifier, Qsuper) 6159 emacs_event->modifiers |= control_modifiers;
6163 && !fnKeysym 6160
6164 && [[theEvent characters] length] != 0) 6161 if (NS_KEYLOG)
6165 { 6162 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6166 /* XXX: the code we get will be unshifted, so if we have 6163 code, fnKeysym, flags, emacs_event->modifiers);
6167 a shift modifier, must convert ourselves */ 6164
6168 if (!(flags & NSEventModifierFlagShift)) 6165 /* If it was a function key or had control-like modifiers, pass
6169 code = [[theEvent characters] characterAtIndex: 0]; 6166 it directly to Emacs. */
6170#if 0
6171 /* this is ugly and also requires linking w/Carbon framework
6172 (for LMGetKbdType) so for now leave this rare (?) case
6173 undealt with.. in future look into CGEvent methods */
6174 else
6175 {
6176 long smv = GetScriptManagerVariable (smKeyScript);
6177 Handle uchrHandle = GetResource
6178 ('uchr', GetScriptVariable (smv, smScriptKeys));
6179 UInt32 dummy = 0;
6180 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6181 [[theEvent characters] characterAtIndex: 0],
6182 kUCKeyActionDisplay,
6183 (flags & ~NSEventModifierFlagCommand) >> 8,
6184 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6185 &dummy, 1, &dummy, &code);
6186 code &= 0xFF;
6187 }
6188#endif
6189 }
6190 }
6191
6192 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6193 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6194 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6195
6196 if (is_right_key)
6197 emacs_event->modifiers |= parse_solitary_modifier
6198 (EQ (ns_right_control_modifier, Qleft)
6199 ? ns_control_modifier
6200 : ns_right_control_modifier);
6201
6202 if (is_left_key)
6203 emacs_event->modifiers |= parse_solitary_modifier
6204 (ns_control_modifier);
6205
6206 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6207 emacs_event->modifiers |=
6208 parse_solitary_modifier (ns_function_modifier);
6209
6210 left_is_none = NILP (ns_alternate_modifier)
6211 || EQ (ns_alternate_modifier, Qnone);
6212
6213 is_right_key = (flags & NSRightAlternateKeyMask)
6214 == NSRightAlternateKeyMask;
6215 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6216 || (! is_right_key
6217 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6218
6219 if (is_right_key)
6220 {
6221 if ((NILP (ns_right_alternate_modifier)
6222 || EQ (ns_right_alternate_modifier, Qnone)
6223 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6224 && !fnKeysym)
6225 { /* accept pre-interp alt comb */
6226 if ([[theEvent characters] length] > 0)
6227 code = [[theEvent characters] characterAtIndex: 0];
6228 /*HACK: clear lone shift modifier to stop next if from firing */
6229 if (emacs_event->modifiers == shift_modifier)
6230 emacs_event->modifiers = 0;
6231 }
6232 else
6233 emacs_event->modifiers |= parse_solitary_modifier
6234 (EQ (ns_right_alternate_modifier, Qleft)
6235 ? ns_alternate_modifier
6236 : ns_right_alternate_modifier);
6237 }
6238
6239 if (is_left_key) /* default = meta */
6240 {
6241 if (left_is_none && !fnKeysym)
6242 { /* accept pre-interp alt comb */
6243 if ([[theEvent characters] length] > 0)
6244 code = [[theEvent characters] characterAtIndex: 0];
6245 /*HACK: clear lone shift modifier to stop next if from firing */
6246 if (emacs_event->modifiers == shift_modifier)
6247 emacs_event->modifiers = 0;
6248 }
6249 else
6250 emacs_event->modifiers |=
6251 parse_solitary_modifier (ns_alternate_modifier);
6252 }
6253
6254 if (NS_KEYLOG)
6255 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6256 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6257
6258 /* if it was a function key or had modifiers, pass it directly to emacs */
6259 if (fnKeysym || (emacs_event->modifiers 6167 if (fnKeysym || (emacs_event->modifiers
6260 && (emacs_event->modifiers != shift_modifier) 6168 && (emacs_event->modifiers != shift_modifier)
6261 && [[theEvent charactersIgnoringModifiers] length] > 0)) 6169 && [[theEvent charactersIgnoringModifiers] length] > 0))
6262/*[[theEvent characters] length] */ 6170/*[[theEvent characters] length] */
6263 { 6171 {
6264 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; 6172 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6173 /* FIXME: What are the next four lines supposed to do? */
6265 if (code < 0x20) 6174 if (code < 0x20)
6266 code |= (1<<28)|(3<<16); 6175 code |= (1<<28)|(3<<16);
6267 else if (code == 0x7f) 6176 else if (code == 0x7f)
6268 code |= (1<<28)|(3<<16); 6177 code |= (1<<28)|(3<<16);
6269 else if (!fnKeysym) 6178 else if (!fnKeysym)
6179 /* FIXME: This seems wrong, characters in the range
6180 [0x80, 0xFF] are not ASCII characters. Can’t we just
6181 use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds
6182 of characters? */
6270 emacs_event->kind = code > 0xFF 6183 emacs_event->kind = code > 0xFF
6271 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; 6184 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6272 6185
@@ -6277,11 +6190,32 @@ not_in_argv (NSString *arg)
6277 } 6190 }
6278 } 6191 }
6279 6192
6193 /* If we get here, a non-function key without control-like modifiers
6194 was hit. Use interpretKeyEvents, which in turn will call
6195 insertText; see
6196 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html. */
6280 6197
6281 if (NS_KEYLOG && !processingCompose) 6198 if (NS_KEYLOG && !processingCompose)
6282 fprintf (stderr, "keyDown: Begin compose sequence.\n"); 6199 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6283 6200
6201 /* FIXME: interpretKeyEvents doesn’t seem to send insertText if ⌘ is
6202 used as shift-like modifier, at least on El Capitan. Mask it
6203 out. This shouldn’t be needed though; we should figure out what
6204 the correct way of handling ⌘ is. */
6205 if ([theEvent modifierFlags] & NSEventModifierFlagCommand)
6206 theEvent = [NSEvent keyEventWithType:[theEvent type]
6207 location:[theEvent locationInWindow]
6208 modifierFlags:[theEvent modifierFlags] & ~NSEventModifierFlagCommand
6209 timestamp:[theEvent timestamp]
6210 windowNumber:[theEvent windowNumber]
6211 context:nil
6212 characters:[theEvent characters]
6213 charactersIgnoringModifiers:[theEvent charactersIgnoringModifiers]
6214 isARepeat:[theEvent isARepeat]
6215 keyCode:[theEvent keyCode]];
6216
6284 processingCompose = YES; 6217 processingCompose = YES;
6218 /* FIXME: Use [NSArray arrayWithObject:theEvent]? */
6285 [nsEvArray addObject: theEvent]; 6219 [nsEvArray addObject: theEvent];
6286 [self interpretKeyEvents: nsEvArray]; 6220 [self interpretKeyEvents: nsEvArray];
6287 [nsEvArray removeObject: theEvent]; 6221 [nsEvArray removeObject: theEvent];