Autohotkeyを使ってGUIメニューを出すことでキーボードがなくてもPCを操作する環境を作る。(Ver.3)
Autohotkeyを使ってGUIメニューを出すことでキーボードがなくてもPCを操作する環境を作る。って書き始めて、 前にこの話を書いて、またちょうど1年。
これで3回目のUpdateです。
2025/11/24 Ver.3.5にUpdateです。
以下、もう古くなりましたが、参考までに。
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 */
