Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into extension
Browse files Browse the repository at this point in the history
  • Loading branch information
groverlynn committed Apr 4, 2024
2 parents 45697d0 + cc0aea0 commit 27d9b02
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 53 deletions.
182 changes: 148 additions & 34 deletions input_source.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#import <Carbon/Carbon.h>

static const char kInstallLocation[] = "/Library/Input Methods/Squirrel.app";
static const char kInstallPath[] = "/Library/Input Methods/Squirrel.app";

static const CFStringRef kHansInputModeID =
CFSTR("im.rime.inputmethod.Squirrel.Hans");
Expand All @@ -16,44 +16,156 @@ typedef NS_OPTIONS(int, RimeInputMode) {
CANT_INPUT_MODE = 1 << 2
};

RimeInputMode GetEnabledInputModes(void);

void RegisterInputSource(void) {
CFURLRef installedLocationURL = CFURLCreateFromFileSystemRepresentation(
NULL, (UInt8*)kInstallLocation, (CFIndex)strlen(kInstallLocation), false);
if (installedLocationURL) {
TISRegisterInputSource((CFURLRef)CFAutorelease(installedLocationURL));
NSLog(@"Registered input source from %s", kInstallLocation);
if (GetEnabledInputModes()) { // Already registered
return;
}
CFURLRef installPathURL = CFURLCreateFromFileSystemRepresentation(
NULL, (UInt8*)kInstallPath, (CFIndex)strlen(kInstallPath), false);
if (installPathURL) {
TISRegisterInputSource((CFURLRef)CFAutorelease(installPathURL));
NSLog(@"Registered input source from %s", kInstallPath);
}
}

void EnableInputSource(void) {
RimeInputMode input_modes_enabled = GetEnabledInputModes();
if (input_modes_enabled != 0) {
// keep user's manually enabled input modes
return;
}
RimeInputMode input_modes_to_enable = 0;
CFArrayRef localizations = CFArrayCreate(
NULL, (CFTypeRef[]){CFSTR("zh-Hans"), CFSTR("zh-Hant"), CFSTR("zh-HK")},
3, &kCFTypeArrayCallBacks);
CFArrayRef preferred =
CFBundleCopyLocalizationsForPreferences(localizations, NULL);
if (CFArrayGetCount(preferred) > 0) {
CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(preferred, 0);
if (!CFStringCompare(language, CFSTR("zh-Hans"), 0)) {
input_modes_to_enable |= HANS_INPUT_MODE;
} else if (!CFStringCompare(language, CFSTR("zh-Hant"), 0)) {
input_modes_to_enable |= HANT_INPUT_MODE;
} else if (!CFStringCompare(language, CFSTR("zh-HK"), 0)) {
input_modes_to_enable |= CANT_INPUT_MODE;
}
} else {
input_modes_to_enable = HANS_INPUT_MODE;
}
CFRelease(preferred);
CFDictionaryRef property = CFDictionaryCreate(
NULL, (CFTypeRef[]){kTISPropertyBundleID},
(CFTypeRef[]){CFBundleGetIdentifier(CFBundleGetMainBundle())}, 1,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFArrayRef sourceList = TISCreateInputSourceList(property, true);
for (CFIndex i = 0; i < CFArrayGetCount(sourceList); ++i) {
TISInputSourceRef inputSource =
(TISInputSourceRef)CFArrayGetValueAtIndex(sourceList, i);
CFStringRef sourceID = (CFStringRef)TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceID);
// NSLog(@"Examining input source: %@", sourceID);
if ((!CFStringCompare(sourceID, kHansInputModeID, 0) &&
(input_modes_to_enable & HANS_INPUT_MODE)) ||
(!CFStringCompare(sourceID, kHantInputModeID, 0) &&
(input_modes_to_enable & HANT_INPUT_MODE)) ||
(!CFStringCompare(sourceID, kCantInputModeID, 0) &&
(input_modes_to_enable & CANT_INPUT_MODE))) {
CFBooleanRef isEnabled = (CFBooleanRef)TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceIsEnabled);
if (!CFBooleanGetValue(isEnabled)) {
OSStatus enableError = TISEnableInputSource(inputSource);
if (enableError) {
NSLog(@"Failed to enable input source: %@ (%@)", sourceID,
[NSError errorWithDomain:NSOSStatusErrorDomain
code:enableError
userInfo:nil]);
} else {
NSLog(@"Enabled input source: %@", sourceID);
}
}
}
}
CFRelease(sourceList);
}

void ActivateInputSource(RimeInputMode modes) {
CFArrayRef sourceList = TISCreateInputSourceList(NULL, true);
void SelectInputSource(void) {
RimeInputMode enabled_input_modes = GetEnabledInputModes();
RimeInputMode input_mode_to_select = 0;
CFArrayRef localizations = CFArrayCreate(
NULL, (CFTypeRef[]){CFSTR("zh-Hans"), CFSTR("zh-Hant"), CFSTR("zh-HK")},
3, &kCFTypeArrayCallBacks);
CFArrayRef preferred =
CFBundleCopyLocalizationsForPreferences(localizations, NULL);
for (CFIndex i = 0; i < CFArrayGetCount(preferred); ++i) {
CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(preferred, i);
if (!CFStringCompare(language, CFSTR("zh-Hans"), 0) &&
(enabled_input_modes & HANS_INPUT_MODE)) {
input_mode_to_select = HANS_INPUT_MODE;
break;
}
if (!CFStringCompare(language, CFSTR("zh-Hant"), 0) &&
(enabled_input_modes & HANT_INPUT_MODE)) {
input_mode_to_select = HANT_INPUT_MODE;
break;
}
if (!CFStringCompare(language, CFSTR("zh-HK"), 0) &&
(enabled_input_modes & CANT_INPUT_MODE)) {
input_mode_to_select = CANT_INPUT_MODE;
break;
}
}
CFRelease(preferred);
if (input_mode_to_select == 0) {
NSLog(@"No enabled input sources.");
return;
}
CFDictionaryRef property = CFDictionaryCreate(
NULL, (CFTypeRef[]){kTISPropertyBundleID},
(CFTypeRef[]){CFBundleGetIdentifier(CFBundleGetMainBundle())}, 1,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFArrayRef sourceList = TISCreateInputSourceList(property, false);
for (CFIndex i = 0; i < CFArrayGetCount(sourceList); ++i) {
TISInputSourceRef inputSource =
(TISInputSourceRef)CFArrayGetValueAtIndex(sourceList, i);
CFStringRef sourceID = (CFStringRef)TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceID);
// NSLog(@"Examining input source: %@", sourceID);
if ((!CFStringCompare(sourceID, kHansInputModeID, 0) &&
(modes & HANS_INPUT_MODE)) ||
((input_mode_to_select & HANS_INPUT_MODE) != 0)) ||
(!CFStringCompare(sourceID, kHantInputModeID, 0) &&
(modes & HANT_INPUT_MODE)) ||
((input_mode_to_select & HANT_INPUT_MODE) != 0)) ||
(!CFStringCompare(sourceID, kCantInputModeID, 0) &&
(modes & CANT_INPUT_MODE))) {
TISEnableInputSource(inputSource);
NSLog(@"Enabled input source: %@", sourceID);
((input_mode_to_select & CANT_INPUT_MODE) != 0))) {
// select the first enabled input mode in Squirrel.
CFBooleanRef isSelectable = (CFBooleanRef)TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceIsSelectCapable);
if (CFBooleanGetValue(isSelectable)) {
TISSelectInputSource(inputSource);
NSLog(@"Selected input source: %@", sourceID);
CFBooleanRef isSelected = (CFBooleanRef)TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceIsSelected);
if (!CFBooleanGetValue(isSelected) && CFBooleanGetValue(isSelectable)) {
OSStatus selectError = TISSelectInputSource(inputSource);
if (selectError) {
NSLog(@"Failed to select input source: %@ (%@)", sourceID,
[NSError errorWithDomain:NSOSStatusErrorDomain
code:selectError
userInfo:nil]);
} else {
NSLog(@"Selected input source: %@", sourceID);
break;
}
}
}
}
CFRelease(sourceList);
}

void DeactivateInputSource(void) {
CFArrayRef sourceList = TISCreateInputSourceList(NULL, true);
void DisableInputSource(void) {
CFDictionaryRef property = CFDictionaryCreate(
NULL, (CFTypeRef[]){kTISPropertyBundleID},
(CFTypeRef[]){CFBundleGetIdentifier(CFBundleGetMainBundle())}, 1,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFArrayRef sourceList = TISCreateInputSourceList(property, false);
for (CFIndex i = CFArrayGetCount(sourceList); i > 0; --i) {
TISInputSourceRef inputSource =
(TISInputSourceRef)CFArrayGetValueAtIndex(sourceList, i - 1);
Expand All @@ -63,10 +175,13 @@ void DeactivateInputSource(void) {
if (!CFStringCompare(sourceID, kHansInputModeID, 0) ||
!CFStringCompare(sourceID, kHantInputModeID, 0) ||
!CFStringCompare(sourceID, kCantInputModeID, 0)) {
CFBooleanRef isEnabled = (CFBooleanRef)TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceIsEnabled);
if (CFBooleanGetValue(isEnabled)) {
TISDisableInputSource(inputSource);
OSStatus disableError = TISDisableInputSource(inputSource);
if (disableError) {
NSLog(@"Failed to disable input source: %@ (%@)", sourceID,
[NSError errorWithDomain:NSOSStatusErrorDomain
code:disableError
userInfo:nil]);
} else {
NSLog(@"Disabled input source: %@", sourceID);
}
}
Expand All @@ -76,7 +191,11 @@ void DeactivateInputSource(void) {

RimeInputMode GetEnabledInputModes(void) {
RimeInputMode input_modes = 0;
CFArrayRef sourceList = TISCreateInputSourceList(NULL, true);
CFDictionaryRef property = CFDictionaryCreate(
NULL, (CFTypeRef[]){kTISPropertyBundleID},
(CFTypeRef[]){CFBundleGetIdentifier(CFBundleGetMainBundle())}, 1,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFArrayRef sourceList = TISCreateInputSourceList(property, false);
for (CFIndex i = 0; i < CFArrayGetCount(sourceList); ++i) {
TISInputSourceRef inputSource =
(TISInputSourceRef)CFArrayGetValueAtIndex(sourceList, i);
Expand All @@ -86,20 +205,15 @@ RimeInputMode GetEnabledInputModes(void) {
if (!CFStringCompare(sourceID, kHansInputModeID, 0) ||
!CFStringCompare(sourceID, kHantInputModeID, 0) ||
!CFStringCompare(sourceID, kCantInputModeID, 0)) {
CFBooleanRef isEnabled = (CFBooleanRef)TISGetInputSourceProperty(
inputSource, kTISPropertyInputSourceIsEnabled);
if (CFBooleanGetValue(isEnabled)) {
if (!CFStringCompare(sourceID, kHansInputModeID, 0)) {
input_modes |= HANS_INPUT_MODE;
} else if (!CFStringCompare(sourceID, kHantInputModeID, 0)) {
input_modes |= HANT_INPUT_MODE;
} else if (!CFStringCompare(sourceID, kCantInputModeID, 0)) {
input_modes |= CANT_INPUT_MODE;
}
if (!CFStringCompare(sourceID, kHansInputModeID, 0)) {
input_modes |= HANS_INPUT_MODE;
} else if (!CFStringCompare(sourceID, kHantInputModeID, 0)) {
input_modes |= HANT_INPUT_MODE;
} else if (!CFStringCompare(sourceID, kCantInputModeID, 0)) {
input_modes |= CANT_INPUT_MODE;
}
}
}
CFRelease(sourceList);
NSLog(@"EnabledInputModes: %d", input_modes);
return input_modes;
}
36 changes: 21 additions & 15 deletions main.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@
#import <Cocoa/Cocoa.h>
#import <InputMethodKit/InputMethodKit.h>
#import <rime_api.h>

typedef NS_OPTIONS(int, RimeInputMode) {
DEFAULT_INPUT_MODE = 1 << 0,
HANS_INPUT_MODE = 1 << 0,
HANT_INPUT_MODE = 1 << 1,
CANT_INPUT_MODE = 1 << 2
};
#import <string.h>

void RegisterInputSource(void);
RimeInputMode GetEnabledInputModes(void);
void DeactivateInputSource(void);
void ActivateInputSource(RimeInputMode modes);
void DisableInputSource(void);
void EnableInputSource(void);
void SelectInputSource(void);

// Each input method needs a unique connection name.
// Note that periods and spaces are not allowed in the connection name.
Expand All @@ -38,12 +32,24 @@ int main(int argc, char* argv[]) {
return 0;
}

if (argc > 1 && !strcmp("--install", argv[1])) {
// register and enable Squirrel
if (argc > 1 && (!strcmp("--register-input-source", argv[1]) ||
!strcmp("--install", argv[1]))) {
RegisterInputSource();
RimeInputMode input_modes = GetEnabledInputModes();
DeactivateInputSource();
ActivateInputSource(input_modes ?: DEFAULT_INPUT_MODE);
return 0;
}

if (argc > 1 && !strcmp("--enable-input-source", argv[1])) {
EnableInputSource();
return 0;
}

if (argc > 1 && !strcmp("--disable-input-source", argv[1])) {
DisableInputSource();
return 0;
}

if (argc > 1 && !strcmp("--select-input-source", argv[1])) {
SelectInputSource();
return 0;
}

Expand Down
12 changes: 8 additions & 4 deletions scripts/postinstall
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
#!/bin/bash
set -e

login_user=`/usr/bin/stat -f%Su /dev/console`
squirrel_app_root="${DSTROOT}/Squirrel.app"
squirrel_executable="${squirrel_app_root}/Contents/MacOS/Squirrel"
rime_package_installer="${squirrel_app_root}/Contents/MacOS/rime-install"
rime_shared_data_path="${squirrel_app_root}/Contents/SharedSupport"

/usr/bin/sudo -u "${login_user}" /usr/bin/killall Squirrel > /dev/null
/usr/bin/sudo -u "${login_user}" /usr/bin/killall Squirrel > /dev/null || true

"${squirrel_executable}" --register-input-source

if [ -z "${RIME_NO_PREBUILD}" ]; then
pushd "${rime_shared_data_path}" > /dev/null
"${squirrel_executable}" --build
popd > /dev/null
fi

/usr/bin/sudo -u "${login_user}" "${squirrel_executable}" --install
fi && (
/usr/bin/sudo -u "${login_user}" "${squirrel_executable}" --enable-input-source
/usr/bin/sudo -u "${login_user}" "${squirrel_executable}" --select-input-source
)

0 comments on commit 27d9b02

Please sign in to comment.