diff options
| author | Philipp Stephani | 2016-03-30 19:22:56 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2018-02-04 20:44:45 +0100 |
| commit | 8fbf28536ee1169f59206523e2af050916befbf6 (patch) | |
| tree | 3bb3e08efc13ba21fbedb4bafe17b8023fb48ca7 /src | |
| parent | d2630e456923d2bd70fdd59267fe6e3d8eeb69ca (diff) | |
| download | emacs-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.m | 174 |
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]; |