AHK 八倒記 (4)

前回の続き。
AutoHotkey で Space キーをワンショットモディファイヤとして使う定義がとりあえず実用レベルに達した。
昨日のやり方だとキー1個につき modify() と unmodify() の2行を書かなきゃいけないのが気に入らないので、キー1個につき1行で済むやり方をいろいろ考えた。

  • モディファイヤキーの状態に応じて入力すべきキー名を動的に生成し、その名前のホットキーラベルがあれば gosub で飛ばす。なければその名前のキーを send する。…ラベルは字面で比較されるので、 ^+End と +^End は別物扱い。 Shift, Ctrl, Alt, Win の全パターンに対応しようとすると組合せ爆発が起きる。
$*sc027::
	if (getkeystate("Space")) {
		next := "End"	; ← Shift は? Ctrl は?
	} else {
		next := "sc027"
	}
	if (islabel(next)) {
		gosub %next%
	} else {
		send {%next%}
	}
	return
  • ラッパー関数を用意し、その中で Hotkey コマンドを使って2つのホットキー(modify() と unmodify())を動的に定義する。… Hotkey コマンドでは関数を呼ぶホットキーが作れない。
AddModifiedKey(keyname, key0, key1) {
	Hotkey %keyname%, OM_Modify(key0, key1)	; ← 関数は呼べない
	Hotkey %keyname% up, OM_Unmodify()
}

てな感じで両方とも実現不可能という結論に。仕方ないので昨日のやつをちょっと改良して実際に使う定義ファイルを書いた。ここでまた罠が… $+sc027:: と $*sc027:: が同時に存在するとき Shift+セミコロン を押すと $+sc027:: の方しか発動しない。となると 104on109.ahk を温存したまま共存させることはできなくて、両者の内容をマージしなきゃいけない。めんどくせー。 AutoHotkey はキー定義を全部ひとつのレイヤに押し込む設計だから、本質的にモディファイヤを作るのには向いてないし、モジュール化もできないんだなぁ。にんともかんとも。
というわけで、一部未完成だけどとりあえず実用レベルに達したものを貼っときます。識者の意見を求む。

 ; 		ikki_phase14.ahk  (2008/06/05)
 ; 		by IKKI  http://mobitan.org/
 
 #NoEnv
 ; #NoTrayIcon
 #SingleInstance force
 SetWorkingDir %A_ScriptDir%
 SendMode input
 
 gosub OM_Init
 return
 
 #Include %A_ScriptDir%
 #Include OneshotModifier_Space.ahk
 
 ;========== ウィンドウ操作 ==========
 sc029:: send !{F4}          ; 半角/全角
 Pause:: send !{F4}
 
 ;========== IME 切替 ==========
 Alt::   send {sc029}        ; 半角/全角 = IME ON/OFF
 Shift:: send {sc070}        ; ひらがな = 和文モード/英文モード
 
 ;========== リマップ ==========
 ; 単純なリマップはレジストリで行う
 ; sc073::     Delete        ; \ → Delete
 ; sc07B::     BS            ; 無変換 → Backspace
 ; sc079::     NumpadEnter   ; 変換 → NumEnter
 ; NumLock::   NumpadSub     ; NumLock → NumMinus
 ; NumpadSub:: BS            ; NumMinus → Backspace
 ; NumpadAdd:: Tab           ; NumPlus → Tab
 *Numpad0:: send {blind}{Numpad0}
  Numpad0 & NumLock::   send {Blind}{NumpadAdd}  ; Num0+NumLock → Num+
  Numpad0 & NumpadAdd:: send {Blind}+{Tab}       ; Num0+NumPlus → Shift+Tab
 ^Numpad0::   SetNumLockState off                ; Ctrl+Num0 → NumLock
 ^NumpadIns:: SetNumLockState on                 ; 
 
 ;========== モディファイヤ ==========
 $*sc002:: OM_Modify("{blind}{sc002}", "{blind}{F1}")        ;       1
 $+sc003:: OM_Modify("{sc01A}",        "{blind}{F2}")        ; Shift+2 = @
 $*sc003:: OM_Modify("{blind}{sc003}", "{blind}{F2}")        ; Other+2
 $*sc004:: OM_Modify("{blind}{sc004}", "{blind}{F3}")        ;       3
 $*sc005:: OM_Modify("{blind}{sc005}", "{blind}{F4}")        ;       4
 $*sc006:: OM_Modify("{blind}{sc006}", "{blind}{F5}")        ;       5
 $+sc007:: OM_Modify("{sc00D}",        "{blind}{F6}")        ; Shift+6 = ^
 $*sc007:: OM_Modify("{blind}{sc007}", "{blind}{F6}")        ; Other+6
 $+sc008:: OM_Modify("+{sc007}",       "{blind}{F7}")        ; Shift+7 = &
 $*sc008:: OM_Modify("{blind}{sc008}", "{blind}{F7}")        ; Other+7
 $+sc009:: OM_Modify("+{sc028}",       "{blind}{F8}")        ; Shift+8 = *
 $*sc009:: OM_Modify("{blind}{sc009}", "{blind}{F8}")        ; Other+8
 $+sc00A:: OM_Modify("+{sc009}",       "{blind}{F9}")        ; Shift+9 = (
 $*sc00A:: OM_Modify("{blind}{sc00A}", "{blind}{F9}")        ; Other+9
 $+sc00B:: OM_Modify("+{sc00A}",       "{blind}{F10}")       ; Shift+0 = )
 $*sc00B:: OM_Modify("{blind}{sc00B}", "{blind}{F10}")       ; Other+0
 $+sc00C:: OM_Modify("+{sc073}",       (A_ComputerName = "Reinforce") ? "{blind}{PgDn}" : "{blind}{F11}") ; Shift+− = _
 $*sc00C:: OM_Modify("{blind}{sc00C}", (A_ComputerName = "Reinforce") ? "{blind}{PgDn}" : "{blind}{F11}") ; Other+−
 $sc00D::  OM_Modify("+{sc01A}",       (A_ComputerName = "Reinforce") ? "{blind}{F11}"  : "{blind}{F12}") ; Alone ^ = `
 $+sc00D:: OM_Modify("+{sc00D}",       (A_ComputerName = "Reinforce") ? "{blind}{F11}"  : "{blind}{F12}") ; Shift+^ = 〜
 $*sc00D:: OM_Modify("{blind}{sc00D}", (A_ComputerName = "Reinforce") ? "{blind}{F11}"  : "{blind}{F12}") ; Other+^
 $*sc07D:: OM_Modify("{blind}{sc07D}", (A_ComputerName = "Reinforce") ? "{blind}{F12}"  : "{blind}{}")    ;       ¥
 $*q::     OM_Modify("{blind}{q}",     "{blind}{AppsKey}")
 $*w::     OM_Modify("{blind}{w}",     "WebSearch")          ; Web 検索
 $*e::     OM_Modify("{blind}{e}",     "{blind}^{sc079}")    ; IME 確定履歴
 $*r::     OM_Modify("{blind}{r}",     "{blind}+{sc079}")    ; IME 再変換
 $*t::     OM_Modify("{blind}{t}",     "IMEDic")             ; IME 辞書引き
 $*y::     OM_Modify("{blind}{y}",     "{blind}^{Home}")     ; 
 $*u::     OM_Modify("{blind}{u}",     "{blind}^{Left}")     ; 
 $*i::     OM_Modify("{blind}{i}",     "{blind}{Up}")        ; 
 $*o::     OM_Modify("{blind}{o}",     "{blind}^{Right}")    ; 
 $*p::     OM_Modify("{blind}{p}",     "{blind}{PgUp}")      ; 
 $sc01A::  OM_Modify("+{sc00C}",       "{blind}{Esc}")       ; Alone @ = =
 $+sc01A:: OM_Modify("+{sc027}",       "{blind}{Esc}")       ; Shift+@ = +
 $*sc01A:: OM_Modify("{blind}{sc01A}", "{blind}{Esc}")       ; Other+@
 $*sc01B:: OM_Modify("{blind}{sc01B}", "{blind}{}")          ;       [
 $*a::     OM_Modify("{blind}{a}",     "ShiftAltTab")        ; 
 $*s::     OM_Modify("{blind}{s}",     "{blind}^+{Tab}")     ; 
 $*d::     OM_Modify("{blind}{d}",     "{blind}^{F4}")       ; 
 $*f::     OM_Modify("{blind}{f}",     "{blind}^{Tab}")      ; 
 $*g::     OM_Modify("{blind}{g}",     "AltTab")             ; 
 $*h::     OM_Modify("{blind}{h}",     "{blind}{Home}")      ; 
 $*j::     OM_Modify("{blind}{j}",     "{blind}{Left}")      ; 
 $*k::     OM_Modify("{blind}{k}",     "{blind}{Down}")      ; 
 $*l::     OM_Modify("{blind}{l}",     "{blind}{Right}")     ; 
 $+sc027:: OM_Modify("{sc028}",        "{blind}{End}")       ; Shift+; = :
 $*sc027:: OM_Modify("{blind}{sc027}", "{blind}{End}")       ; Other+;
 $sc028::  OM_Modify("+{sc008}",       "{blind}{}")          ; Alone : = ’
 $+sc028:: OM_Modify("+{sc003}",       "{blind}{}")          ; Shift+: = ”
 $*sc028:: OM_Modify("{blind}{sc028}", "{blind}{}")          ; Other+:
 $*sc02B:: OM_Modify("{blind}{sc02B}", "{blind}{}")          ;       ]
 $*z::     OM_Modify("{blind}{z}",     "{blind}^{z}")        ; 
 $*x::     OM_Modify("{blind}{x}",     "{blind}^{x}")        ; 
 $*c::     OM_Modify("{blind}{c}",     "{blind}^{c}")        ; 
 $*v::     OM_Modify("{blind}{v}",     "{blind}^{v}")        ; 
 $*b::     OM_Modify("{blind}{b}",     "{blind}{Space}")     ; 
 $*n::     OM_Modify("{blind}{n}",     "{blind}+{Tab}")      ; 
 $*m::     OM_Modify("{blind}{m}",     "{blind}{Tab}")       ; 
 $+sc033:: OM_Modify("{blind}{sc033}", "{blind}^{x}")        ; Shift+,
 $*sc033:: OM_Modify("{blind}{sc033}", "{blind}^{c}")        ; Other+,
 $*sc034:: OM_Modify("{blind}{sc034}", "{blind}^{v}")        ;       .
 $*sc035:: OM_Modify("{blind}{sc035}", "{blind}^{End}")      ;       /
 
 AltTab:         ; Alt+Tab
 	; 未対応
 	return
 
 ShiftAltTab:    ; Alt+Shift+Tab
 	; 未対応
 	return
 
 IMEDic:         ; IME 辞書引き
 	send +{sc079}	; 再変換
 	sleep 100
 	send {F1}
 	return
 
 WebSearch:      ; Web 検索
 	; 未対応
 	return
 
 ClipHist:       ; クリップボード履歴
 	; 未対応
 	return
 
 ~$*sc002  up:: OM_Unmodify()
 ~$*sc003  up:: OM_Unmodify()
 ~$*sc004  up:: OM_Unmodify()
 ~$*sc005  up:: OM_Unmodify()
 ~$*sc006  up:: OM_Unmodify()
 ~$*sc007  up:: OM_Unmodify()
 ~$*sc008  up:: OM_Unmodify()
 ~$*sc009  up:: OM_Unmodify()
 ~$*sc00A  up:: OM_Unmodify()
 ~$*sc00B  up:: OM_Unmodify()
 ~$*sc00C  up:: OM_Unmodify()
 ~$*sc00D  up:: OM_Unmodify()
 ~$*sc07D  up:: OM_Unmodify()
 ~$*q      up:: OM_Unmodify()
 ~$*w      up:: OM_Unmodify()
 ~$*e      up:: OM_Unmodify()
 ~$*r      up:: OM_Unmodify()
 ~$*t      up:: OM_Unmodify()
 ~$*y      up:: OM_Unmodify()
 ~$*u      up:: OM_Unmodify()
 ~$*i      up:: OM_Unmodify()
 ~$*o      up:: OM_Unmodify()
 ~$*p      up:: OM_Unmodify()
 ~$*sc01A  up:: OM_Unmodify()
 ~$*sc01B  up:: OM_Unmodify()
 ~$*a      up:: OM_Unmodify()
 ~$*s      up:: OM_Unmodify()
 ~$*d      up:: OM_Unmodify()
 ~$*f      up:: OM_Unmodify()
 ~$*g      up:: OM_Unmodify()
 ~$*h      up:: OM_Unmodify()
 ~$*j      up:: OM_Unmodify()
 ~$*k      up:: OM_Unmodify()
 ~$*l      up:: OM_Unmodify()
 ~$*sc027  up:: OM_Unmodify()
 ~$*sc028  up:: OM_Unmodify()
 ~$*sc02B  up:: OM_Unmodify()
 ~$*z      up:: OM_Unmodify()
 ~$*x      up:: OM_Unmodify()
 ~$*c      up:: OM_Unmodify()
 ~$*v      up:: OM_Unmodify()
 ~$*b      up:: OM_Unmodify()
 ~$*n      up:: OM_Unmodify()
 ~$*m      up:: OM_Unmodify()
 ~$*sc033  up:: OM_Unmodify()
 ~$*sc034  up:: OM_Unmodify()
 ~$*sc035  up:: OM_Unmodify()
 ; 		OneshotModifier_Space.ahk  v1.0  (2008/06/05)
 ; 		by IKKI  http://mobitan.org/
 
 ; スペースキーをワンショットモディファイヤにする。半ロールオーバー対応。
 
 #NoEnv
 #SingleInstance force
 
 OM_Init:
 	OM_mod1 = 0
 	return
 
 *Space::
 	OM_mod1 |= 2
 ; 	tooltip % "mod1 = " . OM_mod1
 	return
 
 *Space up::
 	if (OM_mod1 & 1 == 0) {
 		send {blind}{Space}
 	}
 	OM_mod1 &= 5
 	if (OM_mod1 & 4 == 0) {
 		OM_mod1 := 0
 	}
 ; 	tooltip % "mod1 = " . OM_mod1
 	return
 
 OM_Modify(key0, key1) {
 	global OM_mod1
 	if (OM_mod1 & 2) {
 		OM_mod1 |= 5
 		if (islabel(key1)) {
 			gosub % key1
 		} else {
 			send % key1
 		}
 	} else if (OM_mod1 == 0) {
 		if (islabel(key0)) {
 			gosub % key0
 		} else {
 			send % key0
 		}
 	}
 ; 	tooltip % "mod1 = " . OM_mod1 . "`n" . A_ThisHotkey . " is modified"
 }
 
 OM_Unmodify() {
 	global OM_mod1
 	OM_mod1 &= 3
 	if (OM_mod1 & 2 == 0) {
 		OM_mod1 := 0
 	}
 ; 	tooltip % "mod1 = " . OM_mod1 . "`n" . A_ThisHotkey . " is unmodified"
 }
 
 ; ~Esc:: tooltip	; ツールチップを消す(デバッグ用)