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.
This commit is contained in:
Lukhnos Liu 2014-05-18 20:41:53 -07:00
parent 3640c9f55f
commit 5f19be59b4
1 changed files with 55 additions and 31 deletions

View File

@ -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;
}