diff --git a/.gitignore b/.gitignore
index 910b488..e290077 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,4 @@ util/releases.json
.vscode/
node_modules/
*.dmg
+*.pkg
diff --git a/README.md b/README.md
index 3830fac..cbc243b 100644
--- a/README.md
+++ b/README.md
@@ -17,15 +17,13 @@
# 下载与安装
-1. 下载编译好的输入法应用(注意:不要点击 "Clone or download",要从下面的链接下载 dmg 文件或者 zip 压缩包)
+1. 下载编译好的输入法应用(注意:不要点击 "Clone or download",要从下面的链接下载 pkg 文件或者 zip 压缩包)
- macOS 10.12 ~ 10.14 下载 **最新版** : https://github.com/dongyuwei/hallelujahIM/releases/latest
- macOS 10.9 ~ 10.11 老版本: https://github.com/dongyuwei/hallelujahIM/releases/tag/v1.1.1
-2. 打开 dmg 文件,安装 hallelujah.app 到`/Library/Input Methods/` 目录内。
-3. 通过 `System Preferences` --> `Input Sources` --> 点击 `+` --> 选中 `English` --> 选中 `hallelujah`
- ![setup](https://github.com/dongyuwei/NumberInput_IMKit_Sample/blob/master/object-c/hallelujahIM/snapshots/setup.png?raw=true)
-4. 切换到 hallelujah 输入法即可使用,如果不能正常使用,建议退出当前用户重新登录或者重启系统,毕竟输入法是比较特殊的程序。
+2. 打开下载后的 hallelujah .pkg 文件,会自动安装、注册、激活哈利路亚输入法。
+3. 如果输入法不能正常使用,建议退出当前用户重新登录或者重启系统,毕竟输入法是比较特殊的程序。
注意:因为本程序不是通过 App store 发布的,Macos 会有下面的安全警告。选中 `/Library/Input Methods/hallelujah.app`,右键点击 `Open` 来打开输入法,即可正常使用。
@@ -102,9 +100,9 @@ pinyin in, English out:
`sh dev.sh`
-## build dmg
+## 构建安装包 pkg
-`sh build-dmg.sh`
+`bash package/build-package.bash`
## 开源协议
@@ -131,6 +129,7 @@ make
4. [GCDWebServer](https://github.com/swisspol/GCDWebServer),用于用户使用偏好配置。
5. [talisman](https://github.com/Yomguithereal/talisman),使用其中的 phonex 算法,实现模糊近似音输入。
6. [MDCDamerauLevenshtein](https://github.com/modocache/MDCDamerauLevenshtein),配合 talisman 的 phonex 算法,在音似词中按 Damerau Levenshtein 编辑距离筛选最接近的候选词。
+7. [鼠鬚管 squirrel 输入法](https://github.com/rime/squirrel) 哈利路亚输入法安装包 pkg 的制作 copy/参考了 squirrel 的实现。
## 问题反馈,意见和建议
diff --git a/dev.sh b/dev.sh
index 0ec4d40..131823b 100644
--- a/dev.sh
+++ b/dev.sh
@@ -5,4 +5,6 @@ mkdir -p ${HOME}/.hallelujah/debug
xcodebuild -workspace hallelujah.xcworkspace/ -scheme hallelujah -configuration Release CONFIGURATION_BUILD_DIR=${HOME}/.hallelujah/debug
pkill -9 hallelujah
sudo rm -rf /Library/Input\ Methods/hallelujah.app/
-sudo cp -R ${HOME}/.hallelujah/debug/hallelujah.app /Library/Input\ Methods/hallelujah.app
\ No newline at end of file
+sudo cp -R ${HOME}/.hallelujah/debug/hallelujah.app /Library/Input\ Methods/hallelujah.app
+sudo /Library/Input\ Methods/hallelujah.app/Contents/MacOS/hallelujah --install
+echo "hallelujah IME is installed and activated. Wait a moment to use it..."
\ No newline at end of file
diff --git a/package/PackageInfo b/package/PackageInfo
new file mode 100644
index 0000000..93be899
--- /dev/null
+++ b/package/PackageInfo
@@ -0,0 +1,3 @@
+
+
+
diff --git a/package/build-package.bash b/package/build-package.bash
new file mode 100755
index 0000000..6c5ac25
--- /dev/null
+++ b/package/build-package.bash
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+cd "$(dirname $0)"
+PROJECT_ROOT=$(cd ..; pwd)
+
+Version=`date "+%Y%m%d%H%M%S"`
+
+cd ${PROJECT_ROOT}
+sh build.sh
+cd -
+
+rm /tmp/hallelujah-*.pkg
+rm -rf /tmp/hallelujah/build/release/root/
+mkdir -p /tmp/hallelujah/build/release/root
+cp -R /tmp/hallelujah/build/release/hallelujah.app /tmp/hallelujah/build/release/root/
+
+
+pkgbuild \
+ --info "${PROJECT_ROOT}/package/PackageInfo" \
+ --root "/tmp/hallelujah/build/release/root" \
+ --identifier "github.dongyuwei.inputmethod.hallelujahInputMethod" \
+ --version ${Version} \
+ --install-location "/Library/Input Methods" \
+ --scripts "${PROJECT_ROOT}/package/scripts" \
+ /tmp/hallelujah-${Version}.pkg
diff --git a/package/scripts/postinstall b/package/scripts/postinstall
new file mode 100755
index 0000000..e51a246
--- /dev/null
+++ b/package/scripts/postinstall
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+pkill -9 hallelujah
+
+login_user=`/usr/bin/stat -f%Su /dev/console`
+
+/usr/bin/sudo -u "${login_user}" "/Library/Input Methods/hallelujah.app/Contents/MacOS/hallelujah" --install
+
+echo "hallelujah input method registered and activated successfully" > /tmp/hallelujah-postinstall
diff --git a/src/main.mm b/src/main.mm
index f682c3f..065fdc7 100644
--- a/src/main.mm
+++ b/src/main.mm
@@ -14,6 +14,50 @@
NSDictionary *phonexEncoded;
NSUserDefaults *preference;
+static const unsigned char kInstallLocation[] = "/Library/Input Methods/hallelujah.app";
+static NSString *const kSourceID = @"github.dongyuwei.inputmethod.hallelujahInputMethod";
+
+void registerInputSource() {
+ CFURLRef installedLocationURL =
+ CFURLCreateFromFileSystemRepresentation(NULL, kInstallLocation, strlen((const char *)kInstallLocation), NO);
+ if (installedLocationURL) {
+ TISRegisterInputSource(installedLocationURL);
+ CFRelease(installedLocationURL);
+ NSLog(@"Registered input source from %s", kInstallLocation);
+ }
+}
+
+void activateInputSource() {
+ CFArrayRef sourceList = TISCreateInputSourceList(NULL, true);
+ for (int i = 0; i < CFArrayGetCount(sourceList); ++i) {
+ TISInputSourceRef inputSource = (TISInputSourceRef)(CFArrayGetValueAtIndex(sourceList, i));
+ NSString *sourceID = (__bridge NSString *)(TISGetInputSourceProperty(inputSource, kTISPropertyInputSourceID));
+ if ([sourceID isEqualToString:kSourceID]) {
+ TISEnableInputSource(inputSource);
+ NSLog(@"Enabled input source: %@", sourceID);
+ CFBooleanRef isSelectable = (CFBooleanRef)TISGetInputSourceProperty(inputSource, kTISPropertyInputSourceIsSelectCapable);
+ if (CFBooleanGetValue(isSelectable)) {
+ TISSelectInputSource(inputSource);
+ NSLog(@"Selected input source: %@", sourceID);
+ }
+ }
+ }
+ CFRelease(sourceList);
+}
+
+void deactivateInputSource() {
+ CFArrayRef sourceList = TISCreateInputSourceList(NULL, true);
+ for (int i = (int)CFArrayGetCount(sourceList); i > 0; --i) {
+ TISInputSourceRef inputSource = (TISInputSourceRef)(CFArrayGetValueAtIndex(sourceList, i - 1));
+ NSString *sourceID = (__bridge NSString *)(TISGetInputSourceProperty(inputSource, kTISPropertyInputSourceID));
+ if ([sourceID isEqualToString:kSourceID]) {
+ TISDisableInputSource(inputSource);
+ NSLog(@"Disabled input source: %@", sourceID);
+ }
+ }
+ CFRelease(sourceList);
+}
+
NSDictionary *deserializeJSON(NSString *path) {
NSInputStream *inputStream = [[NSInputStream alloc] initWithFileAtPath:path];
[inputStream open];
@@ -50,6 +94,13 @@ void loadTrie() {
}
int main(int argc, char *argv[]) {
+ if (argc > 1 && !strcmp("--install", argv[1])) {
+ registerInputSource();
+ deactivateInputSource();
+ activateInputSource();
+ return 0;
+ }
+
NSString *identifier = [[NSBundle mainBundle] bundleIdentifier];
server = [[IMKServer alloc] initWithName:(NSString *)kConnectionName bundleIdentifier:identifier];