![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ||
![]() | ![]() | ![]() | ![]() | ![]() |
|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
以下は、Mac OS X 10.5.5 上の Xcode 3.1 で説明しています。このサンプルは、NumberInput 0 から NumberInput 4 までの 5 段階に分かれていて、何もしないものから次第に高度な機能をもつものへと拡張されていきます。
| 1 NumberInput 0 | 2 NumberInput 1 | 3 NumberInput 2 | ||
| 4 NumberInput 3 | 5 NumberInput 4 | 6 更新履歴 |
| 1.1 ReadMe の日本語訳 1.2 ビルドとインストール 1.3 グループとファイル 1.4 Info.plist 1.5 main.m 1.6 NumberInputController クラス |
このプロジェクトは、何も行わない InputMethodKit の入力メソッドを実例で示します。
プロジェクトには、3 つのソースファイルが含まれます。それらは以下のものです。
入力コントローラーを宣言します。新しい InputMethodKit クラスの IMKInputController のサブクラスを作成する Objective-C オブジェクトです。
入力コントローラーを定義します。このインスタンスでは、単一の何も行わないメソッドが定義されています。このメソッドは -(BOOL)inputText:(NSString*)string client:(id)sender で、もともとファイル IMKInputController.h で定義されていたものです( /System/Library/Frameworks/InputMethodKit.framework/Headers/ を見てください)。このメソッドは、キーボード入力を最終的に受けとることになります。このサンプルでは、単に、キーボード入力が利用側に渡されたほうがいいことを意味する NO を返します。
入力メソッドの進入点 (entry point) を含んでいます。このファイルは、また、IMKServer のインスタンスを割り当てます。サーバーオブジェクトは、NSConnection を通じて利用側アプリケーションと通信します。また、入力メソッドの入力コントローラーオブジェクトの各インスタンスとも通信します。
別の重要なファイルは、Info.plist ファイルです。このファイルには、入力メソッドについての必須情報が含まれていて、それは詳細にコメントされています。ここでどんな情報が提供されているかを調べるために、このファイルを見てください。
単に Xcode でプロジェクトをビルドします。プロジェクトがビルドされた後で、結果のアプリケーションを /Library/Input Methods/ へとドラッグし、ログアウトします。この初期インストールとログアウトの後では、再びログアウトする必要はないはずです。
システム環境設定 (System Preferences) を開いた後、言語環境 (International) を選択し、入力メニュー (Input Menu) タブを選択します。入力メソッドとキーボードレイアウトのリストを目にすることになります。
Number Input という名前の入力メソッドを探し、そのとなりのラジオボタンをクリックします。これで、Number Input 入力メソッドがテキスト入力 (Text Input) メニューへと追加されることになります。
ここで、テキストエディット (TextEdit) アプリケーションを開き、テキスト入力メニューへと行き、NumberInput を選択します。タイプ入力を行ったとき、文字は入力メソッドへと渡されることになり、それはその文字列をログ出力し、NO を返します。
NO を返すことは、入力が処理されず、利用側アプリケーションに渡されたほうがいいことを意味します。コンソール (Console) アプリケーションからログ出力された入力を見ることができます。
これで、何もしない入力メソッドをビルドし、インストールできました。
ソースを調べていく前に、このサンプルをビルドして動かしてみます。プロジェクトファイルを開いてわかるのが、テキストサービスマネージャーを利用した入力メソッドコンポーネントとは違い、入力メソッドキットを利用した入力メソッドがアプリケーションであるということです。これはターゲット > 情報 > プロパティで、タイプが APPL として指定されていることでもわかりますし、main.m 内で NSApplication が起動されていることでもわかります。そのため、BasicInputMethod の解説で書いたような、コンポーネントに対するリソース設定などは必要ありません。もちろん、情報プロパティリストの設定など、通常のアプリケーションとは違うため、気をつけなければならないことはいくつかあります。
説明は後にして、まずビルドして、動作を調べてみましょう。ReadMe の説明のように、ビルドして、ファイルをドラッグし、ログアウト、または再起動します。ログインした後で、システム環境設定を開き、言語環境 > 入力メニューへと移動すれば、以下のようになっています。KIM は私独自のテキストサービスマネージャー利用入力メソッドなので気にしないでください。自分しか使わないため、BasicInputMethod のアイコンに色を塗って使っていたりします。
![]() |
上のように、NumberInput を有効にします。そして、テキストエディットアプリケーションを開きます。まず、入力メニューから NumberInput を使うように選択しなければなりません。以下は、選択した後で、再びメニューを開いたときの表示です。キーボードレイアウトを選択した時と同じで、中間に入れられる入力メソッド独自のメニューが何もないことがわかります。
![]() |
それから、「123456」と入力した後でリターン、「cocoa break」と入力した後でリターンを押します。押した文字がそのまま入力されているのがわかります。同時にコンソールでログ出力が行われているのもわかるでしょう。リターンキーの入力はログ出力されていないことに注意してください。
![]() |
プロジェクトの構成は、以下のようになっています。
![]() |
クラスファイルは NumberInputController.h と .m で、これは ReadMe で説明されていたとおりです。そして、main.m があり、これがアプリケーションのメイン部分です。
通常とは違うものとしては、Resources の nine.tif、そして Other Frameworks の InputMethodKit.framework があげられます。また、InfoPlist.strings もプロジェクトテンプレートなどの空の状態とは違い、きちんと内容をもっているので注意してください。InputMethodKit.framework は、Linked Frameworks に置かれていませんが、ターゲットの「バンドルをライブラリにリンク」で、Cocoa と InputMethodKit の両方にリンクを行っているので注意してください。
リソースの MainMenu.nib ですが、以下に示すように、このサンプルのものは内容を持っていません。代理オブジェクトのみがあるだけです。
![]() |
さて、ReadMe にも書かれていたように、このファイル内に入力メソッドが行うべき設定がいくつかあります。それにコメントが付けられていますが、Xcode のデフォルトでは、このファイルは XMLPropertyList として、キーと値の表として表示されてしまい、コメントが見られません。環境設定 > ファイルタイプ で、text.plist を Plain text file(標準テキストファイル)とすることで、Xcode 内でこのファイルをテキストとして見ることができます。ただし、この設定をする前に、ファイルを見ていた場合、キャッシュが残ったままなので、環境設定を変えても表示が変わりません。一度、プロジェクトを閉じて、再び開く必要があります。一時的にだけ見たいなら、外部のテキストエディタを使って、このファイルを開いたり編集するといいでしょう。デフォルトのプロパティリスト表示は以下のようになります。
![]() |
テキストエディタで開いた場合は、以下のようになります。不要な部分は省いています。
最初のほうの項目は、通常のアプリケーションと同じですす。表の表示と、テキスト内容を比べてみてください。Xcode 内での表示は、各キーの名前ではなく意味を示していることがわかります。途中のコメントから以降が入力メソッドに必須の項目になります。
最初の LSBackgroundOnly は、バックグラウンド専用アプリケーションであること意味します。これを指定すれば、ユーザーインターフェースは一切表示できません。以前のテキストサービスコンポーネントでは、サーバーアプリケーションの情報プロパティリストで、これを設定していました。パレット等を表示する場合は、LSUIElement を指定することで、パレットを表示していました。ネット等で、入力メソッドキット使用の場合は、サーバーは LSBackgroundOnly でないとダメという情報を目にしましたが、LSUIElement で動作しないのか確かめていませんので真偽は不明です。いずれ確認してみたいと思います。
以降は、接続のための NSConnection で使われる名前、入力コントローラークラス、アイコンファイル、文字範囲です。この文字範囲は、以前のコンポーネントでは、リソース内やコードで指定していたものです。今回も、情報プロパティリストの指定と、メソッドによって返される値が別々になっているようです。前者はシステム環境設定等で使われるもので、後者は実際に利用するアプリケーションなどから問い合わされるものです。
コメントもあるため、十分理解できると思うので、情報プロパティリストについてはこのぐらいにして、さっそくソースを見てみましょう。まずは、メインの部分である main.m です。
main.m では main 関数が定義されています。これが、実行可能形式の進入点になります。main 関数の前に、変数等が設定されているので、まずそちらを見てみます。
さて、最初に接続名が定義されています。これは情報プロパティリストにあったものと同じですが、コード内で使えるように、定数文字列として確保しています。
つぎに、グローバル変数としてサーバーを宣言しています。コメントにもあるようにアクセスを簡単にするためです。
いよいよ、main 関数です。どうなっているのでしょうか。それを見る前に、参考として Cocoa アプリケーションの新規プロジェクトテンプレートにおける main 関数がどんな風であるか見てみます。
main 関数この関数内では、アプリケーションオブジェクトを作成し、主要 nib ファイルを読み込み、アプリケーションを実行しています。では、このサンプルの main 関数を見てみましょう。
まず最初に、自動解放プールが作られていることに注意してください。Foudation ツールを含む、Cocoa 利用アプリケーションでは、NSApplicationMain 関数を使わないで、自分で main 関数を書くなら、必ずこれを最初に行います。自動解放オブジェクトは、Cocoa メソッド内で内部的に使われたりしている可能性もあるため、Cocoa メソッドを呼ぶ前に必ず自動解放プールを 1 つ作っておき、終了前にそれを解放します。これは、通常の Cocoa アプリケーションと同じ手順です。
つぎに自身の主要バンドルのバンドル識別子を取得しています。これは、次の初期化メソッドで必要になるためです。ただし、次の文で identifier を使っていません。使うように変更するか、逆に identifier の宣言と取得行を除去して OK です。それから、先ほど説明したグローバル接続名を使って、サーバーオブジェクトを初期化します。この初期化メソッド内で、指定されたバンドルの情報プロパティリストを使って、サーバーを初期化することになります。利用される項目は、先ほど Info.plist で説明した必須項目にあたるもので、このためにも情報プロパティリストを設定することが必要だったわけです。ここで名前には、接続名と同じものが使われていますが、接続に利用する名前は情報プロパティリストで指定されていますので、同じものである必要はありません。
つぎに、主要 nib ファイルを読み込んでいます。コメントにあるとおり、通常は自動で読み込まれますが、この場合バックグラウンド専用なので、明示的に読み込む必要があります。
最後に、アプリケーションを実行しています。他のアプリケーションで入力メソッドの要求があったとき、最初に作られたサーバーインスタンスがそれに応答し、個別のセッションごとに、入力コントローラーインスタンスを作って、それを使うことになります。テキストサービスコンポーネントでは、他アプリケーション内で読み込まれるコンポーネントという形でした。入力メソッドコントローラーも、接続を通じてサーバーと通信する形になっていますので、他アプリケーション内に内部的なコンポーネントが入力コントローラークラスをベースにして作られているのかもしれません。
さて、次に個別の要求の際に作られる、入力コントローラークラスを見てみましょう。
NumberInputController クラスまずヘッダファイルを見てみます。これは非常に簡単です。
このように、NumberInputController クラスは、IMKInputController のサブクラスとして宣言されています。インスタンス変数がなく、継承メソッド以外のメソッドを定義していないので、内容は空になっています。
つぎに、実装ファイルを見てみましょう。まず、クラスの実装宣言があり、その下にコメントが付けられています。これは IKMServerInput プロトコルリファレンスで説明されていることと同じです。リファレンスの翻訳を見てください。簡単にまとめると、IKMServerInput プロトコルでテキスト入力を受けとって処理するのに、キーバインディングを使う方法(このサンプル)、テキストデータのみ、すべてのイベントを処理、という 3 つの方法があるということです。
ここでは、最初の方法を使っていて、この方法では、didCommandBySelector:client: と inputText:client: を使います。システムがキー入力を受けとったら、キーダウンイベントを入力メソッドが実装するアクションメソッドへと対応付けようとします。見つかった場合、didCommandBySelector:client: が呼ばれ、見つからなかったら inputText:client: が呼ばれます。このサンプルでは、文字入力を処理する後者だけが実装されています。
inputText:client:このメソッドでは、単に入ってきた文字をログ出力しているだけです。コメントにもあるように、キーダウンイベントがそのまま渡されるように NO を返しています。「ビルドとインストール」の画像で、コンソールを示しましたが、あの出力はこのメソッドからなされていたものです。このメソッドが呼ばれていることが確認できます。
これで、このサンプルの最初のものについては、ほぼわかったと思います。InfoPlist.strings は説明していませんが、通常のアプリケーションでローカル化のために使われるものとほぼ同じなので、説明していません。実際には他にモード名などのローカル化もありますが、サンプルのこの段階では使われないため、説明を省きました。
入力メソッドとは言っても、サンプルのこの段階では何も行っていません。そのため、ビルドやインストールを行っても、入力メソッドという実感がないかもしれません。次の段階から、じょじょに機能が増やされていきます。(以下、次ファイルへと続く。)
![]() | ![]() |
![]() |
管理人:神吉 秀典 E-mail: