2012年5月24日
ネイティブイベントをハンドリング中ではない場合に発行するイベントにモディファイアをセットしなくてはいけない場合に、正しくセットできていないというバグです。
この修正10.6以降では、[NSEvent modifierFlags]
を利用するようにし、10.5ではCarbon APIを引き続き利用するものの、その戻り値を正しくCarbonのモディファイアフラグからCocoaのモディファイアフラグに変換するようにしています。
このバグの修正でも引き続き、スクロール等による:hover
状態の反映に利用されているsynthesized mousemove
イベントには、モディファイアが引き続き正しく設定されていません。これに関してはbug-org 749553を参照してください。
Keycode ReimplementationのWindows版です。
Gecko(というかほとんどのブラウザ)はキーイベントのkeyCode
の値に、Windowsのキーメッセージで与えられるvirtual keycodeと同じ値で定義しています。おそらくNetscapeあたりが最初に実装した時から、それを見よう見まねで各社が適当にそれっぽく動くようにしたのが原因だと思いますが、とにかく標準的なルールが全く無く、US ANSIキーボード以外での値がブラウザ間で互換がとれていなかったり、Geckoでもプラットフォームごとに値が違うことが多いという状況でした。
これを改善すべく、簡単なルールを決め、GeckoのWindows版、Mac版、Linux(GTK)版ではほぼ同じ挙動をとるように今回改善しています。
そのルールは全プラットフォーム版をMDNにも記述しましたが、こちらではWindowsに絞った内容で紹介しておきます。
- Windowsではvirtual keycodeがAからZか、0から9のキーに対しては、これに対応したDOMキーコード(これに関してはそのままの値)を使用する
- それ以外の文字を入力するキーでは、そのキーで入力される文字がASCII文字の場合、それにあったキーコードを利用する
- もしその文字がASCII文字ではないものの、Shiftキーを押しながらだとASCII文字を入力できる場合、それにあったキーコードを利用する
- それ以外のキーに関してはそのキーにあったキーコードが利用される
- 上記ルールで対応するキーコードが求められない場合は0とする
Windowsではこれまで+
を入力するキーと、-
を入力するキー以外では、システムのvirtual keycodeをそのままDOMキーイベントのkeyCode
に設定していました。平たく言うと、何も考えずに垂れ流ししていたわけです。このままでは他のプラットフォームでは手詰まりに陥るのでWindowsでもきちんと対応するDOMキーコードを自身で定義しているか確認し、存在しない場合にはゼロとするようにしています。
Windowsではあまりキーコードが変化するキーはありませんが、Windowsキーには新たに専用のキーコードが割り当てられています。
JISキーボードの;+キーはDOM_VK_PLUS
ではなく、DOM_VK_SEMICOLON
に変化しています。他の記号キーに関してもいくつか変わっている可能性はあります。ただ、元々文字を入力するキーのkeyCode
値をkeydown
もしくはkeyup
イベントでチェックすべきではないので実際のWebアプリへの影響は限定的だと思います。
Keycode ReimplementationのMac版です。
Mac版は以下のルールでkeyCode
の値を決定します。
- 文字入力のためのキーでは無い場合、Macのネイティブイベントのキーコードから対応するキーのDOMキーコードを用いる
- Macのネイティブイベントのキーコードが0から9のキーであることを示す場合、これに対応したDOMキーコードを用いる
- それ以外の文字入力可能なキーの場合、shiftキー、optionキー無しで入力される文字がASCII文字ならそれにあったDOMキーコードを用いる
- もし、その文字がASCII文字ではなかった場合、shiftキーを押した際に入力される文字がASCII文字ならそれにあったDOMキーコードを用いる
- もし、そのキーボードレイアウトがASCIIアルファベットを入力可能なレイアウトだった場合(具体的に言うと、
kTISPropertyInputSourceIsASCIICapable
プロパティがtrue
の場合)、DOMキーコードは0とする
- それ以外の場合、その時のASCIIアルファベット入力可能なキーボードレイアウト(具体的に言うと
TISCopyCurrentASCIICapableKeyboardLayoutInputSource()
で返されるキーボードレイアウト)で、そのキーがASCIIアルファベットか、ASCIIの数字を入力可能な場合、それにあったDOMキーコードを用いる
- それ以外の場合は0とする
ASCIIアルファベットを直接入力できないキーボードレイアウトの場合(例えばアラビア語、ヘブライ語、キリル文字、タイ語等)がWindowsより複雑です。
Macの日本語版キーボードには英数キーが存在していますが、この挙動がことえりをはじめ、MacのIMEはかなキーと対になっています。ですが、かなキーにはDOMキーコードが割り当てられていますが、英数キーには割り当てられていなかったので、新たにDOM_KEY_EISU
という値を定義してマッピングしています。ちなみに、動作が違うのでWindowsの英数キーはこのキーコードを返すようには修正していません。
Keycode ReimplemtationのLinux(GTK)版です。
Linux版のキーコードは以下のルールで決定されます。
- GDKキーイベントのキーコードがモディファイアキーの場合、他にモディファイアキーが押されていないか、単体でそのキーを押した場合に別のモディファイアキーには変化しないなら、そのモディファイアキーのDOMキーコードを用いる。もし、単体で押した時に別のモディファイアキーとして動作するのであれば、単体で押した時のモディファイアキーにあわせたDOMキーコードを用いる
- 文字入力キーではない場合、そのキーを単体で押した時の機能に対応したDOMキーコードを用いる。もしこの結果が0であれば、現在のGDKキーイベントで与えられたキーコードからDOMキーコードを求める(つまりモディファイアキーで変化した機能からDOMキーコードを求める)
- 文字入力キーの場合、そのキー単体で入力される文字がASCIIアルファベットか、ASCIIの数字の場合、それにあったDOMキーコードを用いる
- それ以外の場合、そのキーとShiftキーで入力される文字がASCIIアルファベットか、ASCIIの数字の場合、それにあったDOMキーコードを用いる
- それ以外の場合かつ、現在のキーボードレイアウトではASCIIアルファベットが入力できない場合(具体的には
GDK_a
キーでASCIIアルファベットを入力できない場合)、システムにインストールされているキーボードレイアウトの中で、ASCIIアルファベットの入力可能な最も優先順位の高いキーボードレイアウトで、そのキーが単体でASCIIアルファベットかASCIIの数字が入力可能ならそれにあったDOMキーコードを用いる。それ以外の文字の場合にはShiftキーを押した場合についても確認する
- それ以外の場合、現在のキーボードレイアウトで、そのキーが単体でASCII文字を入力できる場合はそれにあったDOMキーコードを用いる
- それ以外の場合、現在のキーボードレイアウトで、そのキーがShiftキーが押されている場合にASCII文字を入力できる場合はそれにあったDOMキーコードを用いる
- それ以外の場合、0
ASCIIの文字や数字以外の場合の他のキーボードレイアウトを参照するタイミングがMacとは異なっていますが、よほど特殊なキーボードレイアウト同士の組み合わせでなければこれによる差はでないと思います(この差はレビュアの考え方の差)。
Xのキーボードに関する仕様が少しアレなので、他のプラットフォームに対して非常にややこしいルールになっているように見えますが、意外と他のプラットフォームと実際には変わりません。変わるとしたら、バリバリとカスタマイズしたキーボードレイアウトをユーザが自作した場合だと思います。
ちなみに、Linux(GTK)には明確にAltGrにあたるキーが存在しているので、DOM_KEY_ALTGR
というキーコードが定義されて割り当てられています。
2012年5月31日
Bug-org 630810の修正によるWindows版のみのregressionです。
タイ語のキーボードレイアウトでは+
はShift+1キーで入力できるのですが、このキーはVK_2
が割り当てられていて、ANSI USキーボードレイアウトの=/+キーにあたる、ชキーにVK_OEM_PLUS
が割り当てられていました。
Windowsのネイティブアプリケーションは仮想キーコードを元にショートカットキーを処理しているようで、IE9ではCtrl+ชでズームインできるようになっているので、これにあわせて、一部のキーコード向けに特殊処理を追加しました。
VK_OEM_PLUS
、VK_OEM_COMMA
、VK_OEM_MINUS
、VK_OEM_PERIOD
キーはレイアウトに関係無く、+
、,
、-
、.
キーにあたるとMSDNで定義されていますので、これらのキーが押された場合、そのキーがショートカットキーとして処理されるべきである文字候補のリストの末尾にこの文字を追加するようにしました。ただし、その文字がそのキーによって入力できる場合は従来までと処理の変更はありません。
これは他のプラットフォームのGeckoとは異なる処理ですが、プラットフォームのネイティブアプリケーションのマナーに従うことを優先しています。
Bug-org 677252の修正によるregressionです。
デッドキーで文字を入力した時に、アクセント記号とベース文字が適当な組み合わせではない場合、アクセント記号とベース文字、二文字として確定されます。
このケースの場合、Cocoaでは、insertText
が一文字ずつ2回呼び出され、二回目のキーのkeyDown
で渡されたイベントには二文字とも入っている、という不思議な状態になります。
原因となった修正ではkeypress
イベントの初期化を一カ所にまとめた際に、それまでのコードに従ってキーイベントの一文字目をkeypress
イベントのcharCode
に設定するようにしたため、's
と入力したい場合に'
と'
と入力されてしまうことになっていました。
修正方法は悩んだのですが、keypress
イベントの初期化時に予めcharCode
値が入っていた場合はその文字の入力イベントを初期化しろという指示だと受け取るように書き換えました。
Bug-org 758420の修正によるregressionです。
keypress
イベントの初期化を一手に行うメソッドが意図せずcharCode
を上書きしてしまわないようにassertion
を埋め込んでいたのですがその条件を間違えていて常に出力されてしまってました。