８. カスタマイズ　customize

  付属の `dot.nodoka``` 設定ファイルを利用すれば、エディットコントロールで Emacs 風の操作ができるようになりますが、`dot.nodoka` をカスタマイズすることによって、Windows を自分の好きなキーバインディングで利用することができるようになります。

  `dot.nodoka` はホームディレクトリから検索されます。

  `dot.nodoka` は上から下へ読まれていき、重複する記述があれば、より下に書かれているものが有効になります。コメントは `#` ではじめます。アルファベットの大文字と小文字は区別されません。詳しい文法は `syntax.txt` を参照してください。

  この章を読む前に、`contrib\nodoka-settings.txt` を読んで付属の設定ファイルについて理解を深めておくことをお勧めします。

  i. キー割り当ての変更

    キー割り当てを変更するには、以下のように記述をします。

    key KEY = KEY や FUNCTION …

    `=` より左の `KEY` をキーボードで押すと、Windows へは `=` より右の `KEY` が順番に入力されます。また、右に `FUNCTION` が書かれている場合はウィンドウの最大化や移動などの機能が実行されます。

    `KEY` はキーボード定義で定義されるもので、デフォルトでは `109.nodoka` 又は `104.nodoka` で定義されている `KEY` が使用できます。図示したものは、こちら。

    モディファイヤの指定

      `KEY` の前に以下のような記号を付けることによって、コントロールキーなどの状態を表現できます。また、これらをモディファイヤと呼ぶことにします。

      - `C-` は、`Control` が押されていることを表します。
      - `M-` か `A-` は、`Alt` が押されていることを表します。
      - `S-` は、`Shift` が押されていることを表します。
      - `W-` は、`Windows` が押されていることを表します。
      - `NL-` は、`NumLock` がロック状態であることを表します。
      - `CL-` は、`CapsLock` がロック状態であることを表します。
      - `SL-` は、`ScrollLock` がロック状態であることを表します。
      - `KL-` は、`カナ` がロック状態であることを表します。
        (オプション (`KL-`)をよく読んでください)
        109 キーボードなら、`Control` + `Shift` + `ひらがな`。
        104 キーボードなら、`Control` + `Shift` + `CapsLock`。
      - `IL-` は、IME が on になっていることを表します
      - `IC-` は、IME で変換中であることを表します
      - `MAX-` は、ウィンドウが最大化されていることを表します。
      - `MIN-` は、ウィンドウが最小化されていることを表します。
      - `MMAX-` は、MDI 子ウィンドウが最大化されていることを表します。
      - `MMIN-` は、MDI 子ウィンドウが最小化されていることを表します。
      - `T-` は、タッチパッドに指が触れていることを表します。有効にするためにはオプションを設定する必要があります。
      - `TS-` は、全てのキーが離されるまでオフにならないことを除けば `T-` と同じです。

      以下のように記述すると、`Control` + `A` を押した時に、Windows へは `HOME` キーが入力されます。

      key C-A = HOME

    モディファイヤキーの無視

      上記の例では左側に `C-A` と記述していますが、この記述では、ロックキーなどは押されていても押されてなくても良いと記述していることになります。たとえば、`CapsLock` を押したあとで `Control` + `A` を押しても、押さずに `Control` + `A` を押しても、Windows へは `Home` が入力されます。

      特定のモディファイヤの状態を無視したい場合は、モディファイヤに "`*`" をつけます。逆にモディファイヤが必ず押されていなければならない場合は付けません。またモディファイヤが必ず離されていなければならない場合は "`~`" を付けます。たとえば、

      key *S-F9 = &WindowMinimize

      このように記述すると、`F9` 又は `Shift` + `F9` でウィンドウを最小化することができますが、例えば、`Control` + `F9` ではできません。

      デフォルトでは、暗黙に `~C-~M-~S-*NL-*CL-*SL-*KL-*IL-~IC-*MAX-*MIN-*MMAX-*MMIN-*T-*TS-` が指定されていることになっていますが、変更できます。

      また、`Shift` は必ず押されていてほしいがほかのモディファイヤはどうでもいいという場合は、

      key S-*F9 = &WindowMinimize

      というように "`*`" をキーの直前に記述します。"`~`" についても同様です。

    入力されたキーと同じモディファイヤの指定

      `=` より右側でのモディファイヤの指定の方法です。

      key *S-A = C-*S-B

      例えばこのように記述した場合、`Shift` + `A` を押すと、Windows へは `Shift` + `Control` + `B` が入力されます。`A` を押すと、Windows へは `Control` + `B` が入力されます。

      つまり、`=` の右側で `*` で指定されたモディファイヤは、キーボードで実際に入力したモディファイヤと同じになるように設定されます。

      したがって、`A` を `B` と入れ替えたい場合は、

      key *A = *B
      key *B = *A

      となります。

    キーを押す/離す

      `KEY` の前にモディファイヤと同じように `D-` と `U-` を付けることができます。これは、それぞれキーの押すことと離すことに対応しています。デフォルトでは `*D-*U-` が指定されています。例えば、

      key A = B C

      という記述は、

      key *U-*D-A = D-B U-B D-C U-C

      と同じであり、さらに次のものとも同じになります。キーリピートが起こった場合は、`~U-D-A` が何度も実行され、キーを離したときに `U-~D-A` が実行されます。

      key ~U-D-A = D-B U-B D-C
      key U-~D-A = U-C

    キーリピートした

      `=` より左の `KEY` の前にモディファイヤと同じように `R-` を付けることができます。これは、キーリピートが発生したことを表します。デフォルトでは `*R-` が指定されています。例えば、

      key A = B
      key R-A = C

      という記述をすると、`A` を押しつづけると、

      BCCCCCCCCCCCCCCCCCCCCC

      と入力されます。とてもややこしいのであまり使わないように、しましょう。
    デフォルトモディファイヤの変更

      デフォルトでは、左側のキーには `~C-~M-~S-*NL-*CL-*SL-*KL-*IL-~IC-*MAX-*MIN-*MMAX-*MMIN-*T-*TS-` が指定されていますが、これを変更することができます。例えば、

      key *IC- =

      と記述すると、この文以降のデフォルトモディファイヤは `~C-~M-~S-*NL-*CL-*SL-*KL-*IL-*IC-*MAX-*MIN-*MMAX-*MMIN-*T-*TS-` となります。

      デフォルトモディファイヤの変更を複数行うときには、例えば、

      key L0-*IC-~C- =

      のように、しなければなりません。以下のように指定するのは間違いです。最後のものしか有効になりません。

      key L0- =
      key *IC- =
      key ~C- = # この行しか有効にならない

  ii. キーマップ定義

    「のどか」には、キーマップという概念があります。キーマップにカスタマイズしたいキー情報を書き込んでゆき、ウィンドウごとにキーマップを使い分けます。キーマップを定義するには、以下のどれかの文を書いてからキーを設定します。

    keymap キーマップ名
    keymap2 キーマップ名
    window キーマップ名 ウィンドウクラス名
    window キーマップ名 ( ウィンドウクラス名 && ウィンドウタイトル名 )
    window キーマップ名 ( ウィンドウクラス名 || ウィンドウタイトル名 )

    例えば、メモ帳で `Control` + `Z` を押すと最小化されるが、メモ帳以外のエディットコントロールで `Control` + `Z` を押すと単なる `Z` キーと同じになるという指定がしたい場合は、

    window EditControl /:Edit$/ : Global
    key C-Z = Z
    window Notepad /Notepad:Edit$/ : Global
    key C-Z = &WindowMinimize

    と記述します。ここで `/Notepad:Edit$/` はメモ帳の上にあるエディットコントロールの`ウィンドウクラス名`を表しています。`ウィンドウクラス名`は正規表現で記述します。`: Global` は`親キーマップ`を指定しています。

    ウィンドウクラス/タイトル名

      Windows の全てのウィンドウは、何らかのウィンドウクラスに属しています。例えば、メモ帳のウィンドウクラス名は `Notepad` で、エディットコントロールのウィンドウクラス名は `Edit` です。

      「のどか」は、どのウィンドウでどのキーを押したらどんな動作をするか、ということを区別するために`ウィンドウクラス名`と`ウィンドウタイトル名`を用いています。そのために、「のどか」ではウィンドウの重なりの状態を "`:`" で繋げて表現します。例えば、メモ帳の上のエディットコントロールの`ウィンドウクラス名`ならば、

      C:\WINDOWS\system32\notepad.exe:Notepad:Edit

      と表現します。ただし、一番最初の`ウィンドウクラス名`には 、そのアプリケーションのパス名を付けています。

      `window` 文には、この`ウィンドウクラス名`と`ウィンドウタイトル名`を記述することができますが、`ウィンドウクラス名`全てを書く必要はなく、正規表現で省略することができます。

      例えば、`/:Edit$/` は全てのエディットコントロールの`ウィンドウクラス名`を表しますし、`/:#32770.*:Edit$/` ならば、ダイアログボックス上にある全てのエディットコントロールの`ウィンドウクラス名`を表します (`#32770` はダイアログボックスのウィンドウクラス名)。

      個々のウィンドウの`ウィンドウクラス名`と`ウィンドウタイトル名`を調べるには、タスクトレイメニュー調査(I)...の「ウィンドウの調査」、または `FUNCTION` `&WindowIdentify` を利用してください。

      `ウィンドウクラス名`と`ウィンドウタイトル名`の両方を記述する場合は、括弧で囲みその間を `&&` か `||` で区切ります。`&&` の場合は、両方にマッチするようなウィンドウを表し、`||` の場合はどちらか一方にマッチするようなウィンドウを表します。

    正規表現について

      `ウィンドウクラス名`と`ウィンドウタイトル名`には正規表現が使用できます。正規表現は `/.../` で囲むか、`\m@...@`で囲みます (ただし`@`はどんな文字でも良いです)。

      正規表現エンジンには Boost.Regex を使用しています。このエンジンでは Perl で使用できる正規表現がほぼカバーされています。よく使いそうなものを挙げておきます。

      - "`|`" Alternation
      - "`*`" Match 0 or more times
      - "`+`" Match 1 or more times
      - "`?`" Match 1 or 0 times
      - "`.`" Match any character
      - "`^`" Match the beginning of the string
      - "`$`" Match the end of the string
      - "`\b`" Match a word boundary
      - "`\B`" Match a non word boundary
      - "`\w`" Match a word character (`[0-9a-z_]`)
      - "`\W`" Match a non word character
      - "`\s`" Match a whitespace character
      - "`\S`" Match a non-whitespace character
      - "`\d`" Match a digit character
      - "`\D`" Match a non-digit character
      - "`(`" "`)`" Grouping
      - "`[`" "`]`" Character class
      - より詳しくは Boost.Regex: Regular Expression Syntaxを見てください。
    親キーマップ

      親キーマップとは、現在のキーマップに適切なキー割り当てが定義されていない場合に、キーを捜しに行くキーマップです。"`:`" の後ろに親キーマップ名を書きます。例えば、

      keymap sub : Global
      key C-A = &WindowMinimize
      window EditControl /:Edit$/ : sub
      key C-A = &KeymapParent

      と記述した場合、エディットコントロールで `Control` + `A` を入力すると、ウィンドウは最小化されます。つまり、`&KeymapParent` を記述することで 、親キーマップで定義されたキーを利用することができるのです。もし、親キーマップ名が指定されていなければ `&Default` 扱いとなり、ウィンドウへキーがそのまま入力されます。

    デフォルトキー

      `keymap`、`window`、`keymap2` には、最後にキーを羅列することによってデフォルトキーを定義することができます。例えば、

      window EditControl /:Edit$/ : Global = A
      key *B = *C

      と記述すると、`B` を入力すると `C` を入力したことになるが、`B` 以外のキーを入力すると、`A` を入力したことになります。また、デフォルトキーを指定しなかった場合のデフォルトキーは、`keymap` と `window` の場合は `&KeymapParent` で、`keymap2` の場合は `&Undefined` になります。

    二段階キーマップ

      `keymap2` はデフォルトキーが `&Undefined` になって いるようなキーマップで、主に `&Prefix` を利用して 2 ストロークキーを記述する時に使用します。

    初期キーマップ

      `dot.nodoka` の一番初めの行には、

      window Global ( // || // ) = &OtherWindowClass

      という行が隠れていると考えて下さい。つまり、`dot.nodoka` で何もキーマップを指定せずに書き始めると、キーマップ名 `Global` のキーマップに対するキー定義になるということです。そして、`Global` キーマップのデフォルトキーは `&OtherWindowClass` が設定されています。

    矛盾したキーマップの指定

      同じキーマップに対する `keymap` や `window` や `keymap2` は何度でも指定できますが、矛盾する指定をしてはいけません。例えば、

      keymap Amap : Global
      ...
      keymap Bmap : Amap
      ...
      keymap Amap : Global
      ...

      という指定は問題ありませんが、

      keymap Amap : Global
      ...
      keymap Bmap : Amap
      ...
      keymap Amap : Bmap # 矛盾
      ...

      という指定はしてはいけません。この場合、`keymap Amap : Bmap` のかわりに `keymap Amap : Global` が指定されたものとみなされます。エラーは出ません。

    `window` に複数該当する場合

      例えば、

      window EditControl /:Edit$/ : Global
      key A = A space E D I T enter
      key B = B space E D I T enter
      window Notepad /:Notepad/ : Global
      key A = A space N O T E P A D enter
      key C = C space N O T E P A D enter

      という記述をしたとします。ここで、「メモ帳」を立ち上げると、メモ帳の`ウィンドウクラス名`は

      C:\WINDOWS\system32\notepad.exe:Notepad:Edit

      となっているので、`/:Edit$/` と `/:Notepad/` は両方共もメモ帳の`ウィンドウクラス名`に該当します。この時、`A` を入力すると、メモ帳には「`a notepad`」と表示されます。これは、重複する記述があれば、より下に書かれているものが有効になるからです。しかし、`B` を入力した場合は、重複していないので、メモ帳には「`b edit`」と表示されることになります。

      `B` を入力した場合に、内部で行われる処理は以下のようになります。

      1. まず`ウィンドウクラス名`は `/:Notepad/` に該当しますが、キー割り当てがないので、`window` のデフォルトキーである `&KeymapParent` が採用されます。
      2. `&KeymapParent` は親キーマップの参照なので、`Global` キーマップを参照します。
      3. そうすると、`Global` キーマップでも `B` の割り当てがないので、`Global` キーマップのデフォルトキーである、`&OtherWindowClass` が採用されます。
      4. `&OtherWindowClass` が採用されると、まず、他に該当する`ウィンドウクラス名`がないかどうか探します。もしなければ、`&Default` 扱いとなります。この場合は `/:Edit$/` に該当します。
      5. `/:Edit$/` に該当したので、`/:Edit$/` の `B` が採用されます。したがって、「b edit」と表示されることとなります。
    キーマップが影響する定義
      以下の単語で始まる定義は、キーマップ毎に定義できます。
      - `key ...` キー割り当ての変更
      - `event ...` イベント定義
      - `mod ...` モディファイヤキー割り当ての変更
      以下の単語で始まる定義は、キーマップ毎に定義することはできません。
      - `def ...` キーボード定義
      - `keyseq ...` キーシーケンス定義
  iii. モディファイヤキー割り当ての変更

    mod モディファイヤキー名 = キー名 …
    mod モディファイヤキー名 += キー名 …
    mod モディファイヤキー名 -= キー名 …

    最初の 3 つは、キー名で指定したキーをモディファイヤキーにしたり (`=`) 追加したり (`+=`) 削除したり (`-=`) します。各キーマップ毎に割り当てます。明示的に割り当てない場合は、親キーマップから引き継がれます。例えば、

    mod shift += 無変換

    は、`無変換` キーを shift モディファイヤキーにします。従って、

    key S-A = X

    という記述があった場合に、`無変換` + `A` を押すと `X` を入力したことになります。正確には、`無変換押す` `X押す` `X離す` `無変換離す` というキーが Windows へ入力されます。これでは都合が悪いということは多いと思われるので、

    key *無変換 = *LShift

    として `無変換` キーを押すと `LShift` が入力されるように割り当てます。そうすれば、Windows へは `LShift押す` `LShift離す` `X押す` `X離す` というキーが入力されます。

    モディファイヤキー名には、`shift`, `alt` (`meta`, `menu`), `control` (`ctrl`), `windows` (`win`), `mod0`〜`mod9` が記述できます。括弧の中の名前も使用できます。

    `mod0`〜`mod9` は「のどか」の中でのみ有効なモディファイヤで、例えば以下のように使用します。

    mod mod0 = Up
    key M0-Left = Left Up

    このように割り当てると、`↑` を押しながら `←` を押すとカーソルが左斜め上へ移動することになります。

    真のモディファイヤ

      モディファイヤにしたいキーの前に "`!`" を付けると、真のモディファイヤになります。例えば、

      mod shift += !無変換
      key 無変換 = Y
      key S-A = X

      と記述した場合、`無変換` + `A` を押すと `X押す` `X離す` というキーが Windows へ入力されます。Windows からは、`無変換` キーが押されたということは分かりませんし、`Y` も Windows へ入力されることはありません。つまり、真のモディファイヤに定義されているキーや `FUNCTION` などは実行されません。

      以下のような行を記述すると、

      mod !モディファイヤキー名

      そのモディファイヤキー名に割り当てられているモディファイヤを全て真のモディファイヤに変更します。

    One Shot モディファイヤ と SandS

      モディファイヤにしたいキーの前に "`!!`" を付けると、One Shot モディファイヤになります。たとえば、

      mod shift = !!LShift
      key S-A = X
      key S-LShift = Y

      と記述した場合、`LShift` を押してすぐ離した場合は、Windows へは、`Y` が入力されますが、`LShift` + `A` を入力した場合は、`X` のみが Windows へ入力されます。

      以下のような行を記述すると、

      mod !!モディファイヤキー名

      そのモディファイヤキー名に割り当てられているモディファイヤを全てOne Shot モディファイヤに変更します。

      一般的には SandS (Space and Shift)と呼ばれているスペースキーをシフトキーとして使用するには、次の記述を実施してください。

      mod shift += !!Space

      キーリピート有りにしたい場合には、次のOne Shot(キーリピート有)の項を参考にすると、下記となります。

      mod shift += !!!Space

      シフトを押したけれども、取りやめた時にスペースが入ることを防ぐには下記となります。( http://jisx6004.client.jp/mayu2.html を参考にしました。)

      mod shift += !!Space
      key R-*Space = &Ignore

    One Shot (キーリピート有)

      One Shot モディファイヤは通常キーリピートしませんが、"`!!!`" を付けると、キーリピートをするようになります。例えば、

      mod shift = !!!Up

      とすると、`↑` を押しながら何か別のキー (例えば `A`) を押すと `Shift` + `A` と同じことになりますが、`↑` を押しっぱなしにすると `↑` がキーリピートして、カーソルが上へ動くということになります。

      キーリピートが開始するまでの時間をオプション (`delay-of !!!`) で設定できます。

    ロックキー

      「のどか」には、「のどか」の中でのみ有効なロックキーが存在します。これらはキーのモディファイヤとして `L0-`〜`L9-` を書くことができ、`&Toggle` を使うことによりトグル あるいは、ロックかアンロックの状態に変更させることができます。例えば、

      key ひらがな = &Toggle(Lock0)
      key L0-A = B

      と記述すると、`ひらがな` キーがトグル状態になっているときに `A` を押すと Windows へは `B` が入力されます。

  iv. キーシーケンス定義

    keyseq $キーシーケンス名 = KEY や FUNCTION …

    `keyseq` を使うことで、一連のキー入力に対して名前を付けることができます。例えば、

    keyseq $Right2Times = Right Right
    key C-F = $Right2Times

    とすると、`Control` + `F` で右に二つカーソルを進めることができます。

    key C-F = Right Right

    は、`$Right2Times` という名前が定義されないこと以外は、先の例と同じになります。
    $ToggleIME, $WindowClassName, $WindowTitleName, $NodokaVal などが、のどかのプログラム内部あるいは、104.nodoka、109.nodoka、emacsedit.nodoka などで定義されているので、include している設定ファイルの中で、ユニークな使われていないキーシーケンス名を用いる必要があります。

  v. イベント定義

    event EVENT = KEY や FUNCTION …

    あるイベントが起こったときに `KEY` や `FUNCTION` を実行します。イベントはキーマップ毎に定義され、親キーマップにイベントが定義されていてもそれは無視されます。

    `EVENT` には以下のものが指定できます。

    - `prefixed`: `&Prefix` によってキーマップが指定された時。
    - `before-key-down`: キーが押された時。
    - `after-key-up`: キーが離された後。
  vi. キーボード定義

    基本となるキーボード定義は `109.nodoka` 又は `104.nodoka` に書かれています。図示したものは、こちら。

    キー定義

      キーボードの物理的なキーを定義します。

      def key キー名… = スキャンコード…

      キーが発生する`スキャンコード`を記述していきます。`スキャンコード`は数字で書き、`E0-` や `E1-` という拡張キーフラグをつけることができます。

      def key Pause = E1-0x1d 0x45

      このように一連のスキャンコードを発生させるキーにはスキャンコードを書き並べます。

    モディファイヤ定義

      キーボードの物理的なモディファイヤキーを定義します。

      def mod モディファイヤ名 = キー名…

      `モディファイヤ名`には、`shift`, `alt` (`meta`, `menu`), `control` (`ctrl`), `windows` (`win`), `mod0`〜`mod9` が記述できます。括弧の中の名前も使用できます。

    同期定義

      `&Sync` に使用する`スキャンコード`を定義します。

      def sync = スキャンコード…

      `&Sync` が実行されるとき、「のどか」はこの`スキャンコード`を Windows に送ります。そして、各ウィンドウがこのキーが入力されたことを「のどか」へ連絡してくるまで処理を中断します。このようにして同期をとるので、この`スキャンコード`が不正に設定されていると、同期がとれず「のどか」が 5 秒ほど固まります (つまり 5 秒ほど何も入力できなくなります)。

    別名定義

      キーの別名を定義します。

      def alias 別名 = キー名

      別名が既存のキー名と同じだった場合は、別名のほうが優先されます。

    代用定義

      あるキーを別のキーとして代用します。

      def subst KEY = KEY や キーシーケンス …

      キーが入力されると、まずこの代用定義によって入力されたキーが置き換えられます。その後、キー割り当ての変更に従って変換されます。

      def subst A = B
      key B = C

      上記の例では、`A` を入力すると、まず代用定義で `B` が押されたことになって、`B` が入力された場合は `C` が最終的に Windows へ入力されるので、結局 `A` を押すと `C` が押されたことになります。

      代用定義は、キーマップでキーが変更されるより前に実行されます。例えば、109 キーボード上で 104 キーボードや Dvorak のエミュレートをしたいときに使用します。

      `=` の左右はキー割り当ての変更のものと同じものが指定でき意味も同じになりますが、右側は先頭が `FUNCTION` ではなく `KEY` でなければならず、先頭の `KEY` しか意味を持ちません。

      以下色々な例。

      def subst A = C-B
      key *B = S-*C

      上記の例では `A` を入力すると、最終的に `Shift` + `C` が Windows へ出力されます。

      def subst A = B C D $Hoge &Toggle(Lock0)

      上記の例では `A` を入力すると、`B` が Windows へ出力されます。`C D $Hoge &Toggle(Lock0)` は無視されます。

      keyseq $COLON = ~S-*Colon
      def subst S-*Semicolon = $COLON

      上記の例では `Shift` + `;` を入力すると、`:` になり、`Control` + `Shift` + `;` を入力すると、`Control` + `:` になります。

    オプション カナロック(`KL-`)

      カナロック `KL-` を正しく設定するように、します。

      def option KL- = enable

      このオプションを設定しない場合、特定の場合にカナロックの状態が正しく取得できません。

      このオプションを設定すれば、カナロックの状態は正しく取得できますが、IME で文字列を入力中未確定のまま別のウィンドウへフォーカスを切り替え、元のウィンドウへフォーカスを戻した時に、IME に入力中だった文字列は失われます。

      109 キーボードで `Alt` + `ひらがな` を使用するカナロックにはうまく対応できませんでした。普段 `Alt` + `ひらがな` を使用している人は、

      keymap Global
      key *IC-*IL-A-ひらがな = C-S-ひらがな

      という設定をして代わりに `Control` + `Shift` + `ひらがな` が使用される ように、してください。

      また、IME の機能の「日本語入力と連動してカナロックをon/offする」という設定にしている場合もカナロックの状態を正しく取得 できない。という報告があります。その場合は IME を on/off にするキーに、同時にカナロックもしてくれるように設定すると良いでしょう。

      参考: IME2000:かな/ローマ字入力を切り替える方法

      > 1. ログウィンドウを表示して、「□詳細(D)」をチェックしておきます。
      > 2. 「メモ帳」を 2 つ起動し左右に並べます。
      > 3. 左のメモ帳でカナをロックして何文字か入力してください。
      >    109 キーボードなら、`Control` + `Shift` + `ひらがな`。
      >    104 キーボードなら、`Control` + `Shift` + `CapsLock`。
      >    (左のメモ帳には半角カタカナが表示されます)
      > 4. 右のメモ帳に何文字が入力してください。
      >    (右のメモ帳には半角カタカナが表示されます)
      > 5. IME をオンにしてローマ字入力にして右のメモ帳に何文字か入力してください。
      > 6. 左のメモ帳に何文字か入力してください。
      >    (左のメモ帳には半角カタカナが表示されます)
      > 7. ここで、ログウィンドウを見ると `KL-` が付いていません。

      > カナロックの状態は、IME がオンの時とオフの時で、べつべつに記憶されているようです。

      > しかし、IME がオンのウィンドウから IME がオフのウィンドウへフォーカスが移ったときに、カナロックの状態は正しく反映されないようです。

      > その後 IME をオンオフするタイミングで、カナロックの状態が正しく反映されます。

      > そこで、このオプションを設定すると、フォーカスが変化した時に IME オンオフを自動的に行い、カナロック状態を反映します。

    オプション キーリピートが始まるまでの時間指定 (`delay-of !!!`)

      キーリピート有 One Shot (`!!!`) のキーリピートが始まるまでの時間を指定します。

      def option delay-of !!! = DELAY

      最初の `DELAY` 回のキーリピートを無視するように、します。

      デフォルトでは `DELAY` は 0 です。

    オプション タッチパッドサポート(`sts4nodoka, cts4nodoka`)

      キーボードのホームポジションを維持したまま、タッチパッドと併用することで、マウスの操作を実現する ThumbSense(サムセンス)をオプション扱いですが、サポートしています。

      もともと、「窓使いの憂鬱」の Sourceforge.net で公開されていたソースコードを取り込んで、実現しています。

      ちなみに ThumbSense(サムセンス)のオリジナル紹介ページはこちら。 残念ながら サンプルの設定ファイルである thumbsense.nodoka は &MouseHook を「のどか」で、実装していないために、ホイール機能などを実現していません。(&MouseHookを実装したら、動作が重くなってしまったためです。)

      具体的には、設定ファイルにおいて、モディファイヤ `T-, TS-` のサポートを有効にし 、たとえば、タッチパッドに指を置いたまま、Jキーで、左ボタンクリック。Kキーで、右ボタンクリック。などが利用可能です。

      別途 下記に示すように、DLLファイル(`sts4nodoka.dll` または `cts4nodoka.dll`)が必要です。インストール先フォルダ （通常 32bit OSの場合 C:\Program Files\nodoka )の ts4nodokaフォルダにコピーされているので、`nodoka.exe` と同じフォルダに コピーしてください。

      サンプルの設定ファイル thumbsense.nodoka が ts4nodokaフォルダにあるので、必要であれば、DLLファイル同様にコピーして、下記 def option行の次の行で、include "thumbsense.nodoka" されると良いでしょう。

      なお、実際に Synaptics あるいは GlidePointのドライバが、インストールされていないと、エラーとなります。

      また、作者の環境では、sts4nodoka.dll しか動作確認ができていません。cts4nodoka.dll の動作が確認できた方がいらしたら、ご連絡いただければ幸いです。

      Synaptics のタッチパッドを使用される場合は、`sts4nodoka.dll` を、お使いください。また dot.nodokaファイルにて、次のように記述してください。

      def option sts4nodoka = enable

      Cirque GlidePoint のタッチパッドを使用される場合は、`cts4nodoka.dll を、お使いください。また dot.nodokaファイルにて、次のように記述してください。`

      def option cts4nodoka = enable

      thumbsense.nodoka で定義されている機能は以下の通りです。

      # F,J,Space を左ボタンのクリックに割り当てる。
      key TS-*F TS-*J TS-*Space = &VK(LButton)
      # クリックがリピートされるのを防ぐ
      key D-R-TS-*F D-R-TS-*J D-R-TS-*Space = &Ignore
      # D,K を右ボタンのクリックに割り当てる。
      key TS-*D TS-*K = &VK(RButton)
      # クリックがリピートされるのを防ぐ
      key D-R-TS-*D D-R-TS-*K = &Ignore
      # V を左ボタンのダブルクリックに割り当てる。
      key D-T-*V = &VK(LButton) &Wait(10) &VK(LButton)
      # クリックがリピートされるのを防ぎ、キー離したときは無視する。
      key D-R-T-*V U-T-*V = &Ignore
      # G を第4ボタンのクリックに割り当てる。
      key TS-*G = &VK(XButton1)
      # クリックがリピートされるのを防ぐ
      key D-R-TS-*G = &Ignore
      # H を第5ボタンのクリックに割り当てる。
      key TS-*H = &VK(XButton2)
      # クリックがリピートされるのを防ぐ
      key D-R-TS-*H = &Ignore
      # R でウィンドウの最大化/解除をトグルする。
      key T-R = &WindowMaximize
      # W,B でウィンドウを閉じる。
      key T-W T-B = &WindowClose
      # M で My Document を開く。
      key T-M = &ShellExecute("open", "C:\\WINDOWS\\explorer.exe", "::{450D8FBA-AD25-11D0-98A8-0800361B1103}",, ShowNormal)
      # O で Outlook Express を起動する。
      key T-O = &ShellExecute("open", "C:\\Program Files\\Outlook Express\\msimn.exe",,, ShowNormal)
      # I で Internet Explorer を起動する。
      key T-I = &ShellExecute("open", "C:\\Program Files\\Internet Explorer\\iexplore.exe",,, ShowNormal)
      # P でコマンドプロンプトを起動する。
      key T-P = &ShellExecute("open", "C:\\WINDOWS\\system32\\cmd.exe",,, ShowNormal)

  vii. ファイル読み込み

    include ファイル名

    と書くことによって、その行にファイル名 文字列で示されるファイルを挿入 し、設定ファイルと使用することができます。ファイル名はホームディレクトリから検索されます。

    ホームディレクトリ

      ホームディレクトリは、

      - 設定(S)... でフルパスで指定したファイルのあるディレクトリ
        フルパス指定すれば、そこのフォルダが最優先となるため、例えば、独自フォルダを作って、そこに設定ファイルをまとめて、置いておくことが可能です。
        パスがない単体のファイル名の場合には、ディレクトリを指定したことにならず、下記の順に検索します。
      - `%HOME%`
        環境変数 HOME で指定したフォルダです。
      - `%USERPROFILE%`
        環境変数 USERPROFILE で指定されているフォルダです。Windowsでは、デフォルトで設定されています。
      - `%HOMEDRIVE%%HOMEPATH%`
        環境変数 HOMEDRIVE と HOMEPATH によって指定されているフォルダです。Windowsでは、デフォルトで設定されています。
      - `実行したnodoka.exe` のカレントディレクトリ
        コマンドプロンプトで、実行した場合には、そのコマンドプロンプトで、上記の環境変数が、再定義されている場合があるので、ご注意ください。
      - `インストール先 nodoka.exe` のあるディレクトリ

      の いずれか になります。上から順番に検索されます。

  viii. 条件分岐

    シンボルを定義して、そのシンボルによって条件分岐させることができます。

    define シンボル
    if ( シンボル )
    〜
    else
    〜
    endif

    例えば次のように記述すると、

    if ( SwapAB )
    key *A = *B
    key *B = *A
    endif

    `SwapAB` というシンボルが `define` されている場合に、`A` と `B` を入れ替えます。

    「設定(S)...」で `-Dシンボル名` を書くことでシンボルを定義することができます。

  ix. `FUNCTION` リファレンス
    `&ClipboardCopy(text)`

      `text` 文字列をクリップボードへコピーします。

      もし、そうではなくて、現在選択されているものをクリップボードにコピーしたい場合には、C-C を お使いください。

      key S-F3 = &ClipboardCopy(文字列)

      次のようにすると、クリップボード経由となりますが、指定した任意の文字列を入力します。

      key S-F3 = &ClipboardCopy(文字列) &Sync C-V

    `&ClipboardUpcaseWord`, `&ClipboardDowncaseWord`

      それぞれ、クリップボードの中身の文字を大文字化又は小文字化します。

    `&Default`

      入力されたキーをそのまま Windows へ入力します。そのため、「のどか」を起動してない時と同じ動作が期待できます。

    `&DescribeBindings`

      `&DescribeBindings` は、現在のキーマップでどのようなキー操作をするとどのような動作が起こるかをログウィンドウに表示します。

    `&DirectSSTP(/name/, protocol [, header ...])`

      Direct SSTP プロトコルをしゃべります。

      `/name/` にマッチする名前のゴーストへリクエストを Direct SSTP を使用して送ります。

      `protocol` 文字列 を省略すると `NOTIFY SSTP/1.1` になります。

      `header` 文字列 にカンマで区切ってヘッダを書き並べます。`Sender` ヘッダを省略すると「のどか」の名前が挿入されます。`HWnd` ヘッダと `Charset` ヘッダは「のどか」が適切に指定するので引数として指定してはいけません。

      選択肢などを表示しても答えを受け取ることはできませんが、「のどか」はゴーストから返事を 5 秒間待ちます。

      例:

      key F12 = \
      &DirectSSTP(/カレン/, \
      "SEND SSTP/1.2", \
      "Script: " \
      "\\1こんにちわ" \
      "\\_w[1000]\\0\\s3カレンのこと呼んだ？" \
      "\\_w[1000]\\1＞みんな" \
      "\\_w[1000]\\0\\s4\\n\\n……。" \
      "\\e" ) \
      &DirectSSTP(/双葉/, \
      "SEND SSTP/1.2", \
      "Sender: まゆ", \
      "Script: " \
      "\\_w[1000]\\0よばれてますよただきちさん。" \
      "\\_w[1000]\\1きにするな。" \
      "\\e" )

    `&EditNextModifier(モディファイヤ)`と Sticky-Shift

      次にユーザーがキーを入力した時に、`モディファイヤ` が押されていることにします。例えば、

      key ESC = &EditNextModifier(M-)

      とすると、`Alt` + `X` などを `ESCAPE` `X` などで代用することが可能になります。
      例えば、Sticky-Shift と呼ばれる任意のキーを押したときに、次のキーはシフト有りとするには、以下の記述となります。

      key Space = &EditNextModifier(S-)

      この例では、スペースを押すと、次に入力するキーは、シフト有りとなります。

    `&EmacsEditKillLinePred`, `&EmacsEditKillLineFunc`

      エディットコントロールで emacs の kill-line のような機能を実現します。使い方は `emacsedit.nodoka` を参照のこと。

      kill-line は非常にややこしい処理をしています。

      まず、`C-k` の期待される動作は、

      (C-k-1) カーソルが行末にある場合、クリップボードに改行を追加してテキストからは改行を削除する。

      (C-k-2) カーソルが行末以外の場合、行末までをクリップボードに追加して行末までのテキストを削除。

      です。「のどか」での定義は、`emacsedit.nodoka` では、

      keyseq $EmacsEdit/kill-line = \
      &EmacsEditKillLineFunc S-End C-X &Sync \
      &EmacsEditKillLinePred((Delete), (Return Left))

      こうなってるはずです。

      `&EmacsEditKillLineFunc` は初回だけ、クリップボードの中身をクリアします。初回でない場合は、クリップボードの中身を「のどか」内部に保存 (※) します。

      その後 `S-End C-X` で行末までを選択し「切り取り」ます。ここで、クリップボードに行末までがコピーされたわけですが、クリップボードの中身には幾つか可能性があります。

      EDIT コントロールの場合

      (EDIT-1) カーソルが行末にあると、「」(からっぽ)

      (EDIT-2) カーソルが行末以外だと、「行末までの文字列」

      です。IE の中のエディットボックスの場合、

      (IE-1) カーソルが行末にあると、「改行」

      (IE-2) カーソルが行末以外だと、「行末までの文字列＋改行」

      です。

      `&EmacsEditKillLinePred` は、クリップボードの中身を調べて、

      (EDIT-1) の場合は、※で保存したデータに「改行」を追加してクリップボードへ書き戻します。その後、第一引数、つまり `Delete` を実行します。

      (EDIT-2) の場合は、※で保存したデータに「行末までの文字列」を追加してクリップボードへ書き戻します。

      (IE-1) の場合は、※で保存したデータに「改行」を追加してクリップボードへ書き戻します。

      (IE-2) の場合は、※で保存したデータに「行末までの文字列(改行は除く)」を追加してクリップボードへ書き戻します。その後、第二引数、つまり `Return Left` を実行します。

      このように動作することで (EDIT-1) と (IE-1) は (C-k-1) 相当、(EDIT-2) と (IE-2) は (C-k-2) 相当になります。

    `&HelpMessage(title, message)`

      IE5.0 以降が入っていれば、タスクトレイ付近にメッセージを表示します。`title` 文字列 と `message` 文字列 を省略すると、表示されているメッセージを消します。

      インストールされている Internet Explorer のバージョンによっては、挙動が異なります。Windows 2000では、表示した後、消えないようですが、Vista では表示後、３０秒程度で何もしなくても消えます。

    `&HelpVariable(title)`

      IE5.0 以降が入っていれば、タスクトレイ付近に `&Variable` で設定された値が `title` 文字列 と共に表示されます。

    `&IconColor(color)`
      通知領域（タスクトレイ）における「のどか」のアイコンの色を指定します。colorには、下記 表の0から7が指定可能です。

      | 0：灰色　デフォルト
      | 1：茶色　(注1. Windows 2000では右側の濃い灰色)
      | 2：赤色
      | 3：橙色　(注1. Windows 2000では右側の赤と黒)
      | 4：緑色
      | 5：青色
      | 6：紫色　(注1. Windows 2000では右側の白とマジェンタ)
      | 7：黄色

      注1. Windows 2000では、アイコンの色数が16色のため、異なる色となります。
      nodoka.exe の引数でも、アイコンの色を指定可能です。既に起動済みの場合にも、色だけ変更指示することが可能です。
      コマンドプロンプトで、のどかインストールディレクトリに移動し、nodoka 2[enter] を実行すると、アイコンの色が赤色に変更されます。
      引数を付けなければ、アイコンの色は変更されません。4.03以前では、二重起動のエラーダイアログ が表示されましたが、4.04以降では表示されません。
      スタートアップなどのショートカットでは、プロパティでのリンク先に、"C:\Program Files\nodoka\nodoka.exe" 2 のように指定することで、指定の色で起動するようになります。

    `&Ignore`

      なにも起こりません。なにも実施しないがベルを鳴らしたい場合には、`&Undefined` を お使いください。

    `&InvestigateCommand`

      ウィンドウへ送られてくる `WM_COMMAND` と `WM_SYSCOMMAND` を調べ ログに出力します。トグルになっていますので、調査が終わったらもう一度この `FUNCTION` を実行してください。さもないとアプリケーションの実行速度が遅くなる可能性があります。ログの出力は `&PostMessage` や &SendPostMessage で使用することが出来ます。

    `&Keymap(キーマップ名)`

      別のキーマップのキーを指定します。例えば、

      keymap sub : Global
      key C-A = &WindowMinimize
      window EditControl /:Edit$/ : Global
      key C-A = &Keymap(sub)

      というように利用します。この場合、エディットコントロールで `Control` + `A` を入力すると、最小化されます。あまり実用的な機能はないかもしれません。ループしないように気をつけて利用してください。

    `&KeymapParent`

      親キーマップ参照。

    `&KeymapPrevPrefix`

      現在のキーマップ (仮に `CURRENT` という名前とする) が二段階キーマップの場合、`&Prefix``(CURRENT)` を実行したキーマップで定義されているキーを指定します。引数が無いと 1 段階前のキーマップになりますが、引数に数字を書くとその段階数前のキーマップになります。たとえば、

      keymap E
      key A = &KeymapPrevPrefix(2)
      keymap D
      key X = &Prefix(E)
      key A = D
      keymap C
      key X = &Prefix(D)
      key A = C
      key Y = &Prefix(E)
      keymap B
      key X = &Prefix(C)
      key A = B
      keymap Global
      key X = &Prefix(B)
      key A = A

      ここで `X` `X` `X` `X` `A` と入力すると `C` が、`X` `X` `Y` `A` と入力すると `B` が入力されます。

    `&KeymapWindow`

      現在のウィンドウに定義されたキーマップのキーを入力します。プレフィックスキーの入力中に使用すると便利です。例えば

      keymap2 NotepadC-X
      key A = &KeymapWindow
      window Notepad /:Notepad:Edit$/ : Global
      key C-X = &Prefix(NotepadC-X)
      key A = T E S T

      この場合、メモ帳で `Control` + `X` を押した後に `A` を入力すると、`&KeymapWindow` は `Nodepad` キーマップに定義されているキーを入力しようとします。従って、`TEST` が入力されます。

    `&LoadSetting(設定名)`

      設定ファイルを再読み込みします。`設定名` 文字列 は「設定(I)...」で設定した「名前」で、再読み込みする設定を指定します。`設定名`を省略すると現在の設定を再読み込みします。

    `&MouseMove(dx, dy)`

      マウスカーソルを水平に `dx`、垂直に `dy` 移動します。

    `&MouseWheel(delta)`

      ホイールを回します。`delta` を `-120` にするとホイールを手前に 1 単位まわしたことになります。逆に `120` にするとホイールを奥へ 1 単位まわしたことになります。

    `&NodokaDialog(dialog, show_command)`
      「のどか」のダイアログボックスを表示したり隠したりします。`dialog` には `Investigate` と `Log` が指定できます。それぞれ「調査」ダイアログと「ログ」ダイアログです。`show_command` には、`HIDE`, `SHOW`, `SHOWNA` などが指定できます。
    `&OtherWindowClass`

      `window` に複数該当する場合参照。

    `&PlugIn(DLLNAME, FUNCNAME, FUNCPARAM, runAsThread)`

      プラグインを実行します。`nodoka.exe` のあるディレクトリの中の `Plugins` というディレクトリにプラグイン DLL を置いておくとそのプラグインの中の関数を「のどか」から直接呼ぶことが出来ます。

      `DLLNAME` はプラグイン DLL 名です。`Plugins\DLLNAME.dll` が使用されます。

      `FUNCNAME` は DLL 中の関数名です。DLL は、以下の関数のうちのどれか実装していなければなりません。この引数は省略することができます。省略すると空文字列になります。

      void WINAPI nodokaFUNCNAMEW(const wchar_t *FUNCPARAM);
      void WINAPI nodokaFUNCNAMEA(const char *FUNCPARAM);
      void WINAPI nodokaFUNCNAME(const char *FUNCPARAM);
      void WINAPI FUNCNAME(const char *FUNCPARAM);

      `FUNCPARAM` は DLL の関数を呼び出すときに渡される引数です。省略すると空文字列 (`NULL` ではない) になります。

      `runAsThread` に `true` を指定すると指定の関数をスレッドの中で実行します。省略すると `false` が指定されたことになります。

      「窓使いの憂鬱」用のプラグインが、「のどか」で動作しない場合、DLLで公開されている関数名が mayuFUNCNAME で、記述されている可能性が高いです。修正しビルドしなおす必要があります。 なお、いくつかの著名なプラグインについては、リビルドして、こちらで 配布しています。

      あるいは mayuFUNCNAME で呼べば動く可能性がありますが未確認です。

    `&PostMessage(window, message, wParam, lParam)`

      現在アクティブとなっているウィンドウへメッセージを送ることができます。高度な機能なので完全に理解してから利用してください。 任意のウィンドウへメッセージを送るには、&SendPostMessage()を お使いください。

      keyseq $WM_CUT = &PostMessage(ToItself, 0x0300, 0, 0)
      window EditControl /:Edit$/ : Global
      key C-W = $WM_CUT

      と書くと、一部のウィンドウで `Control` + `W` でカットできるようになります。

      `window` には、メッセージを送る先のウィンドウを指定します。以下の種類があります。

      - `ToItself` はそのウィンドウ自身へ。
      - `ToMainWindow` は最も親のウィンドウへ。
      - `ToOverlappedWindow` は子でない最初のウィンドウへ。
      - `ToParentWindow` は親ウィンドウへ。
      - `正の数` は `1`:親ウィンドウ、`2`:親の親、`3`:親の親の親…

      どのようなメッセージを送ればよいかは Spy++ などで調べられますが、`WM_COMMAND` (0x0111) と `WM_SYSCOMMAND` (0x0112) については`&InvestigateCommand` で調べることもできます。

    `&Prefix(キーマップ名, ignore_modifiers)`

      プレフィックスキーを指定します。例えば、

      keymap2 NotepadC-X
      key C-C = &WindowClose
      window Notepad /:Notepad:Edit$/ : Global
      key C-X = &Prefix(NotepadC-X)

      というように記述しておくと、メモ帳で `Control` + `X` `Control` + `C` と続けて入力するとメモ帳を終了することができます。

      `ignore_modifiers` は省略可能な引数で `true` か `false` を指定します。省略すると `true` が指定されたとみなされます。`true` が指定された場合、`キーマップ名` で指示されるキーマップは

      mod !shift !alt !control !windows \
      !mod0 !mod1 !mod2 !mod3 !mod4 \
      !mod5 !mod6 !mod7 !mod8 !mod9

      が指定されたものとして扱われます。つまり、全てのモディファイヤが真のモディファイヤとして扱われるようになります。

      `keymap2` を利用しているときには、デフォルトキーが `&Undefined` になっているので、モディファイヤを入力した時にもベルが鳴るはずですが、このように `true` を指定しておけば鳴らなくなります。(`mod` を参照)

      `false` を指定すれば、2 ストローク目にモディファイヤキーそのものを使用することができる可能性がありますが、通常はそのような使用方法はしないと思われます。また、さまざまな問題により `false` の指定にはバグがありますので使用はオススメしません。

      > 1. キーの押す・離す、が順番に来ない場合

      >    例えば `Control` + `X` `Control` + `L` という入力をユーザーがした場合、`D-C-X U-C-X D-C-L U-C-L` という順序で入力されるのが正しいのですが、`X` は左手、`L` は右手で入力するため、 `D-C-X D-C-L U-C-X U-C-L` という順序で入力されてしまうことがしばしばあります。

      >    ですから、現在の実装では `&Prefix` はキーダウン (`D-`) 部分でしか正しく動作しないようになっています。入力されるキーの順序が入れ替わるため、`U-` 部分で `&Prefix` が動作してしまうとおかしなことになるからです。(現在は中途半端に動作しているので、バグかもしれません。要調査)

      > 2. キーリピート

      >    キーリピートは、キーダウン (`D-`) がたくさん入力されたあとに、キーアップ (`U-`) が一度だけ入力されます。この場合に `&Prefix` がどのように動作すべきかは自明ではありません。

      > 3. モディファイヤキーのキーマップ

      >    `false` を指定した時に `Control` + `X` `F` と入力したとします。`D-C-Control D-C-X U-C-X U-Control D-F U-F` このような順序でキーが入力されますが、`U-Control` はどのキーマップで解釈されるべきでしょうか？

      >    現在は、`&Prefix` 先のキーマップで解釈されていますが、モディファイヤを真のモディファイヤへ自動的に変換するため、`U-Control` は何の機能ももたないので、うまく動作しているように見えます。ですが、本来ならば元のキーマップで解釈されるべきなのでこれはバグなのですが、修正する予定はありません。

    `&Recenter`

      エディットコントロールかリッチエディットコントロールでのみ動作し、カレットの位置を縦方向の中央に移動させます。

    `&Repeat(キーシーケンス, 最大回数)`
      `&Variable` で設定した回数だけ `キーシーケンス` を実行します。ただし、実行しすぎると危険なので最大回数を指定できます。最大回数は省略することができ、その場合 10 回が最大になります。

      key A = &Variable(0, 10) &Repeat((X))

      上の例では、`A` を押すと、`X` が 10 回入力されます 。

    `&SendPostMessage("Send/Post/PostTray", window class name, [window title name], message, wParam, lParam)`
      任意のウィンドウや、通知領域（タスクトレイ）のアイコンに、メッセージを送ります。 お試し版であり、将来仕様は変更されることがあります。また、複雑な機能のため、完全に理解してから お使いください。
      なお、アクティブなウィンドウに、メッセージを送る場合には、&PostMessage()を お使いください。

      > 最初の引数に`"Send"` あるいは`"Post"` を指定すると、Win32 SDK の SendMessage(), PostMessage() と同等の機能となります。通常は、終了を待たない `"Post"` を指定することになると考えます。

      > `window class name, window title name` には、メッセージを送る先のウィンドウクラス名やウィンドウタイトル名を 文字列で指定します。 Win32 SDK の FindWindow() の第１引数や第２引数と同じです。

      > `window title name` は、省略可能です。

      > `message` には、送りたいウィンドウメッセージID番号を、また wParam, lParam には、適切な引数を指定する必要があります。これらは、Win32 SDK の SendMessage() あるいは PostMessage() の第2,3,4引数と同じです。

      > key S-F3 = &SendPostMessage("Post", "nodokaTasktray",, 0x0010, 0, 0)

      > 上の例では、「のどか」の通知領域（タスクトレイ）上のアイコンに対し、WM_CLOSE (0x0010) を送り、「のどか」を正常終了させます。

      > どのようなメッセージを送ればよいかは Microsoft社の開発ツールである Visual Studio (Express版を除く) に付属してる Spy++ などで調べられますが、`WM_COMMAND` (0x0111) と `WM_SYSCOMMAND` (0x0112) については `&InvestigateCommand` で調べることもできます。

      > 最初の引数に`"PostTray"` を指定すると、通知領域（タスクトレイ）上のアイコンに対して、ウィンドウメッセージを送ります。(Vista x64, XP x64 ではアイコンが検索できず、機能しません。)

      > この指定を行った場合、引数の与え方が変わり、３番目の `window title name` にアイコンのタイトル名を指定します。部分一致で検索します。このタイトル名称は、ログウィンドウ の詳細にチェックして、この機能を実行した際に、そのとき通知領域にあるアイコンごとにログに表示されますので、参考にしてください。

      > `message` には、送りたいウィンドウメッセージID番号、wParam, lParam には、0 を指定します。

      > 2番目の引数 `window class name` に実行ファイル名のフルパスを記述すると、通知領域 のアイコンが検出できなかったときに、その実行ファイルを実行します。なお記述しなければ、実行されません。

      > 以下は設定例となります。

      > # Tweenというアプリのウィンドウを開く。なお通知領域に居ない場合には、起動する。
      > key S-F2 = W-M &Sync &SendPostMessage("PostTray","C:\\Program Files\\Tween\\Tween.exe","Tween", 0x0202, 0, 0)
      > key S-F3 = &SendPostMessage("PostTray", "C:\\Program Files\\Tween\\Tween.exe","Tween", 0x0202, 0, 0)
      > # のどかのログウィンドウを開く。
      > key S-F4 = &SendPostMessage("PostTray",,"のどか", 0x0201, 0, 0)
      > # USBメモリの取り外しのためのウィンドウを開く。カーソルキーで選んでEnterで取り外せる。
      > key S-F5 = &SendPostMessage("PostTray",,"ハードウェアの安全な取り外し", 0x0201, 0, 0)
      > #key S-F5 = &SendPostMessage("PostTray",,"ハードウェアの取り外しまたは取り出し", 0x0201, 0, 0) # for W2K
      > #key S-F5 = &SendPostMessage("PostTray",,"Unplug or Eject Hardware", 0x0201, 0, 0) # for W2K US

      > `message` に記述するウィンドウメッセージID番号において、マウスのクリックによるものは、次に示す番号となります。

      > WM_LBUTTONDOWN 0x0201、WM_LBUTTONUP 0x0202、WM_LBUTTONDBLCLK 0x0203

      > WM_RBUTTONDOWN 0x0204、WM_RBUTTONUP 0x0205、WM_RBUTTONDBLCLK 0x0206

      > WM_MBUTTONDOWN 0x0207、WM_MBUTTONUP 0x0208、WM_MBUTTONDBLCLK 0x0209

      > アプリケーションによっては、マウスのボタンクリックに対する動作が実装されていない 場合、機能しないことがあります。例えば、左ボタンによるシングルクリックを試そうと送ってみても WM_LBUTTONDOWN(0x0201) では無反応だが WM_LBUTTONUP(0x0202) で動作するものもあります。
      > また、Windowsの仕様により、例えば左ボタンクリックで、ダイアログやウィンドウが開くアプリケーションでも、最前面に表示されずに、タスクバーで点滅するのみとなることがあるのでご注意ください。

    `&SetImeStatus(status)`

      IME の ON/OFF を切り替えます。`status` は `on`, `off`, `toggle` のいずれかで、省略時は `toggle` として扱われます。

      例えば、変換キーと無変換キーで、それぞれ IME ON とIME OFFを実現するには、次のようになります。

      key *IC-変換 = &SetImeStatus(on)
      key *IC-無変換 = &SetImeStatus(off)

      MS-IME2002/2003 と一部のアプリケーション (例えば MS Word2002/2003) の組み合わせでは「詳細なテキストサービス」を無効にしない限り機能しません。 なおVistaでは「詳細なテキストサービス」を無効にすることは出来ませんが、XPよりも挙動が安定しており、ある程度使えます。

      なお、104.nodoka や 109.nodoka では、keyseq $ToggleIME が定義されているので、トグル操作で、&SetImeStatus(toggle) の代わりに $ToggleIME が使用可能です。 また操作対象となるウィンドウによっては、&SetImeStatus(status)が、うまく機能しないことがあり 、その場合でも $ToggleIME が有効な場合があります。

      もし、$ToggleIME でトグルではなく、ON あるいは OFF を実現させる場合、例えば、変換キーで IME ON、無変換キーで IME OFFを実現させるには、次のような記述となります。

      key ~IL-変換 = $ToggleIME
      key IL-*IC-無変換 = $ToggleIME

      なお、IME ON/OFFに関しては、IME自身のかな漢字入力 ON/OFFキーの設定でも、使いたいキーにもよりますが、実現可能なので、お使いの環境に合わせて、一番、安定して正しく動く設定を、お使いになるのが一番でしょう。

    `&SetImeString(text)`

      IME を経由して `text` 文字列 を入力します。 実際の動作については、使用されているIMEによって挙動は異なります。

    `&ShellExecute(operation, file, parameters, directory, show_command)`

      プログラムを実行します。

      - `operation` 文字列 にはファイルに対してどのような操作をするかを指示し、通常 `open` を指定します。`open` 以外も指定可能ですが、どのように動作するかについては、指定した実行ファイルに依存します。
      - `file` 文字列 には 文書ファイルか実行ファイル名を書きます。
      - `parameters` 文字列 には `file` に実行ファイルを書いたとき に渡す引数を記述します。直接記述する他に、引数置換変数 を用いて、現在アクティブなウィンドウの Class名やTitle名を渡せます。
      - `directory` 文字列 は作業ディレクトリを指定します。
      - `show_command` には `ShowNormal` を指定します。`ShowNormal` 以外にも、`hide maximaize minimize restore show showDefault showMaximized showMinimized showMinNoActive showNA showNoActivate` が指定可能ですが、その挙動は実行ファイルに依存します。``

      コントロールパネルを開く例:

      key M-B = &ShellExecute("open", "C:\\WINDOWS\\system32\\Control.exe",,, ShowNormal)

      システムのプロパティを開く例:

      key M-C = &ShellExecute("open", "C:/WINDOWS/system32/Control.exe", "sysdm.cpl",, ShowNormal)

      インターネットエクスプローラで「のどか」のホームページを開く例:

      key M-I = &ShellExecute("open", "C:\\Program Files\\Internet Explorer\\iexplore.exe", "http://appletkan.com/",, ShowNormal)
      key M-H = &ShellExecute("open", "http://appletkan.com/",,, ShowNormal)

      `flourish.mid` を演奏する例:

      key M-R = &ShellExecute("play", "C:\\WINDOWS\\Media\\flourish.mid",,, ShowNormal)

    `&Sync`

      基本的に、ウィンドウへのキー入力と `FUNCTION` は非同期に実行されます。つまりキー入力と `FUNCTION` の実行順序は不明です。例えば、

      key C-A = A &WindowMinimize

      このように記述して `Control` + `A` を入力すると、Windows へ `A` が入力されるのが先か、`&WindowMinimize` が実行されるのが先かは不明です。そこで、以下のように記述すればちゃんと順序が守られることを保証できます。

      key C-A = A &Sync &WindowMinimize

      また、`FUNCTION` にはモディファイヤを指定することが可能ですが、`FUNCTION` とモディファイヤキー入力が非同期に実行されるため通常は意味がありません。しかし、`&Sync` を使えばモディファイヤキーの指定に意味が出てきます。

      window Explorer /Explorer\.exe/ : Global
      key C-S-Z = &Sync &WindowMaximize # ウィンドウの最大化
      key C-A-Z = C-&Sync *&WindowMaximize # ウィンドウの全画面化

      前者の指定では、ウィンドウを最大化するときに `Control` と `Shift` が入力されていない ように、しています。後者では、`Control` は入力されるが、`Alt` は入力されていない ように、します。

      `def sync` 参照。

    `&Toggle(LockN [, on|off])`

      ロックキーと呼んでいる内部変数の状態を変更し、モディファイヤーとして使用できます。`&Toggle(Lock0)`〜`&Toggle(Lock9)` が利用できます。ロックキーの項もご覧ください。

      引数に `,on` `あるいは,off` を追加すると、ロックキーを強制的にオンにしたりオフにしたりできます。

      オンには、`on, true, pressed` が、またオフには、`off, false, released` が使えます。

      10個しかありませんが、on/off を 1bitの状態と考え、複数のロックキーを、組み合わせると、最大 2^10 = 1024個の状態を表すことが可能です。

    `&Undefined`

      キーに何も割り当てられていないことにします。もしそのキーが押されると、ベルが鳴ります。 ベルを鳴らしたくない時には、&Ignore を用います。

    `&VK(virtual_key)`

      仮想キーを Windows へ入力します。仮想キーには、物理的なキーボードから入力できないキーも存在しますのでそのようなキーの入力に使用します。仮想キーを調べるには、タスクトレイメニュー調査(I)...の「仮想キーの調査」を利用します。例えば、

      key 変換 = &VK(F13)

      と記述すると `変換` キーを押すと `F13` を入力できます。又、`E-` を付けると拡張キーを表し、`D-` はキーを押す、`U-` はキーを離すことを表します。

      `virtual_key` に `LButton`、`MButton`、`RButton`、`XButton1`、`XButton2` を指定することによって、マウスのボタンをシミュレートすることができます。

      この `FUNCTION` を利用するときは、必ず最後にキーを離していることを確認してください (つまり最後に `&VK(U-F13)` などを書いておく)。さもないと、そのキーが押されっぱなしになります。

    `&Variable(mag, inc)`

      `&Repeat` と `&HelpVariable` で使用可能な内部変数です。`mag` 倍してから `inc` を加えます。 通常 `mag` には、0を指定することになります。

    `&Wait(milli_second)`

      `milli_second` ミリ秒だけ実行を中断します。その間はキーを入力することはできません。最大 5000ミリ 秒 すなわち 5秒待つことができます。

    `&WindowClingToLeft`, `&WindowClingToRight`, `&WindowClingToTop`, `&WindowClingToBottom`,

      現在アクティブなプログラムのウィンドウを、それぞれの辺が画面のそれぞれの辺にくっつくように移動させます。`(MDI)`を追加すると、MDI 子ウィンドウを操作します。

      - `&WindowClingToTop` は `&WindowMoveTo(N, 0, 0)`と同じ。
      - `&WindowClingToRight` は `&WindowMoveTo(E, 0, 0)` と同じ。
      - `&WindowClingToLeft` は `&WindowMoveTo(W, 0, 0)` と同じ。
      - `&WindowClingToBottom` は `&WindowMoveTo(S, 0, 0)` と同じ。
    `&WindowClose`

      現在アクティブなプログラムのウィンドウを閉じます。`(MDI)`を追加すると、MDI 子ウィンドウを操作します。

    `&WindowIdentify`

      現在アクティブなプログラムのウィンドウのウィンドウクラス名とタイトルを調査して、ログウィンドウに出力します。又、各種ウィンドウの位置と大きさも出力します。
      お使いのWindows によっては、正しく取得できないプログラムのウィンドウが存在します。バグの項をご覧ください。

    `&WindowMinimize`, `&WindowMaximize`, `&WindowHMaximize`, `&WindowVMaximize`

      現在アクティブなプログラムのウィンドウを、それぞれ、最小化、最大化、横方向に最大化、縦方向に最大化します。`(MDI)`を追加すると、MDI 子ウィンドウを操作します。

    `&WindowMonitor(monitor, adjust_position, adjust_size)`

      複数のディスプレイを用いたマルチモニタ環境の場合において、ウィンドウをモニタ `monitor` へ移動します。`&WindowMonitorTo(primary, monitor, adjust_position, adjust_size)` と同じ動作をします。

    `&WindowMonitorTo(from, monitor, adjust_position, adjust_size)`

      マルチモニタ環境の場合において、現在アクティブなプログラムのウィンドウを `from` を基準としてモニタ `monitor` へ移動します。`from` には、次のものが指定できます。

      - `primary` : プライマリモニタを基準とします
      - `current` : 現在ウィンドウがあるモニタを基準とします

      `monitor` には、数字が指定できます。`0` が基準となるモニタ、正の数は `1`: 次のモニタ、`2`: 次の次のモニタ…、負の数は `-1`: 前のモニタ、`-2`: 前の前のモニタ…、を意味します。

      `adjust_position` は省略可能な引数で `true` か `false` を指定します。省略すると `true` が指定されたとみなされます。`true` が指定された場合、移動先がモニタからはみ出すときにできる限りモニタ内におさまる位置へ移動します。

      `adjust_size` は省略可能な引数で `true` か `false` を指定します。省略すると `false` が指定されたとみなされます。`adjust_position` が `true` の場合のみ有効です。`true` が指定された場合、移動先がモニタからはみ出すときにモニタ内におさまるようウィンドウの大きさを調整します。

    `&WindowMove(dx, dy)`

      現在アクティブなプログラムのウィンドウを水平方向に `dx`、垂直方向に `dy` 移動します。`MDI` を引数の最後に追加指定すると、MDI 子ウィンドウを操作します。`&WindowMoveTo(C, dx, dy)` と同じ動作をします。

    `&WindowMoveTo(gravity, dx, dy)`

      現在アクティブなプログラムのウィンドウを、基準位置から相対的にウィンドウを水平方向に `dx`、垂直方向に `dy` 移動します。`MDI` を引数の最後に追加指定すると、MDI 子ウィンドウを操作します。`gravity` には、次のものが指定できます。

      - `C` : 現在位置からの相対位置に移動します。
      - `N` : 上下方向はデスクトップの上からの相対位置、左右方向は現在位置からの相対位置に移動します。
      - `E` : 上下方向は現在位置からの相対位置、左右方向はデスクトップの右からの相対位置に移動します。
      - `W` : 上下方向は現在位置からの相対位置、左右方向はデスクトップの左からの相対位置に移動します。
      - `S` : 上下方向はデスクトップの下からの相対位置、左右方向は現在位置からの相対位置に移動します。
      - `NE` : デスクトップ右上からの相対位置に移動。
      - `NW` : デスクトップ左上からの相対位置に移動。
      - `SE` : デスクトップ右下からの相対位置に移動。
      - `SW` : デスクトップ左下からの相対位置に移動。

      また、他の移動 `FUNCTION` とは以下のような関係があります。

      - `&WindowMoveTo(C, dx, dy)` は `&WindowMove(dx, dy)` と同じ。
      - `&WindowMoveTo(N, 0, 0)` は `&WindowClingToTop` と同じ。
      - `&WindowMoveTo(E, 0, 0)` は `&WindowClingToRight` と同じ。
      - `&WindowMoveTo(W, 0, 0)` は `&WindowClingToLeft` と同じ。
      - `&WindowMoveTo(S, 0, 0)` は `&WindowClingToBottom` と同じ。
    `&WindowMoveVisibly`

      現在アクティブなプログラムのウィンドウ全体が、画面に入るように表示されるような位置へウィンドウを移動します。`(MDI)` を追加すると、MDI 子ウィンドウを操作します。

    `&WindowRedraw`

      現在アクティブなプログラムのウィンドウを強制的に再描画させます。

    `&WindowResizeTo(width, height)`

      現在アクティブなプログラムのウィンドウの大きさを幅 `width`、高さ `height` に変更します。`0` を指定すると現在の大きさに、負の値を指定するとデスクトップの大きさより指定したピクセル数だけ小さい大きさになります。`MDI` を引数の最後に追加指定すると、MDI 子ウィンドウを操作します。

    `&WindowRaise`, `&WindowLower`

      現在アクティブなプログラムのウィンドウを、それぞれ、一番上、一番下へ移動します。`(MDI)` を追加すると、MDI 子ウィンドウを操作します。

    `&WindowSetAlpha(alpha)`

      現在アクティブなプログラムのウィンドウを半透明化、又は半透明化解除します。トグルになっています。`alpha` は半透明の度合いを表し、`0` で透明、`100` で不透明になります。`-1` を指定すると、この `FUNCTION` で半透明化されたウィンドウを全て不透明状態に戻します。

    `&WindowToggleTopMost`

      現在アクティブなプログラムのウィンドウの最前面フラグをトグルします。

    引数置換

      引数として `$` で始まる下記キーワードを指定することにより `FUNCTION` の引数に文字列が使えるところで、それぞれが意味する文字列の内容を渡すことができます。値の取り出しは `FUNCTION` の実行時に行われます。

      $NodokaVal は、お試し機能であり、将来の版では変更される可能性がありますが、$Clipboard, $WIndowClassName, $WindowTitleNameには、展開された文字列が入ります。制限事項として、それぞれの文字列の長さは、最大2058byteであり、展開された文字列に " (ダブルクォーテーション)記号があると、分断されて渡されます。

      - `$Clipboard` : クリップボードの中身
      - `$WindowClassName` : フォーカスされているウィンドウのクラス名
      - `$WindowTitleName` : フォーカスされているウィンドウのタイトル名
      - `$NodokaVal` : /Clipboard:"`$Clipboard`" /Class:"`$WindowClassName`" /Title:"`$WindowTitleName`"

      クリップボード内の文字列を URL としてブラウザで開く例:

      key M-C-O = &ShellExecute("open", $Clipboard,,, ShowNormal)

      フォーカスされているウィンドウのクラス名やタイトル名をクリップボードにコピーする例:

      key M-C-C = &ClipboardCopy($WindowClassName)
      key M-C-T = &ClipboardCopy($WindowTitleName)

      $NodokaVal の使用例

      key C-S-F = &ShellExecute("open", "C:¥¥Users¥¥hogehoge¥¥testNodokaVal.vbs", $NodokaVal,, ShowNormal)

      テストスクリプト testNodokaVal.vbs の中身

      ' $NodokaVal による引数表示
      Option Explicit
      Dim ws
      Dim args
      Dim any_string
      Dim program_name
      Dim class_name
      Dim title_name
      Set ws = CreateObject("WScript.Shell")
      Set args = WScript.Arguments
      If args.Named.Exists("Clipboard") Then
      ws.Popup "/Clipboard:" & args.Named("Clipboard") & " ,文字数 " & Len(args.Named("Clipboard")), , , vbInformation
      End If
      If args.Named.Exists("Class") Then
      any_string = Split(args.Named("Class"), ":")
      program_name = any_string(0) + ":" + any_string(1)
      class_name = Mid(args.Named("Class"), 1 + Len(program_name))
      ws.Popup "/Program:" & program_name , , , vbInformation
      ws.Popup "/Class:" & class_name & " ,文字数 " & Len(class_name), , , vbInformation
      End If
      If args.Named.Exists("Title") Then
      ws.Popup "/Title:" & args.Named("Title") & " ,文字数 " & Len(args.Named("Title")), , , vbInformation
      End If
      If args.Unnamed.Count > 0 Then
      ws.Popup "名前なし:" & args.Unnamed(0) & " ,文字数 " & Len(args.Unnamed(0)) , , , vbInformation
      End If
      Set ws = Nothing
      Set args = Nothing

    文字列

      文字列が記述できる箇所には `"文字列"` と記述することができますが、`\` という文字は、その次にくる文字と組み合わせて特殊な文字を表します。

      - `\a` (U+0007) ベル文字
      - `\e` (U+001b) ESC 文字
      - `\f` (U+000c) 改頁文字
      - `\n` (U+000a) 改行文字
      - `\r` (U+000d) 復帰文字
      - `\t` (U+0009) タブ文字
      - `\v` (U+000b) 垂直タブ文字
      - `\'` 「`'`」
      - `\"` 「`"`」
      - `\\` 「`\`」
      - `\cX` コントロール文字一般。`^X`
      - `\xXXXX` (U+XXXX) 16 進数で表現した UNICODE 文字。X は 0〜9 と a〜f。
      - `\0XXXX` 8 進数で表現した UNICODE 文字。X は 0〜7。
      - 上記に当てはまらない `\X` は X という文字そのもの。