macOS 用の絵文字入力専用メソッド(IME)。 InputMethodKit フレームワークを使用し、キーワード入力で絵文字を検索・入力する。IME 切り替えで絵文字入力モードに移行する設計。
- IME を切り替えるだけで絵文字入力モードに移行、キーワードを入力すると即座に候補を表示
- ローマ字入力で日本語と英語の両方から絵文字を検索(例:
smile→ 😀😊、neko→ 🐱🐈) - SQLite3 ベースの絵文字データベース(CLDR データ利用、約 3,700 絵文字)
- 使用頻度による学習機能(候補の並び順に反映)、メニューから学習データのリセットが可能
- メニューバーにアイコンを表示(ダーク/ライトモード自動対応)
- メニュー・ダイアログの多言語対応(日本語/英語)
- macOS 14.0 以降
- Xcode 15.4 以降
- Swift 5.0 / C++17 以降
| キー | 状態 | 動作 |
|---|---|---|
英字 / - / _ |
待機中 | 絵文字検索を開始、候補を逐次表示 |
英字 / - / _ |
検索中 | 検索キーワードに追加、候補を逐次更新 |
| Enter(候補あり) | 検索中 | 先頭候補を確定 |
| Space / Tab / ↓ | 検索中 | 候補選択モードに遷移 |
| Escape | 検索中 | 検索をキャンセル |
| Delete | 検索中 | バッファ末尾を削除(空になったらキャンセル) |
| ↓ / Space / Tab | 候補選択中 | 次の候補へ移動 |
| ↑ / Shift+Space / Shift+Tab | 候補選択中 | 前の候補へ移動 |
| Enter | 候補選択中 | 選択中の候補を確定(使用回数を記録) |
| Escape | 候補選択中 | 検索モードに戻る |
| Delete | 候補選択中 | 検索モードに戻り末尾を削除 |
| マウスクリック | 候補選択中 | 候補を直接選択・確定 |
| Command+Enter | 検索中/候補選択中 | 検索をキャンセル |
英語キーワード:
smile → 😀😊😄 等の候補を表示
heart → ❤️💜💙 等の候補を表示
cat → 🐱🐈 等の候補を表示
日本語キーワード(ローマ字入力で日本語の絵文字名も検索):
neko → 🐱🐈 等
egao → 😀😃😄 等
sakura → 🌸
sakana → 🐟🐠🐡 等
hana → 💐🌸🌹 等
inu → 🐶🐕🐩 等
kuruma → 🚗🚕🚙 等
ongaku → 🎵🎶🎤 等
taiyou → 🌞🌅 等
densha → 🚃🚄🚅 等
絵文字データベース(emoji.db)とメニューバーアイコン(emoji_icon.tiff)はリポジトリに含まれているため、クローン後すぐにビルド・インストールできる。
./install.shCLDR データを更新したい場合や、対応ロケールを変更したい場合は build_db.sh で再生成できる。
./build_db.sh # デフォルト(ja en ロケール)
./build_db.sh --locales ja en zh # ロケールを指定build_db.sh は初回実行時に data/cldr-json/(約 1GB)と data/emoji-test.txt を自動取得する。これらの元データは .gitignore で除外されている。
swift tools/generate_icon.swift emojiIME/emoji_icon.tiffビルド → インストール → プロセス再起動を一括実行するシェルスクリプト。
./install.sh # Debug ビルド(デフォルト)
./install.sh Release # Release ビルド処理内容:
xcodebuildでビルドrm -rf→cp -Rで~/Library/Input Methods/にインストールlsregister -f+TISRegisterInputSourceで入力ソースキャッシュを更新pkillでプロセス再起動(macOS が自動的に再起動)
cd emojiIME
xcodebuild -project emojiIME.xcodeproj -scheme emojiIME -configuration Debug buildXcode の場合: emojiIME.xcodeproj を開き、Product → Build(⌘B)
ビルド成果物は build/Build/Products/Debug/emojiIME.app に生成される。
# 旧バージョンを削除(Info.plist を確実に更新するため rm -rf が必要)
rm -rf ~/Library/Input\ Methods/emojiIME.app
# ビルド成果物をコピー
cp -R build/Build/Products/Debug/emojiIME.app ~/Library/Input\ Methods/インストール後、ログアウト → ログイン(または再起動)を行い、以下の手順で入力ソースを追加する。
- システム設定 → キーボード → 入力ソース → 編集...
- 左下の + ボタン
- その他 カテゴリから emojiIME を選択して追加
IME プロセスは macOS によって自動管理されている。コード変更を反映するには、プロセスを終了して再起動させる必要がある。
pkill -f emojiIMEmacOS が自動的にプロセスを再起動する。
- アクティビティモニタを開く
emojiIMEを検索- プロセスを選択して ×(強制終了)ボタン
確実にすべてのキャッシュをクリアしたい場合は、ログアウト→ログインを行う。Info.plist の変更(入力ソースカテゴリ変更等)を反映する場合はこの方法が必要。
cp -Rだけでは既存の.appバンドル内の Info.plist が正しく上書きされない場合がある。アップデート時は必ずrm -rf→cp -Rの順で行う- LaunchServices の登録情報は
lsregisterで更新できるが、入力ソースの表示名・カテゴリの変更はログアウト/ログインが必要な場合がある
emojiIME/
├── emojiIME.xcodeproj/
│ └── project.pbxproj
├── emojiIME/
│ ├── AppDelegate.swift # アプリエントリポイント、IMKServer 起動
│ ├── EmojiInputController.swift # IMKInputController サブクラス(イベント処理・絵文字検索)
│ ├── RomajiConverter.swift # C++ 実装の Swift ラッパー(二段検索用)
│ ├── RomajiConverter.cpp # ローマ字→ひらがな変換エンジン(C++ 実装)
│ ├── RomajiConverter.h # C 言語インターフェース(extern "C")
│ ├── EmojiDB.cpp # 絵文字 DB C++ 実装(EmojiDBImpl, ATTACH パターン)
│ ├── EmojiDB.h # 絵文字 DB extern "C" インターフェース
│ ├── EmojiDB.swift # 絵文字 DB Swift ラッパー
│ ├── emoji.db # 絵文字データベース(CLDR データ、ビルド時バンドル)
│ ├── emoji_icon.tiff # メニューバーアイコン(SF Symbols から生成したテンプレートイメージ)
│ ├── emojiIME-Bridging-Header.h # Swift-C ブリッジヘッダー
│ ├── en.lproj/
│ │ ├── InfoPlist.strings # 入力ソース表示名(英語)
│ │ └── Localizable.strings # UI 文字列(英語)
│ ├── ja.lproj/
│ │ ├── InfoPlist.strings # 入力ソース表示名(日本語)
│ │ └── Localizable.strings # UI 文字列(日本語)
│ ├── Info.plist # InputMethodKit 設定
│ └── emojiIME.entitlements # Mach ポート登録権限
├── data/
│ ├── emoji-test.txt # Unicode 絵文字テストデータ(Emoji 15.1)
│ ├── cldr-json/ # CLDR annotations(unicode-org/cldr-json リポジトリ)
│ └── keyword.txt # 全キーワードリスト(build_db.sh で自動生成)
├── tools/
│ ├── build_emoji_db.py # 絵文字 DB 生成ツール(Python)
│ ├── tis_register.swift # TISRegisterInputSource ヘルパー(Swift)
│ ├── tis_register # tis_register コンパイル済みバイナリ
│ └── generate_icon.swift # SF Symbols → TIFF アイコン生成ツール(Swift)
├── install.sh # ビルド・インストール・キャッシュ更新・再起動スクリプト
└── build_db.sh # 絵文字 DB 生成スクリプト
┌──────────────────────────────────────────────────────────┐
│ macOS InputMethodKit │
│ └─ IMKServer / IMKInputController / IMKCandidates │
├──────────────────────────────────────────────────────────┤
│ EmojiInputController.swift │
│ ├─ ステートマシン (none → emojiComposing → emojiSelecting) │
│ ├─ 二段検索 (ja: ひらがな + en: ローマ字) │
│ └─ 候補選択・確定・学習 │
├──────────────────────────────────────────────────────────┤
│ RomajiConverter.cpp (C++ 実装) │
│ ├─ RomajiConverterImpl クラス │
│ │ ├─ conversionTable (unordered_map) │
│ │ └─ resolveBuffer() — バッファ解決ロジック │
│ └─ extern "C" 関数群 (void* opaque pointer) │
├──────────────────────────────────────────────────────────┤
│ EmojiDB.cpp (C++17 実装) │
│ ├─ EmojiDBImpl クラス(SQLite3, ATTACH パターン) │
│ │ ├─ search / searchPrefix — 完全一致・前方一致検索 │
│ │ ├─ recordUsage — 学習(使用回数記録) │
│ │ └─ emoji.db (bundle) + emoji_user.db (user) │
│ └─ extern "C" 関数群 │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────┐
│ │
none ──(英字)──→ emojiComposing ──(Space/Tab/↓)──→ emojiSelecting
│ │
│←──────────(Escape/Delete)───────────┘
│
(文字入力) → performEmojiSearch() → 候補リスト更新
│
(Enter) → 先頭候補を確定
ユーザーのキー入力に対し、日本語と英語の両方で検索を行い結果をマージする。 日本語検索では、内部的に RomajiConverter(C++ 実装、hiragaIME から流用)でローマ字→ひらがな変換を行い、日本語 term を検索する。ユーザーの画面にはローマ字のまま表示され、ひらがなは見えない。
ユーザーが "smile" と入力:
├─ ① ローマ字バッファ "smile" → en 検索 → "smile" にヒット ✓
└─ ② ひらがな変換結果 "すみぇ" → ja 検索 → ヒットなし ✗
→ ①の候補を表示(😀😊 等)
ユーザーが "neko" と入力:
├─ ① ローマ字バッファ "neko" → en 検索 → ヒットなし ✗
└─ ② ひらがな変換結果 "ねこ" → ja 検索 → "ねこ" にヒット ✓
→ ②の候補を表示(🐱🐈 等)
日本語キーワードはローマ字入力→ひらがな変換を経由して検索される。そのため漢字・カタカナ・数字を含むキーワードにはローマ字入力から到達できない。
DB 内の日本語キーワード 5,168 件のうち、到達可能なのは約 1,411 件(ひらがなのみ)。
変換できる例(ひらがなのみの term_norm):
| ローマ字入力 | ひらがな変換 | ヒットする絵文字 |
|---|---|---|
neko |
ねこ | 🐱🐈 |
hana |
はな | 💐🌸🌹 |
inu |
いぬ | 🐶🐕🐩 |
sakura |
さくら | 🌸 |
aisatsu |
あいさつ | 👋 |
egao |
えがお | 😀😃😄 |
azarashi |
あざらし | 🦭 |
変換できない例(漢字・カタカナ・数字を含む term_norm):
| term_raw | term_norm | 理由 |
|---|---|---|
| 2位 | 2位 | 数字+漢字 |
| 10時 | 10時 | 数字+漢字 |
| 0系新幹線 | 0系新幹線 | 数字+漢字 |
| 100点満点 | 100点満点 | 数字+漢字 |
| 2人でキス | 2人できす | 数字+漢字(term_norm にひらがな以外を含む) |
現在到達できないキーワードも、将来の拡張(漢字変換対応、カタカナ入力対応等)に備えてデータベースに残している。
InputMethodKit に必要な設定:
| キー | 値 | 説明 |
|---|---|---|
InputMethodConnectionName |
com.mitsuruk.inputmethod.emojiIME_Connection |
IMKServer の Mach ポート名 |
InputMethodServerControllerClass |
$(PRODUCT_MODULE_NAME).EmojiInputController |
コントローラクラス名 |
TISInputSourceLocalizedName |
emojiIME |
入力ソースの表示名 |
tsInputModeScriptKey |
smUnicodeScript |
入力ソースを「その他」カテゴリに配置 |
TISIntendedLanguage |
und |
特定言語に紐付けない |
tsInputMethodIconFileKey |
emoji_icon.tiff |
メニューバーアイコン |
tsInputModeMenuIconFileKey |
emoji_icon.tiff |
入力モードのメニューバーアイコン |
tsInputMethodCharacterRepertoireKey |
Latn |
ラテン文字入力 |
LSUIElement |
true |
Dock に表示しない |
CFBundleIdentifier |
com.mitsuruk.inputmethod.emojiIME |
.inputmethod. を含む必要あり |
| 項目 | 仕様 |
|---|---|
| ファイル形式 | TIFF(PNG も可) |
| サイズ | 16×16 pt(1x: 16×16px, 2x: 32×32px) |
| 解像度 | 1x: 72dpi, 2x: 144dpi |
| カラー | 黒一色 + 透明背景(テンプレートイメージ) |
| アルファ | 必須(背景は透明) |
| 色空間 | sRGB / DeviceRGB |
| 備考 | macOS がダーク/ライトモードに応じて自動着色する。マルチ解像度(1x + 2x)を 1 つの TIFF にまとめるのが理想 |
配置先: emojiIME/emoji_icon.tiff → バンドルの Contents/Resources/ にコピーされる。
現在は tools/generate_icon.swift で SF Symbols number.square.fill から自動生成している。
swift tools/generate_icon.swift emojiIME/emoji_icon.tiffカスタムアイコンに差し替える場合は、上記仕様に従った TIFF ファイルを emojiIME/emoji_icon.tiff に上書きする。
注意: メニューバーアイコンの変更を反映するには logout → login が必要(InputMethodKit の制約)。
| 項目 | 選択 | 理由 |
|---|---|---|
| イベント処理方式 | handleEvent(_:client:) |
修飾キーを含むすべてのキーイベントを制御可能 |
| 候補ウィンドウ | IMKCandidates(システム提供) |
カスタムウィンドウより実装が簡潔 |
| 絵文字 DB エンジン | C++17 + SQLite3 | macOS フレームワーク非依存、高速検索 |
| Swift-C++ 連携 | Bridging Header + extern "C" | Swift/C++ interop より広い互換性 |
| 検索方式 | 二段検索(ja + en) | モード切替不要で日英両方の入力に対応 |
| 学習機能 | use_count によるソート | 頻繁に使う絵文字が上位に表示される |
| RomajiConverter 保持 | 二段検索に必要 | hiragaIME のコードを流用し、ローマ字→ひらがな変換で日本語 term を検索 |
| 英字以外のパススルー | return false |
記号・数字等は通常入力として処理 |
| クラス名属性 | @objc(EmojiInputController) |
Swift 名前マングリングを回避 |
絵文字データベース(emoji.db)を生成するシェルスクリプト。
./build_db.sh # デフォルト(ja en ロケール)
./build_db.sh --no-pykakasi # pykakasi をスキップ
./build_db.sh --locales ja en zh # ロケールを指定処理内容:
- 元データの自動取得(
data/emoji-test.txt,data/cldr-json/が無い場合) tools/build_emoji_db.pyを実行してemojiIME/emoji.dbを生成- 全キーワードリストを
data/keyword.txtに出力
pykakasi は漢字→ひらがな変換を行う Python ライブラリ。CLDR の日本語キーワードには漢字を含むもの(例: "笑顔", "自動車")があり、pykakasi でひらがな読み("えがお", "じどうしゃ")を生成して DB に登録する。これにより、ローマ字入力から漢字キーワードにも到達できる。未インストールの場合は自動的にスキップされる(pip install pykakasi でインストール)。
生成後は ./install.sh で再ビルド・インストールする。
データベースの設計・スキーマ・データ取得方法の詳細は EmojiDB.md を参照。
本プロジェクトは 現時点では非公開のhiragaIME(実験中のプロジェクト)から絵文字入力機能のみを抽出して作成した。hiragaIME は macOS 用ひらがな入力 IME のプロトタイプであり、RomajiConverter や EmojiDB 等のコードを本プロジェクトで流用している。
| 項目 | hiragaIME | emojiIME |
|---|---|---|
| ローマ字→ひらがな変換 | あり(画面に表示) | 内部のみ(画面には非表示) |
| 絵文字検索 | : トリガー |
即時検索(トリガー不要) |
| ステートマシン | 5 状態(none, composing, selecting, emojiComposing, emojiSelecting) | 3 状態(none, emojiComposing, emojiSelecting) |
| RomajiConverter | ひらがな変換 + 二段検索 | 二段検索のみ |
| メニューバーアイコン | 「ひ」 | SF Symbols number.square.fill |
| バンドル識別子 | com.mitsuruk.inputmethod.hiragaIME |
com.mitsuruk.inputmethod.emojiIME |
メニューバーの emojiIME アイコンを クリック、Ctrl+クリック(または右クリック)すると、メニューが表示される。「絵文字の学習をリセット」(英語環境では "Reset Emoji Learning Data")を選択すると、確認ダイアログの後に使用頻度データ(emoji_user.db)をすべて削除できる。
メニューとダイアログの文字列は NSLocalizedString で多言語対応しており、日本語環境では日本語、それ以外の環境では英語で表示される。ローカライズファイルは en.lproj/Localizable.strings と ja.lproj/Localizable.strings に配置されている。
本プロジェクトの絵文字キーワードは Unicode CLDR (Common Locale Data Repository) から取得している。CLDR は Unicode Consortium が管理する、世界最大のロケールデータリポジトリであり、Apple・Google・Microsoft・Meta 等が利用している。
本プロジェクトでは CLDR の annotations(絵文字に対するキーワードと短い説明文)を使用し、build_db.sh で unicode-org/cldr-json リポジトリから取得する。
| データ | 説明 | 取得元 |
|---|---|---|
cldr-annotations-full |
絵文字のキーワード(tts, annotations) | cldr-json/cldr-json/cldr-annotations-full/ |
cldr-annotations-derived-full |
派生キーワード(skin tone 等のバリエーション) | cldr-json/cldr-json/cldr-annotations-derived-full/ |
CLDR データは Unicode License V3(SPDX: Unicode-3.0)の下で提供されている。
- 使用・コピー・改変・配布・販売が無償で許可される
- 著作権表示とライセンス表示の保持が必要
- 「AS IS」提供(無保証)