Merge pull request #29464 from bruvzg/macos_fix_non_ime_unicode_input

[macOS] Fixes unicode input with IME input mode inactive.
This commit is contained in:
Rémi Verschelde 2019-06-04 18:49:53 +02:00 committed by GitHub
commit d0dc42f80c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 42 deletions

View File

@ -29,7 +29,7 @@
Key scancode, one of the [enum KeyList] constants. Key scancode, one of the [enum KeyList] constants.
</member> </member>
<member name="unicode" type="int" setter="set_unicode" getter="get_unicode"> <member name="unicode" type="int" setter="set_unicode" getter="get_unicode">
Key unicode identifier when relevant. Key unicode identifier when relevant. Unicode identifiers for the composite characters and complex scripts may not be available unless IME input mode is active. See [method OS.set_ime_active] for more information.
</member> </member>
</members> </members>
<constants> <constants>

View File

@ -221,14 +221,16 @@
<return type="Vector2"> <return type="Vector2">
</return> </return>
<description> <description>
Returns IME selection range. Returns IME cursor position (currently edited portion of the string) relative to the characters in the composition string.
[code]NOTIFICATION_OS_IME_UPDATE[/code] is sent to the application to notify it of changes to the IME cursor position.
</description> </description>
</method> </method>
<method name="get_ime_text" qualifiers="const"> <method name="get_ime_text" qualifiers="const">
<return type="String"> <return type="String">
</return> </return>
<description> <description>
Returns IME intermediate text. Returns IME intermediate composition string.
[code]NOTIFICATION_OS_IME_UPDATE[/code] is sent to the application to notify it of changes to the IME composition string.
</description> </description>
</method> </method>
<method name="get_latin_keyboard_variant" qualifiers="const"> <method name="get_latin_keyboard_variant" qualifiers="const">
@ -710,6 +712,9 @@
</argument> </argument>
<description> <description>
Sets whether IME input mode should be enabled. Sets whether IME input mode should be enabled.
If active IME handles key events before the application and creates an composition string and suggestion list.
Application can retrieve the composition status by using [method get_ime_selection] and [method get_ime_text] functions.
Completed composition string is committed when input is finished.
</description> </description>
</method> </method>
<method name="set_ime_position"> <method name="set_ime_position">

View File

@ -60,6 +60,7 @@ public:
unsigned int osx_state; unsigned int osx_state;
bool pressed; bool pressed;
bool echo; bool echo;
bool raw;
uint32_t scancode; uint32_t scancode;
uint32_t unicode; uint32_t unicode;
}; };

View File

@ -392,7 +392,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
@interface GodotContentView : NSView <NSTextInputClient> { @interface GodotContentView : NSView <NSTextInputClient> {
NSTrackingArea *trackingArea; NSTrackingArea *trackingArea;
NSMutableAttributedString *markedText; NSMutableAttributedString *markedText;
bool imeMode; bool imeInputEventInProgress;
} }
- (void)cancelComposition; - (void)cancelComposition;
- (BOOL)wantsUpdateLayer; - (BOOL)wantsUpdateLayer;
@ -418,7 +418,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
- (id)init { - (id)init {
self = [super init]; self = [super init];
trackingArea = nil; trackingArea = nil;
imeMode = false; imeInputEventInProgress = false;
[self updateTrackingAreas]; [self updateTrackingAreas];
[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]]; [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
markedText = [[NSMutableAttributedString alloc] init]; markedText = [[NSMutableAttributedString alloc] init];
@ -452,7 +452,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
[markedText initWithString:aString]; [markedText initWithString:aString];
} }
if (OS_OSX::singleton->im_active) { if (OS_OSX::singleton->im_active) {
imeMode = true; imeInputEventInProgress = true;
OS_OSX::singleton->im_text.parse_utf8([[markedText mutableString] UTF8String]); OS_OSX::singleton->im_text.parse_utf8([[markedText mutableString] UTF8String]);
OS_OSX::singleton->im_selection = Point2(selectedRange.location, selectedRange.length); OS_OSX::singleton->im_selection = Point2(selectedRange.location, selectedRange.length);
@ -467,7 +467,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
} }
- (void)unmarkText { - (void)unmarkText {
imeMode = false; imeInputEventInProgress = false;
[[markedText mutableString] setString:@""]; [[markedText mutableString] setString:@""];
if (OS_OSX::singleton->im_active) { if (OS_OSX::singleton->im_active) {
OS_OSX::singleton->im_text = String(); OS_OSX::singleton->im_text = String();
@ -540,6 +540,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
ke.osx_state = [event modifierFlags]; ke.osx_state = [event modifierFlags];
ke.pressed = true; ke.pressed = true;
ke.echo = false; ke.echo = false;
ke.raw = false; // IME input event
ke.scancode = 0; ke.scancode = 0;
ke.unicode = codepoint; ke.unicode = codepoint;
@ -1045,29 +1046,52 @@ static int remapKey(unsigned int key) {
- (void)keyDown:(NSEvent *)event { - (void)keyDown:(NSEvent *)event {
//disable raw input in IME mode // Ignore all input if IME input is in progress
if (!imeMode) { if (!imeInputEventInProgress) {
OS_OSX::KeyEvent ke; NSString *characters = [event characters];
NSUInteger length = [characters length];
ke.osx_state = [event modifierFlags]; if (!OS_OSX::singleton->im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode]))) {
ke.pressed = true; // Fallback unicode character handler used if IME is not active
ke.echo = [event isARepeat]; for (NSUInteger i = 0; i < length; i++) {
ke.scancode = remapKey([event keyCode]); OS_OSX::KeyEvent ke;
ke.unicode = 0;
push_to_key_event_buffer(ke); ke.osx_state = [event modifierFlags];
ke.pressed = true;
ke.echo = [event isARepeat];
ke.scancode = remapKey([event keyCode]);
ke.raw = true;
ke.unicode = [characters characterAtIndex:i];
push_to_key_event_buffer(ke);
}
} else {
OS_OSX::KeyEvent ke;
ke.osx_state = [event modifierFlags];
ke.pressed = true;
ke.echo = [event isARepeat];
ke.scancode = remapKey([event keyCode]);
ke.raw = false;
ke.unicode = 0;
push_to_key_event_buffer(ke);
}
} }
if (OS_OSX::singleton->im_active == true) // Pass events to IME handler
if (OS_OSX::singleton->im_active)
[self interpretKeyEvents:[NSArray arrayWithObject:event]]; [self interpretKeyEvents:[NSArray arrayWithObject:event]];
} }
- (void)flagsChanged:(NSEvent *)event { - (void)flagsChanged:(NSEvent *)event {
if (!imeMode) { // Ignore all input if IME input is in progress
if (!imeInputEventInProgress) {
OS_OSX::KeyEvent ke; OS_OSX::KeyEvent ke;
ke.echo = false; ke.echo = false;
ke.raw = true;
int key = [event keyCode]; int key = [event keyCode];
int mod = [event modifierFlags]; int mod = [event modifierFlags];
@ -1114,17 +1138,37 @@ static int remapKey(unsigned int key) {
- (void)keyUp:(NSEvent *)event { - (void)keyUp:(NSEvent *)event {
if (!imeMode) { // Ignore all input if IME input is in progress
if (!imeInputEventInProgress) {
NSString *characters = [event characters];
NSUInteger length = [characters length];
OS_OSX::KeyEvent ke; // Fallback unicode character handler used if IME is not active
if (!OS_OSX::singleton->im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode]))) {
for (NSUInteger i = 0; i < length; i++) {
OS_OSX::KeyEvent ke;
ke.osx_state = [event modifierFlags]; ke.osx_state = [event modifierFlags];
ke.pressed = false; ke.pressed = false;
ke.echo = false; ke.echo = [event isARepeat];
ke.scancode = remapKey([event keyCode]); ke.scancode = remapKey([event keyCode]);
ke.unicode = 0; ke.raw = true;
ke.unicode = [characters characterAtIndex:i];
push_to_key_event_buffer(ke); push_to_key_event_buffer(ke);
}
} else {
OS_OSX::KeyEvent ke;
ke.osx_state = [event modifierFlags];
ke.pressed = false;
ke.echo = [event isARepeat];
ke.scancode = remapKey([event keyCode]);
ke.raw = true;
ke.unicode = 0;
push_to_key_event_buffer(ke);
}
} }
} }
@ -2612,30 +2656,44 @@ void OS_OSX::process_key_events() {
const KeyEvent &ke = key_event_buffer[i]; const KeyEvent &ke = key_event_buffer[i];
if ((i == 0 && ke.scancode == 0) || (i > 0 && key_event_buffer[i - 1].scancode == 0)) { if (ke.raw) {
k.instance(); // Non IME input - no composite characters, pass events as is
get_key_modifier_state(ke.osx_state, k);
k->set_pressed(ke.pressed);
k->set_echo(ke.echo);
k->set_scancode(0);
k->set_unicode(ke.unicode);
push_input(k);
}
if (ke.scancode != 0) {
k.instance(); k.instance();
get_key_modifier_state(ke.osx_state, k); get_key_modifier_state(ke.osx_state, k);
k->set_pressed(ke.pressed); k->set_pressed(ke.pressed);
k->set_echo(ke.echo); k->set_echo(ke.echo);
k->set_scancode(ke.scancode); k->set_scancode(ke.scancode);
k->set_unicode(ke.unicode);
if (i + 1 < key_event_pos && key_event_buffer[i + 1].scancode == 0) {
k->set_unicode(key_event_buffer[i + 1].unicode);
}
push_input(k); push_input(k);
} else {
// IME input
if ((i == 0 && ke.scancode == 0) || (i > 0 && key_event_buffer[i - 1].scancode == 0)) {
k.instance();
get_key_modifier_state(ke.osx_state, k);
k->set_pressed(ke.pressed);
k->set_echo(ke.echo);
k->set_scancode(0);
k->set_unicode(ke.unicode);
push_input(k);
}
if (ke.scancode != 0) {
k.instance();
get_key_modifier_state(ke.osx_state, k);
k->set_pressed(ke.pressed);
k->set_echo(ke.echo);
k->set_scancode(ke.scancode);
if (i + 1 < key_event_pos && key_event_buffer[i + 1].scancode == 0) {
k->set_unicode(key_event_buffer[i + 1].unicode);
}
push_input(k);
}
} }
} }