Skip to content

Commit

Permalink
prevent commit keystroke being hijacked & inline placeholder &fix ter…
Browse files Browse the repository at this point in the history
…minal non-inline
  • Loading branch information
groverlynn committed Feb 8, 2024
1 parent 7de3919 commit b357d5d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 39 deletions.
2 changes: 1 addition & 1 deletion SquirrelConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ typedef NSMutableDictionary<NSString *, NSNumber *> SquirrelMutableAppOptions;
- (BOOL)hasSection:(NSString *)section;

- (BOOL)getBool:(NSString *)option;
- (NSInteger)getInt:(NSString *)option;
- (int)getInt:(NSString *)option;
- (double)getDouble:(NSString *)option;
- (NSNumber *)getOptionalBool:(NSString *)option;
- (NSNumber *)getOptionalInt:(NSString *)option;
Expand Down
18 changes: 11 additions & 7 deletions SquirrelConfig.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ - (BOOL)getBool:(NSString *)option {
return [self getOptionalBool:option].boolValue;
}

- (NSInteger)getInt:(NSString *)option {
return [self getOptionalInt:option].integerValue;
- (int)getInt:(NSString *)option {
return [self getOptionalInt:option].intValue;
}

- (double)getDouble:(NSString *)option {
Expand All @@ -82,7 +82,7 @@ - (NSNumber *)getOptionalBool:(NSString *)option {
}
Bool value;
if (_isOpen && rime_get_api()->config_get_bool(&_config, option.UTF8String, &value)) {
return _cache[option] = @(!!value);
return _cache[option] = [NSNumber numberWithBool:(BOOL)value];
}
return [_baseConfig getOptionalBool:option];
}
Expand All @@ -94,7 +94,7 @@ - (NSNumber *)getOptionalInt:(NSString *)option {
}
int value;
if (_isOpen && rime_get_api()->config_get_int(&_config, option.UTF8String, &value)) {
return _cache[option] = @(value);
return _cache[option] = [NSNumber numberWithInt:value];
}
return [_baseConfig getOptionalInt:option];

Expand All @@ -107,7 +107,7 @@ - (NSNumber *)getOptionalDouble:(NSString *)option {
}
double value;
if (_isOpen && rime_get_api()->config_get_double(&_config, option.UTF8String, &value)) {
return _cache[option] = @(value);
return _cache[option] = [NSNumber numberWithDouble:value];
}
return [_baseConfig getOptionalDouble:option];
}
Expand Down Expand Up @@ -145,8 +145,12 @@ - (SquirrelAppOptions *)getAppOptions:(NSString *)appName {
rime_get_api()->config_begin_map(&iterator, &_config, rootKey.UTF8String);
while (rime_get_api()->config_next(&iterator)) {
//NSLog(@"DEBUG option[%d]: %s (%s)", iterator.index, iterator.key, iterator.path);
BOOL value = [self getBool:@(iterator.path)];
appOptions[@(iterator.key)] = @(value);
NSNumber *value = [self getOptionalBool:@(iterator.path)] ? :
[self getOptionalInt:@(iterator.path)] ? :
[self getOptionalDouble:@(iterator.path)];
if (value) {
appOptions[@(iterator.key)] = value;
}
}
rime_get_api()->config_end(&iterator);
return [appOptions copy];
Expand Down
111 changes: 80 additions & 31 deletions SquirrelInputController.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@interface SquirrelInputController(Private)
-(void)createSession;
-(void)destroySession;
-(void)rimeConsumeCommittedText;
-(BOOL)rimeConsumeCommittedText;
-(void)rimeUpdate;
-(void)updateAppOptions;
@end
Expand All @@ -29,6 +29,10 @@ @implementation SquirrelInputController {
NSString *_schemaId;
BOOL _inlinePreedit;
BOOL _inlineCandidate;
// app-specific bug fix
BOOL _inlinePlaceholder;
BOOL _panellessCommitFix;
int _inlineOffset;
// for chord-typing
int _chordKeyCodes[N_KEY_ROLL_OVER];
int _chordModifiers[N_KEY_ROLL_OVER];
Expand Down Expand Up @@ -150,8 +154,20 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender
modifiers & OSX_CAPITAL_MASK);
if (rime_keycode) {
int rime_modifiers = osx_modifiers_to_rime_modifiers(modifiers);
handled = [self processKey:rime_keycode modifiers:rime_modifiers];
[self rimeUpdate];
if ((handled = [self processKey:rime_keycode modifiers:rime_modifiers])) {
[self rimeUpdate];
} else if (_panellessCommitFix && [_currentClient markedRange].length > 0) {
if (rime_keycode == XK_Delete || (rime_keycode >= XK_Home && rime_keycode <= XK_KP_Delete) ||
(rime_keycode >= XK_BackSpace && rime_keycode <= XK_Escape)) {
[self showPlaceholder:@""];
} else if (!(modifiers & (NSEventModifierFlagControl | NSEventModifierFlagCommand)) &&
event.characters.length > 0) {
[self showPlaceholder:nil];
[_currentClient insertText:event.characters
replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
return YES;
}
}
}
} break;
default:
Expand Down Expand Up @@ -418,6 +434,17 @@ -(void)commitString:(NSString*)string
[NSApp.squirrelAppDelegate.panel hide];
}

-(void)showPlaceholder:(NSString*)placeholder
{
NSDictionary* attrs = [self markForStyle:kTSMHiliteSelectedRawText
atRange:NSMakeRange(0, placeholder ? placeholder.length : 1)];
NSAttributedString* attrString = [[NSAttributedString alloc] initWithString:placeholder ? : @""
attributes:attrs];
[_currentClient setMarkedText:attrString
selectionRange:NSMakeRange(0, 0)
replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
}

-(void)showPreeditString:(NSString*)preedit
selRange:(NSRange)range
caretPos:(NSUInteger)pos
Expand Down Expand Up @@ -464,6 +491,8 @@ -(void)showPanelWithPreedit:(NSString*)preedit
_candidates = candidates;
NSRect inputPos;
[_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&inputPos];
NSWidth(inputPos) > NSHeight(inputPos) ? (inputPos.origin.x += _inlineOffset)
: (inputPos.origin.y += _inlineOffset);
SquirrelPanel* panel = NSApp.squirrelAppDelegate.panel;
panel.position = inputPos;
panel.inputController = self;
Expand Down Expand Up @@ -504,10 +533,16 @@ -(void)updateAppOptions
SquirrelAppOptions* appOptions = [NSApp.squirrelAppDelegate.config getAppOptions:_currentApp];
if (appOptions) {
for (NSString* key in appOptions) {
BOOL value = appOptions[key].boolValue;
NSLog(@"set app option: %@ = %d", key, value);
rime_get_api()->set_option(_session, key.UTF8String, value);
NSNumber *number = appOptions[key];
if (!strcmp(number.objCType, @encode(BOOL))) {
Bool value = number.intValue;
//NSLog(@"set app option: %@ = %d", key, value);
rime_get_api()->set_option(_session, key.UTF8String, value);
}
}
_panellessCommitFix = appOptions[@"panelless_commit_fix"].boolValue;
_inlinePlaceholder = appOptions[@"inline_placeholder"].boolValue;
_inlineOffset = appOptions[@"inline_offset"].intValue;
}
}

Expand All @@ -521,14 +556,22 @@ -(void)destroySession
[self clearChord];
}

-(void)rimeConsumeCommittedText
-(BOOL)rimeConsumeCommittedText
{
RIME_STRUCT(RimeCommit, commit);
if (rime_get_api()->get_commit(_session, &commit)) {
NSString *commitText = @(commit.text);
[self commitString: commitText];
if (_panellessCommitFix) {
[self showPlaceholder:commitText];
[self commitString:commitText];
[self showPlaceholder:sizeof(commit.text) == 1 ? @"" : nil];
} else {
[self commitString:commitText];
}
rime_get_api()->free_commit(&commit);
return YES;
}
return NO;
}

NSString *substr(const char *str, int length) {
Expand All @@ -541,7 +584,7 @@ -(void)rimeConsumeCommittedText
-(void)rimeUpdate
{
//NSLog(@"rimeUpdate");
[self rimeConsumeCommittedText];
BOOL committedText = [self rimeConsumeCommittedText];

RIME_STRUCT(RimeStatus, status);
if (rime_get_api()->get_status(_session, &status)) {
Expand Down Expand Up @@ -570,32 +613,38 @@ -(void)rimeUpdate
NSUInteger start = substr(preedit, ctx.composition.sel_start).length;
NSUInteger end = substr(preedit, ctx.composition.sel_end).length;
NSUInteger caretPos = substr(preedit, ctx.composition.cursor_pos).length;
NSUInteger numCandidate = ctx.menu.num_candidates;
NSRange selRange = NSMakeRange(start, end - start);
if (_inlineCandidate) {
const char *candidatePreview = ctx.commit_text_preview;
NSString *candidatePreviewText = candidatePreview ? @(candidatePreview) : @"";
if (_inlinePreedit) {
if ((caretPos >= NSMaxRange(selRange)) && (caretPos < preeditText.length)) {
candidatePreviewText = [candidatePreviewText stringByAppendingString:[preeditText substringWithRange:NSMakeRange(caretPos, preeditText.length-caretPos)]];
if (!(_panellessCommitFix && committedText)) {
if (_inlineCandidate) {
const char *candidatePreview = ctx.commit_text_preview;
NSString *candidatePreviewText = candidatePreview ? @(candidatePreview) : @"";
if (_inlinePreedit) {
if ((caretPos >= NSMaxRange(selRange)) && (caretPos < preeditText.length)) {
candidatePreviewText = [candidatePreviewText stringByAppendingString:[preeditText substringWithRange:NSMakeRange(caretPos, preeditText.length-caretPos)]];
}
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length-(preeditText.length-caretPos)];
} else {
if ((NSMaxRange(selRange) < caretPos) && (caretPos > selRange.location)) {
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(caretPos-NSMaxRange(selRange)))];
} else if ((NSMaxRange(selRange) < preeditText.length) && (caretPos <= selRange.location)) {
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(preeditText.length-NSMaxRange(selRange)))];
}
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length];
}
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length-(preeditText.length-caretPos)];
} else {
if ((NSMaxRange(selRange) < caretPos) && (caretPos > selRange.location)) {
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(caretPos-NSMaxRange(selRange)))];
} else if ((NSMaxRange(selRange) < preeditText.length) && (caretPos <= selRange.location)) {
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(preeditText.length-NSMaxRange(selRange)))];
if (_inlinePreedit) {
_inlinePlaceholder && preeditText.length == 0 && numCandidate > 0
? [self showPlaceholder:@" "]
: [self showPreeditString:preeditText selRange:selRange caretPos:caretPos];
} else {
NSRange empty = {0, 0};
// TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
// note this is a full-shape space U+3000; using half shape characters like "..." will result in
// an unstable baseline when composing Chinese characters.
_inlinePlaceholder && preedit ? [self showPlaceholder:@" "]
: [self showPreeditString:@"" selRange:empty caretPos:0];
}
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length];
}
} else {
if (_inlinePreedit) {
[self showPreeditString:preeditText selRange:selRange caretPos:caretPos];
} else {
NSRange empty = {0, 0};
// TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
// note this is a full-shape space U+3000; using half shape characters like "..." will result in
// an unstable baseline when composing Chinese characters.
[self showPreeditString:(preedit ? @" " : @"") selRange:empty caretPos:0];
}
}
// update candidates
Expand Down
8 changes: 8 additions & 0 deletions data/squirrel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ app_options:
com.apple.Terminal:
ascii_mode: true
no_inline: true
inline_placeholder: true
com.googlecode.iterm2:
ascii_mode: true
no_inline: true
Expand All @@ -350,6 +351,7 @@ app_options:
vim_mode: true # 退出VIM插入模式自動切換輸入法狀態
com.apple.dt.Xcode:
ascii_mode: true
no_inline: true
com.barebones.textwrangler:
ascii_mode: true
com.macromates.TextMate.preview:
Expand All @@ -367,9 +369,15 @@ app_options:
no_inline: true
co.zeit.hyper:
ascii_mode: true
org.alacritty:
ascii_mode: true
vim_mode: true
panelless_commit_fix: true
inline_offset: -10
com.google.Chrome:
# 規避 https://github.com/rime/squirrel/issues/435
inline: true
inline_placeholder: true
ru.keepcoder.Telegram:
# 規避 https://github.com/rime/squirrel/issues/475
inline: true

0 comments on commit b357d5d

Please sign in to comment.