From 5f19be59b484c22f15be6d401a9c063bc96c3e91 Mon Sep 17 00:00:00 2001 From: Lukhnos Liu Date: Sun, 18 May 2014 20:41:53 -0700 Subject: [PATCH] Override keyboard layout correctly. Fixes #86. Using numerous NSLog's led to the discovery that when McBopofomo lost function (as described in #86), -setValue:forTag:client: was often called not just on the context of the foreground app, but also on the contexts of the background apps. This led to the theory that calling keyboard layout override in that method (not a documented way of doing things anyways) might corrupt the input method context. That we swapped out language model and the builder when the method got called didn't help. In this commit, we put back the keyboard layout override code to where it belongs -- in -activateServer: -- and we now only swap the language model and re-create the builder if the input method really changes (e.g. from Bopomofo to Plain Bopomofo, or vice versa). Similar defensive coding is also used in the function key handler in the -handleEvent:client: method. --- Source/InputMethodController.mm | 86 +++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/Source/InputMethodController.mm b/Source/InputMethodController.mm index bbccadb5..199cd044 100644 --- a/Source/InputMethodController.mm +++ b/Source/InputMethodController.mm @@ -251,6 +251,13 @@ public: { [[NSUserDefaults standardUserDefaults] synchronize]; + // Override the keyboard layout. Use US if not set. + NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; + if (!basisKeyboardLayoutID) { + basisKeyboardLayoutID = @"com.apple.keylayout.US"; + } + [client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; + // reset the state _currentDeferredClient = nil; _currentCandidateClient = nil; @@ -328,35 +335,46 @@ public: - (void)setValue:(id)value forTag:(long)tag client:(id)sender { + NSString *newInputMode; + Formosa::Gramambular::FastLM *newLanguageModel; + if ([value isKindOfClass:[NSString class]] && [value isEqual:kPlainBopomofoModeIdentifier]) { - _inputMode = kPlainBopomofoModeIdentifier; - _languageModel = &gLanguageModelPlainBopomofo; + newInputMode = kPlainBopomofoModeIdentifier; + newLanguageModel = &gLanguageModelPlainBopomofo; } else { - _inputMode = kBopomofoModeIdentifier; - _languageModel = &gLanguageModel; + newInputMode = kBopomofoModeIdentifier; + newLanguageModel = &gLanguageModel; } - NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; - if (!basisKeyboardLayoutID) { - basisKeyboardLayoutID = @"com.apple.keylayout.US"; - } + // Only apply the changes if the value is changed + if (![_inputMode isEqualToString:newInputMode]) { + [[NSUserDefaults standardUserDefaults] synchronize]; - [sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; + // Remember to override the keyboard layout again -- treat this as an activate eventy + NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; + if (!basisKeyboardLayoutID) { + basisKeyboardLayoutID = @"com.apple.keylayout.US"; + } + [sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; - if (!_bpmfReadingBuffer->isEmpty()) { - _bpmfReadingBuffer->clear(); - [self updateClientComposingBuffer:sender]; - } + _inputMode = newInputMode; + _languageModel = newLanguageModel; - if ([_composingBuffer length] > 0) { - [self commitComposition:sender]; - } + if (!_bpmfReadingBuffer->isEmpty()) { + _bpmfReadingBuffer->clear(); + [self updateClientComposingBuffer:sender]; + } - if (_builder) { - delete _builder; - _builder = new BlockReadingBuilder(_languageModel); - _builder->setJoinSeparator("-"); + if ([_composingBuffer length] > 0) { + [self commitComposition:sender]; + } + + if (_builder) { + delete _builder; + _builder = new BlockReadingBuilder(_languageModel); + _builder->setJoinSeparator("-"); + } } } @@ -1110,24 +1128,30 @@ public: - (BOOL)handleEvent:(NSEvent *)event client:(id)client { if ([event type] == NSFlagsChanged) { - // function key pressed - BOOL includeShift = [[NSUserDefaults standardUserDefaults] boolForKey:kFunctionKeyKeyboardLayoutOverrideIncludeShiftKey]; - if (([event modifierFlags] & ~NSShiftKeyMask) || (([event modifierFlags] & NSShiftKeyMask) && includeShift)) { - NSString *functionKeyKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kFunctionKeyKeyboardLayoutPreferenceKey]; - if (!functionKeyKeyboardLayoutID) { - functionKeyKeyboardLayoutID = @"com.apple.keylayout.US"; - } - - [client overrideKeyboardWithKeyboardNamed:functionKeyKeyboardLayoutID]; - return NO; + NSString *functionKeyKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kFunctionKeyKeyboardLayoutPreferenceKey]; + if (!functionKeyKeyboardLayoutID) { + functionKeyKeyboardLayoutID = @"com.apple.keylayout.US"; } - // reset when function key is released NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; if (!basisKeyboardLayoutID) { basisKeyboardLayoutID = @"com.apple.keylayout.US"; } + // If no override is needed, just return NO. + if ([functionKeyKeyboardLayoutID isEqualToString:basisKeyboardLayoutID]) { + return NO; + } + + // Function key pressed. + BOOL includeShift = [[NSUserDefaults standardUserDefaults] boolForKey:kFunctionKeyKeyboardLayoutOverrideIncludeShiftKey]; + if (([event modifierFlags] & ~NSShiftKeyMask) || (([event modifierFlags] & NSShiftKeyMask) && includeShift)) { + // Override the keyboard layout and let the OS do its thing + [client overrideKeyboardWithKeyboardNamed:functionKeyKeyboardLayoutID]; + return NO; + } + + // Revert back to the basis layout when the function key is released [client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; return NO; }