2013年やったこと - Mozc 編

2013年やったこと - Mozc 編,いつもどおりコードが公開されている範囲で.

Mozc IPC の Windows 64-bit 対応

Windows 環境で動く Mozc は名前付きパイプ使ってプロセス間通信を行うのですが,いわゆる "Squatting Attack" 対策として,GetNamedPipeServerProcessId API で接続先のプロセス ID を取得し,さらにそのプロセス ID から GetModuleFileNameExW API で実行ファイル名を取得して検証しています.が,この仕組みが今は動いていても将来的にうまく動かないことがあるかもという問題.
このころ mozc_server や mozc_renderer を 64-bit で動かす実験を行っていて気付いたわけですが, 32-bit プロセスから 64-bit プロセスに対して GetModuleFileNameExW API を呼び出すと必ず失敗するようです.仕方ないので GetProcessImageFileNameW API を使うように変更して対処.これまで mozc_server と mozc_renderer は常に 32-bit プロセスだったので問題が表面化していなかったというわけでした.

TSF-Mozc 使用時に ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0) が動作しない

IMM32 の頃には,アプリケーション側から進行中のコンポジションをキャンセルするという API が存在しました.TSF になってそういう API はなくなったのですが,CUAS はなにかしらの方法でこの IMM32 API を エミュレートする必要があります.実際これは「コンポジションの範囲を空にする」という形で行われています.ということで TSF-Mozc でも対応する必要があるというわけでした.
Excel が,インライン補完のためにこの機能に依存しているので割と重要だったりします.

TSF-Mozc で候補ウィンドウの候補をマウスで選択・決定できない問題の修正

経験上ほとんどの人はマウスで候補ウィンドウを選択しないのを知っていたので,TSF-Mozc ではマウス関係の処理を後回しにしていました.とはいえ,タッチイベントでも動作しないのはそろそろよろしくないというのもあって修正という感じです.

TSF-Mozc での InputScope のサポート

InputScope も登場後 10 年以上経っている仕組みで,いまさらという感もありますが,Windows 8 以降はだいぶ InputScopeへの移行が進んでいます.最近はブラウザの HTML Forms の種類が InputScope で通知されたり,Windows 8 以降でImmSetConversionStatus API が (デフォルト設定では) 実質廃止になったりで,IME 側も InputScope 対応が割と重要になってきています.というわけで TSF-Mozc でも対応してみました.
アプリケーション開発者様におかれましても,Windows 8 以降,ImmSetConversionStatus API は大多数のユーザー環境で期待通り動作していない可能性が高いため,この機会に InputScope に移行してしまうのが良いのではないかと思います.詳細については下記資料等を参照してください.

さて,デスクトップ IME の文脈で気を付けるべき点として,アプリケーション側からのモード変更リクエストを永続的なものとして扱うか,一時的な変更リクエストとして扱うかという問題があります.たとえば次のような順序でテキストフィールドを移動していったとしましょう.

  1. 通常のテキストフィールド
  2. パスワードフィールド
  3. 通常のテキストフィールド

多くの場合,ステップ 1 で IME がオンの状態であれば,ステップ 3 でIME がオンの状態に復帰します.つまり,パスワードフィールドで IME が自動的にオフになるのは,永続的なモード変更ではなく一時的なモード変更というわけです.
では次の場合はどうなるべきでしょうか?

  1. 通常のテキストフィールド
  2. 全角カタカナが期待されるテキストフィールド
  3. 通常のテキストフィールド

ステップ 2 で IME の入力モードが「全角カタカナ」になるのはまあ良いとします.では,ステップ 3 に移動したときにも「全角カタカナ」のままであるべきでしょうか? それともステップ 1 のときのモードに復帰すべきでしょうか.
TSF-Mozc に関しては,InputScope によるモード変更リクエストはその場限りの一時的なものであるという解釈を行いました.したがって,上記ステップ 3 ではステップ 1 のときのモードに復帰します.簡単に Design Doc を書いていますので詳細についてはそちらを参照してください.

Windows 版 Mozc での Mode Indicator のサポート

これ.
f:id:NyaRuRu:20140102115121p:plain
位置形状とフォントサイズの決定以外のほぼ全てを担当しました.個人的にはカーソル直下よりもカーソルに対して左揃えの方が良いんではないかとか,ちょっと大きすぎるんではないかとか色々思うところはあるのですが,まあデザイナーさんがそう言っているわけで案件.個人的にはもうちょっと作りこみたかったのですが,別の仕事が忙しくてあんまり専念できなかったのが心残りです.
InputScope で自動モード変更を行う以上,この種の視覚的フィードバックは必須ですね.というわけで InputScope 対応とセットで実装されました.

周辺文字列を利用した変換の (部分的) サポート

周辺文字列を利用した変換も十数年以上の歴史があるいまさら技術ではあります.前世紀の IMM32 時代から IMR_DOCUMENTFEED メッセージをサポートしたアプリケーションでは周辺文字列を利用した変換は可能でした.
さて,周辺文字列を利用した変換というのは実際のところあんまりコストパフォーマンスの良くないアプローチだと思っています.細切れ変換対策という意味では,変換エンジン側で前回コミットされた文字列を覚えておけばすむ話です.というわけで,今回注目したのは,IME をオフにして入力しがちな文字種,つまり半角英数です.
たとえば「明日1日」という文章を入力するのに,

  1. 「明日」を入力
  2. IME をオフにする
  3. 「1」を入力
  4. IME をオンにする
  5. 「日」を入力

という使い方をする人は一定いることが分かっています.以前の Mozc では,ステップ 4 実行時に内部ステートは「文頭」状態でした.というのも,IME がオフの状態で入力された内容はモニタリングしていないので,ステップ 5 で入力する内容がどういう文章に続くものなのか把握できません.今回救いたかったのはまさにこういうケースで,カーソル前にある文字種がアルファベットか数字かどうかだけを判定します.このあたりの詳細についても Design Doc を書いておきましたので詳細が気になる人はどうぞ.

imm32-mozc と tsf-mozc,ibus-mozc および mozc_server の実装を担当しました.
IMM32 版では IMR_DOCUMENTFEED を単純に使うだけですが,TSF では Transitory Extensions という拡張的な仕組みも使っていて,メモ帳や Internet Explorer にも対応しています.軽く調べてみた限り,ATOK 2013 も MS-IME 2013 も Transitory Extensions までは使っていないようなので,ちょっとしたアピールポイントではないかと思っております.
このとき書いたコードは別のオープンソースプロジェクトで使われたりもしているようです.

C++11 対応

最近社内コード規約的に C++11 が解禁されつつあるので Mozc でもいくつかコードのクリーンアップを行っています.具体的には,

  • 自前 scoped_ptr から std::unique_ptr への置き換え
  • COMPILE_ASSERT マクロの static_assert への置き換え
  • auto での書き換え
  • NULL から nullptr への置き換え

あたりをちまちまやってます.
最近は Visual C++ の C++11 適応度合が上がってきていてだいぶ楽なのですが,意外に足を引っ張るのが Mac OS X だったり.というのも,libc++ の実行時ライブラリが標準で入るようになったのが Mac OS X 10.7 以降.未だに Snow Leopard をサポートしていたりすると C++11 の大部分の機能が使えないのでした.

UCS2 しかサポートできない内部関数の削除

Mozc コードベースに残っていた UCS2 専用関数をすべて削除しました.

TSF-Mozc でタッチに最適化されたオンスクリーンキーボードを表示するように

ITfFnGetPreferredTouchKeyboardLayout を実装するだけ,というわけでもなくて Windows のオンスクリーンキーボードは U+F003 と U+F004 に特別な意味を持たせたりしているのでその対応とか.詳しくは下記資料参照のこと.

可能なら LogicalToPhysicalPointForPerMonitorDPI API を使う

Mozc の候補ウィンドウや Mode Indicator は,入力中のプロセスとは別のプロセスで動いているので,DPI 仮想化にともなう座標変換が必要になることがあります.Windows 8.1 Preview で LogicalToPhysicalPoint API が動作しなくなっていたので,新しく追加された LogicalToPhysicalPointForPerMonitorDPI API が利用可能ならそちらを使う,といった修正を行っていました.Windows の DPI 周り,ほんと落ち着かないですね.
次の資料とかが詳しいです.
http://go.microsoft.com/fwlink/?LinkID=307061

アプリケーションマニフェストに Windows 8.1 対応宣言を追加

恒例行事.

ITfLangBarItemButton::GetIcon で返すモノクロフォントを実行時に描画

Accessibility (a11y) 案件.
Windows 版の Mozc は,控えめに言っても Accessibility 関係の機能が全然足りていないのですが,珍しく対応している機能のひとつに言語バーのテキストアイコン色があります.Windows では,デスクトップテーマをハイコントラストモード(背景色黒・文字色緑) に変更すると,言語バーのテキストアイコンも緑色に切り替わります.
f:id:NyaRuRu:20140102115125p:plain
f:id:NyaRuRu:20140102115128p:plain
ではこれどうやって実装するかですが,大まかに方法は 2 つ.
A. 実行時にアイコンを描画する.この場合,テーマカラーを実行時に取得できるので文字色は問題ない.テーマが変更されるたびにアイコンを再生成する必要がある.
B. モノクロアイコンを事前に生成しておき,言語バーAPI に TF_LBI_STYLE_TEXTCOLORICON フラグを渡す.この場合,言語バー側で色変更を行ってくれる.
Mozc はながらく B の方法を使っていました.が,最近になってビットマップハンドルのリークが発生しているという報告を受けて調べてみると驚きの事実が! ITfLangBarItemButton::GetIcon にモノクロアイコンを渡すと,言語バー内部でビットマップハンドルのリークが発生するようです.というわけで方向 A で書き直しました.
この問題,原因の発見までがとにかく大変だったのが印象的でした.ハンドルリークが全然再現できず困っていたのですが,ユーザーの方からアップロードしていただいたスクリーンショットがクラシックテーマだったことが気になってテーマを変更してみたところやっと再現できた,というケースです.どういうやりとりが行われたか興味がある人は以下のスレッドをどうぞ.

TF_LBI_STYLE_TEXTCOLORICON を使用している IME 作者様はご注意ください.

Adobe Sandbox をサポート

@corvussolis さんから Adobe Flash および Adobe Acrobat Reader で使われている Sandbox の動作について教えてもらって Mozc でも対応してみたという話.これでやっと Firefox でも「保護モード」オンのままニコニコ動画にコメントを書けるようになりました.
ご協力いただいた皆様に感謝.

Windows 8 以降で MS-IME からのユーザー辞書インポートが動かなくなっていたのを修正

詳細については diff を参考にしてください.

Owner Rights SID を設定

Windows では,オブジェクト所有者に暗黙に WRITE_DAC および READ_CONTROL 権限が許可されるという仕様がありましたが,Vista 以降この挙動を拒否することが可能になりました.

というわけで Mozc でも不要な権限を削除してみたという話.追加すると権限が減る系の SID ですね.

Windows 版 Mozc のビルド時に Cygwin が不要になった

Mozc のビルドは,もともと Cygwin に依存しないように作られていました.しかし,Mozcのビルドシステムを SCons から gyp に変更したときに,gyp に引っ張られる形で Cygwin 依存が生まれてしまいました.
外部コマンドの呼び出しに時に色々気を付ければ Cygwin は不要というのは分かっていたのですが,とりあえず重要度は低いので後回しのままとなってはや数年,いい加減直すかということでやっと依存関係を解消したという話です.Windows 版 OSS Mozc のチェックアウトサイズもだいぶ減ったはず.
ちなみに Chromium も同様の問題があって,以下のようにビルド時の Cygwin 依存を取り除く努力が行われています (こっちも数年がかり).

以下 OSS Mozc 固有っぽいもの

Issue 42: get rid of absolute path in unix/ibus/gen_mozc_xml.py

https://code.google.com/p/mozc/issues/detail?id=41
ibus-mozc のバイナリとアイコンファイルのインストール先はカスタマイズできるべきだという案件.3 年ぐらい放置されていのですが (すみません) リファクタリングの一環として対応.

Issue 180: Mozc and IBus does not respect xinerama at all

https://code.google.com/p/mozc/issues/detail?id=180
マルチディスプレイ環境で mozc_renderer が画面境界の判定に失敗するというバグ.gdk_screen_get_monitor_at_point を使うことで解決.

Issue 182: mozc property titles are empty in gnome-shell

https://code.google.com/p/mozc/issues/detail?id=182
Red Hat で ibus-mozc をメンテナンスされている Tagoh さんから転送されてきたバグの対応.Gnome-Shell はいくつかの IBus メタデータに依存しているのですが,ibus-mozc がそれらを設定していないという問題.具体的には,

  • IBus 1.5 以降にのみ存在する symbol というプロパティをセットするようにする (これを行わないと現在の入力モードがアイコンとして表示されない)
  • Gnome Shell は "InputMode" という名前のプロパティに現在のモード (全角カタカナとか直接入力とか) が設定されていることを期待しているので,プロパティ名を変更

という感じです.ちなみにこのあたりの Gnome-Shell の仕様はどこにもドキュメント化されていません.自分でソースを読んで調べる必要があります.結果的に以下のような見た目になりました.
f:id:NyaRuRu:20140102115130p:plain
このパッチがあたっていないバージョンの Mozc (具体的には 1.6.1187.102 以前) では,入力中のモードは分かりませんし,入力モードを Gnome Shell から選択することもできません.

Issue 188: Add Session command for ConvertPrevPage and ConvertNextPage

https://code.google.com/p/mozc/issues/detail?id=188
Fcitx の開発者から来た機能追加リクエスト.Fcitx の候補ウィンドウには次頁・前頁に相当するボタンが存在するのですが,その動作に対応するメッセージが Mozc のプロトコルに存在しなかったという問題.たまたま Windows 8 のソフトウェアキーボード対応で似たような需要があったので合わせて対応となりました.

Issue 189: use_libprotobuf=1 does not work in Mozc 1.10.1390.102

https://code.google.com/p/mozc/issues/detail?id=189
Red Hat で ibus-mozc をメンテされている Tagoh さんから,システムにインストールされている libprotobuf を使用する場合のビルドが壊れているとの報告があったので粛々と修正.壊したのも私なのでマッチポンプ案件だったりします.

Issue 195: Candidate Popup is hidden by Cinnamon menu

https://code.google.com/p/mozc/issues/detail?id=195
Linux で Cinnamon を使っていると,mozc_renderer がメニューの後ろ側に行ってしまうという問題.修正は 2 行で済んだんですが,環境のセットアップやら調査やらで結局 1 日ぐらいかかっているという.ちなみにこのケースでは日曜日が消えました.

Issue 198: 'build_mozc.py gyp' fails when gyp r1667 or higher is used

https://code.google.com/p/mozc/issues/detail?id=198
Mozc 開発ではビルドに使用する gyp のリビジョンを固定しているのですが,OSS Mozc をビルドする人は推奨リビジョン以外の gyp と組み合わせている人もいるらしく,gyp 側の変更でビルドできなくなることがあります.
今回は,Mozc r171 以前と gyp の r1667 以降を組み合わせるとビルドに失敗するという問題でした.

Issue 199: ibus-mozc must be locked down on the Gnome Shell's locked screen

https://code.google.com/p/mozc/issues/detail?id=199
CVE-2013-4509 の ibus-mozc 側の対処を一通りやりました.
私も完全に背景を把握できているか怪しいのですが,概ね以下のような感じだと理解しております.

  1. 2013年1月4日,Gnome 3 環境で IME をオンにしたままスクリーンをロックし, Gnome-Shell のスクリーンロック解除画面からパスワードを入力してロック解除しようとすると,パスワードフィールドで IME がオンのままになっているというバグが Red Hat の Jens Petersen さんから報告される.Red Hat Bug 891835
  2. 2013年1月9日,Red Had の Ueno さんから,GTK の "input-purpose" と "input-hints" を,パスワードフィールドにセットすることで問題が回避したらよいのではという提案がなされる.Gnome Bug 691392
  3. 2013年1月10日,Red Hat の Ueno さん,ibus-gtk2 にパッチをコミット (927e9f58).この変更は IBus 1.5.3 としてリリースされる.変更は ibus-gtk2 に対するもので,IM Engine 側では何もする必要がない.具体的には,"input-purpose" が password であれば,使用している IM Engine に関わらず IM Engine が無効化される.
  4. 2013年8月14日,Red Hat の Ueno さん,ibus-gtk にパッチをコミット (3b3a7cec).この変更は IBus 1.5.4 としてリリースされる.この変更によりまたしても挙動が変わり,"input-purpose" が password のときの振る舞いは各 IM Engineの責任になる.具体的には,IM Engine が IBus 1.5.4 以降の環境で動作する場合のみ,このコミットで追加された ibus_engine_get_content_type 等の新しい API を使って IM Engine の動作を変更する必要がある.
  5. 2013年9月21日,Red Hat の Fujiwara さんから IBus 1.5.4 のリリースがアナウンスされる.この中で "Handle GTK+ input purose for gnome-shell password dialog and each engine need to implement it" として各 IM Engine 開発者向けにアナウンス.
  6. 2013年9月21日,俺のターン! IBus 1.5.4 のリリースノートを受けて OSS Mozc Issue 199 をファイル.この時点では状況を完全に把握できていませんでした.
  7. 2013年9月30日,俺のターン! やっと状況を把握.急いでOSS Mozc Issue 199 へのパッチを公開.帰宅後色々弄っていて事態の深刻さに気付き急いで書き上げた感じの奴です.翌日ほんと眠かったです.
  8. 2013年10月1日,Red Hat の Mike FABIAN さんから,IBus 1.5.4 側の問題で "input-purpose" が正しく通知されないことがある問題が報告される.Red Hat Bug 1013948 この問題はすぐに修正されるものの,対応する IBus の安定板リリースは行われておらず,各ディストリビューションでは独自にパッチを取り込んで IBus 1.5.4 として配布している.
  9. 2013年10月25日,openSUSE のコミュニティメンバーの Takeyama さんから,Novel Bug 847718 がファイルされる.
  10. 2013年11月4日,Red Hat の Kurt Seifried さんにより今回の問題に CVE-2013-4509 が付与される.

この後 IBus を採用する各種ディストリビューションで色々対応が進んだようです.

Issue 201: making initial mode customizable for ibus-mozc

https://code.google.com/p/mozc/issues/detail?id=201
1.5.2 のころまでの IBus は,各 IM Engine は「直接入力 (いわゆる IME オフ)」というステートを持たないことを前提に設計されていました.従って,ibus-mozc は起動直後にひらがなモードである必要があります.
が,IBus 1.5.3 頃から,日本語 IME に関しては各 IM Engine 内部でオンオフ状態を切り替える方向に IBus 上流の人たちは心変わりしたようです.Red Hat の Fujiwara さんが ibus-anthy の挙動変更について下で説明されています.
https://code.google.com/p/ibus/issues/detail?id=747#c31
この変更にともない,以前の使い勝手を再現するためには,ibus-mozc が起動直後に「直接入力 (いわゆる IME オフ)」になって欲しいという要望が来たのが OSS Mozc Issue 201 です.
とはいえ Mozc は IBus 1.4 もまだ対応していますから,IBus のバージョンによらずデフォルトモードを変えてしまうと今度は IBus 1.4 ユーザーが困ることになります.また,デフォルトモードを選択する UI を追加しようにも,Mozc の設定画面は imm32-mozc, tsf-mozc, ibus-mozc, uim-mozc, fcitx-mozc, emacs-mozc, Mozc for IMKit で共有されているため,IBus 1.5.3 以降専用の項目を追加するのは躊躇するところです.
とりあえず初期状態をオフにするパッチだけは公開しましたが,以後のリリースでどうするかは未定です.
https://code.google.com/p/mozc/issues/detail?id=201#c8
ちなみに,初期値を変更するぐらい簡単だろうと思われる方もいらっしゃるかもしれません.が,実際は結構面倒です.事実,上のパッチを適用すると,mozc_server が予想外のクラッシュをした時のプレイバックの仕組みが壊れることが分かっています.初期値が変わっちゃったわけですね.

その他 OSS Mozc 関係でやったこと

2013年4月ぐらいに fcitx-mozc のマニュアルテストを行って 6 件ぐらいバグを見つけたところ,作者様にものすごい勢いで修正していただきました.

あと,fcitx-mozc の再変換には,ibus-mozc の再変換用に私が書いたコードが使われていたりするようです.

今年の話とか

入社後なんだかんだでずっと Mozc に関わってきましたが,2014 年 1 月から社内の別プロジェクトに移ることにしました.オープンな場で何をやったか話すのはいつも通り書いたコードが公開されてからにしようかと思います.
Windows 版 Mozc は 20% の枠内で今後も協力していきたいところですが,ibus-mozc のメンテナンスまでやる余裕はなさそうです.ibus-mozc の今後の開発・メンテナンスを引き継いでもいいという方がいらっしゃいましたら社内外問わずお知らせください.

「ファイルの中身に依存しつつそのファイル自体を更新する」コマンドラインツールはビルドシステムと相性が悪い

関数型プログラミングのメリットについて語られることはあっても,「ファイルの中身に依存しつつそのファイル自体を更新する」コマンドラインツールがビルドシステムと相性が悪い,みたいな話をする人はあんまりいないようなので書いてみた.

Windows には signtool.exe というデジタル署名ツールがある.実行ファイル myapp.exeに署名したい場合は以下のようにする.

signtool sign /a myapp.exe

十分にシンプルなように見える.が,典型的なビルドシステムはこの処理がお気に召さない.試しに Chromium や node.js で使われているメタビルドシステムである Gyp で書いてみる.

{
  'targets': [
    {
      'target_name': 'myapp',
      'type': 'executable',
      'sources': [
        'main.cc',
      ],
    },
    {
      'target_name': 'sign',
      'type': 'none',
      'dependencies': [
        'myapp',
      ],
      'actions': [
        {
          'action_name': 'run_signtool',
          'inputs': [
            '<(PRODUCT_DIR)/myapp.exe',
          ],
          'outputs': [
            '<(PRODUCT_DIR)/myapp.exe',
          ],
          'action': ['signtool', 'sign', '/a', '<(PRODUCT_DIR)/myapp.exe'],
          'msvs_cygwin_shell': 0,
        },
      ],
    },
  ],
}

この Gyp ファイルから生成された Ninja 用ビルドファイルは,以下のようにビルド時にエラーとなる.

C:\work\dag>ninja -C out/Default sign
ninja: warning: multiple rules generate myapp.exe. builds involving this target will not be correct; continuing anyway
ninja: Entering directory `out/Default'
ninja: error: dependency cycle: myapp.exe -> myapp.exe

myapp.exe をビルドするのに myapp.exe が必要なのはけしからん,とのこと.
私の場合,ラッパースクリプトを書いて署名前後でファイルパスの一部が変わるようにして回避することが多い.
例1.

mysigntool --input=myapp.exe --output=myapp.signed.exe

例2.

mysigntool --input=unsigned/myapp.exe --output=signed/myapp.exe

デジタル署名に限らず,mt.exe を利用したマニフェストファイルの埋め込み,rebase.exe を利用した事前バインド,Profile Guided Optimization (PGO) などで,うっかり入力ファイルと出力ファイルを同一パスにすると同様の問題に直面する.

なんでこんな話を書く気になったかというと,暇つぶしに Gyp にパッチを書いていて突然気付いたからである.
https://codereview.chromium.org/82703007#msg3
Directed Acyclic Graph (DAG; 無閉路有向グラフ) を事前に構築できることを前提としているシステムというのは,ビルドシステムにしろ MapReduce にしろ,案外日常的にお世話になっている.そういうシステムで「ちょっとした処理」を行うとして,なんだかうまく書けないなぁという処理,実はそれ入力と出力に循環があったりしませんか,というまあただそれだけの話.
こうやって考えてみると,世間のビルドシステムというのはファイルシステムと割とべったりくっついているということに気付かされる.

まとめ

入力パス名と出力パス名が同じになる操作は,一般的にビルドシステムと相性が悪い.典型的なビルドシステムでは,ファイルの内容ではなくパス名だけを用いて依存関係を記述する必要があることに注意.

Windows の IME を変換エンジンとして使う

f:id:NyaRuRu:20131218051110p:plain
プロセス分離型の IME の開発に携わった以上,一度は試してみたいと思っていた奴,の基礎実証実験っぽいのをやってみた.Windows向け IME を (とくに個人規模で) 作っている人にはもしかしたら役に立つかも.

テーマ

メインテーマは,Windows で IME を実装するとして,バックグラウンドで別 IME を有効化し,その IME に対してクエリを投げ,返ってきた結果を利用するための技術的な枠組みについて.ここではプロセスモデル的に Windows で可能かどうかという点のみを考える.

大まかな流れ

今回試した手法では,Windows 8 で TSF に追加された ITfFnSearchCandidateProvider という仕組みを活用する.このインターフェイスは,複雑なことはできない反面,1) 文字列を投げて文字列のリストが返ってくるというシンプルな仕組みである,2) ステートを持たず,IME でユーザーが入力中かどうかに関わらず自由に使える,という点で大変使いやすい.ただしすべての IME が実装しているわけではない.これについては後述.
また,このインターフェイスには "Windows 8 [desktop apps only]" と注釈がついている.ここで,プロセス分離型の IME 実装を前提とするのが生きてくる.プロセス分離型の実装では,好きにデスクトッププロセスと連携できるのでこれは特に問題にはならない.

具体的な流れ

以下の手順で,キーボードフォーカスを持たないバックグラウンドプロセス内で,ITfFnSearchCandidateProvider をサポートした IME を変換エンジンとして使用できる.

  1. バックグラウンドスレッドを作る
  2. スレッド内で COM を初期化する (STA 推奨)
  3. ITfInputProcessorProfileMgr.ActivateProfile を使用して,使用したい IME を有効化する.
  4. ITfThreadMgr2.ActivateEx を呼んで IME に初期化処理を行わせる.
  5. ITfThreadMgr2.GetFunctionProvider に,対象 IME の CLSID を渡して ITfFunctionProvider を取得
  6. GetFunctionProvider.GetFunction 経由で ITfFnSearchCandidateProvider を取得
  7. ITfFnSearchCandidateProvider.GetSearchCandidates で任意のクエリを行う

罠ポイント

上記手順の 3 が問題. Windows 8 以降はデスクトッププロセス間で IME 関係の設定を共有するようになったため,うかつに別 IME を選択すると他スレッド/他プロセスにも影響が及んでしまう.これについては, API を使って一時的にこの挙動に関する設定そのものを変更することで回避できそう.具体的には,SystemParametersInfo API に SPI_GETTHREADLOCALINPUTSETTINGS/ SETTHREADLOCALINPUTSETTINGS を指定して,以前の「スレッドごとに IME 関係の設定を保持」に変更する.変更は永続的である必要はなくて,IME を変更するごく短い間だけで十分なようだ.というわけで先ほどの手順をもう少し改良する.

  1. バックグラウンドスレッドを作る
  2. スレッド内で COM を初期化する (STA 推奨)
  3. 「スレッドごとに IME 関係の設定を保持」が有効でなければ SETTHREADLOCALINPUTSETTINGS を使って有効にする
  4. ITfInputProcessorProfileMgr.ActivateProfile を使用して,使用したい IME を有効化する.
  5. ITfThreadMgr2.ActivateEx を呼んで IME に初期化処理を行わせる.
  6. ITfThreadMgr2.GetFunctionProvider に,対象 IME の CLSID を渡して ITfFunctionProvider を取得
  7. GetFunctionProvider.GetFunction 経由で ITfFnSearchCandidateProvider を取得
  8. 「スレッドごとに IME 関係の設定を保持」を変更していれば,SETTHREADLOCALINPUTSETTINGS で元に戻す
  9. ITfFnSearchCandidateProvider.GetSearchCandidates で任意のクエリを行う

実際には「スレッドごとの IME 設定」を元に戻すのはもう少し手前でも問題ないかもしれない.
また,ユーザーが「アプリウィンドウごとに異なる入力方式を設定する」を有効にしている場合,GETTHREADLOCALINPUTSETTINGS は TRUE を返す.この場合はスレッドごとに異なる IME を有効化できるため何もしなくてよい.

応用

上の罠ポイントさえ回避できれば,複数のバックグラウンドスレッドを用意し,それぞれに別 IME をロードして構わない.つまり,複数の IME に対して同時にクエリを行うことができる.

ITfFnSearchCandidateProvider をサポートしている IME はどれぐらいあるのか?

手元の Windows 8.1 環境でしらべたところ,MS-IME 日本語版と ATOK 2013 はサポートしている.Google 日本語入力 / OSS Mozc は1.12.1599.102 の時点で未サポート.以下,実験したい人のための GUID 一覧.

{
  name: "MS-IME Japanese (Windows 8.1)",
  langid: 0x0411,
  clsid: "03B5835F-F03C-411B-9CE2-AA23E1171E36",
  profile: "A76C93D9-5523-4E90-AAFA-4DB112F9AC76",
},
{
  name: "ATOK 2013",
  langid: 0x0411,
  clsid: "E7602D3E-204C-4662-B92F-78DF0DE5752D",
  profile: "3C4DB511-189A-4168-B6EA-BFD0B4C85615",
},
{
  name: "Google Japanese Input",
  langid: 0x0411,
  clsid: "D5A86FD5-5308-47EA-AD16-9C4EB160EC3C",
  profile "773EB24E-CA1D-4B1B-B420-FA985BB0B80D",
},
{
  name: "OSS Mozc",
  langid: 0x0411,
  clsid: "10A67BC8-22FA-4A59-90DC-2546652C56BF",
  profile: "186F700C-71CF-43FE-A00E-AACB1D9E6D3D",
},
{
  name: "Corvus-skk",
  langid: 0x0411,
  clsid: "EAEA0E29-AA1E-48ef-B2DF-46F4E24C6265",
  profile: "956F14B3-5310-4cef-9651-26710EB72F3A",
},

まとめ

Windows 8.1 環境で ITfFnSearchCandidateProvider を利用すると,MS-IME 日本語版と ATOK 2013 を(同時に)フォールバックエンジンとして使う IME が作成可能.

速度とか所感

MS-IME Japanese は大体 10 msec 以内で返ってくるのでサジェストでも大丈夫かも.ATOK 2013 はクエリが返ってくるまで 100 msec 以上かかっていて,リアルタイムのサジェストに使うのはちょっときついかも.

サンプルコード

次のコードは,現在使用中の IME からのみ ITfFnSearchCandidateProvider を取得することで色々処理を簡略化したもの.起動後に何か入力すると,その入力を ITfFnSearchCandidateProvider.GetSearchCandidates に渡した結果が返ってくる.空行入力で終了.
ビルドには要 NuGet.Package Manager から TSF.SearchCandidateProvider を追加.

PM > Install-Package TSF.SearchCandidateProvider
using System;
using System.Linq;
using TSF;

static class Program {
  static void Main(string[] args) {
    using (var provider = SearchCandidateProvider.FromCurrentProfile().Result) {
      if (provider == null) {
        Console.WriteLine("No provider found.");
        return;
      }
      Console.WriteLine("{0} is found", provider.Profile.Name);
      while (true) {
        var line = Console.ReadLine();
        if (string.IsNullOrEmpty(line)) {
          return;
        }
        var result = provider.GetSearchCandidates(line).Result;
        Console.WriteLine("Elapsed time: {0} msec", result.Elaplsed.TotalMilliseconds);
        result.Candidates.ToList().ForEach(s => Console.WriteLine("  " + s));
        Console.WriteLine();
      }
    }
  }
}

ビルドするのは面倒なのでビルド済みファイルが欲しいという人はこちら.
http://d.hatena.ne.jp/NyaRuRu/files/SearchCandidateProviderSample.zip

TSF.SearchCandidateProvider のコードが見たい人はこちらから.
NyaRuRu/TSF-SearchCandidateProvider · GitHub

類似研究

アレ用の何か
ITfFnReconversion を使う例.

HTML5 Forms の type 指定がデスクトップ IMEに影響するという話

最近やっていた仕事について,一通りリリースが終わって誰でも試せる段階になったので書いてみる.Web アプリ開発者の人や,IME 作成者の人には影響があるかも知れない.ただし Windows デスクトップを相手にしていなければ,ここで読むのをやめてもなんら問題はない.

最近 Chromium と Firefox にパッチを書いて,HTML5 Forms の type 指定が InputScope として TSF ベースの IME (いわゆる Text Input Processors; TIP) やソフトウェアキーボードに通知されるようにした.これは,基本的に Windows 8 上での Internet Explorer 10 の動作に合わせたものである.具体的には,以下の環境で,各種ブラウザが InputScope をサポートするようになった.

  • Microsoft Internet Explorer 10以降 (ただし Windows 8以降)
  • Google Chrome 26以降 (ただし Windows Vista以降)
  • Mozilla Firefox 23以降 (ただし Windows Vista以降)

なぜこれが問題になるのか.それは,一部の InputScope が指定されたとき,(Windows Vista 以降の) MS-IME は自動的に自分自身をオフにするからだ.
モダンなブラウザの実装では,HTML5 Forms input 要素の type 属性に,number, email, tel, time (Firefox 23+ の場合のみ), url のいずれかを指定したときこの「一部の InputScope」に該当する.結果として,対応する InputScope を受け取った MS-IME は自分自身のモードをオフに設定する.

ポイントは,これが IME 自身の判断によって行われるモード変更ということだ.この挙動についてブラウザベンダーを責めるのは難しい.ブラウザは単に対応する InputScope を IME に伝えているだけである.この点で,非標準の CSS に存在する ime-mode とは大きく異なる (ただし,type = password だけは以前からブラウザ自身が IME をオフにしている).

影響を受けないのは,

  • TSF 非対応の IME を使っている場合
  • InputScope を無視する IME を使っている場合 (たとえば ATOK 2013 とそれ以前)
  • Windows XP で上記ブラウザを使っている場合

である.なお,各 InputScope に対する挙動は各 IME にゆだねられているため,今後のアップデートで振る舞いが変化する可能性もある.

まとめ

InputScope に対応したデスクトップブラウザ

  • Microsoft Internet Explorer 10以降 (ただし Windows 8以降)
  • Google Chrome 26以降 (ただし Windows Vista以降)
  • Mozilla Firefox 23以降 (ただし Windows Vista以降)

InputScope に対応した IME

  • Microsoft IME (Windows Vista以降)
  • Mozc / Google 日本語入力 1.11.x 以降 (TSF モードのみ)

HTML5 Forms の input 要素の type

  • number
  • email
  • tel
  • time (Firefox 23+ の場合のみ)
  • url

の組み合わせで,(結果として) IME がオフになる.これは IME が自主的に行っているもので,ブラウザ側から IME のオフを設定しているわけではない.この動作に関して意見がある場合,基本的には IME ベンダーへどうぞということになる.

謝辞

Mozilla Firefox への InputScope 対応パッチについて,Mozilla Japan の中野さんにレビュー等たいへんお世話になりました.この場をお借りしてお礼申し上げます.

余談 0

各ブラウザでの Forms の type と InputScope の対応については Mozc のデザインドキュメントでまとめておいた.詳細についてはそちらを参考にしてほしい.
https://code.google.com/p/mozc/wiki/InputScope#Scope

余談 1

Windows 8 の Immersive モードで,MS-IME 2012 は入力モードをカーソル周辺に表示するようになった.今後,自動モード変更が受け入れられていくためには,このようなモード表示は必須と考えられる.
f:id:NyaRuRu:20130707205612p:plain

余談 2

InputScope に応じて,IME は変換に関する挙動を最適化することができる.たとえば,InputScope が「サーチ」のときに名詞中心のサジェストを行う,といった最適化が考えられる.実際すでに MS-IME 2012 は InputScope が「サーチ」のときに,挙動を変えている.

余談 3

現在 W3C で (主にデスクトップ向けの) IME API が議論されている.その流れの中で Microsoft から inputmode という追加の属性が提案されている.
https://dvcs.w3.org/hg/ime-api/raw-file/tip/proposals/IMEProposal.html#inputmode-attribute
この属性を使うと,ひらがなモードやカタカナモードといった,より日本人になじみが深い入力モードを指定できるようになる.InputScope にはこういったモードが既に存在するため,将来的には「半角カタカナモード」が期待される入力フィールド,といったものが HTML5 で実現可能になる可能性がある.興味がある人が議論に参加して欲しい.

余談 4

Tablet PC の時代に InputScope が設計され,10 年以上たってようやく HTML と InputScope が結びついたわけであるが,ブラウザでの InputScope への取り組み自体は以前から存在する.
たとえば Google Summer of Code 2008 では,Mozilla に対して -moz-input-scope という拡張が試みられた.
https://wiki.mozilla.org/Community:SummerOfCode08:TSF

余談 5

Input 要素の type 指定だが,実際のところモバイル用途の方が需要は高い.理由として,ソフトウェアキーボードのレイアウトが Input 要素の typeによって変化すると便利であること,CJK以外の国でもソフトウェアキーボードが使用されること,が挙げられる.

Fcitx-mozc を試してみた

(4/7 追記) fcitx-mozc の master branch では下記の問題は修正されたようです.Great!


Fcitxのテストのお願い - いくやの斬鉄日記 というのがあったので,軽く動作を見てみました.環境はこんな感じ.

  • Ubuntu 13.04 Final Beta 64-bit
  • VMWare 9.0.2
  • Mozc / fcitx は 2013年4月6日午後8時(日本時間)の時点で,ppa:ikuya-fruitsbasket/fcitx に登録されていたバージョン

f:id:NyaRuRu:20130406212509p:plain
以下,ibus-mozc から後退する部分で気付いたものを列挙してみます.

一部の Ctrl 付きのショートカットが動作しない

  1. Open gedit
  2. Enable Mozc
  3. type "kyouha"
  4. hit Ctrl+H

Expected: "きょう"
Actual: "きょうは"

Mozc (というか Windows の代表的な IME は),F7 キー,F8 キー,F9 キーの代わりにそれぞれ Ctrl+i,Ctrl+o,Ctrl+p という感じのショートカットが用意されています (QWERTY 配列では横に並んでいることに注目).また,IME での入力中は Ctrl+h によってバックスペース相当の動作をすることも可能です.これらが fcitx-mozc では使えないようです.ibus-mozc 1.6.1187.102 では動作するはずです.
Mozc プロトコルでのモディファイアキーの扱いについては commands.proto で解説されて います.Windows 版 Mozc の keyevent_handler_test.cc にも大量にテストケースがあります.

ひらがな/カタカナキーが常にカタカナキーとして振る舞う

(On 109 Japanese keyboard)

  1. Open gedit
  2. Enable Mozc
  3. Type "a"
  4. Hit Shift+Hiragana/Katakana
  5. Type "i"
  6. Hit Hiragana/Katakana
  7. Type "u"

Expected: "あイう"
Actual: "あイウ"

期待される実装方法については ibus-mozc の以下のコードあたりが参考になるかと.
https://code.google.com/p/mozc/source/browse/trunk/src/unix/ibus/key_translator.cc?r=131#57

  {IBUS_Hiragana, mozc::commands::KeyEvent::KANA},
  {IBUS_Hiragana_Katakana, mozc::commands::KeyEvent::KANA},
  {IBUS_Katakana, mozc::commands::KeyEvent::KATAKANA},

https://code.google.com/p/mozc/source/browse/trunk/src/unix/ibus/key_translator.cc?r=124#377

  // Due to historical reasons, many linux ditributions set Hiragana_Katakana
  // key as Hiragana key (which is Katkana key with shift modifier). So, we
  // translate Hiragana_Katanaka key as Hiragana key by mapping table, and
  // Shift + Hiragana_Katakana key as Katakana key by functionally.
  // TODO(nona): Fix process modifier to handle right shift
  if (IsHiraganaKatakanaKeyWithShift(keyval, keycode, modifiers)) {
    modifiers &= ~IBUS_SHIFT_MASK;
    keyval = IBUS_Katakana;
  }

一時的な英数モードからシフトキーで復帰しない

  1. Unset "L_SHIFT" from "Extra key for trigger input method" in the Fcitx global config.
  2. Open gedit
  3. Enable Mozc
  4. Hit key as follows
    1. Down Shift key
    2. Hit a key
    3. Up Shift key
    4. Hit i key
    5. Hit u key
    6. Down Shift key
    7. Up Shift key
    8. Hit a key
    9. Hit i key
    10. Hit u key

Expected: "Aiuあいう"
Actual: "Aiuaiu"

MS-IME のローマ字モードには,Shift キーと共に入力を行うことで一時的に英数モードに入るという機能があるのですが、この入力状態はシフトキーを単独で押すことで解除できます。fcitx-mozc ではこの機能が働かないようです。ibus-mozc 1.6.1187.102 では動作するはずです.

ツールを起動する系のショートカットが動作しない

  1. Open the config tool of Mozc
  2. Enter key customize mode
  3. Add an entry as "Precomposition/F2/Launch word register dialog"
  4. Open gedit
  5. Enable Mozc
  6. Hit F2

Expected: word register dialog is launched
Actual: nothing happens

Mozc (というか Windows の代表的な IME )はショートカットキーで設定ダイアログを起動したり単語登録ダイアログを起動したりできるのですが,fcitx-mozc では機能していないようです.ibus-mozc 1.6.1187.102 では動作するはずです.

gedit で確定取り消しが動作しない

  1. Open gedit
  2. Enable Mozc
  3. Type "kyouha"
  4. Hit enter to commit
  5. Hit Ctrl+BackSpace

Expected: commit action is canceled
Actual: nothing happens

Mozc (というか Windows の代表的な IME )は直前の確定動作を取り消せるのですが,fcitx-mozc では機能していないようです.ibus-mozc 1.6.1187.102 では動作するはずです.

gedit で再変換が動作しない

(On 109 Japanese keyboard)

  1. Open gedit
  2. Type something
  3. Enable Mozc
  4. Select some text
  5. Hit Henkan key

Expected: The selected text is reconverted by Mozc
Actual: nothing happens

Mozc (というか Windows の代表的な IME は)選択した単語を再変換できるのですが,fcitx-mozc では機能していないようです.ibus-mozc 1.6.1187.102 では動作するはずです.


冒頭にも追記したとおり,ここに挙げた問題は全て master branch では修正済みのようです.良かった良かった.

2012年他にやったこと - Mozc 編

Mozc 1.10.1389.102 が公開されたということやっと書ける感じの 2012年やったこと - Mozc 編 - NyaRuRuが地球にいたころ の続き.2012 年にやっていたことの今回公開分.

Support IBus 1.5

Red Hat によって主導され,GNU/Linux 界隈で使われている Input Method Framework であるところの IBus が,メジャーアップデートにあたって設定ファイルの解釈を変えるという決定を下したところ,挙動の変化に気づいたユーザーが IME 側にバグを登録してくることになり,IME 側で設定ファイルを変更することで対処することになったという案件.
平常心平常心と自分に言い聞かせつつ淡々と対処.

Increase opaque buffer size for x32

Mozc が日本語入力を提供しているところの Chromium OS から,x32 でビルドすると static assert に引っかかったからバッファサイズ変更してねとやってきたバグ.こんな身近に x32 を検討中のプロジェクトがあったのかという驚きの気持ちで淡々と対処……したんだけど,その後色々あって Chromium OS の日本語入力は PNaCl でビルドした Mozc が使われることになったため,たぶんこの修正は無意味なはず……

プロセス間通信の AppContainer 対応

Windows 8 で導入された AppContainer サンドボックス下で動作するストアアプリから Mozc を使うにはどうすればよいか考えて実装する,というお仕事.
Mozc のように out-of-process 型の IME にとって,サンドボックスは天敵.実際 Windows 8 のベータテストの段階から色々実験を行っていて,AppContainer から外部プロセスへは単純に名前付きパイプで通信できないというのは分かっていた……んだけど同時にどうしようもなく過ぎていく日々.もちろん胃は痛い.マルチプロセス設計を見直すというのは,Mozc のコード規模では既に悪夢と言ってよく,ストアアプリ対応を諦めるという選択までもがかなりの現実味を持つという状況.ほんと胃が痛かった日々.
結局 AppContainer 導入による Windows 開発への影響 - NyaRuRuが地球にいたころ で紹介したように,名前付きパイプの DACL にエントリを追加すればよいという情報を発見しほっと胸をなで下ろしたのが 8 月頃.
ちなみにこの手法,API の説明を読むに,out-of-process で動作するアクセシビリティ系常駐ソフトへの配慮から残された裏口のようにも読める.変化と互換性の間で綱渡りをする Microsoft らしい配慮がなければ,今でも没入型 UI で Mozc は動作しないままだったかもしれない.
今回公開されたコードでは,以下のうち "(A;;GA;;;AC)" を足している部分がそれ.
https://code.google.com/p/mozc/source/browse/trunk/src/base/win_sandbox.cc?r=131#247

case WinSandbox::kSharablePipe:
  // Sharable Named Pipe:
  // - Deny Remote Acccess
  // - Allow general access to LocalSystem
  // - Allow general access to Built-in Administorators
  // - Allow general access to the current user
  // - Allow general access to ALL APPLICATION PACKAGES
  // - Allow read/write access to low integrity
  ssdl += L"D:(D;;GA;;;NU)(A;;GA;;;SY)(A;;GA;;;BA)";
  if (SystemUtil::IsWindows8OrLater()) {
    ssdl += L"(A;;GA;;;AC)";
  }
  ssdl += allow_user;
  if (SystemUtil::IsVistaOrLater()) {
    ssdl += allow_rw_low_integrity;
  }
  break;

Mozc を Windows 8 対応させるにあたって,最も重要だったのはこの一行だといっても過言ではない.

TSF 再対応

Windows 8 の没入型 UI では TSF ベースの IME (正確には Text Input Processor; TIP) 以外は使えないというのは割と知られた話.しかし実際の ところ迫害はこれにとどまらず,デスクトップモードでも IMM32 ベースの IME には次のような制限がある.

  • 言語バー API を使用して,通知領域にアイコンを表示できない
  • 言語設定から IME の設定画面を開けない

正直 Windows 8 では IMM32 ベースの IME は現実的とは言えないんじゃなかろうか.
このような理由もあって,Mozc を TSF に再対応させるのは割と早いうちから決心していた.もっとも,プロセス間通信の問題の方がより頭が痛かったので TSF の問題は割と放置気味だった.
プロセス間通信の問題が片付いて,Chromium の TSF 対応も一段落しところで,一人で淡々と TSF 対応を開始.それも無事 12 月中にすべてリリース.短期間に大量のコードレビューをこなしてくれた同僚に感謝.
こうして,IMM32/TSF との関わりがまた増えた.

  1. 学生時代に C# で TSF ベースの IME を途中まで作る
  2. 学生時代に Windows Vista 向け TSF 対応記事を書いたり CEDEC で講演したり
  3. 入社後,TSF で書かれていた初代 Mozc クライアントの開発を手伝う
  4. Windows XP 環境での CUAS に絶望し,IMM32 で Mozc クライアントをゼロから書き直す
  5. Chromium の TSF 対応を指揮
  6. Windows 8 向けに Mozc クライアントを TSF で書き直す (New!)

今回書き散らかしたコードはこのあたりに見ることができる.
https://code.google.com/p/mozc/source/browse/trunk/src/#src%2Fwin32%2Ftip

vcbuild から Ninja への移行

2012 年末,TSF 対応コードを一通りリリースし終わった後,同僚たちが休暇モードに入るのを横目に始めた年末ビルドパイプライン大掃除.
Mozc の Windows ビルドは,gyp のおかげで柔軟性が高く,ターゲットとなる Visual C++ のバージョンを変更するのは容易である.実際手元の開発では Visual C++ 2012 + Visual Assist X で快適開発ということが割と簡単にできている.一方,ビルドサーバーはいまだに Visual C++ 2008 を使っていた.これに関して最近以下のような懸念点があった.

  • Chromium がデフォルトコンパイラを Visual C++ 2008 から Visual C++ 2010 に移行した
  • Visual C++ 2010 になると,nullptr や auto が使えるようになる

そんなわけで,Mozc のデフォルトコンパイラを Visual C++ 2008 から Visual C++ 2010 に変更しようと思い立つ.
この変更で問題になるのは,従来コマンドラインからのビルドに使っていた vcbuild.exe が使えなくなり,.NET ベースの msbuild.exe に移行しなければならないことである.密閉型のビルドサーバーに .NET ベースの複雑な依存関係を持ち込むのはうれしくない.そこで,最近 Chromium でも併用されている ninja を使ってみることにした.
Ninja は,当時 Chromium チーム に在籍していた Evan Martin による make 代替ツールで,gyp や CMake のようなツールから自動生成されたビルド設定を読み込むことを前提に,とにかく高速に動作することを目指している.Ninja は Chromium 開発で多用されているだけでなく,最近は LLVM のような CMake 利用プロジェクトにもファンを広げているようだ.今回 vcbuild.exe ではなく Ninja を採用したもう一つの理由は,社内で勢いを持ちつつあるツールにはなるべく乗っかっておくという経験則もある.困ったときに聞きやすいし,自分の経験が同僚の役に立つこともある.
もっとも,Chromium 付随プロジェクトにありがちな話として,Chromium が必要になった部分だけ実装され,他は未実装というのは今回も同じ.Mozc を gyp + Ninja + Visual C++ 2010 で快適にビルドするには,gyp の Ninja 向けジェネレータ側にいくつか追加実装を行う必要があった.12 月頃せっせとパッチをアップストリームしている姿を以下に見ることができる.

移行は無事予定していた期間で終わり,現在の Mozc のビルドサーバーは gyp + Ninja + Visual C++ 2010 で動いている.

その名は「新しい (Windows) UI の…」

発端

マイクロソフト社がIEの舵取りに迷っている。同社は先週、Windows 8の“Windows ストアアプリ”として動作する「Internet Explorer 10」でFlashコンテンツを表示する際の方針を変更すると発表した。この方針転換が意味することを理解するためには、Windows 8が発売される前までさかのぼる必要がある。

【#モリトーク】第50話:IEのジレンマ - 窓の杜

という記事を読んだのだけど,どうも用語の使い方が危なっかしい.枝葉の部分ならともかく記事の論点に直結する部分だけに余計に気になる.というわけでちょっとだけ書いてみたのが以下.

Windows 8 向けブラウザの 3 分類

Windows 8 でウェブブラウザというと,大きく 3 種類に分けられる.

  1. いわゆる Windows ストアアプリであって,標準ブラウザコンポーネントを利用するもの
  2. いわゆるデスクトップアプリケーションとして動作するブラウザ
  3. Windows ストアアプリではないものの,Windows ストアアプリと同様の没入型 UI で動作するブラウザ

単独製品としての「Internet Explorer 10」が該当するのは 2 と 3 である.この厳密な定義に従えば,元記事にあった,

“Windows ストアアプリ”として動作する「Internet Explorer 10

なるものは,実は存在しない.元記事に登場する Google Chrome も同様で,“Windows ストアアプリ”として動作する Google Chrome というものは存在しない.Chrome もタイプ 2 とタイプ 3 で動作する.
なぜこの区別が重要かというと,タイプ 3 のブラウザは,没入型 UI で動作するという点ではタイプ 1 に近いものの,開発者視点ではむしろタイプ 2 のデスクトップアプリケーションとしてのブラウザに近いからだ.タイプ 1 ブラウザと対照的な,タイプ 3 のブラウザの特徴を挙げてみよう.

  • AppContainer サンドボックスが強制されず,Integrity Level Medium で起動される
  • WinRT に縛られず,デスクトップアプリケーションとほぼ同等の Win32 API にアクセスできる
  • Windows ストアを経由せずにインストールできる

このように,タイプ 3 ブラウザは,実際にはデスクトップブラウザと同じ技術で作られている.プラグイン的な実行時ライブラリの使用や,JIT コンパイルのような実行時コード生成についても特に技術的な制約はない.
もう一点強調しておくと,Windows 8 で没入型 UI が導入されるにあたって,こんな動作モードが許されたのはブラウザだけである.この動作モードが許されるのはデフォルトブラウザに限定され,その他のブラウザには許されないというところからも,今回の措置が例外的なものであることが透けて見える.

参考資料

Windows 8 のサードパーティー製ブラウザ事情については,Microsoft がブラウザ開発者向けに公開している Developing a new experience enabled desktop browser という資料に詳しい.なかでは,Windows 8 で動作するタイプ 3 のブラウザを開発する方法について解説されている.プロセス分離型ブラウザについても言及されているあたり個人的には好感度が高い.
ちなみにこの資料で,タイプ 1, 2, 3 ブラウザはそれぞれ以下のように呼ばれている.

  1. Windows Store app
  2. Desktop browsers.
  3. New experience enabled desktop browser

3 については,"New experience enabled" のあたりに没入型 UI を,"desktop browser" のあたりに API 的な側面を感じるとよいのではなかろうか.

きみの名は……

さて,以上の話を理解してから見る次のツイートは味わい深い.



背景事情が分かってしまえば簡単な話である.つまり,開発者向け資料で New experience enabled desktop browser と呼ばれる動作モードの IE が,ユーザー向けには "新しい (Windows) UI の IE"、"Windows 8 スタイルの IE" と紹介されているわけだ.まあ他に呼びようなかったのやもしれず.