torazaemon2016’s blog

手書き文字認識メモ開発

AutohotkeyでGUIメニューを表示し、ペン1本で PCを操作する Ver.3

Autohotkeyを使ってGUIメニューを出すことでキーボードがなくてもPCを操作する環境を作る。(Ver.3)

Autohotkeyを使ってGUIメニューを出すことでキーボードがなくてもPCを操作する環境を作る。って書き始めて、 前にこの話を書いて、またちょうど1年。

これで3回目のUpdateです。

今(Ver.3)はこんなふうになっています。

2025/11/24 Ver.3.5にUpdateです。

torazaemon2016.hatenablog.jp

以下、もう古くなりましたが、参考までに。

Ver.2での横並びが縦になった形です。 また、ボタンの大きさを大きく統一して整然と並ぶようにして、押しやすくなることと、メニューの整理・変更などが容易にしています。

(下はVer.2)

前回の記事:AutohotkeyでGUIメニューを表示し、ペン1本で PCを操作する Ver.2 - torazaemon2016’s blog

前々回の記事:AutohotkeyでGUIメニューを表示し、ペン1本で PCを操作する - torazaemon2016’s blog

以下 スクリプト

タブやボタンの生成の部分について、CSVで定義するやり方になりました。

直接ButtonなどのGUI部品を記載するのではなく、CSVで列挙することでボタンの追加変更を 容易にしています。

(一部func_xxx()は,コメントアウトしていますので、ご自身の環境に合わせてインストールや、パスの設定などを実装ください(Run("実行パス")))

;https://zenn.dev/kaerunrun/articles/31b6155765f2747d4a43
; 2023-11-21
; 2024-11-21 Ver.2
; 2025-11-21 Ver.3

#Requires AutoHotkey 2.0+       ; Version 2以上
#SingleInstance Force

SetTitleMatchMode 2  ;部分一致OK

GUI_menu()  ; 2025-09-18 常駐版 (Hide,Show)

GUI_menu()
{
    ; Hotキーの定義
    toggle_hotkey := "F6"               ; keyboard on/off
    gui_BackColor := "Silver"           ; 背景色 + Show()のあとに透明化も
    gui_Font := "s10 bold"                      ; フォントサイズ(ポイント)を設定

    tab_width := 90
    tab_height := 300
    btn_width := 70
    btn_height := 35
    
    ; 自分のホーム(Username)を指定
    Home := "C:\Users\Username\"   
    browser := "C:\Program Files\Google\Chrome\Application\chrome.exe"

    ; 常駐アイコン
    TraySetIcon("%SystemRoot%\System32\shell32.dll",42) ; 緑の木
    ; システムトレイでのメニュー表示
    A_TrayMenu.Delete
    A_TrayMenu.Add "&Show/Hide", (*) => CloseWindow()        ; &S キーボードのSをショートカット指定
    A_TrayMenu.Add                                      ; -----
    A_TrayMenu.Add "&Reload", (*) => Reload()            ; &R キーボードのRをショートカット指定
    A_TrayMenu.Add "&Edit", (*) => Edit()                ; 
    A_TrayMenu.Add "E&xit", (*) => ExitApp()             ; 
    A_TrayMenu.Default := "&Show/Hide"
    
    MyGui := Gui("-Resize +AlwaysOnTop +E0x08000000","AHK Menu")    ; メニューはこれでないと、カーソルなどが動かせない

    MyGui.BackColor := gui_BackColor 
    MyGui.SetFont(gui_Font)

    ; Tabの縦長化
    ; csv化によるtab
    ; 1:tab名, 2:表示名, 3:色, 4:Tab番号, 5:(コメント) の項目  
    ; AutoHotkey では、( で始めて ) で終わる部分を「行継続セクション」でこの中はそのまま文字列リテラルとして扱われる
    ; csv := と 次の行の ( と 次の行の " は、このとおりにしておかないとエラー。同様に、一番最後の " と ) も独立行
    tab_csv := 
    (
    "
    tab_Desktop,Desktop,Yellow,1,
    tab_System,System,Yellow,2,
    tab_Cursor,Cursor,Aqua,3,
    tab_Keys,Keys,Aqua,4,
    tab_Explorer,Explorer,00FF00,5,
    tab_Google,Google,Red,6,
    tab_App,App,FF00FF,7,
    tab_Obsidian,Obsidian,080808,8,
    tab_ahk,Autohotkey,FF8800,9,
    "
    )

    ; csv定義からボタンを生成
    button_num := 0
    max_height := 5
    y := 0
    tabnum := 1
    tabs := Array()

    Loop Parse, tab_csv, "`n", "`r"
    {
        line := Trim(A_LoopField)
        
        if ( (line = "") || (InStr(line, ";", 0, 1) = 1) )  ; 読み飛ばし定義: 空行 または 1文字目が「;」
            continue

        ;MsgBox("line=|" line "|")
        parts := StrSplit(line, ",")    ; , で分ける
        if (parts.Length >= 4) {     ; 4項目以上
            name := parts[1]
            displayname := parts[2]
            color := parts[3]
            function := parts[4]
            comment := parts[5]

            if(InStr(name, "tab") == 1)
            {
                ;MsgBox("Tab: " name " " tab_width " " tab_height " " function)
                t3 := MyGui.AddTab3("X+0 +Background" color " W" tab_width " H" tab_height,[ displayname ])
                tabs.Push(t3)
                tabnum := tabnum + 1
            }
        }
    }

    ; csv化によるButton
    ; 1:どのTabか(Tab番号), 2:button名, 3:表示名, 4:function名,  5:(コメント) の項目  
    ; AutoHotkey では、( で始めて ) で終わる部分を「行継続セクション」でこの中はそのまま文字列リテラルとして扱われる
    ; csv := と 次の行の ( と 次の行の " は、このとおりにしておかないとエラー。同様に、一番最後の " と ) も独立行
    csv := 
    (
    "
    ;tab_Desktop,Desktop,Yellow,,,,,,
    1,btn_1,VD\n1番,Win_1,
    1,btn_2,VD\n2番,Win_2,
    ;1,btn_3,VD\n3番,Win_3,
    1,btn_wintab,Win\n+Tab,Win_Tab, ; Win+Tab
    1,btn_WinD,Desktop\n表示,Key_WinD,
    1,btn_DeskIcon,ICON表示\n非表示,Key_ShiftF10VD,
    
    ;tab_System,System,Yellow,,,,,
    2,btn_scrcapture,Win+Shift+s,Capture_click,
    2,btn_onsei,音声入力,Mic_click,
    2,btn_taskmgr,Task Mgr,TaskManager_click,
    2,btn_vk40,40%KB,VK40keyboard_click,

    ;tab_Cursor,Cursor,080808,,,,
    3,btn_ctrlHome,Ctrl+Home,Goto_Head,
    3,btn_ctrlEnd,Ctrl+End,Goto_Tail,
    3,btn_Up,↑,Arrow_Up,
    3,btn_Right,→,Arrow_Right,
    3,btn_Left,←,Arrow_Left,
    3,btn_Down,↓,Arrow_Down,

    ;tab_Keys,Keys,080808,,,,
    ;4,btn_1secCtrl,1sec after\nCtrl+Click,Key_CtrlClick,   ; 改行は\nとして記載する
    4,btn_Ctrl,Ctrl\n(扱い注意),Ctrl_Hold,                      ; 改行は\nとして記載する
    4,btn_Alt,Alt\n(扱い注意),Alt_Hold,                     ; 改行は\nとして記載する
    4,btn_Tab,Tab,Key_Tab,
    4,btn_ZenkakuSPC,全角空白,Zenkaku_space,
    4,btn_Esc,Esc,Key_Escape,4,

    ;tab_Explorer,Explorer,00FF00,,,,
    5,btn_Exp_Home,Home,Exp_Home,
    5,btn_Exp_Download,Download,Exp_Download,
    5,btn_Exp_MyDoc,MyDoc,Exp_MyDOc,
    5,btn_Exp_Desktop,Desktop,Exp_Desktop,
    5,btn_Exp_Picture,Picture,Exp_Picture,
    5,btn_Exp_Stnology,Synology,Exp_Synology,

    ;tab_Google,Google,Red,,,,
    6,btn_Google,Chrome,Chrome_click,
    6,btn_Crome_capture,WebClip,Chrome_get_click,
    6,btn_F11,Chrome\n全画面/戻,Key_F11,                            ; 改行は\nとして記載する
    6,btn_Gmail,Gmail,Gmail_click,
    6,btn_Calendar,Calendar,Calendar_click,

    ;tab_App,App,FF00FF,,,,
    7,btn_Kobo,kobo,Kobo_Click,
    7,btn_hwrinput,HWRinput,HWRinput_Click,
    7,btn_OnseiMemo,音声メモ,OnseiMemo_Click,
    7,btn_SyncTrayzor,SyncTrayzor,SyncTrayzor_Click,
    7,btn_WinMerge,WinMerge,WinMerge_Click,
    7,btn_ActiveMail,ActiveMail,ActiveMail_Click,

    ;tab_Obsidian,Obsidian,Maroon,,,,
    8,btn_obsidian,Obsidian,Obsidian_click,
    8,btn_Exp_obs_vault,Vault,Exp_obs_Vault,
    8,btn_Exp_obs_daily,daily,Exp_obs_daily,
    8,btn_Exp_iPhonePic,iPhone,Exp_obs_iPhone,
    8,btn_menu_Gesture,Gesture\nHelp,Gesture_menu_Click,

    ;tab_ahk,Autohotkey,FF8800,,,,,
    9,btn_ahk_Edit,Edit ahk,Ahk_Edit_click,
    9,btn_ahk_Edit_GUI,Edit GUI,Ahk_Edit_gui_click,
    9,btn_ahk_Spy,Spy,Ahk_Spy_click,
    9,btn_ahk_Reload,Reload,Ahk_Reload_click,
    9,btn_Exp_ahk,ahk,Exp_ahk,
    "
    )

    ; csv定義からボタンを生成
    button_num := 0

    Loop Parse, csv, "`n", "`r"
    {
        line := Trim(A_LoopField)
        
        if ( (line = "") || (InStr(line, ";", 0, 1) = 1) )  ; 読み飛ばし定義: 空行 または 1文字目が「;」
            continue

        ;MsgBox("line=|" line "|")
        parts := StrSplit(line, ",")    ; , で分ける
        if (parts.Length >= 5) {     ; 5項目以上
            tabnum := parts[1]
            name := parts[2]
            displayname := parts[3]
            function := parts[4]
            comment := parts[5]

            if(InStr(name, "btn") == 1)
            {
                ;MsgBox("Button: " name " " displayname " " function " " tabnum "   " comment)

                button_num := button_num + 1

                ; ボタンの表示の際に二行以上にするため (\n をcsvで書くと、ここで改行に変える) csvで`nではうまくいかなかったためorz
                if InStr(displayname, "\n")
                {
                    displayname := StrReplace(displayname,"\n","`n")
                }
                tabs[tabnum].useTab(1)
                con := MyGui.AddButton('w' btn_width ' h' btn_height ' v' name, displayname)

                ;https://ahkscript.github.io/ja/docs/v2/Functions.htm#DynCall
                ;関数呼び出しのターゲットとして、ダブルデフを含む他の式を使用することができます。
                ;例えば、MyArray[1]()はMyArrayの最初の要素に含まれる関数を呼び出し、
                ;%MyVar%()はMyVarに含まれる名前の 変数に含まれる関数を呼び出します。
                ;つまり、パラメータリストの前にある式をまず評価して関数オブジェクトを取得し、そのオブジェクトを呼び出すのです。
                func_obj := %function%
                con.OnEvent('Click', func_obj)
            }
        }
    }

    Hotkey("*" toggle_hotkey, CloseWindow)  ; keyboard on/off
    MyGui.OnEvent("Escape", CloseWindow)    ; [ESC] キーで閉じる
    MyGui.OnEvent("Close", CloseWindow)     ; X で閉じる
    OnExit(clear_mods)                      ; 終了するときにも一応CtrlやAltの状態をクリア

    MyGui.Show('Center NoActivate')         ; 中央に表示
    ;WinSetTransparent 220, "AHK Menu"      ; ちょっと透明 0-255 Show()したあとでないとエラーになるよう
    
    ;---MyGui を閉じる関数-----
    CloseWindow(*)
    {
        if WinExist('ahk_id ' MyGui.hwnd) ; 表示されていれば隠す
        {
            MyGui.Hide()                  ; 隠す
            clear_mods()                  ; Ctrl,ALtの状態をクリア
            MyGui.BackColor := "default"
        }
        else
        {   
            MyGui.Show('NoActivate')     ; 表示へ
        }
    }

    ; --- Ctrl,ALtキーなどが押されたままになっていたりするのを外す ---
    clear_mods(*) 
    {
        for _, key in ['LCtrl', 'LAlt' , 'LWin']
            if GetKeyState(key)             ; もし押されたままの状態だったら
                SendInput('{' key ' Up}')   ; 上げる(押されてない)にする
    }

    ;============================================================
    ;---MyGuiオブジェクトにアクセスできないといけない処理
    ; GUI_menu()の中で定義が必要
    Ctrl_Hold(*)    
    {
        key := "LCtrl"
        if GetKeyState(key)
        {
            clear_mods()                    ; Altの状態もクリアしたいので
            ;state := 'Up'                  ; 上でUpしているの
            ;SendInput('{' key ' ' state '}')
            MyGui.BackColor := "default"
        }
        else
        {
            clear_mods()                    ; Altの状態もクリアしたいので
            state := 'Down'                 ; LCtrlだけを押した状態へ
            SendInput('{' key ' ' state '}')
            MyGui.BackColor := "Yellow"
        }
    }

    ; 
    Alt_Hold(*) 
    {
        key := "LAlt"
        if GetKeyState(key)
        {
            clear_mods()                    ; Ctrlの状態もクリアしたいので
            ;state := 'Up'                  ; 上でUpしているので
            ;SendInput('{' key ' ' state '}')
            MyGui.BackColor := "default"
        }
        else
        {
            clear_mods()                    ; Ctrlの状態もクリアしたいので
            state := 'Down'                 ; LAltだけを押した状態へ
            SendInput('{' key ' ' state '}')
            MyGui.BackColor := "Olive"
        }
    }

    Capture_click(*)
    {
        CloseWindow()
        Send "#+s"      ; Win+Shift+s
    }

    Key_WinD(*)
    {
        CloseWindow()
        Send "#d"       ; デスクトップ表示
    }

    Key_ShiftF10VD(*)
    {
        CloseWindow()
        Send "#d"       ; デスクトップ表示
        Sleep(1000)
        Send "+{F10}"   ; 
        Sleep(1000)
        Send "V"        ;
        Sleep(1000)
        Send "D"        ;
    }
    
    Key_F11(*)
    {
        CloseWindow()
        Send("{F11}")   ; F11 (Chrome FullScreen)
    }

    Mic_click(*)
    {
        CloseWindow()
        Send("#h")      ; 音声認識
    }

    ;-----------------
    ; Google Chrome関係
    Chrome_click(*)
    {
        Run(browser " `"https://www.google.co.jp/`"")
    }

    Chrome_get_click(*)
    {
        ; Obsidian Web Clipper拡張機能を追加 
        Send("+!O") ; Alt+Shift+o でクリップ (obdisian/Clippings 以下に入る
    }

    Gmail_click(*)
    {
        ;func_gmail_open()
        Run(browser " `"https://www.google.co.jp/`"")
    }

    Calendar_click(*)
    {
        ;func_calendar_open()
        Run(browser " `"https://www.google.co.jp/`"")
    }

    ;----------------
    ; Obsidian関係
    Obsidian_Click(*)
    {
        SetTitleMatchMode(2)
        If WinExist("ahk_exe Obsidian.exe")
        {
            WinActivate()

            Send("!+t") ; 2023-09-06 Today (shortcutの設定がしてある場合)
            Sleep(2000)
            Send("^{End}")
        }
        Else
        {
            Run(Home "AppData\Local\Obsidian\Obsidian.exe")

            Sleep(5000)
        
            Send("!+t") ; 2023-09-06 Today (shortcutの設定がしてある場合)
            Sleep(2000)
            Send("^{End}")
        }
    }

    WinMerge_Click(*)
    {
        ;func_WinMerge()
    }

    SyncTrayzor_Click(*)
    {
        ;func_SyncTrayzor()
    }

    Gesture_menu_Click(*)
    {
        ;func_Gesture_menu()
    }
    ;------------
    ; Kobo
    Kobo_Click(*)
    {
        CloseWindow()
        Run("C:\Program Files (x86)\Kobo\Kobo.exe") ;
    }

    ;------------------
    ; Explorerでフォルダ表示
    Exp_Home(*)
    {
        Run(Home)
    }
    Exp_Download(*)
    {
        Run(Home "Downloads")
    }
    Exp_MyDoc(*)
    {
        Run(Home "Documents")
    }
    Exp_Desktop(*)
    {
        Run(Home "Desktop")
    }

    Exp_Picture(*)
    {
        Run(Home "Pictures\Screenshots")
    }

    Exp_Synology(*)
    {
        Run(Home "SynologyDrive")
    }

    Exp_ahk(*)
    {
        Run(Home "SynologyDrive\tool\ahk")
    }

    Exp_obs_Vault(*)
    {
        Run(Home "SynologyDrive\obs")
    }
    Exp_obs_daily(*)
    {
        Run(Home "SynologyDrive\obs\daily")
        
    }
    Exp_obs_iPhone(*)
    {
        Run(Home "Desktop\iPhone14 All Photos")
    }
        
    ;--------------------
    ; アプリ呼び出し
    HWRinput_Click(*)
    {
        CloseWindow()

        ;ストアアプリを起動するショートカットを作成する:
        ;Windowsキー + R を押して「ファイル名を指定して実行」を開き、「shell:AppsFolder」と入力してEnterキーを押します。
        ;表示されたアプリ一覧の中から起動したいUWPアプリのアイコンを右クリックし、「ショートカットの作成」を選択します。
        ;作成されたショートカットをデスクトップに移動させ、そのショートカットをダブルクリックしてアプリを起動します。
        Run(Home "Desktop\HWRinput - ショートカット.lnk") ; 
    }

    OnseiMemo_Click(*)
    {
        CloseWindow()
        Run(Home "Desktop\音声認識メモ - ショートカット.lnk") ; 
    }

    ActiveMail_Click(*)
    {
        CloseWindow()
        Run(Home "Desktop\Active! mail.lnk")
    }

    ; TaskManagerを起動
    TaskManager_Click(*)
    {
        CloseWindow()
        Run("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\System Tools\Task Manager.lnk")
    }

    ;vk40keyboardを起動
    VK40Keyboard_Click(*)
    {
        ;CloseWindow()
        if WinExist("AHK Keyboard") ;
        {
            WinActivate()
        }
        else
        {   
            Run(Home "Desktop\virtualkeyboard-40qwerty.ahk")
        }
    }

    ;---------------
    ; Autohotkey関係
    Ahk_Edit_click(*)
    {
        CloseWindow()
        Run("notepad++.exe `"" A_ScriptDir "\AutoHotkey_V2.ahk`"") ;ahkのスクリプトを編集 
    }

    Ahk_Edit_gui_click(*)
    {
        CloseWindow()
        Run("notepad++.exe `"" A_ScriptDir "\GUI.ahk`"") ;このスクリプトを編集 
    }

    Ahk_Spy_Click(*)
    {
        CloseWindow()
        Run("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\AutoHotkey Window Spy.lnk")
    }

    Ahk_Reload_click(*)
    {
        CloseWindow()
        msg := "`"Reload Autohotkey `"" 
        ToolTip(msg)
        Sleep(500)
        ToolTip()
        Reload()    ;スクリプトをリロードして適用
        return
    }
}   

;----------------
; カーソルとかキー入力とか
Arrow_Left(*)
{
    Send "{Left}"   ; ←移動
}
Arrow_Right(*)
{   
    Send "{Right}"  ; →移動
}
Arrow_Down(*)
{
    Send "{Down}"   ; ↓移動
}
Arrow_Up(*)
{
    Send "{Up}"     ; ↑移動
}

Goto_Head(*)
{
    Send "^{Home}"  ; 先頭へ移動
}
Goto_Tail(*)
{
    Send "^{End}"   ; 末尾へ移動
}

Zenkaku_space(*)
{
    Send " "      ; 全角の空白
}

Key_Tab(*)
{
    Send("{Tab}")   ; Tab
}

Key_CtrlClick(*)
{
    MouseGetPos &xpos, &ypos 
    msg := "`"chrome`"" xpos " " ypos   ; 2024-06-05 
    ToolTip(msg)
    Sleep(1000)
    ToolTip()
    Send("^{Click}")    ; Ctrl + Click
}

Key_Escape(*)
{
    Send("{Esc}")
}


; 仮想デスクトップ移動
Win_1(*)
{
    Send("#^{Left}")
    ;Sleep(100)
    ;Send("#^{Left}")
}
Win_2(*)
{
    ;Send("#^{Left}")
    ;Sleep(50)
    ;Send("#^{Left}")
    ;Sleep(100)
    Send("#^{Right}")
}
Win_3(*)
{
    Send("#^{Right}")
    Sleep(50)
    Send("#^{Right}")
}

Win_Tab(*)
{
    Send("#{Tab}")
}

/* END */