このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

Autohotkey で、長音記号の入力を楽にした話

IME(日本語入力)において長音記号〈音引き〉の入力には通常マイナスキーを押すでしょう。僕も右小指でマイナスキーを押して長音記号を入力していたのですが、このとき右肘を外に回転させる動作が気になってきました(歳のせいでしょう)。肘・指の動作を少なくするように設定しました。

途中で予想外のことが起こり、けっこう手間取ってしまいました。

内容:

やりたかったこと/やったこと

日本語キーボードだと、右シフトキーの左隣に「\, _, ろ」の三文字が刻印されたキーがあります。このキーは、半角モード(IMEがOFF状態)ではASCII文字(Unicode の Basic Latin の文字)のバックスラッシュ(U+005C)の入力に使われます。シフトするとアンダースコア(U+005F)が入力されます。全角モード(IMEがON状態)だと、(原則的には)対応する全角文字(Unicode の Fullwidth ASCII variants の文字)「¥」「_」が入力されます。「バックスラッシュと円マークが対応する文字なのか?」に関しては、とてもゴチャゴチャした歴史的経緯があります(が、もう興味ないので割愛)。このキーを、刻印されているメインの文字からバックスラッシュキーと呼ぶことにします。

マイナスキー(刻印は「-, =, ほ」)は上段にあって遠いので、代わりにバックスラッシュキーで長音記号(U+30FC の文字*1)を入力しよう、というのが最初の発想です。アンダースコアと長音記号は似てるので、アンダースコア入力(シフト+バックスラッシュキー)を長音記号入力に置き換えちゃえ、ということです。置き換えには Autohotkey を使います。

試してみたら、シフトキーを押すのはバカバカしいと気づきました。キーストロークと入力は次のように対応させます。

  • 半角モード、バックスラッシュキー : バックスラッシュ文字(「\」) が入力される
  • 半角モード、シフト+バックスラッシュキー : アンダースコア文字(「_」) が入力される
  • 全角モード、バックスラッシュキー : 長音記号(「ー」) が入力される
  • 全角モード、シフト+バックスラッシュキー : 全角アンダースコア文字(「_」) が入力される

全角円マークは右上にある円マークキー(刻印は「¥, |, ほ」)で入力できるので、バックスラッシュキーから全角円マークが入力できなくても問題ありません。

結果として、小指の位置をほぼ動かさずシフトキーも押さずに長音記号を入力できるようになりました。

Autohotkey

Autohotkey については、過去記事「プログラミング言語としての AutoHotKey」で書いています。Windows OS でしか使えません。プログラミング言語としてはクセが強く、どうにも歪んだ言語仕様なので、過去記事では、

プログラミング初心者がAutoHotKeyを入門や学習用に使うことはまったくおすすめできません

と書いています。

最近では、新しいバージョン Autohotkey v2 が主流になりつつあります。Autohotkey v2 は、言語仕様がだいぶマトモになり、スクリプト言語として(ホットキー定義以外にも)使えそうです。とはいえ、スクリプト言語として積極的にオススメする気はありません。もちろん、ホットキー定義言語としては、唯一無二の優位性を持っています。

Autohotkey v2 では、ホットキー定義は次のように書けます。

キーストロークの記述::
{
    任意のコード
}

つまり、キーストロークをトリガー・イベントとするイベントハンドラーの形に書けます。コードブロックは、関数の本体ブロックと変わりません。スッキリしましたね。

互換性から変な構文/変な仕様は残ってますが、できるだけ変なコードは書かないようにすれば、そこそこモダンな感じのプログラムになります。

長音記号の入力のためのホットキー定義は次のようです。

sc073::
{
    if (IME_GET()) {
        Send("ー")
    } else {
        Send("\")
    }
}

キーのスキャンコード

Autohotkey のキーストローク記述において、[A] キーなら単に a と書くだけです。[Ctrl]+[A] ならば ^a ですね、簡単。しかし、文字「/」を発生させるキーは、バックスラッシュキーと円マークキーの2つがあります。どちらのキーが押されたかをどう区別するのだろうか?

キーが押される(そして、放される)と、KeyDown, KeyUp イベントが発生します。どのキーが押されたかはスキャンコードという番号で識別されるとのこと。Autohotkey では、"sc" のあとにスキャンコードでキーを記述できます。例えば、sc029 は無変換キーを表します。

スキャンコードを使えば異なるキーを区別できますね。それに、スキャンコードを使ったほうが確実で安心。じゃ、スキャンコードはどう調べればいいだろう? ここで僕はしくじってしまいました。以下、しくじりを時系列順で書きますが、興味がなければスキップして次の節へどうぞ。

リアルタイムに押したキーの情報を表示してくれるソフトウェアはないだろうか? 探したら次が見つかりました。

実行するために、古いバージョン(バージョン 3.5 以前)の .NET Framework が必要なのでインストールしました。思ってたとおりのソフトウェアで、「おー、これだこれだ」と。

上の画像は、バックスラッシュキーを押して、記録停止した状態の画面スナップショットです。スキャンコードが 125 だったので、次のような Autohotkey のテストコードを書いて試してみました。チルダは、キーストロークを消費せずにそのまま素通りさせることを指示します。

~sc125::
{
    MsgBox("Pressed!")
}

アリッ? うまくいかない。 KeyMill の数値が10進数で、Autohotkey は16進数だとは気付いたのですが、それを修正してもダメ。KeyMill の「仮想キーコード」ってのが実は Autohotkey の「スキャンコード」なのでは? とか試行錯誤したのですが、うまくいかず(困惑して無為な時間を過ごす)。KeyMill の表示と Autohotkey のスキャンコードの翻訳ルールが今でもわかりません。

実はドキュメンテーションもあったし、Autohotkey 自体の機能でスキャンコードを調べることもできたのです(そりゃそうだよね)。

設定の手順

スキャンコードに関するドキュメンテーションは以下です。

AutoHotKey でキーの情報を調べるには:

  1. タスクトレイの AutoHotKey のアイコンをダブルクリックする。Autohotkey のコンソールウィンドウが表示される。
  2. メニューから View → Key history and script info を選択。
  3. [F5] を押すと、ウィンドウの一番下に押したキーの情報が表示される。

コンソールの VK(仮想キー)や SC(スキャンコード)の欄を見れば、Autohotkey で使えるキーストローク記述がわかります。

バックスラッシュキーのスキャンコードは sc073 だと分かるので以下のコード(再掲)で目的が達成できます。

sc073::
{
    if (IME_GET()) {
        Send("ー")
    } else {
        Send("\")
    }
}

ここで使っている IME_GET 関数は、以下の記事からそのままコピーしました(ありがとうございます)。

上記記事からの IME_GET 関数のコードを貼り付けておきます。

;-----------------------------------------------------------
; IMEの状態の取得
;   WinTitle="A"    対象Window
;   戻り値          1:ON / 0:OFF
;-----------------------------------------------------------
IME_GET(WinTitle:="A")  {
    hwnd := WinExist(WinTitle)
    if  (WinActive(WinTitle))   {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        cbSize := 4+4+(PtrSize*6)+16
        stGTI := Buffer(cbSize,0)
        NumPut("DWORD", cbSize, stGTI.Ptr,0)   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", "Uint",0, "Uint", stGTI.Ptr)
                 ? NumGet(stGTI.Ptr,8+PtrSize,"Uint") : hwnd
    }
    return DllCall("SendMessage"
          , "UInt", DllCall("imm32\ImmGetDefaultIMEWnd", "Uint",hwnd)
          , "UInt", 0x0283  ;Message : WM_IME_CONTROL
          ,  "Int", 0x0005  ;wParam  : IMC_GETOPENSTATUS
          ,  "Int", 0)      ;lParam  : 0
}

*1:文字の名前は Katakana-Hiragana Prolonged Sound Mark です