blechmusikの日記

キー・カスタマイズ・ソフトウェア "DvorakJ" の覚え書きをはじめとして様々なことを書いています。

Ctrl + v や Ctrl + c のようなキーを内部から送信するソフトウェアへの対策を考えた

AutoHotkey_L の #if をうまく使用すれば、修飾キー付きのキーを内部から送信するソフトウェアにうまく対応できそうだ。以下のスクリプトでは、Clibor の自動貼り付け処理と、ユーザーが実際に Ctrl-v を打鍵したときの処理を区別できるようにしている。
AutoHotkey の不具合であるCtrl-zのための処理を追加しなくてはならないが*1、それを除けば、概ねこのような処理で大丈夫だろう。

#UseHook
#InstallKeybdHook
#InstallMouseHook

#NoEnv
#SingleInstance FORCE


;; Clibor のようなソフトウェアから送信されたキーなのか、
;; それとも、ユーザーがまさにそのキーを打鍵したのかを検出する

*v::tooltip,% test()
F12::reload


/*
;;; ホットキーどおりユーザーがキーを物理的に打鍵したとき、
;;; すなわち、他のソフトウェアからキーが送信されていないときに限り
;;; ホットキーの処理をすすめる
#if get_state_of_modifier_and_key( a_thishotkey )
*v::tooltip,% test()
*/


test(){
    ;; 他のソフトウェアにより送信されたキーか?
    return, % "OS 起動時からの経過秒:`t" . a_tickcount . "`n`n"
            . "設定している修飾キーがすべて物理的に押し下げられている?`t" . get_state_of_modifier( a_thishotkey ) . "`n"
            . "修飾キー以外のキーは物理的に押し下げられている?`t" . get_state_of_key( a_thishotkey ) . "`n"
            .  "設定しているホットキーはすべて物理的に押し下げられている?`t" . get_state_of_modifier_and_key( a_thishotkey )
}



get_state_of_modifier_and_key( p_set_key ) {
    return, % ( ( get_state_of_modifier( a_thishotkey ) )
                and ( get_state_of_key( a_thishotkey ) ) )
}


get_state_of_key( p_set_key ) {
    return, GetKeyState( get_key_without_modifier( p_set_key ), "P")
}


get_state_of_modifier( p_set_key ) {
    all_state := Array()

    ;; ホットキーの設定から修飾キーの設定を読み取る
    for index,key_name in get_modifier( p_set_key )
    {
        ;; 修飾キーすべての状態を調べあげるとき
        if ( key_name = "all") {
            if ( ( GetKeyState("shift", "P") )
                or ( GetKeyState("alt", "P") )
                or ( GetKeyState("rwin", "P") )
                or ( GetKeyState("lwin", "P") )
                or ( GetKeyState("ctrl", "P") ) ) {

                all_state[index] := True
            } else {
                all_state[index] := False
            }
        } else if ( key_name = "win") {
            all_state[index] := ( GetKeyState("lwin", "P") ) or ( GetKeyState("rwin", "P") )
        } else {
            all_state[index] := GetKeyState(key_name, "P")
        }
    }

    ;; 物理的に押し下げられていないキーがあれば False
    ;; すべて押し下げられていれば True
    return, % all_state.indexOf(False) ? False
           :                             True
}


get_modifier( p_keys ) {
    keys := Array()

    RegExMatch(p_keys, "[\^\!\+\*#]+", modifier)

    Loop, Parse, modifier
    {
        if ( A_LoopField ) {
            if (A_LoopField = "^") {
                keys.append("ctrl")
            } else if (A_LoopField = "+") {
                keys.append("shift")
            } else if (A_LoopField = "!") {
                keys.append("alt")
            } else if (A_LoopField = "#") {
                keys.append("win")
            } else {
                keys.append("all")
            }
        }
    }

    return keys
}


get_key_without_modifier( p_keys ) {
    RegExMatch(p_keys, "[\^\!\+\*#]+(.+)", key_without_modifier)
    return key_without_modifier1
}






;;; [AHK_L] Arrays
;;; http://www.autohotkey.com/forum/topic49736.html

;;; 一度に操作しうる要素の数を制限しないようにした


; Array Lib - temp01 - http://www.autohotkey.com/forum/viewtopic.php?t=49736
Array(params*){
     static ArrBase := Object("len", "Array_Length"
                            , "indexOf", "Array_indexOf"
                            , "join", "Array_Join"
                            , "append", "Array_Append")

     arr := Object("base", ArrBase)

     for index,param in params {
          arr.insert(index, param)
     }

    Return arr
}


Array_indexOf(p_arr, p_val, p_startpos=1){
    for index,value in p_arr {
        If ( index >= p_startpos
            && value == p_val ) {

            Return index
        }
    }
} 


Array_Join(p_arr, p_sep="`n"){
    str := ""

    for index,value in p_arr {
        str .= p_arr[index] . p_sep
    }

    StringTrimRight, str, str, % StrLen(p_sep)
    return str
}


Array_Append(p_arr, params*) {
    max_index := p_arr.MaxIndex()

    for index,value in params {
        p_arr.insert(value)
    }

    return p_arr
}