ページ

2009年6月21日日曜日

ホットキー変更対応(10) - キー入力値と表示文字の変換表を作る

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

結局、キー入力値と表示文字(文字列)の対応表を作る事にした。
キー値は Event.h の値を使うことにする。これは現在のホットキー実装が Carbonを使っているから。

まずは Cの構造体でソースへ埋め込むことにする。
こんな感じ。

static const struct {
UInt32 keycode;
NSString* description;
NSString* string;
BOOL is_hotkey;
}
keymap[] = {
{ kVK_ANSI_A , @"A" , @"A" , YES },
{ kVK_ANSI_S , @"S" , @"S" , YES },
{ kVK_ANSI_D , @"D" , @"D" , YES },
{ kVK_ANSI_F , @"F" , @"F" , YES },
:


最初のkeycodeは Event.h で定義されているキー値。続く descriptionはデバッグ用の説明文字列。3番目は画面表示用の文字列。そして最後はホットキー利用の可否を表すフラグ。

定義されているキーはすべて使えるわけではなく、例えばエスケープキーなどは使えない。これを判断するために is_hotkey を設けてある。

- - - -
さて、これを使って入力キー値を表示させようとするが NSTextFiledが keyDown: を受け取れないことを思い出した。これは困った。さてどうするか。

2009年6月20日土曜日

ホットキー変更対応(9) - AppleSpecificCodePoints を試す

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回紹介した AppleSpecificCodePoints を実際に表示させてみた。

CocoaDev: AppleSpecificCodePoints

コードはこんな感じ。

static const struct { NSString* name; unichar code; } KeyGlyphs[] =
{
{ @"pb_enter", 0x2324 },

{ @"left", 0x2190 },
{ @"up", 0x2191 },
{ @"right", 0x2192 },
{ @"down", 0x2193 },

{ @"ib_left", 0x21E0 },
{ @"ib_up", 0x21E1 },
{ @"ib_right", 0x21E2 },
{ @"ib_down", 0x21E3 },

{ @"home", 0x2196 },
{ @"end", 0x2198 },
{ @"return", 0x21A9 },
{ @"pageup", 0x21DE },
{ @"pagedown", 0x21DF },
{ @"tab", 0x21E5 },
{ @"backtab", 0x21E4 },
{ @"shift", 0x21E7 },
{ @"control", 0x2303 },
{ @"enter", 0x2305 },
{ @"command", 0x2318 },
{ @"modifier", 0x2325 },
{ @"backspace", 0x232B },
{ @"delete", 0x2326 },
{ @"escape", 0x238B },
{ @"numlock", 0x2327 },
{ @"help", 0x225F },
};

- (void)awakeFromNib
{
for(int i=0; i < sizeof(KeyGlyphs)/sizeof(KeyGlyphs[0]); i++) {
NSLog(@"0x%x : %C : %@", KeyGlyphs[i].code, KeyGlyphs[i].code, KeyGlyphs[i].name);
}
}


実行してみよう。

デバッガコンソールへ出力された結果は次の通り。



なるほど一通り揃っているようだ。

- - - -
キー値を文字コードに変換する関数もあるようだが、今のところ分かった限りでは最低でも特殊キー(ESCや矢印)は自前で表(キーコード対Unicode)を用意する必要がありそうだ。
となると以前紹介したように始めから全コードを対象にした表を持っていた方がいい気がしてきた。

2009年6月19日金曜日

ホットキー変更対応(8) - 入力キーを表示文字へ変換するには?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

入力されたキーコードを表示用の文字コードに変換する方法についてネットで調べてみた。


これはまさに同じ問題を扱っている。問題解決の参考になる URLが紹介されている。
Cocoabuilder - KeyTranslate and UCKeyTranslate question

ここでは特殊な文字については自前でUnicode Character Pointの配列を用意する方法が紹介されている。
Cocoabuilder - Re: Key codes and characters in NSEvents

上記で紹介されていた方法をまとめたもの。サンプルコードもある。
CocoaDev: AppleSpecificCodePoints

Glyph Access Protocol についての解説(Unicodeに含まれない unencodedな Glyphについて)。
Technical Note TN2079: Glyph Access Protocol

Carbon’s HIToolbox framework に含まれる Text Input Serviceのリファレンス。前回はこの中の関数を使った。
Text Input Source Services Reference

その他、参考で。
Unicode Utilities Reference

- - - -
うーむ。
キーの表示くらい簡単に行くかと思っていたが奥が深い。。

2009年6月18日木曜日

ホットキー変更対応(7) - キーを表示する(その2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回紹介した方法では入力キーを表現する為に plistで文字を用意していた。
SimpleCapでもその方法を取ろうかと思ったが、APIぐらいあるんじゃないかとも思い調べてみた。

すると情報があった。

Cocoa-dev - virtual keycode to character

この情報によると Carbonで用意されている関数を使うと入力キーを文字表現に変換することができるらしい。

早速試してみよう。幸いソースコードもこのメーリングリストに出ている。
Re: virtual keycode to character


こんな感じになった。デバッガコンソールへ表示するようにしてある。
AppController.m

- (void)awakeFromNib
{
UInt32 key = 29; //'0'
UInt32 dead_key_state = 0;
UniCharCount count = 0;
UniChar base_char;

TISInputSourceRef source_ref = TISCopyCurrentKeyboardLayoutInputSource();
CFDataRef unicodekey_layout_ref = (CFDataRef)TISGetInputSourceProperty(source_ref, kTISPropertyUnicodeKeyLayoutData);
CFRelease(source_ref);

UCKeyTranslate((UCKeyboardLayout*)CFDataGetBytePtr(unicodekey_layout_ref),
key,
kUCKeyActionDown,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&dead_key_state,
1,
&count,
&base_char);
NSLog(@"%C", base_char);}



実行してみよう。キーコード 29 は '0'と表示されるはず。
[Session started at 2009-06-18 22:25:17 +0900.]
2009-06-18 22:25:19.105 HotkeyUI[1667:10b] 0


出た。'0'だとわかりずらいので他のコードを試してみよう。

'c' (0x08)はどうだ。
[Session started at 2009-06-18 22:27:58 +0900.]
2009-06-18 22:27:59.200 HotkeyUI[1727:10b] c


出た。

TABキー (0x30)はどうだ。
[Session started at 2009-06-18 22:31:15 +0900.]
2009-06-18 22:31:17.820 HotkeyUI[1827:10b]


出ない。

ESCキーなど特殊なキーの場合は特別文字が割り当てられないようだ。

2009年6月17日水曜日

ホットキー変更対応(6) - キーを表示する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回修飾キーまでは表示することができた。後は通常のキーを表示するのだが、イベント判別用にキーに割り当てられているコードと、画面表示用に割り当てられるキャラクターコードが異なっている。これをなんらか変換してやる必要がある。

以前紹介したソースコードを見ると変換用のテーブルを言語とに plist で持っていた。
下記は japanese.lproj 下の PTKeyCodes.plist。他に English.lproj や Frentch.lproj などが用意されていた。


なるほど。これならキー表現をローカライズして提供できる。

なおこのキーの割当(0 => 'A')は Events.h (Carbon)の中で定義されている。
Events.h

enum {
kVK_ANSI_A = 0x00,
kVK_ANSI_S = 0x01,
kVK_ANSI_D = 0x02,
kVK_ANSI_F = 0x03,
kVK_ANSI_H = 0x04,
:
:


さて今回はどうするか。

2009年6月16日火曜日

ホットキー変更対応(5) - 修飾キーを表示する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

入力は後回しにして先に表示を片付けよう。

まずは表示確認用にcommand+option+0 を表す値を NSUserDefaultsへ固定で入れておく。これが画面上 command option 0 (それぞれ記号)で表示されれば良い。

表示確認用の値は - [AppController awakeFromNib]で設定する。

AppController.m

- (void)awakeFromNib
{
UInt32 modifier = optionKey | cmdKey;
UInt32 key = 29; //'0'

UInt32 hotkey = (modifier << 16) | key;
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedInt:hotkey] forKey:@"hotkey"];
}


NSUserDefaults には Unsinged Int 32ビットで格納し、上位 16ビットを修飾キーに、下位 16ビットを通常キーに割り当てる。


実行すると10進数値が表示される(※16進数値では 0x9000001d)。



次はこの値から修飾キー表示用の文字列を作成する。前回用意した [HotkeyFormatter stringForObjectValue:] にこの処理を書く。

HotkeyFormatter.m
- (NSString *)stringForObjectValue:(id)anObject
{
NSString* key_desc = @"";
if (anObject && [anObject isKindOfClass:[NSNumber class]]) {
UInt32 value = [anObject unsignedIntValue];
UInt32 modifier = value >> 16;
UInt32 key = value & 0xff;

NSLog(@"mod=%x", modifier);
NSLog(@"key=%x", key);

if (modifier & controlKey) {
key_desc = [key_desc stringByAppendingFormat:@"%C", kControlUnicode];
}
if (modifier & optionKey) {
key_desc = [key_desc stringByAppendingFormat:@"%C", kOptionUnicode];
}
if (modifier & cmdKey) {
key_desc = [key_desc stringByAppendingFormat:@"%C", kCommandUnicode];
}
if (modifier & shiftKey) {
key_desc = [key_desc stringByAppendingFormat:@"%C", kShiftUnicode];
}
}
return key_desc;
}


実行してみよう。




出た。

- - - -
修飾キーは表示できたので、後は実際のキー(今回は '0')を表示するのだが、これを表示するにはどうしたら良いのだろうか。キーボードの'0'を表す 29 (0x1d)は '0'のキャラクターコード 48 (0x30) では無い。変換する必要があるな。

2009年6月15日月曜日

ホットキー変更対応(4) - 設定画面を試作する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

サンプルアプリを試作してホットキー設定画面を試作してみる。

まずこんなウィンドウを作る。


設定キーを文字列表現させたいので、モデル(NSUserDefaults)の値を加工するフォーマッタ HotkeyFormatter を用意する。

HotkeyFormatter.h

@interface HotkeyFormatter : NSFormatter {
}

@end


HotkeyFormatter.m
@implementation HotkeyFormatter

- (NSString *)stringForObjectValue:(id)anObject
{
NSString* key_desc = [anObject description];
return key_desc;
}

- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error
{
*anObject = string;
return YES;
}
@end


実装は後で行う。現在は動作確認用にメソッドだけ用意しておく。


これを InterfaceBuilder上でインスタンス化しておき、テキストボックスの Formatterアウトレットへ接続する。


こんな具合になる。


Cocoaバインディングを使い、入力した値を NSUserDefaults で管理させる。


実行して文字を入力するとそれがそのまま表示される。
入力した文字列はアプリを再起動すると復元される。



ベースができたので次回は NSUserDefaultsへ格納されたホットキーの値を表示させる処理を実装する。