diff options
| author | Alan Third | 2018-02-14 20:28:46 +0000 |
|---|---|---|
| committer | Alan Third | 2018-02-17 12:34:50 +0000 |
| commit | 5b464a9ceab6aa48138d0353669b426ff69e5365 (patch) | |
| tree | 5119e77a4f76885f732ce06594d76cf3ba150781 /src | |
| parent | 4429f97b58653540985387caa554fc0f25f90000 (diff) | |
| download | emacs-5b464a9ceab6aa48138d0353669b426ff69e5365.tar.gz emacs-5b464a9ceab6aa48138d0353669b426ff69e5365.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/nsterm.m | 100 |
1 files changed, 89 insertions, 11 deletions
diff --git a/src/nsterm.m b/src/nsterm.m index 627a61cac62..1919c6defaf 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -67,6 +67,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) | |||
| 67 | 67 | ||
| 68 | #ifdef NS_IMPL_COCOA | 68 | #ifdef NS_IMPL_COCOA |
| 69 | #include "macfont.h" | 69 | #include "macfont.h" |
| 70 | #include <Carbon/Carbon.h> | ||
| 70 | #endif | 71 | #endif |
| 71 | 72 | ||
| 72 | static EmacsMenu *dockMenu; | 73 | static EmacsMenu *dockMenu; |
| @@ -2679,7 +2680,78 @@ x_get_keysym_name (int keysym) | |||
| 2679 | return value; | 2680 | return value; |
| 2680 | } | 2681 | } |
| 2681 | 2682 | ||
| 2683 | #ifdef NS_IMPL_COCOA | ||
| 2684 | static UniChar | ||
| 2685 | ns_get_shifted_character (NSEvent *event) | ||
| 2686 | /* Look up the character corresponding to the key pressed on the | ||
| 2687 | current keyboard layout and the currently configured shift-like | ||
| 2688 | modifiers. This ignores the control-like modifiers that cause | ||
| 2689 | [event characters] to give us the wrong result. | ||
| 2690 | |||
| 2691 | Although UCKeyTranslate doesn't require the Carbon framework, some | ||
| 2692 | of the surrounding paraphernalia does, so this function makes | ||
| 2693 | Carbon a requirement. */ | ||
| 2694 | { | ||
| 2695 | static UInt32 dead_key_state; | ||
| 2696 | |||
| 2697 | /* UCKeyTranslate may return up to 255 characters. If the buffer | ||
| 2698 | isn't large enough then it produces an error. What kind of | ||
| 2699 | keyboard inputs 255 characters in a single keypress? */ | ||
| 2700 | UniChar buf[255]; | ||
| 2701 | UniCharCount max_string_length = 255; | ||
| 2702 | UniCharCount actual_string_length = 0; | ||
| 2703 | OSStatus result; | ||
| 2704 | |||
| 2705 | CFDataRef layout_ref = (CFDataRef) TISGetInputSourceProperty | ||
| 2706 | (TISCopyCurrentKeyboardLayoutInputSource (), kTISPropertyUnicodeKeyLayoutData); | ||
| 2707 | UCKeyboardLayout* layout = (UCKeyboardLayout*) CFDataGetBytePtr (layout_ref); | ||
| 2708 | |||
| 2709 | UInt32 flags = [event modifierFlags]; | ||
| 2710 | UInt32 modifiers = (flags & NSEventModifierFlagShift) ? shiftKey : 0; | ||
| 2711 | |||
| 2712 | NSTRACE ("ns_get_shifted_character"); | ||
| 2713 | |||
| 2714 | if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask | ||
| 2715 | && (EQ (ns_right_alternate_modifier, Qnone) | ||
| 2716 | || (EQ (ns_right_alternate_modifier, Qleft) | ||
| 2717 | && EQ (ns_alternate_modifier, Qnone)))) | ||
| 2718 | modifiers |= rightOptionKey; | ||
| 2719 | |||
| 2720 | if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask | ||
| 2721 | && EQ (ns_alternate_modifier, Qnone)) | ||
| 2722 | modifiers |= optionKey; | ||
| 2723 | |||
| 2724 | if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask | ||
| 2725 | && (EQ (ns_right_command_modifier, Qnone) | ||
| 2726 | || (EQ (ns_right_command_modifier, Qleft) | ||
| 2727 | && EQ (ns_command_modifier, Qnone)))) | ||
| 2728 | /* Carbon doesn't differentiate between left and right command | ||
| 2729 | keys. */ | ||
| 2730 | modifiers |= cmdKey; | ||
| 2731 | |||
| 2732 | if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask | ||
| 2733 | && EQ (ns_command_modifier, Qnone)) | ||
| 2734 | modifiers |= cmdKey; | ||
| 2735 | |||
| 2736 | result = UCKeyTranslate (layout, [event keyCode], kUCKeyActionDown, | ||
| 2737 | (modifiers >> 8) & 0xFF, LMGetKbdType (), | ||
| 2738 | kUCKeyTranslateNoDeadKeysBit, &dead_key_state, | ||
| 2739 | max_string_length, &actual_string_length, buf); | ||
| 2740 | |||
| 2741 | if (result != 0) | ||
| 2742 | { | ||
| 2743 | NSLog(@"Failed to translate character '%@' with modifiers %x", | ||
| 2744 | [event characters], modifiers); | ||
| 2745 | return 0; | ||
| 2746 | } | ||
| 2747 | |||
| 2748 | /* FIXME: What do we do if more than one code unit is returned? */ | ||
| 2749 | if (actual_string_length > 0) | ||
| 2750 | return buf[0]; | ||
| 2682 | 2751 | ||
| 2752 | return 0; | ||
| 2753 | } | ||
| 2754 | #endif /* NS_IMPL_COCOA */ | ||
| 2683 | 2755 | ||
| 2684 | /* ========================================================================== | 2756 | /* ========================================================================== |
| 2685 | 2757 | ||
| @@ -6148,8 +6220,6 @@ not_in_argv (NSString *arg) | |||
| 6148 | code = ([[theEvent charactersIgnoringModifiers] length] == 0) ? | 6220 | code = ([[theEvent charactersIgnoringModifiers] length] == 0) ? |
| 6149 | 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0]; | 6221 | 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0]; |
| 6150 | 6222 | ||
| 6151 | /* (Carbon way: [theEvent keyCode]) */ | ||
| 6152 | |||
| 6153 | /* is it a "function key"? */ | 6223 | /* is it a "function key"? */ |
| 6154 | /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad | 6224 | /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad |
| 6155 | flag set (this is probably a bug in the OS). | 6225 | flag set (this is probably a bug in the OS). |
| @@ -6191,8 +6261,8 @@ not_in_argv (NSString *arg) | |||
| 6191 | charactersIgnoringModifiers method). An annoyance happens if | 6261 | charactersIgnoringModifiers method). An annoyance happens if |
| 6192 | we have both shift-like and control-like modifiers because | 6262 | we have both shift-like and control-like modifiers because |
| 6193 | the NSEvent API doesn’t let us ignore only some modifiers. | 6263 | the NSEvent API doesn’t let us ignore only some modifiers. |
| 6194 | Therefore we ignore all shift-like modifiers in that | 6264 | In that case we use UCKeyTranslate (ns_get_shifted_character) |
| 6195 | case. */ | 6265 | to look up the correct character. */ |
| 6196 | 6266 | ||
| 6197 | /* EV_MODIFIERS2 uses parse_solitary_modifier on all known | 6267 | /* EV_MODIFIERS2 uses parse_solitary_modifier on all known |
| 6198 | modifier keys, which returns 0 for shift-like modifiers. | 6268 | modifier keys, which returns 0 for shift-like modifiers. |
| @@ -6218,7 +6288,6 @@ not_in_argv (NSString *arg) | |||
| 6218 | if (fnKeysym || (emacs_event->modifiers | 6288 | if (fnKeysym || (emacs_event->modifiers |
| 6219 | && (emacs_event->modifiers != shift_modifier) | 6289 | && (emacs_event->modifiers != shift_modifier) |
| 6220 | && [[theEvent charactersIgnoringModifiers] length] > 0)) | 6290 | && [[theEvent charactersIgnoringModifiers] length] > 0)) |
| 6221 | /*[[theEvent characters] length] */ | ||
| 6222 | { | 6291 | { |
| 6223 | emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; | 6292 | emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; |
| 6224 | /* FIXME: What are the next four lines supposed to do? */ | 6293 | /* FIXME: What are the next four lines supposed to do? */ |
| @@ -6227,12 +6296,21 @@ not_in_argv (NSString *arg) | |||
| 6227 | else if (code == 0x7f) | 6296 | else if (code == 0x7f) |
| 6228 | code |= (1<<28)|(3<<16); | 6297 | code |= (1<<28)|(3<<16); |
| 6229 | else if (!fnKeysym) | 6298 | else if (!fnKeysym) |
| 6230 | /* FIXME: This seems wrong, characters in the range | 6299 | { |
| 6231 | [0x80, 0xFF] are not ASCII characters. Can’t we just | 6300 | #ifdef NS_IMPL_COCOA |
| 6232 | use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds | 6301 | /* We potentially have both shift- and control-like |
| 6233 | of characters? */ | 6302 | modifiers in use, so find the correct character |
| 6234 | emacs_event->kind = code > 0xFF | 6303 | ignoring any control-like ones. */ |
| 6235 | ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; | 6304 | code = ns_get_shifted_character (theEvent); |
| 6305 | #endif | ||
| 6306 | |||
| 6307 | /* FIXME: This seems wrong, characters in the range | ||
| 6308 | [0x80, 0xFF] are not ASCII characters. Can’t we just | ||
| 6309 | use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds | ||
| 6310 | of characters? */ | ||
| 6311 | emacs_event->kind = code > 0xFF | ||
| 6312 | ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; | ||
| 6313 | } | ||
| 6236 | 6314 | ||
| 6237 | emacs_event->code = code; | 6315 | emacs_event->code = code; |
| 6238 | EV_TRAILER (theEvent); | 6316 | EV_TRAILER (theEvent); |