既知の不具合

提供: AutoHotkey Wiki
移動: 案内検索
リファレンス > 既知の不具合

ホットキー・ホットストリング関係[編集]

メニュー表示中にホットキーやホットストリングが効かない[編集]

Menu, ~, Add で作成し、Menu, ~, Show で表示している最中は、ホットキーホットストリングが効かない。
これは現在のところ、仕様となっている。
どうしても併用したい場合は、スクリプトを分割して二つ実行させるか、マルチスレッドが利用できる AutoHotkey_H を利用するなどの対策が必要となる。

日本語OSで利用する上での不具合[編集]

CapsLockやかなキー等への割り当てが上手くいかない[編集]

半角/全角、CapsLock、かな(カナロック) などのLock系のキーへのキー割り当ては上手く行かない。
これはOSのローカライズ段階で発生してる問題であり、フック系のキーカスタマイズユーティリティ全般で発生する。
AutoHotkeyがキーを認識する前の段階で、OS側がキーUp/Down情報を変更してしまっているためである。
(※ ちなみに日本語キーボードには単独のCapsLockキーは無い)

これを解決するには、AutoHotkeyよりも上流でキー信号を捕らえて何らかの加工をする必要がある。具体的には、以下のいずれかの方法を行う。

  1. レジストリに手を加えキー信号のリマップを行う。
  2. AutoHotkeyよりも上流(ドライバレベル)でのキーアサインが可能なユーティリティ(窓使いの憂鬱, のどか等)を利用する。
  3. 英語キーボードを利用する。

ここではレジストリに手を加えキー信号のリマップを行う方法を簡単に解説する。

レジストリデータはバイナリ値であり、手動での変更は容易ではないのでChangeKey等の補助ツールを使うと便利である。
なお、この機能はログオンユーザ毎に設定が可能である。

この方法を利用すると任意のキーを入れ替えることが可能となる。
CapsLock と Ctrl を入れ替えるといった単純な方法ならこれだけで可能であるが、キーの置き換え以上のことはできないので、AHKのように複数キーの組み合わせに変更するといったことは出来ない。

単純なキーの置き換え以上の事をしたい場合は、キーボードに無いキー(F13~F24など)にいったん割り当てを行った上で、そのキーに対してAHKで割り当てを行うという二段構えを行う必要がある。

日本語を扱う上での不具合[編集]

AuthoHotkeyは英語圏でつくられたソフトでマルチバイト文字列のことを全く考慮していないので以下の問題が起き得る。
なお、AutoHotkey_Lのユニコード版では以下の問題は発生しない。

一般的な事項[編集]

2バイト(全角)文字を意識していないため文字列長や文字位置はバイト単位となっている。つまり半角xx文字相当である。

長さを得るだけでは問題はあまりないが、位置を指定しての部分切り出しや(String[Trim]Left/Right, SubStr()など)、文字毎のループ(Loop, Parse,変数)などでは、2バイト文字の途中であろうがなんだろうが分割してしまう。

スクリプトに記述しても無効な文字列がある[編集]

以下の文字をスクリプトに記載した場合に不正となってしまう。

  • ~AチЯ㌔荏柿義形港餐汁秦疏蛋伝覗描冒輿倭兪啻嫣彖拜杼歔

これは上記の文字の2バイト目がAHKの標準のエスケープ文字である「`」と同じ 0x60 になっているためである。
これを回避するには以下の方法のいずれかを行う。

  • これらの文字の"直後"に「`」を記述する(例:「線形`代数」)
  • 外部ファイルに文字列を定義して後から読み込む方式にする(IniRead, FileRead 等)
  • #EscapeChar でエスケープ文字を別のものに変える(互換性の面で非推奨)

文字列のマッチングで意図しないところでマッチが起きてしまう[編集]

IfInString, InStr(), StringReplace など文字列の一致を検索(して置換)するコマンドや関数で、意図しないところでマッチや置換が起きることがある。

以下の例を参照。

; 全角の"c"を半角"c"に置換するつもりが…
str = モノ                          ; 0x83 0x82 0x83 0x6d
StringReplace, str, str, c, c, All ;    「0x82 0x83」 を 「0x63」に置換
MsgBox, %str%                       ; 0x83 0x63 0x6d  → 「ツm」と表示される

これを回避するのはDllCallなどでいったんUTF-16やUTF-8などに、それぞれの文字列を変換してから、文字列マッチングや置換を行うことで回避できるがあまり現実的ではない。
日本語を含む文字列を多く処理する場合は、AutoHotkey_L のユニコード版を利用することを検討した方が良いと思われる。

ファイルやディレクトリパスを扱う時に結果が不正になることがある[編集]

SplitPathコマンドや、組み込み変数の A_ScriptDir, A_LoopFileDir など、ファイルパスからディレクトリとファイル名部分を分割する際に、ファイル名や拡張子に以下の文字がある場合に結果が不正になる。

  • ―ソЫⅨ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭偆砡纊犾

これはディレクトリ区切り文字である「\」記号の文字コード 0x5c が上記の文字の2バイト目となっており、全角文字を一切認識しないANSIでは強制的な文字列分割が行われてしまうためである。

これを完全に回避するには、AutoHotkey_Lのユニコード版を利用する。

SplitPathに関しては以下の関数群を用いる、ファイルループでは常に A_LoopFileFullPath を参照して以下の関数を使うなどで代用は可能。しかし、A_ScriptDirを利用した #Include で問題が起きうるので、スクリプト名には全角文字を使わないなどの回避策が必要。

; パスから拡張子を取り除く
Path_RemoveExtension(strPath)
{
  DllCall("shlwapi.dll\PathRemoveExtension", "Str", strPath)
  Return strPath
}

; パスからファイル名とバックスラッシュを取り除きディレクトリを取得する
Path_RemoveFileSpec(strPath)
{
  DllCall("shlwapi.dll\PathRemoveFileSpec", "Str", strPath)
  Return strPath
}

; パスから拡張子を得る("."が含まれる)
Path_FindExtension(pPath)
{
  Return DllCall("shlwapi.dll\PathFindExtension", "Str", pPath, "Str")
}

; パスからファイル名のみを得る
Path_FindFileName(path)
{
  Return DllCall("shlwapi.dll\PathFindFileName", "Str", path, "Str")
}

正規表現パターンに日本語を使うとマッチングがうまくいかない[編集]

これは上記の例と同様で、正規表現パターンで利用する様々なメタ文字(\ () | + * ? : [] {} など)が全角文字の2バイト目に来ていることがあるためである。

これは「\」を利用してエスケープをすることで回避可能だが、動的なパターンの場合はなかなか厳しい。
または内蔵の正規表現エンジンを諦めて「BREGEXP.dll」や「鬼車」 などの外部の正規表現エンジンを利用するのも手である。

なお、ユニコード版の正規表現では全角文字に関する不具合は今のところ報告されていない。

AutoHotkey_L固有の不具合[編集]

AutoHotkey_Lのユニコード文字列を Send したときの不具合[編集]

Send または ControlSend を用いてユニコード文字を送信すると(例:「Send, あいうえお」)、強制的にIMEがOnになってしまうことがある。
これは文字列の送信をIME経由で行っているためである。{U+xxxx}形式での文字指定でも同様である。

これは、IME.ahk などのIME状態を取得・設定出来るライブラリを利用して以下のようにすれば対処は可能である。

ime := IME_Get()
Send, あいうえお
IME_Set(ime)

※ リマップやホットストリングでも同機能を利用しているため、以下の様なことをしても同様の事象が起きる。

A::漢
::kita::キターーー

日本語EUCに関する制限事項[編集]

AHKLの FileEncodingFileOpen() などでコードページを直に指定してもEUCファイルの読み書きはうまくいかない。
これはおそらく kernel32.dll の WideCharToMultiByte()MultiByteToWideChar() などでも変換ができないのと同じなのが理由だと思われる。

どうしてもEUCのファイルをAHKで読みたい場合は、NKF等で一時ファイルに変換してから読み込む。
または、ファイルをバイナリモードで読み込んでから、 ConvertINetMultiByteToUnicodeConvertINetString を利用して変換する。といった手法が考えられる。

以下は本家版またはAHKLのANSI版で利用可能なEUCとSJISとの変換関数。

; http://pc12.2ch.net/test/read.cgi/software/1253888736/840 より
; SJISからEUCに変換する
EUC_ConvertTo(srcStr) {
  Return ConvertINetString(srcStr, CP_SJIS:=932, CP_EUCJP:=51932)
}

; EUCからSJISに変換する
EUC_ConvertFrom(srcStr) {
  Return ConvertINetString(srcStr, CP_EUCJP:=51932, CP_SJIS:=932)
}

; 内部用関数
ConvertINetString(srcStr, srcEncoding, dstEncoding) {
  Mode := 0
  srcSize := StrLen(srcStr)
  dstSize := srcSize *3
  VarSetCapacity(dstStr, dstSize, 0x00)
  DllCall("mlang.dll\ConvertINetString"
    , "UIntP", Mode
    , "UInt",  srcEncoding
    , "UInt",  dstEncoding
    , "Str",   srcStr
    , "IntP",  srcSize
    , "Str",   dstStr
    , "IntP",  dstSize
    , "Int")
  Return dstStr
}

関連項目: FileEncoding, FileOpen(), FileAppend, FileRead, File Reading Loop, A_FileEncoding