🆕

初めてのSwiftアプリ開発:FlowIMEを作った話

に公開

はじめに

macOSで日本語と英語を切り替えながら文章を書くの、めんどくさくないですか?

「日本語打って、英語打って、また日本語に戻して...」この繰り返しがストレスすぎて、IMEを自動で切り替えるアプリ「FlowIME」を作ることにしました。

これが私の初Swift、初macOSアプリ開発です。この記事では、開発で苦労したこと、ハマったところ、そして今も抱えている課題について書いていきます。

🔗 公式サイト: https://flowime.netlify.app/

FlowIMEとは?

FlowIMEは、カーソル前の文字が日本語か英語かを判定し、自動的にIMEを切り替えるmacOSアプリです。

主な機能

  1. スマートな自動切り替え

    • カーソル前の文字が日本語なら日本語IMEに、英語なら英語モードに自動切り替え
  2. コンテキスト認識

    • 空白・改行・文頭では切り替えを行わず、ユーザーの意図を尊重
  3. 高速入力対応

    • 連続入力中は判定をスキップし、タイピングの邪魔をしない
  4. 手動操作の尊重

    • ユーザーが手動でIMEを切り替えた場合、自動判定を一時停止

なぜ作ったのか

プログラミングのコメント書いたり、技術文書作ったりしてると、日本語と英語を行ったり来たりすることが多いんですよね。

で、ふと思ったんです。「カーソルの前の文字見れば、次に何語打つかわかるんじゃね?」って。

このシンプルすぎるアイデアから、全てが始まりました。

苦労したこと

1. 日本語変換処理中のバグとの戦い

これが一番ハマりました。日本語変換してる最中に英語に切り替わるんですよ。

日本語打ってる途中で、変換もまだ確定してないのに自動切り替えが発動して、入力が中断されちゃう。マジで困りました。

特にやばかったケース:

  • Enterで変換確定した直後:確定直後に次の文字打つと、システムの遅延で英語と誤判定される
  • Spaceで変換候補選んでる時:候補選んでる間に切り替わったら最悪
  • Deleteで変換キャンセルした時:日本語入力やり直したいだけなのに英語になる

解決策:日本語セッションの追跡

「日本語入力セッション」っていう仕組みを作りました。日本語文字(ひらがな、カタカナ、漢字)を打ち始めたら、以下のどれかが起こるまでセッション継続:

  1. カーソル移動(矢印キー)
  2. マウスクリック
  3. アプリ切り替え
  4. 1.5秒放置

セッション中は自動切り替えしません。ユーザーの日本語入力を邪魔しないようにしました。

あと、Spaceキー押してる間(変換候補選択中)は絶対に切り替えないようにしました。これ超重要。

2. 日本語入力中に英語を打ちたい時の対処

これも結構難しかった。

例えば、こんな文章:

このアプリはhttps://example.comで公開してます。

「このアプリは」まで日本語で書いて、次にURL英語で打ちたいじゃないですか。でも単純に「カーソルの前が日本語だから日本語IME」って判定すると、URLまで日本語モードで打つことになっちゃう。

問題の本質

ユーザーの意図を読み取る必要がありました:

  • 連続して日本語打ってる時:切り替えない(上の日本語セッション)
  • カーソル移動して新しい場所に入力する時:前の文字見て判断
  • 手動でIME切り替えた時:ユーザーの意図を尊重

解決策:決定ゲート

「決定ゲート」っていう仕組みを作りました。自動切り替えするかどうかの判断を、ゲート(門)で制御するイメージ。

ゲート開いてる時(自動切り替えON):

  • マウスクリック直後
  • 矢印キー押した後
  • アプリ切り替えた後
  • しばらく何も打たなかった後

ゲート閉じてる時(自動切り替えOFF):

  • 日本語を連続入力中
  • 手動でIME切り替えた直後(数秒間)

スロットル処理

0.2秒以内に連続でキー押された場合は判定スキップ。高速タイピング中に余計な判定入って遅くなるの防ぎます。

手動切り替えの尊重

Cmd+SpaceとかControl+Spaceで手動切り替えしたら、「ユーザーが自分で切り替えた」って判断して、数秒間は自動切り替え停止します。

これらを組み合わせて、やっと実用的になりました。

3. Accessibility APIとイベントタップの複雑さ

他のアプリの入力監視するには、Accessibility権限が必要なんですよ。これが予想以上にめんどくさかった。

イベントタップが壊れやすすぎる

キーボード入力監視するために「イベントタップ」っていう仕組み使うんですけど、これがマジで壊れやすい。

タイムアウトで勝手に無効化される:システムが忙しいと、macOSが勝手にイベントタップ無効化しちゃうんです。悪意のあるアプリからシステム守るための機能なんですけど、正当なアプリにとっては迷惑すぎ。

無効化検出して、自動で再有効化する仕組み作る必要がありました。

権限が突然消える:ユーザーがアプリ動かしてる最中にシステム設定でAccessibility権限外すと、アプリがクラッシュする可能性あり。

これ防ぐために、2秒ごとに権限チェックして、なくなったら安全に再起動する仕組み入れました。

テキスト取得が超難しい

「カーソルの前の文字取得する」って、簡単そうじゃないですか?実は超難しいです。

Accessibility API使って取得するんですけど:

  • アプリによって動作が違う:VSCodeは取れるけどChromeは取れない、みたいな
  • 遅延がヤバい:100ms以上かかることもあって、タイピングの邪魔になる
  • セキュリティ制約:パスワードフィールドとかは取得できない

取得失敗した時のフォールバック処理とか、遅延最小化するための最適化とか、色々やる必要ありました。

あと、ユーザーに権限付与してもらう必要があるから、初回起動時の説明どうするかも悩みました。

4. IME切り替えAPIの制約とGoogle日本語入力の問題

macOSには公式の「IME切り替えAPI」がないんですよ。だからText Input Services(TIS)っていう低レベルAPI直接いじる必要がありました。

macOS標準IMEは簡単

macOS標準の日本語入力(ことえり/日本語IM)は、わりと簡単:

  1. 利用可能な入力ソース一覧取得
  2. 日本語IME探す
  3. TISSelectInputSourceで切り替え

これだけで動きます。

Google日本語入力の悪夢

ところが、Google日本語入力は全く別物でした。

Google日本語入力って内部的に複数の「モード」持ってるんです:

  • ひらがなモードcom.google.inputmethod.Japanese.base
  • 英数モードcom.google.inputmethod.Japanese.Roman

で、これらが通常の方法で切り替えられない

macOSのAPIで「選択可能な入力ソース」として認識されないことがあって、直接切り替えようとしても失敗します。

苦肉の策:Control+Spaceのシミュレーション

仕方ないから、Control+Spaceキーみたいに入力ソースを順番にサイクルする方法実装しました。

仕組み:

  1. 現在の入力ソース確認
  2. 目的のモード(.base)じゃなかったら、次の入力ソースに切り替え
  3. また確認して、まだ違えば次へ
  4. 最大10回試行して、それでもダメなら諦め

問題点:

  • 不安定:システムの状態で失敗する
  • 遅い:複数回切り替え必要で、各50ms待機
  • 予測不能:ユーザーが他のIME入れてると予期しない動作

公式ドキュメントほぼなくて、試行錯誤とログ出力の繰り返しでした。

現在の課題と制約

対応IMEについて(重要)

実は、基本的にABC(英語キーボード)と日本語ローマ字入力でしか動作確認してません

私が普段使ってるのがこの組み合わせなんで、開発もこれベースでやってました。

動作確認済み

  • ABC(英語キーボード) + macOS標準の日本語ローマ字入力

一応実装はしてるけど不安定

  • Google日本語入力:実装はしてるけど超不安定です

Google日本語入力は以下の問題があります:

  1. .baseモード(ひらがな)が選択不可能とマークされてる場合がある
  2. 入力ソース切り替え中に予期しない動作
  3. システムの状態で切り替え失敗する

これ、Google日本語入力がmacOSのInput Source APIと完全に統合されてないのが原因で、個人開発じゃ完全解決は難しいです。

未対応

  • US配列以外のキーボード
  • JIS配列
  • かな入力
  • その他のIME(ATOK、Azookey等)

申し訳ないですが、色んな環境でテストする時間なかったんで、ABC + 日本語ローマ字以外は動かない可能性高いです。

OSバージョンによって動かない可能性

現在、macOS 15.5以降を動作環境としていますが、それ以前のバージョンや将来のバージョンでは動作しない可能性があります。

個人開発のため、広範囲のOSバージョンでのテストやメンテナンスが難しく、最新のmacOSでの動作を優先しています。

特に、macOSのセキュリティポリシーやAccessibility APIの仕様変更により、将来的に動作しなくなるリスクもあります。

Apple Siliconとの互換性

幸い、SwiftUIとAppKitを使用しているため、Apple Silicon(M1/M2/M3)とIntel Macの両方で動作します。

ただし、実機テストは限られた環境でしか行えていないため、一部の環境では予期しない問題が発生する可能性があります。

技術スタック

  • 言語: Swift
  • フレームワーク: SwiftUI, AppKit
  • API:
    • Accessibility API(キーボード入力の監視)
    • Text Input Services(IME切り替え)
    • Carbon Events(キーボードイベント)
  • 開発環境: Xcode, macOS 15.5+

配布について

アプリは完全無料で公開しています:

DMGファイルをダウンロードして、Applicationsフォルダにドラッグ&ドロップするだけで使用できます。

ただし、初回起動時にAccessibility権限の付与が必要です。

学んだこと

Swiftの表現力

Swiftは初めて触る言語でしたが、型安全性が高く、モダンな言語機能(Optional、Guard文、Extensionなど)により、安全で読みやすいコードが書けました。

// Optionalの安全な展開
guard let button = statusItem?.button else { return }

// Extensionで機能を拡張
extension String {
    var isJapanese: Bool {
        // 日本語判定ロジック
    }
}

SwiftUIの便利さと制約

設定画面の実装にはSwiftUIを使用しましたが、宣言的UIの書き心地は非常に快適でした。

ただし、メニューバーアプリのような特殊なUIはAppKitを併用する必要があり、両方のフレームワークを理解する必要がありました。

macOSアプリ開発特有の難しさ

iOSアプリと比べて、macOSアプリは以下の点で難易度が高いと感じました:

  • セキュリティ制約(Sandbox、権限管理)
  • ドキュメントの少なさ(特にメニューバーアプリ)
  • レガシーAPI(Carbon)との共存
  • コード署名とNotarization(公証)の複雑さ

今後の展望

個人開発なんで限界ありますけど、以下考えてます:

  1. Google日本語入力の安定化(できれば)
  2. 多言語対応
    • 韓国語、中国語、フランス語など
    • 多言語混在の文章にも対応したい
  3. 設定のカスタマイズ性向上
    • 自動切り替えの感度調整
    • 特定アプリでの無効化
  4. パフォーマンスの最適化

特に多言語対応は将来的にやりたいですね。日本語・英語だけじゃなくて、韓国語とか中国語とか混ぜて使う人もいるでしょうし。

ただ、時間とリソースの制約あるんで、いつ実現できるかは未定です。

まとめ

初Swiftアプリ開発、想像以上に大変でしたけど、めちゃくちゃ学びになりました。

特に日本語変換中のバグとか、日本語入力中に英語挿入したい時の対処とか、IME制御の複雑さは予想外。

完璧なアプリじゃないですけど、私は毎日使ってて、IME切り替えのストレスかなり減りました。

同じ不便さ感じてる人いたら、ぜひ試してみてください。


ダウンロード: FlowIME公式サイト

対応環境: macOS 15.5以降(Apple Silicon / Intel)
価格: 無料


おまけ:開発期間と統計

  • 開発期間: 約3日(空き時間)
  • 総コード行数: 約800行
  • 主要ファイル数: 8ファイル
  • 使用したライブラリ: 標準ライブラリのみ
  • 開発パートナー: Claude(生成AI)

正直、3日でここまで作れたのは生成AIと一緒に開発したからです。

私、Swift初心者なんですよ。でもClaude Code使って、AIと対話しながら開発したら、めちゃくちゃスムーズに進みました。

  • わからないAPIの使い方 → AIに聞いたらすぐ教えてくれる
  • バグで詰まった → AIと一緒にデバッグ
  • 複雑なロジック → AIと会話しながら整理

AIの進化、マジでやばいです。

数年前なら、Swift初心者が3日でこんなアプリ作るの無理でした。でも今は、AIがペアプログラミングのパートナーになってくれる。

技術的なハードルが劇的に下がってます。「プログラミングできないから無理」って時代じゃないですよ。

「こんなアプリあったらいいな」って思ったら、AIと一緒にチャレンジしてみてください!


バグ報告・機能要望・質問について

個人開発なんで、色んな環境でテストできてないんですよ。バグ見つけたり、機能要望あったら、Twitterで連絡ください。

Twitter/Xでのフィードバック

開発者: @taro05069596

ハッシュタグ: #FlowIMEつけてツイートしてください

以下の情報あると助かります:

🐛 バグ報告:

  • macOSのバージョン
  • 使ってるIME(Google日本語入力、macOS標準など)
  • どんな操作した時に起きたか
  • 期待してた動作と実際の動作

💡 機能要望:

  • どんな機能欲しいか
  • それがあると何が便利になるか

❓ 質問:

  • 使い方わかんない
  • 設定どうすればいい

対応について

個人開発なんですぐ対応できないかもですけど、できる限り早く対応します。

優先的に対応するやつ:

  • クリティカルなバグ(クラッシュするとか)
  • 多くの人に影響する問題
  • 再現手順が明確な問題

フィードバック待ってます!

Discussion