rcmdnk's blog

遊戯王OCG 無効 アルティメットレア SOD-JP57-UL

AutoHotkeyで色々設定していて、 ある状態にした時に設定したキー以外全てを向こうにして余計な入力を受け付けないようにしたい時に どうするか、という話。

Sponsored Links

AutoHotkeyで特定の条件下で設定したキー以外を無効化する

その様な機会がどれだけあるか分かりませんが、 やりたいと思ったのはWindowsのどこでもVim操作を実現する vim_ahkの設定。

ノーマルモードで H/J/K/L とかで移動出来る様になった時に 再現出来ないキー(Qとか)はそのままにしておくと押すと普通にqが入力されてしまいます。

それ程困るものでもないですがどうせならこれらはなにもしない様に無効化したいところ。

ということでいくつか考えて試してたんですが 取り敢えず一番マシかな、というのを見つけました。

その設定とそれに至るまでに試したことについてちょっとメモしておきます。

それぞれの条件下で無効化

AutoHotkeyでは同じ条件下で同じキーに対する設定があると 読み込み時にエラーが出るので 適当にスクリプトの最後で全部無効化する、ということは出来ません。

なのでそれぞれの条件下で使ってないキーだけを調べて それぞれ無効化の設定をしなくてはいけない、と思っていて かなり面倒なので辞めてました。 キー設定を追加したらそれをまた外したりしなくてはいけないし。

Hotkeyコマンドを使う

AutoHotkeyにはHotkey というコマンドがあります。

Disable:
Return

Hotkey, a, Disable

みたいな設定をしておくとAを押した時になにもしない様になります。

Disable:としてるのはLabelsの設定で 特定の動作に名前を付ける事が出来る機能です。

なので:以降は通常のキー設定の様に書けますが、 上ではなにもせずにReturnが来るので なにもしない設定になります。

Hotkeyコマンドでは最初にキー、次にラベルを与えることで キーにラベルに対応する動作を割り当てる事が出来ます。

Hotkeyは通常のa::...と言った通常のキー設定と違って Auto-execute sectionで行うか キー設定に割り当てて呼び出さないと有効可されません。

一方、この設定はすでに設定があっても上書きするので キーに割り当てたりすることで動的にキー設定を変更することが出来ます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
VimMode := "Insert"
Vim_g := 0
Vim_n := 0
VimLineCopy := 0
VimLastIME := 0

VimAlphabetKeys := ["a", "b", "c", "d", "e", "f", "g", "h", "i"
                    , "j", "k", "l", "m", "n", "o", "p", "q", "r"
                    , "s", "t", "u", "v", "w", "x", "y", "z"]
VimAllKeys := []
For k, v in VimAlphabetKeys {
  VimAllKeys.Push(v, "+" . v, "^" . v)
}
VimAllKeys.Push("``", "~", "!", "@", "#", "$", "%", "&", "*", "(", ")", "-", "_"
                , "=", "+", "[", "]", "{", "}", "\", "|", ";", ":", "'", """"
                , ",", ".", ">", "<", "Space")

VimChangeModeKeys := ["i", "+i", "a", "+a", "o", "+o", "v", "^v", ":", ";"]
VimNumberKeys := ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
VimMoveKeys := ["g", "h", "j", "k", "l", "^h", "^j", "^k", "^l"
                , "$", "^a", "^e", "^", "w", "+w", "e", "+e", "b", "+b"
                , "^u", "^d", "^b", "^f", "+g"]
VimYDCKeys := ["y", "d", "c", "+y", "+d", "+c"]
VimOtherKeys := ["u", "^r", "+j", "~", "+z", "+q", "Space", ".", "r", "+r"
                 , "x", "+x", "p", "+p", "*", "/", "n", "+n"]
VimCommandKeys := ["w", "q", "h", "Return", "Space", "Return"]

VimDisableKeys := {}

VimDisableKeys["Vim_Normal"] := VimAllKeys.Clone()
VimDisableKeys["Vim_Normal"] := RemoveFromArray(VimDisableKeys["Vim_Normal"], VimChangeModeKeys)
VimDisableKeys["Vim_Normal"] := RemoveFromArray(VimDisableKeys["Vim_Normal"], VimNumberKeys)
VimDisableKeys["Vim_Normal"] := RemoveFromArray(VimDisableKeys["Vim_Normal"], VimMoveKeys)
VimDisableKeys["Vim_Normal"] := RemoveFromArray(VimDisableKeys["Vim_Normal"], VimYDCKeys)
VimDisableKeys["Vim_Normal"] := RemoveFromArray(VimDisableKeys["Vim_Normal"], VimOtherKeys)

VimDisableKeys["Vim_Visual"] := VimAllKeys.Clone()
VimDisableKeys["Vim_Visual"] := RemoveFromArray(VimDisableKeys["Vim_Visual"], VimChangeModeKeys)
VimDisableKeys["Vim_Visual"] := RemoveFromArray(VimDisableKeys["Vim_Visual"], VimNumberKeys)
VimDisableKeys["Vim_Visual"] := RemoveFromArray(VimDisableKeys["Vim_Visual"], VimMoveKeys)
VimDisableKeys["Vim_Visual"] := RemoveFromArray(VimDisableKeys["Vim_Visual"], VimYDCKeys)
VimDisableKeys["Vim_Visual"] := RemoveFromArray(VimDisableKeys["Vim_Visual"], VimOtherKeys)

VimDisableKeys["Vim_VisualChar"] := VimDisableKeys["Vim_Visual"].Clone()
VimDisableKeys["Vim_VisualLine"] := VimDisableKeys["Vim_Visual"].Clone()
VimDisableKeys["Vim_VisualLineFirst"] := VimDisableKeys["Vim_Visual"].Clone()
VimDisableKeys["Vim_VisualChar"] := VimDisableKeys["Vim_Visual"].Clone()
VimDisableKeys["Vim_VisualLine"] := VimDisableKeys["Vim_Visual"].Clone()
VimDisableKeys["Vim_VisualLineFirst"] := VimDisableKeys["Vim_Visual"].Clone()

VimDisableKeys["Command"] := ["w", "q"]
VimDisableKeys["Command_w"] := ["Return", "q", "Space"]
VimDisableKeys["Command_q"] := ["Return"]

VimDisableKeys["Z"] := ["+z", "+q"]

VimDisable:
Return

DisableOthers(){
  global
  if(VimDisableKeys.HasKey(VimMode)){
    For, k, v in VimDisableKeys[VimMode] {
      Hotkey, %v%, VimDisable
    }
  }
}

VimSetMode(Mode="", g=0, n=0, LineCopy=-1){
  global
  if(Mode!=""){
    VimMode := Mode
    If(Mode=="Insert") and (VimRestoreIME==1){
      VIM_IME_SET(LastIME)
    }
    SetIcon(VimMode)
  }
  if(g != -1){
    Vim_g := g
  }
  if(n != -1){
    Vim_n := n
  }
  if(LineCopy!=-1){
    VimLineCopy := LineCopy
  }
  DisableOthers()
  VimCheckMode(VimVerbose, Mode, g, n, LineCopy)
  Return
}

#IfWInActive, ahk_group VimGroup

Esc:: ; Just send Esc at converting, long press for normal Esc.
  KeyWait, Esc, T0.5
  if (ErrorLevel){ ; long press
    Send,{Esc}
    Return
  }
  VimLastIME := VIM_IME_Get()
  if(VimLastIME){
    if(VIM_IME_GetConverting(A)){
      Send,{Esc}
    }else{
      VIM_IME_SET()
      VimSetMode("Vim_Normal")
    }
  }else{
    VimSetMode("Vim_Normal")
  }
Return

...

Auto-execute sectionでキーセット (各状態で使ってる設定を抜いてキーセットの作成)、 VimDisableラベルを作って 特定のキーセットを全てHotkeyで無効化する関数を作成、 後はモードを変更する際に対応するキーセットについて 無効化するように無効化関数を呼ぶ方法。

これだとちょっとごちゃごちゃしますが キー設定とか最初の所でまとめられるから楽かな、と。

ただこの設定は上手く行きませんでした。

問題はHotkeyで行われる設定が全ての状態に適用されてしまう、ということ。

つまりノーマルモードでQを無効化しようとすると 全ての場面で無効化されてしまってQが全く使えなくなります。

なのでやるとしたら全ての設定をHotkeyに割当て、 モード切替時に全ての設定をしなおす、という必要があります。

また、通常モードに戻るときには一旦全てのキー設定をサスペンドする必要がありますが、 これはウィンドウを移動した時にも行わなくてはいけないため ほとんど無理な設定になります。

これ、バグなのか何か使い方が違うのかわからないんですが 特定の条件下でHotkeyを使っても他の条件下でもいつでもその設定が有効になってしまいます。

Hotkeyでは

Hotkey, If [, Expression]

みたいな条件を設定することも出来て、これを呼び出した後にキー設定用の Hotkeyを呼び出すとその条件下だけで有効になる(#If ...と同じ) というものなんですが これが思った通り動きませんでした。

多分何か使い方が違うんだと思うのですが。。。

複数の条件をORで組み合わせて全てのOFF設定を書く(うまくいった今の設定)

AutoHotkeyでは同じ条件下で同じキーに関する設定があるとエラーが出るので、 各条件下できちんと無効化することを考えてました。

ですが同じ条件下になるとしても、 他の条件との組み合わせがあったりすると書いてもエラーにならない、ということがあります。

具体的には

1
2
3
4
5
6
7
#If (VimMode = "Normal")

a::b

#If (VimMode = "Normal") or (VimMode = "Visual")

a::c

といった感じの設定。

両方のaの設定がVimModeNormalな条件で発動する様な設定ですが、 この場合は条件が違うものになるのでエラーは出ません。

また、この様な重複がある場合には先に書いたものが優先されます。

同じ様なことで

1
2
a::b
*a::c

みたいな事もエラー無く出来ます。*は修飾キーのなにが来ても(なにも無くても)発動する様な 設定でa::も含んでいますが これらは別のものと認識されてエラーは出ません。 設定はやはり先のものが優先され、この場合はA単独ならb、 それ以外ならcが出ます。 *a::cを先に書けば全てcが出るようになります。

話が逸れましたが、最初の条件の組み合わせを使うことで簡単に 設定されてるキーなどを気にせずに必要ないキーだけ無効化することが出来ます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#If WInActive("ahk_group VimGroup") and ((InStr(VimMode,"Vim_")) or (InStr(VimMode, "Command")) or (VimMode == "Z"))
*a::
*b::
*c::
*d::
*e::
*f::
*g::
*h::
*i::
*j::
*k::
*l::
*m::
*n::
*o::
*p::
*q::
*r::
*s::
*t::
*u::
*v::
*w::
*x::
*y::
*z::
0::
1::
2::
3::
4::
5::
6::
7::
8::
9::
`::
~::
!::
@::
#::
$::
%::
^::
&::
*::
(::
)::
-::
_::
=::
+::
[::
{::
]::
}::
\::
|::
:::
`;::
'::
"::
,::
<::
.::
>::
Space::
Return

こんな設定を他の設定をした後に最後に書くことで Vim_NormalVim_Visualと言った設定を含む必要な状態に対して 使ってないキーだけを無効化することが可能です。

AutoHotkeyでは<key>::のあと、同じ行になにも書かないと 次の行から複数行の設定を書いていく事が出来ますが、 それはReturnが来るまで続きます。

この間に他のキーが入ってきてもOKで、そのキーに関しては入ってきた所からReturn が来るまでの設定が有効になります。

上の設定では最後にReturnがあってそれまではずっとキーが書かれてるだけなので 結果的に全てのキーに対してなにもしない、という設定を行っています。

また、ここで書いた条件は使ってる条件の組み合わせで 他ではこの様な設定は使ってないのでなにを書いてもエラーにはなりません。

さらにはVim_Normalなどの条件下で設定されてるキーに関しては先に設定されているため ここでは単に無視されるだけです。

これを全てのキーを羅列することで1 各条件下で設定されてないキーだけを無効化することが出来ています。

ここでは使っている条件が元々複数あったのでそれらを組み合わせて 他で使ってない条件を作りましたが、例えば条件が一つしかない場合でも

1
#If WInActive("ahk_class Notepad") or (1 == 2)

みたいな感じで絶対に他に無い条件をorで付け足せばそれまでに 書いた設定と重複エラーを出さずに書くことが出来ます。

Sponsored Links
  1. ;の設定だけコメント行にならないように`)のエスケープが必要。

Sponsored Links

« Mintty(Cygwin)でのDelete sends DELの設定 今更basenameで後ろ側も切れることを知った »