A new approach to handling flagsChanged with IME
Bypass cocoa's flagsChanged handling and call handleevent ourselves, this allows us to know exactly what the IME is doing. Hopefully fixes issues with IMEs that change state on modifier key presses. Fixes #4541
This commit is contained in:
parent
0a3acd9738
commit
e8c683db8b
@ -800,12 +800,26 @@ int _glfwPlatformInit(void)
|
|||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NSEvent* (^flags_changed_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||||
|
{
|
||||||
|
debug_key("-------------- flags changed -----------------\n");
|
||||||
|
debug_key("%s\n", [[event description] UTF8String]);
|
||||||
|
last_keydown_shortcut_event.virtual_key_code = 0xffff;
|
||||||
|
NSWindow *kw = [NSApp keyWindow];
|
||||||
|
if (kw && kw.contentView) [kw.contentView flagsChanged:event];
|
||||||
|
else debug_key("flagsChanged ignored as no keyWindow present\n");
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
_glfw.ns.keyUpMonitor =
|
_glfw.ns.keyUpMonitor =
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
|
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
|
||||||
handler:keyup_block];
|
handler:keyup_block];
|
||||||
_glfw.ns.keyDownMonitor =
|
_glfw.ns.keyDownMonitor =
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
|
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
|
||||||
handler:keydown_block];
|
handler:keydown_block];
|
||||||
|
_glfw.ns.flagsChangedMonitor =
|
||||||
|
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFlagsChanged
|
||||||
|
handler:flags_changed_block];
|
||||||
|
|
||||||
if (_glfw.hints.init.ns.chdir)
|
if (_glfw.hints.init.ns.chdir)
|
||||||
changeToResourcesDirectory();
|
changeToResourcesDirectory();
|
||||||
@ -890,6 +904,8 @@ void _glfwPlatformTerminate(void)
|
|||||||
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
||||||
if (_glfw.ns.keyDownMonitor)
|
if (_glfw.ns.keyDownMonitor)
|
||||||
[NSEvent removeMonitor:_glfw.ns.keyDownMonitor];
|
[NSEvent removeMonitor:_glfw.ns.keyDownMonitor];
|
||||||
|
if (_glfw.ns.flagsChangedMonitor)
|
||||||
|
[NSEvent removeMonitor:_glfw.ns.flagsChangedMonitor];
|
||||||
|
|
||||||
if (_glfw.ns.appleSettings != nil) {
|
if (_glfw.ns.appleSettings != nil) {
|
||||||
[_glfw.ns.appleSettings release];
|
[_glfw.ns.appleSettings release];
|
||||||
|
|||||||
3
glfw/cocoa_platform.h
vendored
3
glfw/cocoa_platform.h
vendored
@ -174,8 +174,7 @@ typedef struct _GLFWlibraryNS
|
|||||||
IOHIDManagerRef hidManager;
|
IOHIDManagerRef hidManager;
|
||||||
id unicodeData;
|
id unicodeData;
|
||||||
id helper;
|
id helper;
|
||||||
id keyUpMonitor;
|
id keyUpMonitor, keyDownMonitor, flagsChangedMonitor;
|
||||||
id keyDownMonitor;
|
|
||||||
id appleSettings;
|
id appleSettings;
|
||||||
id nibObjects;
|
id nibObjects;
|
||||||
|
|
||||||
|
|||||||
@ -752,7 +752,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
NSMutableAttributedString* markedText;
|
NSMutableAttributedString* markedText;
|
||||||
NSRect markedRect;
|
NSRect markedRect;
|
||||||
bool marked_text_cleared_by_insert;
|
bool marked_text_cleared_by_insert;
|
||||||
bool in_key_down;
|
|
||||||
NSString *input_source_at_last_key_event;
|
NSString *input_source_at_last_key_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1151,14 +1150,12 @@ is_ascii_control_char(char x) {
|
|||||||
debug_key("\x1b[31mPress:\x1b[m native_key: 0x%x (%s) glfw_key: 0x%x %schar_count: %lu deadKeyState: %u repeat: %d ",
|
debug_key("\x1b[31mPress:\x1b[m native_key: 0x%x (%s) glfw_key: 0x%x %schar_count: %lu deadKeyState: %u repeat: %d ",
|
||||||
keycode, safe_name_for_keycode(keycode), key, format_mods(mods), char_count, window->ns.deadKeyState, event.ARepeat);
|
keycode, safe_name_for_keycode(keycode), key, format_mods(mods), char_count, window->ns.deadKeyState, event.ARepeat);
|
||||||
marked_text_cleared_by_insert = false;
|
marked_text_cleared_by_insert = false;
|
||||||
in_key_down = true;
|
|
||||||
if (process_text) {
|
if (process_text) {
|
||||||
// this will call insertText which will fill up _glfw.ns.text
|
// this will call insertText which will fill up _glfw.ns.text
|
||||||
[self interpretKeyEvents:@[event]];
|
[self interpretKeyEvents:@[event]];
|
||||||
} else {
|
} else {
|
||||||
window->ns.deadKeyState = 0;
|
window->ns.deadKeyState = 0;
|
||||||
}
|
}
|
||||||
in_key_down = false;
|
|
||||||
if (window->ns.deadKeyState && (char_count == 0 || keycode == 0x75)) {
|
if (window->ns.deadKeyState && (char_count == 0 || keycode == 0x75)) {
|
||||||
// 0x75 is the delete key which needs to be ignored during a compose sequence
|
// 0x75 is the delete key which needs to be ignored during a compose sequence
|
||||||
debug_key("Sending pre-edit text for dead key (text: %s markedText: %s).\n", format_text(_glfw.ns.text), glfw_keyevent.text);
|
debug_key("Sending pre-edit text for dead key (text: %s markedText: %s).\n", format_text(_glfw.ns.text), glfw_keyevent.text);
|
||||||
@ -1201,16 +1198,19 @@ is_ascii_control_char(char x) {
|
|||||||
// insertText followed by setMarkedText
|
// insertText followed by setMarkedText
|
||||||
UPDATE_PRE_EDIT_TEXT;
|
UPDATE_PRE_EDIT_TEXT;
|
||||||
}
|
}
|
||||||
#undef CLEAR_PRE_EDIT_TEXT
|
|
||||||
#undef UPDATE_PRE_EDIT_TEXT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)flagsChanged:(NSEvent *)event
|
- (void)flagsChanged:(NSEvent *)event
|
||||||
{
|
{
|
||||||
int action = GLFW_RELEASE;
|
int action = GLFW_RELEASE;
|
||||||
const unsigned int modifierFlags =
|
const char old_first_char = _glfw.ns.text[0];
|
||||||
[event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
_glfw.ns.text[0] = 0;
|
||||||
|
const NSUInteger modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||||
const uint32_t key = vk_code_to_functional_key_code([event keyCode]);
|
const uint32_t key = vk_code_to_functional_key_code([event keyCode]);
|
||||||
|
const unsigned int keycode = [event keyCode];
|
||||||
|
const int mods = translateFlags(modifierFlags);
|
||||||
|
const bool process_text = !_glfw.ignoreOSKeyboardProcessing && (!window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, keycode, modifierFlags) != 1);
|
||||||
|
|
||||||
switch(key) {
|
switch(key) {
|
||||||
case GLFW_FKEY_CAPS_LOCK:
|
case GLFW_FKEY_CAPS_LOCK:
|
||||||
action = modifierFlags & NSEventModifierFlagCapsLock ? GLFW_PRESS : GLFW_RELEASE; break;
|
action = modifierFlags & NSEventModifierFlagCapsLock ? GLFW_PRESS : GLFW_RELEASE; break;
|
||||||
@ -1229,7 +1229,17 @@ is_ascii_control_char(char x) {
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = [event keyCode], .native_key_id = [event keyCode], .action = action, .mods = translateFlags(modifierFlags)};
|
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = keycode, .native_key_id = keycode, .action = action, .mods = mods};
|
||||||
|
marked_text_cleared_by_insert = false;
|
||||||
|
NSTextInputContext *inpctx = [NSTextInputContext currentInputContext];
|
||||||
|
if (process_text && inpctx) {
|
||||||
|
// this will call insertText which will fill up _glfw.ns.text
|
||||||
|
[inpctx handleEvent:event];
|
||||||
|
if (marked_text_cleared_by_insert) { CLEAR_PRE_EDIT_TEXT; }
|
||||||
|
if (_glfw.ns.text[0]) glfw_keyevent.text = _glfw.ns.text;
|
||||||
|
else _glfw.ns.text[0] = old_first_char;
|
||||||
|
}
|
||||||
|
glfw_keyevent.ime_state = GLFW_IME_NONE;
|
||||||
_glfwInputKeyboard(window, &glfw_keyevent);
|
_glfwInputKeyboard(window, &glfw_keyevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1246,6 +1256,9 @@ is_ascii_control_char(char x) {
|
|||||||
_glfwInputKeyboard(window, &glfw_keyevent);
|
_glfwInputKeyboard(window, &glfw_keyevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef CLEAR_PRE_EDIT_TEXT
|
||||||
|
#undef UPDATE_PRE_EDIT_TEXT
|
||||||
|
|
||||||
- (void)scrollWheel:(NSEvent *)event
|
- (void)scrollWheel:(NSEvent *)event
|
||||||
{
|
{
|
||||||
double deltaX = [event scrollingDeltaX];
|
double deltaX = [event scrollingDeltaX];
|
||||||
@ -1423,11 +1436,6 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
|
|||||||
char *s = _glfw.ns.text + strnlen(_glfw.ns.text, sizeof(_glfw.ns.text));
|
char *s = _glfw.ns.text + strnlen(_glfw.ns.text, sizeof(_glfw.ns.text));
|
||||||
snprintf(s, sizeof(_glfw.ns.text) - (s - _glfw.ns.text), "%s", utf8);
|
snprintf(s, sizeof(_glfw.ns.text) - (s - _glfw.ns.text), "%s", utf8);
|
||||||
_glfw.ns.text[sizeof(_glfw.ns.text) - 1] = 0;
|
_glfw.ns.text[sizeof(_glfw.ns.text) - 1] = 0;
|
||||||
if (!in_key_down && !strlen(utf8)) {
|
|
||||||
// is called by cocoa when a modifier is pressed, for example shift
|
|
||||||
GLFWkeyevent dummy = {.action = GLFW_RELEASE, .ime_state = GLFW_IME_PREEDIT_CHANGED};
|
|
||||||
_glfwInputKeyboard(window, &dummy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)doCommandBySelector:(SEL)selector
|
- (void)doCommandBySelector:(SEL)selector
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user