Autohotkeyを使ってGUIメニューを出すことでキーボードがなくてもPCを操作する環境を作る(Ver.3.5)
先日の3回目のUpdateのあと、ICON表示や、実行関数を本体autohotkeyのものと共通化するなどしてこんな風になりました。

3回目の記事(2025-11-21):AutohotkeyでGUIメニューを表示し、ペン1本で PCを操作する Ver.3 - torazaemon2016’s blog
前回の記事(2024-11-22):AutohotkeyでGUIメニューを表示し、ペン1本で PCを操作する Ver.2 - torazaemon2016’s blog
前々回の記事(2023-11-26):AutohotkeyでGUIメニューを表示し、ペン1本で PCを操作する - torazaemon2016’s blog
以下 サンプルとして項目を減らした版
実際のスクリプトは最後に載せてあります。
サンプルで表示されるメニュー画面は以下です。

ボタンの定義
ボタンの定義には、
- どのタブのグループかの番号
- プログラム内部GUI登録用名
- 表示名
- クリックされた時の実行関数名
- 実行時の処理方法(0,1,2)
- アイコンのPath(ファイルパス or UWP登録名)
- アイコン番号(Icon? or UWP)
- コメント(省略可能)
の記載が必要です。
記載例:
4,btn_Google,Chrome,Func_chrome,1,C:\Program Files\Google\Chrome\Application\chrome.exe,Icon1,ブラウザ
4.の実行関数
ボタンを定義して、ボタンを押したときの処理を個々に記載する必要があります。
例をいくつか挙げておきます。
; アプリ (Kobo) Program Files以下のexe直接
Func_Kobo(*)
{
Run("C:\Program Files (x86)\Kobo\Kobo.exe") ;
}
; TaskManager (スタート、すべて、Windowsツール、タスクマネージャーで右ボタン「ファイルの場所を開く」にあるショートカットの右ボタン「パスのコピー」
Func_TaskManager(*)
{
Run("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\System Tools\Task Manager.lnk")
}
; キー送出
Func_MS_Voice_Recognizer(*)
{
Send("#h") ; 音声認識
}
;PomodoroTimer (autohotkeyのスクリプト)
Func_PomodoroTimer(*)
{
Run(A_ScriptDir "\pomodoro-timer.ahk")
}
; UWPアプリ呼び出し
Func_HWRinput(*)
{
Run(Home "\Desktop\HWRinput - ショートカット.lnk") ;
}
ストアアプリ(UWPアプリなど)をAutohotkeyのスクリプトから呼び出すのは、ちょっと難しいので、 簡単にやるには、ショートカットを作成することです。
Windowsキー + R を押して「ファイル名を指定して実行」を開き、「shell:AppsFolder」と入力してEnterキーを押します。
表示されたアプリ一覧の中から起動したいアプリのアイコンを右クリックし、「ショートカットの作成」を選択します。
作成されたショートカットをデスクトップに移動させ、そのショートカットをダブルクリックしてアプリが起動することを確認します。
そのショートカットへのパスを記載してください。
プログラム的には
Autohotkey V2でのプログラムとして面白いところは、 関数名として渡された文字列から、% %によって関数オブジェクトを取得して、それで呼び出すことができる点です。
これにより、個々の実行関数でメニューを消してから実行とか不要になり、実行関数の記載が容易にできるようになりました。
(本来のAutohotkeyでのキーでのショートカット設定と同じ関数を呼び出せるようになったので、キーのショートカット定義とGUIメニューの共通化が可能になった(#include "functions-hatena.ahk"))
また、ボタンの定義の5番目の.処理方法で、「0 メニューを消す。1 メニュー表示を消さない。2 関数にGuiそのものを渡す(GUIの色を変えたりが可能) 」と設定します。通常は0か1でOKです。Func_ahk_Reload_GUI()のところで、2の場合の処理の記述例になります。
btn.OnEvent('Click', FuncCall.Bind(function,isGui))
FuncCall(funcname,isgui,*)
{
;MsgBox(funcname " " ishide ,0x40000)
if(isgui == 0)
ShowHideWindow() ; Guiを隠す
try {
;https://ahkscript.github.io/ja/docs/v2/Functions.htm#DynCall
; %記法で関数オブジェクトを取得し、呼び出しを試みる
; これが存在しない場合、TypeErrorやUnsetErrorが発生する可能性がある
funcObj := %funcname% ; csvでの定義でfuncnameのものが正しく定義してあることが前提 名前間違っていたらエラー発生
if(isgui == 2)
funcObj.Call(MyGui)
else
funcObj.Call()
} catch as e {
; エラーが発生
MsgBox("関数が見当たりません: " funcname, ,0x40000)
}
}
アイコン表示
メニューを文字だけではなく、そのアプリのアイコンを出すことにより、ぐっとわかりやすくなりました。
アイコンは、個々の環境で登録のパスなどが変わります。
デスクトップにあるショートカット
アイコンを確認する方法の1つとして、デスクトップにあるショートカットを右ボタン押して、プロパティ出して、 アイコンの変更で、見る方法です。

番号は、左上から1番で下に4つで、次の右の列が5番からになるので、数えるという方法です。
%SystemRoot%\System32\SHELL32.dll などのWindows標準アイコン
フォルダなど、標準のアイコンは、%SystemRoot%\System32\SHELL32.dll などのWindows標準のものが利用できます。
アイコンが一覧になっている良いページなどを参考にしてやるのも便利です。
Autohotkey製のPomodoroTimerは、内部でとして以下のようにアイコン登録しているので、
TraySetIcon("%SystemRoot%\System32\mmcndmgr.dll",15) ; 赤い時計
それを指定しています。
Autohotkeyで 自分好みの ポモドーロタイマー 作成 - torazaemon2016’s blog
Program File以下の実行ファイルの場合
アイコンの確認の方法は、実行ファイルのプロパティを見ることです。
スタートメニューからのアイコンの上で、右ボタンを押して、詳細、ファイルの場所を開く。でその場所を開いて、そこにあるアイコンを右ボタンからプロパティで、アイコンの変更を押すと、パスと、出てくる場所から何番目かを確認する。

Google Chromeの場合
Chrome.exeは、上記の方法でアイコンの確認は容易ですが、GmailやCalendarは、ちょっと工夫が必要です。
まず、ChromeでGmailを開いて、ブラウザの右上の3点リーダー(点が縦に3つ)を押して、プルダウンメニューの「キャスト・保存・共有」のサブメニュー「ショートカットの作成」で、デスクトップにショートカットを作ります。

出来たショートカットを、これまでと同様に右ボタンでプロパティ見て、アイコンの変更からアイコンPathの取得ができます。
UWPアプリの場合
UWPアプリの場合は、素直にアイコンが出せないので、ちょっと複雑です。
UWPの場合は、UWPアプリ番号を見つける必要があります。
例えば電卓であれば、
Microsoft.WindowsCalculator_8wekyb3d8bbwe
となります。
この番号の確認の方法として簡単なのは、UWPアプリのショートカットから知ることです。
上記での実行関数のためにショートカットを作成しているかと思いますので、 ショートカットを右ボタンで押して、プロパティを見ると「ショートカットのタブ」の「種類」のところに、番号の記載があります。 それを、ahkに登録して、最後に 「!App」をつけて、アイコン番号は「UWP」と記載して保存してください。
ストアアプリである画面キャプチャ(Snipping Tool)の例です。
2,btn_scrcapture,Win+Shift+s,Func_Screen_Capture,0,Microsoft.ScreenSketch_8wekyb3d8bbwe!App,UWP, ; Snipping Tool
スクリプト
以下を GUI-menu.ahkと、functions-hatena.ahk と名前を付けて保存して、autohotkeyがインストールされていれば、保存したGUI-menu-ahkファイルをダブルクリックすることで、メニューが表示されてくるかと思います。
functions-hatena.ahkの最初の方に、自分のホームフォルダを指定するところがありますので、 自分に合うように書き換えてください。
; Username を自分のWindowsでの名前(ホームの場所)に書き換えてください。 Home := "C:\Users\Username"
GUI-menu.ahk
;https://zenn.dev/kaerunrun/articles/31b6155765f2747d4a43
; 2023-11-21
; 2024-11-21 Ver.2 Tabによるカラー化
; 2025-11-21 Ver.3 Tabの縦長化
; 2025-11-23 Ver.3.5 ICON表示
; 2025-11-25 Ver.3.5.1 ICON生成時エラー処理、FunCallエラー処理追加
#Requires AutoHotkey 2.0+ ; Version 2以上
#SingleInstance Force
#include "functions-hatena.ahk" ; 実行関数群
;========================================
GUI_menu() ; 常駐版 (Hide,Show)
;========================================
GUI_menu()
{
; Hotキーの定義
toggle_hotkey := "F6" ; keyboard on/off
gui_BackColor := "Silver" ; 背景色 + Show()のあとに透明化も
gui_Font := "s10 bold" ; フォントサイズ(ポイント)を設定
tab_width := 120
tab_height := 320
btn_width := 80
btn_height := 40
;----------------------------------------------------------------------------
; Tab群
; 1:tab名, 2:表示名, 3:色, 4:Tab番号, 5:(コメント) の項目
; AutoHotkey では、( で始めて ) で終わる部分を「行継続セクション」でこの中はそのまま文字列リテラルとして扱われる
; csv := と 次の行の ( と 次の行の " は、このとおりにしておかないとエラー。同様に、一番最後の " と ) も独立行
tab_csv :=
(
"
tab_System,System,Yellow,1,
tab_Explorer,Explorer,00FF00,2,
tab_ahk,Autohotkey,FF8800,3,
tab_App,App,FF00FF,4,
"
)
;----------------------------------------------------------------------------
; Button群
; 1:どのTabか(Tab番号), 2:button名, 3:表示名, 4:function名, 5: GUI消す0,GUI消さない=1,MyGui渡す=2 6:ICON path, 7:ICON番号orUWP, 8:(コメント) の項目
; アイコンのパスにおいて Username を自分のWindowsでの名前(ホームの場所)に書き換えてください。
button_csv :=
(
"
;tab_System,System,Yellow,,,,,
1,btn_wintab,Win\n+Tab,Func_Key_Win_Tab,0,%SystemRoot%\System32\SHELL32.dll,Icon99, ; 改行は\nとして記載する
1,btn_taskmgr,Task Mgr,Func_TaskManager,0,%windir%\system32\Taskmgr.exe,Icon1,
1,btn_scrcapture,Win+Shift+s,Func_Screen_Capture,0,Microsoft.ScreenSketch_8wekyb3d8bbwe!App,UWP,
1,btn_onsei,音声入力,Func_MS_Voice_Recognizer,0,%systemroot%\system32\ddores.dll,Icon4,
1,btn_hwrinput,HWRinput,Func_HWRinput,0,6564torazaemon2016.HWRinput_1904v668w4nzt!App,UWP, ; UWP例
1,btn_PomodoroTimer,Pomodoro\nStart,Func_PomodoroTimer,0,%SystemRoot%\System32\mmcndmgr.dll,Icon15,
;tab_Explorer,Explorer,00FF00,,,,
2,btn_Exp_Desktop,Desktop,Func_Exp_Desktop,0,%SystemRoot%\System32\SHELL32.dll,Icon4,
2,btn_Exp_Download,Download,Func_Exp_Download,0,%SystemRoot%\System32\SHELL32.dll,Icon4,
2,btn_Exp_MyDoc,MyDoc,Func_Exp_MyDoc,0,%SystemRoot%\System32\SHELL32.dll,Icon4,
;tab_ahk,Autohotkey,FF8800,,,,,
3,btn_ahk_Edit,Edit ahk,Func_Ahk_Edit,1,C:\Program Files\AutoHotkey\UX\AutoHotkeyUX.exe,Icon2, ; 0 でメニュー残す
3,btn_ahk_Edit_GUI,Edit GUI,Func_Ahk_Edit_GUI,1,C:\Program Files\AutoHotkey\UX\AutoHotkeyUX.exe,Icon2,
3,btn_ahk_Reload,Reload GUI,Func_Ahk_Reload_GUI,2,C:\Program Files\AutoHotkey\UX\AutoHotkeyUX.exe,Icon1, : 2でGUI渡す
3,btn_ahk_Spy,Spy,Func_Ahk_Spy,0,C:\Program Files\AutoHotkey\UX\inc\spy.ico,Icon1,
;tab_App,App,FF00FF,,,,
4,btn_Google,Chrome,Func_chrome,0,C:\Program Files\Google\Chrome\Application\chrome.exe,Icon1, ; ブラウザ
4,btn_Gmail,Gmail,Func_Gmail,0,C:\Users\level\AppData\Local\Google\Chrome\User Data\Default\Web Shortcut Icons\4262469187\shortcut.ico,Icon1, ; Username は個々で違う
4,btn_Calendar,Calendar,Func_Calendar,0,C:\Users\level\AppData\Local\Google\Chrome\User Data\Default\Web Shortcut Icons\52575180\shortcut.ico,Icon1, ; Username は個々で違う
4,btn_obsidian,Obsidian,Func_Obsidian,0,C:\Users\level\AppData\Local\Obsidian\Obsidian.exe,Icon1, ; Username は個々で違う
"
)
;===ここから本体===================================================================================
MyGui := Gui("-Resize +AlwaysOnTop +E0x08000000","AHK Menu") ; メニューはこれでないと、カーソルなどが動かせない
MyGui.BackColor := gui_BackColor
MyGui.SetFont(gui_Font)
tabs := Array()
make_tabs(tab_csv)
make_buttons(button_csv)
set_Tray()
Hotkey("*" toggle_hotkey, ShowHideWindow) ; keyboard on/off
MyGui.OnEvent("Escape", ShowHideWindow) ; [ESC] キーで閉じる
MyGui.OnEvent("Close", ShowHideWindow) ; X で閉じる
OnExit(clear_ctrlalt) ; 終了するときにも一応CtrlやAltの状態をクリア
MyGui.Show('Center NoActivate') ; 中央に表示
WinSetTransparent 220, "AHK Menu" ; ちょっと透明 0-255 Show()したあとでないとエラーになるよう
;================================================================================
; 以下GUI関数群
make_tabs(csv)
{
; csv定義からボタンを生成
max_height := 5
y := 0
tabnum := 1
;tabs := Array()
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 >= 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
}
}
}
}
make_buttons(csv)
{
; csv定義からボタンを生成
Loop Parse, csv, "`n", "`r"
{
line := Trim(A_LoopField)
if ( (line = "") || (InStr(line, ";", 0, 1) = 1) ) ; 読み飛ばし定義: 空行 または 1文字目が「;」
continue
tooltip(line) ; for Debug 生成中の行を表示
;MsgBox("line=|" line "|")
parts := StrSplit(line, ",") ; , で分ける
if (parts.Length >= 7) {
tabnum := parts[1]
name := parts[2]
displayname := parts[3]
function := parts[4]
isGui := parts[5]
icon_path := parts[6]
icon_number := parts[7]
comment := parts[8]
;MsgBox("Button: " name " " displayname " " function " " tabnum " " comment)
if(InStr(name, "btn") != 1) ; btn_???
continue
tabs[tabnum].useTab(1) ; どのTabに入れるか
if(icon_path != "")
{
hbmp := ""
if(icon_number != "UWP")
{
hBmp := LoadPicture(icon_path, icon_number . " w64 h64") ; ディスプレイ 200%
;hBmp := LoadPicture(icon_path, icon_number . " w48 h48") ; ディスプレイ 150%
;hBmp := LoadPicture(icon_path, icon_number . " w32 h32") ; ディスプレイ 100%
}
else
{
hBmp := GetUwpIcon(icon_path, 64)
}
;MsgBox(icon_path . " " . icon_number . " " . hBmp)
; ボタン作成(BS_BITMAP スタイル)
iconbtn := MyGui.Add("Button", "x" 16 + tab_width * (tabnum - 1) " y+8 w40 h40 +0x80 ", ) ; +0x80 = BS_BITMAP
SendMessage(0xF7, 0, hBmp, iconbtn.Hwnd) ;BM_SETIMAGE := 0xF7, IMAGE_BITMAP := 0
iconbtn.OnEvent('Click', FuncCall.Bind(function,isGui))
; ボタンの表示の際に二行以上にするため (\n をcsvで書くと、ここで改行に変える) csvでで`nでうまくいかなかったため
if InStr(displayname, "\n")
displayname := StrReplace(displayname,"\n","`n")
btn := MyGui.AddButton('x+0 w' btn_width ' h' btn_height ' v' name , displayname)
btn.OnEvent('Click', FuncCall.Bind(function,isGui))
tooltip() ; for Debug うまく行ったら表示を消す (残る場合は、そこでエラー発生)
}
else ; error
{
MsgBox("No path error:" line)
}
}
else ; error
{
MsgBox("error: 7 > " parts.Length " " line)
}
}
}
FuncCall(funcname,isgui,*)
{
;MsgBox(funcname " " ishide ,0x40000)
if(isgui == 0)
ShowHideWindow() ; Guiを隠す
try {
;https://ahkscript.github.io/ja/docs/v2/Functions.htm#DynCall
; %記法で関数オブジェクトを取得し、呼び出しを試みる
; これが存在しない場合、TypeErrorやUnsetErrorが発生する可能性がある
funcObj := %funcname% ; csvでの定義でfuncnameのものが正しく定義してあることが前提 名前間違っていたらエラー発生
if(isgui == 2)
funcObj.Call(MyGui)
else
funcObj.Call()
} catch as e {
; エラーが発生
MsgBox("関数が見当たりません: " funcname, ,0x40000)
}
}
;==UWPアプリのアイコンを取得======================================================
GetUwpIcon(AppID, size := 64) {
static IID_IShellItemImageFactory := "{bcc18b79-ba16-442f-80c4-8a59c30c463b}"
static IID_IShellItem := "{43826D1E-E718-42EE-BC55-A1E261C37BFE}"
try {
; AppsFolder の仮想パスを作成
path := "shell:AppsFolder\" AppID
; SHParseDisplayName → PIDL を取得
pidl := 0 ; PIDL を受け取る変数は "数値 0" でなければいけない
hr := DllCall("Shell32\SHParseDisplayName"
, "wstr", path
, "ptr", 0
, "ptr*", &pidl
, "uint", 0
, "ptr", 0)
if (hr != 0 or pidl = 0)
throw Error("SHParseDisplayName 失敗 HR=" hr)
; PIDL → IShellItem
item := 0
hr := DllCall("Shell32\SHCreateItemFromIDList"
, "ptr", pidl
, "ptr", IIDFromString(IID_IShellItem)
, "ptr*", &item)
if (hr != 0 or item = 0)
throw Error("IShellItem 取得失敗 HR=" hr)
; IShellItemImageFactory の取得
img := ComObjQuery(item, IID_IShellItemImageFactory)
if !img
throw Error("ImageFactory 取得失敗")
; 画像サイズ
sizeBuf := Buffer(8)
NumPut("uint", size, sizeBuf, 0)
NumPut("uint", size, sizeBuf, 4)
hIcon := 0
hr := ComCall(3, img
, "ptr", sizeBuf
, "uint", 0
, "ptr*", &hIcon)
if hr != 0
throw Error("アイコン取得失敗 HR=" hr)
return hIcon
} Catch as e {
MsgBox("UWPのアイコンが生成できません: " AppID, ,0x40000)
}
}
IIDFromString(str) {
buf := Buffer(16)
DllCall("ole32\IIDFromString", "wstr", str, "ptr", buf)
return buf
}
;==========================================================
; -システムトレイでのメニュー表示-
set_Tray()
{
; 常駐アイコン
TraySetIcon("%SystemRoot%\System32\shell32.dll",42) ; 緑の木
A_TrayMenu.Delete
A_TrayMenu.Add "&Show/Hide", (*) => ShowHideWindow() ; &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 を表示・隠す関数---
ShowHideWindow(*)
{
if WinExist('ahk_id ' MyGui.hwnd) ; 表示されていれば隠す
{
MyGui.Hide() ; 隠す
clear_ctrlalt() ; Ctrl,ALtの状態をクリア
MyGui.BackColor := "default"
}
else
{
MyGui.Show('NoActivate') ; 表示へ
}
}
;---終了時関数---
clear_ctrlalt(*)
{
for _, key in ['LCtrl', 'LAlt']
if GetKeyState(key) ; もし押されたままの状態だったら
SendInput('{' key ' Up}') ; 上げる(押されてない)にする
}
}
;=================================================================
; ---MyGuiオブジェクトにアクセスできないといけない処理のため、guiを持ってくる
Func_Ahk_Reload_GUI(guix,*) ; GUI.ahk
{
guix.BackColor := "Red"
Sleep(1000)
Reload() ;スクリプトをリロードして適用
guix.BackColor := "FF8800" ;
}
/* END */
functions-hatena.ahk
; functions-hatena.ahk
#Requires AutoHotkey 2.0+ ; Version 2以上
;=================================================================
; Username を自分のWindowsでの名前(ホームの場所)に書き換えてください。
Home := "C:\Users\Username"
;browser := "C:\Program Files\Google\Chrome\Application\chrome.exe --disk-cache-dir=R:\Temp"
browser := "C:\Program Files\Google\Chrome\Application\chrome.exe"
;--------------------
Func_Key_Win_Tab(*)
{
Send("#{Tab}")
}
; TaskManagerを起動
Func_TaskManager(*)
{
Run("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\System Tools\Task Manager.lnk")
}
Func_Screen_Capture()
{
; Snipping Toolそのものの起動じゃなくて Win+Shift+sのショートカットのほうで
ToolTip("Shift + Win + s")
Send("+#s") ; Shift+Win+s
ToolTip()
; 以下確認用に
Sleep(3000)
Send("#v") ; Win+v (クリップボード一覧)
}
Func_MS_Voice_Recognizer(*)
{
Send("#h") ; 音声認識
}
;PomodoroTimer
Func_PomodoroTimer(*)
{
Run(A_ScriptDir "\pomodoro-timer.ahk")
}
;--------------------
; UWPアプリ呼び出し
Func_HWRinput(*)
{
Run(Home "\Desktop\HWRinput - ショートカット.lnk") ;
}
;------------------
; Explorerでフォルダ表示
Func_Exp_Download(*)
{
Run(Home "\Downloads")
}
Func_Exp_MyDoc(*)
{
Run(Home "\Documents")
}
Func_Exp_Desktop(*)
{
Run(Home "\Desktop")
}
;---------------
; Autohotkey関係
Func_Ahk_Edit(*)
{
Run("notepad++.exe `"" A_ScriptDir "\AutoHotkey_V2.ahk`"") ;ahkのスクリプトを編集
}
Func_Ahk_Edit_GUI(*)
{
Run("notepad++.exe `"" A_ScriptDir "\GUI.ahk`"") ;このスクリプトを編集
}
;Func_Ahk_Reload_GUI(guix,*) ; GUI.ahkのほうに記載
Func_Ahk_Spy(*)
{
Run("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\AutoHotkey Window Spy.lnk")
}
;-----------------
; Google Chrome関係
Func_Chrome(*)
{
Run(browser " `"https://www.google.co.jp/`"")
}
Func_Gmail(*)
{
Run(browser " `"https://mail.google.com/mail/u/0/#inbox`"")
}
Func_Calendar(*)
{
Run(browser " `"https://calendar.google.com/calendar/u/0/r`"")
}
; Obsidian
Func_Obsidian(*)
{
SetTitleMatchMode(2)
If WinExist("ahk_exe Obsidian.exe")
WinActivate()
Else
Run(Home "\AppData\Local\Obsidian\Obsidian.exe")
}
; End
さまざまに拡張してみてください。