macOS: do not pass input events while having marked text

fix chinese input method backspacing issue

macOS: Set pre-edit text for IME

macOS: implement glfwPlatformUpdateIMEState

set firstRectForCharacterRange correctly

macOS: update IME position on each input

macOS: use float instead of int for updateIMEState

minor fix

macOS: ignore marked text on deadkey

fixes german keyboard input

macOS: convert markedRect to screen coord
This commit is contained in:
BlahGeek 2019-05-02 15:01:40 +08:00 committed by Kovid Goyal
parent eaba3cff0b
commit e36e44ab3a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 47 additions and 3 deletions

View File

@ -529,6 +529,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
_GLFWwindow* window; _GLFWwindow* window;
NSTrackingArea* trackingArea; NSTrackingArea* trackingArea;
NSMutableAttributedString* markedText; NSMutableAttributedString* markedText;
NSRect markedRect;
} }
- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
@ -545,6 +546,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
window = initWindow; window = initWindow;
trackingArea = nil; trackingArea = nil;
markedText = [[NSMutableAttributedString alloc] init]; markedText = [[NSMutableAttributedString alloc] init];
markedRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
[self updateTrackingAreas]; [self updateTrackingAreas];
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL]]; [self registerForDraggedTypes:@[NSPasteboardTypeFileURL]];
@ -815,6 +817,8 @@ is_ascii_control_char(char x) {
const int mods = translateFlags(flags); const int mods = translateFlags(flags);
const int key = translateKey(scancode, GLFW_TRUE); const int key = translateKey(scancode, GLFW_TRUE);
const GLFWbool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, scancode, flags) != 1; const GLFWbool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, scancode, flags) != 1;
const bool previous_has_marked_text = [self hasMarkedText];
[self unmarkText];
_glfw.ns.text[0] = 0; _glfw.ns.text[0] = 0;
if (!_glfw.ns.unicodeData) { if (!_glfw.ns.unicodeData) {
// Using the cocoa API for key handling is disabled, as there is no // Using the cocoa API for key handling is disabled, as there is no
@ -859,6 +863,20 @@ is_ascii_control_char(char x) {
if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes
debug_key(@"text: %s glfw_key: %s\n", debug_key(@"text: %s glfw_key: %s\n",
format_text(_glfw.ns.text), _glfwGetKeyName(key)); format_text(_glfw.ns.text), _glfwGetKeyName(key));
debug_key(@"marked text: %@", markedText);
if (!window->ns.deadKeyState) {
if ([self hasMarkedText]) {
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
[[markedText string] UTF8String], 1); // update pre-edit text
} else if (previous_has_marked_text) {
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
NULL, 1); // clear pre-edit text
}
if (([self hasMarkedText] || previous_has_marked_text) && !_glfw.ns.text[0]) {
// do not pass keys like BACKSPACE while there's pre-edit text, let IME handle it
return;
}
}
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, _glfw.ns.text, 0); _glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, _glfw.ns.text, 0);
} }
@ -997,6 +1015,28 @@ is_ascii_control_char(char x) {
[[markedText mutableString] setString:@""]; [[markedText mutableString] setString:@""];
} }
void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d) {
[w->ns.view updateIMEStateFor: which left:(CGFloat)a top:(CGFloat)b cellWidth:(CGFloat)c cellHeight:(CGFloat)d];
}
- (void)updateIMEStateFor:(int)which
left:(CGFloat)left
top:(CGFloat)top
cellWidth:(CGFloat)cellWidth
cellHeight:(CGFloat)cellHeight
{
left /= window->ns.xscale;
top /= window->ns.yscale;
cellWidth /= window->ns.xscale;
cellHeight /= window->ns.yscale;
debug_key(@"updateIMEState: %f, %f, %f, %f\n", left, top, cellWidth, cellHeight);
const NSRect frame = [window->ns.view frame];
const NSRect rectInView = NSMakeRect(left,
frame.size.height - top - cellHeight,
cellWidth, cellHeight);
markedRect = [window->ns.object convertRectToScreen: rectInView];
}
- (NSArray*)validAttributesForMarkedText - (NSArray*)validAttributesForMarkedText
{ {
return [NSArray array]; return [NSArray array];
@ -1016,8 +1056,7 @@ is_ascii_control_char(char x) {
- (NSRect)firstRectForCharacterRange:(NSRange)range - (NSRect)firstRectForCharacterRange:(NSRange)range
actualRange:(NSRangePointer)actualRange actualRange:(NSRangePointer)actualRange
{ {
const NSRect frame = [window->ns.view frame]; return markedRect;
return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0);
} }
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange - (void)insertText:(id)string replacementRange:(NSRange)replacementRange

2
glfw/input.c vendored
View File

@ -919,7 +919,7 @@ GLFWAPI void glfwUpdateIMEState(GLFWwindow* handle, int which, int a, int b, int
assert(window != NULL); assert(window != NULL);
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND) #if defined(_GLFW_X11) || defined(_GLFW_WAYLAND) || defined(_GLFW_COCOA)
_glfwPlatformUpdateIMEState(window, which, a, b, c, d); _glfwPlatformUpdateIMEState(window, which, a, b, c, d);
#else #else
(void)window; (void)which; (void)a; (void)b; (void)c; (void)d; (void)window; (void)which; (void)a; (void)b; (void)c; (void)d;

View File

@ -143,6 +143,11 @@ on_key_input(int key, int scancode, int action, int mods, const char* text, int
} else debug("committed pre-edit text: (null)\n"); } else debug("committed pre-edit text: (null)\n");
return; return;
case 0: case 0:
// for macOS, update ime position on every key input
// because the position is required before next input
#if defined(__APPLE__)
update_ime_position(global_state.callback_os_window, w, screen);
#endif
break; break;
default: default:
debug("invalid state, ignoring\n"); debug("invalid state, ignoring\n");