キー入力のオーバーライド
ここには、Text View に対してのキー入力のオーバーライドについてメモしていく。Table View でも同じようにオーバーライドはできた。
基本的には、NSTextView のサブクラスを作ってそこで keyDown をオーバーライドする。
こんな感じ。
include OSX
class InputTextView < NSTextView
def keyDown(event)
(ここに処理を入れる)
end
end
この event に入力されたキーの情報が入ってる。これは AppController のファイルに含めてもいいし、別のファイルを作ってもいい。AppController が短ければ入れたら楽かも。
まず、次のようなウィンドウを Interface Builder で作ってみた。英語の発音記号を入力する簡単なプログラム。ここでは母音だけ。普通にキーボードから入力できるものは除いてある。
AppController の outlet として、window と text をそれぞれ Window と TextView に結びつけた。
ボタンを押すと、入力できるようにもしたいので、次のようなメソッドを書いて、このアクションをすべてのボタンと結びつける。
def inputIPA(sender)
@text.insertText(sender.title)
end
ib_action :inputIPA
ついでに、フォントもちゃんと表示できるものにしたいので、awakeFromNib でフォントの設定をする。
def awakeFromNib
@text.setFont(NSFont.fontWithName_size("Lucida Grande",24.0))
end
さて、ここからが本番。NSTextView のサブクラスを作る。とりあえず、何が入力されたか知りたいので、文字と Key Code を見れるようにする。keyDown(event) メソッドをオーバーライドして、得られた NSEvent オブジェクトに対して characters や keyCode を使って文字や key code を得る。
class InputTextView < NSTextView
def keyDown(event)
p event.characters p event.keyCode end end
ここで Interface Builder に戻って、TextView をこのサブクラス(InputTextView)と結びつける。TextView を選んで Inspector の Identity で、Class から上で作った InputTextView を選ぶ。
今回のように Text View が一つしかないとかのときには関係ないんだけど、これを書いてるときに理解したのでここにメモ。(いずれはどこか別の項目に移すつもり)。
アプリケーションを立ち上げたときに、最初にフォーカスがあたっていてほしい View を指定したい場合は、その View を InitialFirstResponder にする。方法は、nib ファイルのその View がある WIndow を右クリックするか Window そのものを右クリックして、そこにある InitialFirstResponder を View に結びつける。
これでアプリケーションを立ち上げたときにこの TextView にフォーカスがあたっているはず。まあ、一つしかなければそれにあたるはずだけど。
さて戻って、これで保存する。試しに Xcode でビルドして実行すると、押したキーの文字と Key Code が表示される。a のキーを押した場合、次のような値が返る。
#<NSCFString "a">
0
この情報を使って、オーバーライドの設定をする。発音記号の入力には数字を使わないので、キーボードの数字の1から8に割り当ててみる。
ボタンに割り当ててある発音記号を使いたいので、サブクラス内でボタンを outlet をつくる。
ib_outlets :key01, :key02, :key03, :key04, :key05, :key06, :key07, :key08
これらをそれぞれのボタンに結びつける。
ここで、プログラムを実行して1から8までのキーの Key Code をメモっておく。次の通りなんだけど、なぜ順番じゃないんだろう?
18,19,20,21,23,22,26,28
これらの Key Code を得たときに、対応するボタンにアクセスしたいので、次のような Hash を作る。
@keyHash = Hash[*[18,@key01,19,@key02,20,@key03,21,@key04,23,@key05,22,@key06,26,@key07,28,@key08]]
これで、@keyHash[18](1のキー)が @key01 になる。これは、サブクラス内で awakeFromNib に入れておく。
ただし、これだけだと Shift、Option、Control キーなどを押していても、それぞれのキーに割り当てられている key code が変わるわけではないので、同じ key code が返ってくる。そこで、modifierFlags で一緒にどのキーが押されているかを捕まえる。
event.modiferFlags
いくつかのキーの組み合わせをここにメモしておく。
そして、次のようなスクリプトを書いてみた。
if @keyHash[event.keyCode] != nil && event.modifierFlags == 256
insertText(@keyHash[event.keyCode].title)
else
super_keyDown(event)
end
ここでしているのは、まず、@keyHash に得られた Key Code を入れてボタンが割り当てられていて、かつ修飾キーが押されていない場合は、ボタンの title(ボタンにある文字)を TextView に insertText で挿入する。何も割り当てられていなければ、nil が返るので、その場合は、super_keyDown(event) で入力された文字もしくはそれ以外のキー入力をそのまま処理する。修飾キーが押されている場合も同様。
追記:以前は、modifierFlags で得たキーコードを判別して使ったけど、実は、ちゃんと modifierFlags を扱う方法が用意されてた(まあ当然か)。
下に書いた定数を使って判別できる。例えば、コマンドキーを押しているかを判別したい場合は、NSCommandKeyMask を使って、次のように書く。(!= 0 か > 0 かとにかく、0 じゃない判定をする。)
if event.modifierFlags & NSCommandKeyMask != 0
処理
end
テンキーには、カーソルキーも含まれるようだ。
これで、すべて保存して実行すると、1から8のキーを押したときだけ、発音記号が入力される。ボタンをクリックしても入力できる。
最後に、このスクリプトの全容。このスクリプトをキャプチャーした時点では修飾キーのことを考慮に入れてなかったので入ってない
いずれは直すつもり。
require 'osx/cocoa'
include OSX
class AppController < NSObject
ib_outlets :window, :text
def inputText(sender)
@text.insertText(sender.title)
end
ib_action :inputText
def awakeFromNib
@text.setFont(NSFont.fontWithName_size("Lucida Grande",24.0))
end
end
class InputTextView < NSTextView
ib_outlets :key01, :key02, :key03, :key04, :key05, :key06, :key07, :key08
def keyDown(event)
if (event.modifierFlags & NSControlKeyMask) != 0 && @keyHash[event.keyCode] != nil
insertText(@keyHash[event.keyCode].title)
else
super_keyDown(event)
end
end
def awakeFromNib
@keyHash = Hash[*[18,@key01,19,@key02,20,@key03,21,@key04,23,@key05,22,@key06,26,@key07,28,@key08]]
end
end