Skip to content

Commit b357d5d

Browse files
committed
prevent commit keystroke being hijacked & inline placeholder &fix terminal non-inline
1 parent 7de3919 commit b357d5d

4 files changed

Lines changed: 100 additions & 39 deletions

File tree

SquirrelConfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ typedef NSMutableDictionary<NSString *, NSNumber *> SquirrelMutableAppOptions;
1717
- (BOOL)hasSection:(NSString *)section;
1818

1919
- (BOOL)getBool:(NSString *)option;
20-
- (NSInteger)getInt:(NSString *)option;
20+
- (int)getInt:(NSString *)option;
2121
- (double)getDouble:(NSString *)option;
2222
- (NSNumber *)getOptionalBool:(NSString *)option;
2323
- (NSNumber *)getOptionalInt:(NSString *)option;

SquirrelConfig.m

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ - (BOOL)getBool:(NSString *)option {
6767
return [self getOptionalBool:option].boolValue;
6868
}
6969

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

7474
- (double)getDouble:(NSString *)option {
@@ -82,7 +82,7 @@ - (NSNumber *)getOptionalBool:(NSString *)option {
8282
}
8383
Bool value;
8484
if (_isOpen && rime_get_api()->config_get_bool(&_config, option.UTF8String, &value)) {
85-
return _cache[option] = @(!!value);
85+
return _cache[option] = [NSNumber numberWithBool:(BOOL)value];
8686
}
8787
return [_baseConfig getOptionalBool:option];
8888
}
@@ -94,7 +94,7 @@ - (NSNumber *)getOptionalInt:(NSString *)option {
9494
}
9595
int value;
9696
if (_isOpen && rime_get_api()->config_get_int(&_config, option.UTF8String, &value)) {
97-
return _cache[option] = @(value);
97+
return _cache[option] = [NSNumber numberWithInt:value];
9898
}
9999
return [_baseConfig getOptionalInt:option];
100100

@@ -107,7 +107,7 @@ - (NSNumber *)getOptionalDouble:(NSString *)option {
107107
}
108108
double value;
109109
if (_isOpen && rime_get_api()->config_get_double(&_config, option.UTF8String, &value)) {
110-
return _cache[option] = @(value);
110+
return _cache[option] = [NSNumber numberWithDouble:value];
111111
}
112112
return [_baseConfig getOptionalDouble:option];
113113
}
@@ -145,8 +145,12 @@ - (SquirrelAppOptions *)getAppOptions:(NSString *)appName {
145145
rime_get_api()->config_begin_map(&iterator, &_config, rootKey.UTF8String);
146146
while (rime_get_api()->config_next(&iterator)) {
147147
//NSLog(@"DEBUG option[%d]: %s (%s)", iterator.index, iterator.key, iterator.path);
148-
BOOL value = [self getBool:@(iterator.path)];
149-
appOptions[@(iterator.key)] = @(value);
148+
NSNumber *value = [self getOptionalBool:@(iterator.path)] ? :
149+
[self getOptionalInt:@(iterator.path)] ? :
150+
[self getOptionalDouble:@(iterator.path)];
151+
if (value) {
152+
appOptions[@(iterator.key)] = value;
153+
}
150154
}
151155
rime_get_api()->config_end(&iterator);
152156
return [appOptions copy];

SquirrelInputController.m

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
@interface SquirrelInputController(Private)
1111
-(void)createSession;
1212
-(void)destroySession;
13-
-(void)rimeConsumeCommittedText;
13+
-(BOOL)rimeConsumeCommittedText;
1414
-(void)rimeUpdate;
1515
-(void)updateAppOptions;
1616
@end
@@ -29,6 +29,10 @@ @implementation SquirrelInputController {
2929
NSString *_schemaId;
3030
BOOL _inlinePreedit;
3131
BOOL _inlineCandidate;
32+
// app-specific bug fix
33+
BOOL _inlinePlaceholder;
34+
BOOL _panellessCommitFix;
35+
int _inlineOffset;
3236
// for chord-typing
3337
int _chordKeyCodes[N_KEY_ROLL_OVER];
3438
int _chordModifiers[N_KEY_ROLL_OVER];
@@ -150,8 +154,20 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender
150154
modifiers & OSX_CAPITAL_MASK);
151155
if (rime_keycode) {
152156
int rime_modifiers = osx_modifiers_to_rime_modifiers(modifiers);
153-
handled = [self processKey:rime_keycode modifiers:rime_modifiers];
154-
[self rimeUpdate];
157+
if ((handled = [self processKey:rime_keycode modifiers:rime_modifiers])) {
158+
[self rimeUpdate];
159+
} else if (_panellessCommitFix && [_currentClient markedRange].length > 0) {
160+
if (rime_keycode == XK_Delete || (rime_keycode >= XK_Home && rime_keycode <= XK_KP_Delete) ||
161+
(rime_keycode >= XK_BackSpace && rime_keycode <= XK_Escape)) {
162+
[self showPlaceholder:@""];
163+
} else if (!(modifiers & (NSEventModifierFlagControl | NSEventModifierFlagCommand)) &&
164+
event.characters.length > 0) {
165+
[self showPlaceholder:nil];
166+
[_currentClient insertText:event.characters
167+
replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
168+
return YES;
169+
}
170+
}
155171
}
156172
} break;
157173
default:
@@ -418,6 +434,17 @@ -(void)commitString:(NSString*)string
418434
[NSApp.squirrelAppDelegate.panel hide];
419435
}
420436

437+
-(void)showPlaceholder:(NSString*)placeholder
438+
{
439+
NSDictionary* attrs = [self markForStyle:kTSMHiliteSelectedRawText
440+
atRange:NSMakeRange(0, placeholder ? placeholder.length : 1)];
441+
NSAttributedString* attrString = [[NSAttributedString alloc] initWithString:placeholder ? : @""
442+
attributes:attrs];
443+
[_currentClient setMarkedText:attrString
444+
selectionRange:NSMakeRange(0, 0)
445+
replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
446+
}
447+
421448
-(void)showPreeditString:(NSString*)preedit
422449
selRange:(NSRange)range
423450
caretPos:(NSUInteger)pos
@@ -464,6 +491,8 @@ -(void)showPanelWithPreedit:(NSString*)preedit
464491
_candidates = candidates;
465492
NSRect inputPos;
466493
[_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&inputPos];
494+
NSWidth(inputPos) > NSHeight(inputPos) ? (inputPos.origin.x += _inlineOffset)
495+
: (inputPos.origin.y += _inlineOffset);
467496
SquirrelPanel* panel = NSApp.squirrelAppDelegate.panel;
468497
panel.position = inputPos;
469498
panel.inputController = self;
@@ -504,10 +533,16 @@ -(void)updateAppOptions
504533
SquirrelAppOptions* appOptions = [NSApp.squirrelAppDelegate.config getAppOptions:_currentApp];
505534
if (appOptions) {
506535
for (NSString* key in appOptions) {
507-
BOOL value = appOptions[key].boolValue;
508-
NSLog(@"set app option: %@ = %d", key, value);
509-
rime_get_api()->set_option(_session, key.UTF8String, value);
536+
NSNumber *number = appOptions[key];
537+
if (!strcmp(number.objCType, @encode(BOOL))) {
538+
Bool value = number.intValue;
539+
//NSLog(@"set app option: %@ = %d", key, value);
540+
rime_get_api()->set_option(_session, key.UTF8String, value);
541+
}
510542
}
543+
_panellessCommitFix = appOptions[@"panelless_commit_fix"].boolValue;
544+
_inlinePlaceholder = appOptions[@"inline_placeholder"].boolValue;
545+
_inlineOffset = appOptions[@"inline_offset"].intValue;
511546
}
512547
}
513548

@@ -521,14 +556,22 @@ -(void)destroySession
521556
[self clearChord];
522557
}
523558

524-
-(void)rimeConsumeCommittedText
559+
-(BOOL)rimeConsumeCommittedText
525560
{
526561
RIME_STRUCT(RimeCommit, commit);
527562
if (rime_get_api()->get_commit(_session, &commit)) {
528563
NSString *commitText = @(commit.text);
529-
[self commitString: commitText];
564+
if (_panellessCommitFix) {
565+
[self showPlaceholder:commitText];
566+
[self commitString:commitText];
567+
[self showPlaceholder:sizeof(commit.text) == 1 ? @"" : nil];
568+
} else {
569+
[self commitString:commitText];
570+
}
530571
rime_get_api()->free_commit(&commit);
572+
return YES;
531573
}
574+
return NO;
532575
}
533576

534577
NSString *substr(const char *str, int length) {
@@ -541,7 +584,7 @@ -(void)rimeConsumeCommittedText
541584
-(void)rimeUpdate
542585
{
543586
//NSLog(@"rimeUpdate");
544-
[self rimeConsumeCommittedText];
587+
BOOL committedText = [self rimeConsumeCommittedText];
545588

546589
RIME_STRUCT(RimeStatus, status);
547590
if (rime_get_api()->get_status(_session, &status)) {
@@ -570,32 +613,38 @@ -(void)rimeUpdate
570613
NSUInteger start = substr(preedit, ctx.composition.sel_start).length;
571614
NSUInteger end = substr(preedit, ctx.composition.sel_end).length;
572615
NSUInteger caretPos = substr(preedit, ctx.composition.cursor_pos).length;
616+
NSUInteger numCandidate = ctx.menu.num_candidates;
573617
NSRange selRange = NSMakeRange(start, end - start);
574-
if (_inlineCandidate) {
575-
const char *candidatePreview = ctx.commit_text_preview;
576-
NSString *candidatePreviewText = candidatePreview ? @(candidatePreview) : @"";
577-
if (_inlinePreedit) {
578-
if ((caretPos >= NSMaxRange(selRange)) && (caretPos < preeditText.length)) {
579-
candidatePreviewText = [candidatePreviewText stringByAppendingString:[preeditText substringWithRange:NSMakeRange(caretPos, preeditText.length-caretPos)]];
618+
if (!(_panellessCommitFix && committedText)) {
619+
if (_inlineCandidate) {
620+
const char *candidatePreview = ctx.commit_text_preview;
621+
NSString *candidatePreviewText = candidatePreview ? @(candidatePreview) : @"";
622+
if (_inlinePreedit) {
623+
if ((caretPos >= NSMaxRange(selRange)) && (caretPos < preeditText.length)) {
624+
candidatePreviewText = [candidatePreviewText stringByAppendingString:[preeditText substringWithRange:NSMakeRange(caretPos, preeditText.length-caretPos)]];
625+
}
626+
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length-(preeditText.length-caretPos)];
627+
} else {
628+
if ((NSMaxRange(selRange) < caretPos) && (caretPos > selRange.location)) {
629+
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(caretPos-NSMaxRange(selRange)))];
630+
} else if ((NSMaxRange(selRange) < preeditText.length) && (caretPos <= selRange.location)) {
631+
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(preeditText.length-NSMaxRange(selRange)))];
632+
}
633+
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length];
580634
}
581-
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length-(preeditText.length-caretPos)];
582635
} else {
583-
if ((NSMaxRange(selRange) < caretPos) && (caretPos > selRange.location)) {
584-
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(caretPos-NSMaxRange(selRange)))];
585-
} else if ((NSMaxRange(selRange) < preeditText.length) && (caretPos <= selRange.location)) {
586-
candidatePreviewText = [candidatePreviewText substringWithRange:NSMakeRange(0, candidatePreviewText.length-(preeditText.length-NSMaxRange(selRange)))];
636+
if (_inlinePreedit) {
637+
_inlinePlaceholder && preeditText.length == 0 && numCandidate > 0
638+
? [self showPlaceholder:@" "]
639+
: [self showPreeditString:preeditText selRange:selRange caretPos:caretPos];
640+
} else {
641+
NSRange empty = {0, 0};
642+
// TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
643+
// note this is a full-shape space U+3000; using half shape characters like "..." will result in
644+
// an unstable baseline when composing Chinese characters.
645+
_inlinePlaceholder && preedit ? [self showPlaceholder:@" "]
646+
: [self showPreeditString:@"" selRange:empty caretPos:0];
587647
}
588-
[self showPreeditString:candidatePreviewText selRange:NSMakeRange(selRange.location, candidatePreviewText.length-selRange.location) caretPos:candidatePreviewText.length];
589-
}
590-
} else {
591-
if (_inlinePreedit) {
592-
[self showPreeditString:preeditText selRange:selRange caretPos:caretPos];
593-
} else {
594-
NSRange empty = {0, 0};
595-
// TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
596-
// note this is a full-shape space U+3000; using half shape characters like "..." will result in
597-
// an unstable baseline when composing Chinese characters.
598-
[self showPreeditString:(preedit ? @" " : @"") selRange:empty caretPos:0];
599648
}
600649
}
601650
// update candidates

data/squirrel.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ app_options:
341341
com.apple.Terminal:
342342
ascii_mode: true
343343
no_inline: true
344+
inline_placeholder: true
344345
com.googlecode.iterm2:
345346
ascii_mode: true
346347
no_inline: true
@@ -350,6 +351,7 @@ app_options:
350351
vim_mode: true # 退出VIM插入模式自動切換輸入法狀態
351352
com.apple.dt.Xcode:
352353
ascii_mode: true
354+
no_inline: true
353355
com.barebones.textwrangler:
354356
ascii_mode: true
355357
com.macromates.TextMate.preview:
@@ -367,9 +369,15 @@ app_options:
367369
no_inline: true
368370
co.zeit.hyper:
369371
ascii_mode: true
372+
org.alacritty:
373+
ascii_mode: true
374+
vim_mode: true
375+
panelless_commit_fix: true
376+
inline_offset: -10
370377
com.google.Chrome:
371378
# 規避 https://github.com/rime/squirrel/issues/435
372379
inline: true
380+
inline_placeholder: true
373381
ru.keepcoder.Telegram:
374382
# 規避 https://github.com/rime/squirrel/issues/475
375383
inline: true

0 commit comments

Comments
 (0)