0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

0
Posted at

はじめに

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標準など)
  • どんな操作した時に起きたか
  • 期待してた動作と実際の動作

💡 機能要望:

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

❓ 質問:

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

対応について

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

優先的に対応するやつ:

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

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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?