Autohotkeyを使ってGUIメニューを出すことで物理キーボードがなくてもPCを操作する環境を作る
Autohotkeyなのにキーボードなしって、AutohotkeyのKeyという意味からはちょっと意味がわからない話?と思われるかもしれませんが、 タブレットPCで物理キーボードを付けない状態の総重量の軽いPC環境(500g~1kg以内)を目指しているものです。
軽いSurface Go3に重いキーボードを付けることなし利用できており、 また、後述のペンでの手書き入力アプリやKoboで電子書籍を読むも快適になっています。
なお、Autohotkeyそのものがどういうものとかインストール方法などについては、ここでは説明していませんので、 インターネットなどで検索してください。
この記事を書いてから1年ほど経つので、Updateして、カラー化したバージョン(2024/11/23 )は以下のページです。
最近では、タッチスクリーンキーボードも作ってみました。(2025-09-23)
Autohotkey Ver.2 での文法変更
AHKがVer2になってからGUIの書き方も少し変わったのですが、インターネットでは Ver1でのサンプルのページばかりがヒットするため、なかなかうまく書けてなく Classを作ってうまく書けるより、まずは動作するものとして作ってています。
zenn.dev では、Ver.2でのclass とnewを使った例が紹介されています。
GUI_menu()
では、Autohotkey Ver.2を使ったGUIメニューの例です。
GUIでボタンで、やりたいことを登録しています。
(2024/06/23 Update)

Autohotkey Ver1形式に近い形の記載ですが、 やりたいことができることを確認する意味もあったので、 洗練されていませんので、どんどん拡張していただければと思います。
途中 func_ での関数は また別途定義されているものですが、また別途紹介できればと思います。
基本的にラウンチャーなので、起動時にGUIを消して、コマンドを実行している形ですが、 カーソルキーの動きの際には、一度隠して、コマンドを実行し、再度GUIを出す形です。
また、タイマーで5秒間メニューを出し、何もしなければ消える形にしています。(2024-06-23 タイマー止める)
また、最初でGUIメニューの多重起動を避ける形にしています。 (2024/06/23 Update)
GUI_menu()
{
If WinExist("AHK Menu")
{
WinActivate
return
}
MyGui := Gui(,"AHK Menu")
MyGui.BackColor := "00EE99" ; RGB color
MyGui.SetFont("s12") ; フォントサイズ(ポイント)を設定
MyGui.Add("Button", " default", "Obsidian").OnEvent("Click", Obsidian_click) ;
MyGui.Add("Button", " x+8", "Date").OnEvent("Click", Date_click) ;
MyGui.Add("Button", " x+8", "Time").OnEvent("Click", Time_click) ;
MyGui.Add("Button", " X+8 ", "-").OnEvent("Click", Add_item_click) ;
MyGui.Add("Button", " X+8 ", "- [ ] ").OnEvent("Click", Add_checkitem_click) ;
MyGui.Add("Button", " x16 y+20", "Google").OnEvent("Click", Chrome_click) ;
MyGui.Add("Button", " x+20", "Chrome URL get").OnEvent("Click", Chrome_get_click) ;
MyGui.Add("Button", " x16 y+20", "Gmail").OnEvent("Click", Gmail_click) ;
MyGui.Add("Button", " x+20", "Calendar").OnEvent("Click", Gcalendar_click) ;
MyGui.Add("Button", " X16 y+20", "Edit Autohotkey ").OnEvent("Click", Edit_ahk_click) ;
MyGui.Add("Button", " x+8", "Edit ahk GUI").OnEvent("Click", Edit_ahk_gui_click) ;
MyGui.Add("Button", " x+8", "Reload AHK").OnEvent("Click", Reload_ahk_click) ;
;--------
MyGui.Add("Button", " X16 y+40", "←").OnEvent("Click", Arrow_Left) ;
MyGui.Add("Button", " X+8 ", "↓").OnEvent("Click", Arrow_Down) ;
MyGui.Add("Button", " X+8 ", "↑").OnEvent("Click", Arrow_Up) ;
MyGui.Add("Button", " X+8 ", "→").OnEvent("Click", Arrow_Right) ;
MyGui.Add("Button", " X+20 ", "^{Home}").OnEvent("Click", Goto_Head) ;
MyGui.Add("Button", " X+8 ", "^{End}").OnEvent("Click", Goto_Tail) ;
MyGui.Add("Button", " X+8 ", "BS").OnEvent("Click", Back_space) ;Z
MyGui.Add("Button", " X16 y+40 ", "SPC").OnEvent("Click", Hankaku_space) ;
MyGui.Add("Button", " X+8 ", "全角空白 ").OnEvent("Click", Zenkaku_space) ;
MyGui.Add("Button", " X+8 ", "Tab").OnEvent("Click", Tab_space) ;
MyGui.Add("Button", " X+8 ", "Enter").OnEvent("Click", Enter) ;
MyGui.Add("Button", " x16 y+40", "Win+Shift+s").OnEvent("Click", Capture_click) ;
MyGui.Add("Button", " x+8", "Win+PrtScn(全画面cap)").OnEvent("Click", FullCapture_click) ;
MyGui.Add("Button", " X16 y+40", "1").OnEvent("Click", Win_1) ;
MyGui.Add("Button", " X+8 ", "2").OnEvent("Click", Win_2) ;
MyGui.Add("Button", " X+8 ", "3").OnEvent("Click", Win_3) ;
MyGui.Add("Button", " X+8 ", "4").OnEvent("Click", Win_4) ;
MyGui.Add("Button", " X+20 ", "Win+Tab").OnEvent("Click", Win_Tab) ;
MyGui.Add("Button", " y+40 cRed", "Task Mgr").OnEvent("Click", TaskManager_click) ;
MyGui.Add("Button", " x+16 cRed", "Shutdown").OnEvent("Click", Shutdown_click) ;
Aaa := WinActive("A")
if(Aaa != 0){
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
} else {
Title := "no active"
}
MyGui.Add("Text", " x16 y+20", Title)
MyGui.OnEvent("Escape", CloseWindow) ; [ESC] キーで閉じる
MyGui.OnEvent("Close", CloseWindow) ; X で閉じる
;SetTimer(UpdateMenu, 5000) ;5秒後にメニューを閉じる (2024-06-23 add ;)
MyGui.Show("x1800 y100")
;--------------------
UpdateMenu(*)
{
CloseWindow()
}
;---MyGui を閉じる関数-----
CloseWindow(*)
{
SetTimer(UpdateMenu, 0)
Sleep(100)
MyGui.Destroy()
}
;--------------------
Date_click(*)
{
MyGui.Destroy()
;IME_set(0)
now := FormatTime(, "yyyy-MM-dd")
Sleep(100)
Send(now)
Send(A_Space)
}
Time_click(*)
{
MyGui.Destroy()
;IME_set(0)
now := FormatTime(, "HH:mm")
Sleep(100)
Send(now)
Send(A_Space)
}
Edit_ahk_click(*)
{
MyGui.Destroy()
Run("notepad++.exe `"" A_ScriptDir "\AutoHotkey_V2.ahk`"") ;このスクリプトを編集
}
Edit_ahk_gui_click(*)
{
MyGui.Destroy()
Run("notepad++.exe `"" A_ScriptDir "\GUI.ahk`"") ;このスクリプトを編集
}
Reload_ahk_click(*)
{
msg := "`"Reload Autohotkey `""
ToolTip(msg)
Sleep(500)
ToolTip()
Reload() ;このスクリプトをリロードして適用
return
}
Chrome_click(*)
{
MyGui.Destroy()
func_chrome_open()
}
Chrome_get_click(*)
{
MyGui.Destroy()
func_chrome_capture()
}
Capture_click(*)
{
MyGui.Destroy()
Send "#+s" ; Win+Shift+s
}
FullCapture_click(*)
{
MyGui.Destroy()
Sleep(1000)
Send("#{PrintScreen}")
Sleep(1000)
Run("C:\Users\xxxxxxxx\Pictures\Screenshots") ; xxxxxxx -> User名 キャプチャした画像のFolderを開く(最新ファイル順に並べてあるとすぐアクセスできる)
return
}
Gmail_click(*)
{
MyGui.Destroy()
browser := "C:\Program Files\Google\Chrome\Application\chrome.exe --disk-cache-dir=R:\Temp"
Run(browser " `"https://mail.google.com/mail/u/0/#inbox`"")
}
Gcalendar_click(*)
{
MyGui.Destroy()
browser := "C:\Program Files\Google\Chrome\Application\chrome.exe --disk-cache-dir=R:\Temp"
Run(browser " `"https://calendar.google.com/calendar/u/0/r?pli=1`"")
}
Obsidian_Click(*)
{
MyGui.Destroy()
func_obsidian()
}
Add_item_click(*)
{
MyGui.Destroy()
Sleep(50)
Send "- " ; 行末へ移動
}
Add_checkitem_click(*)
{
MyGui.Destroy()
Sleep(50)
Send "- [ ] " ; 行末へ移動
}
;---画面リストアする(またメニューを表示する)-----
Arrow_Left(*)
{
MyGui.Hide() ; メニュー消す (アクティブがエディタ画面に)
Sleep(50) ; ちょっと待つ(速すぎるとアクティブが切り替わらない)
Send "{Left}" ; ←移動
Sleep(50) ; ちょっと待つ
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.Restore() ; Guiメニューを表示する
;SetTimer(UpdateMenu, 5000)
}
Arrow_Right(*)
{
MyGui.Hide()
Sleep(50)
Send "{Right}" ; →移動
Sleep(50)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.Restore() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Arrow_Down(*)
{
MyGui.Hide()
Sleep(50)
Send "{Down}" ; ↓移動
Sleep(50)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.Restore() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Arrow_Up(*)
{
MyGui.Hide()
Sleep(50)
Send "{Up}" ; ↑移動
Sleep(50)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.Restore() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Goto_Head(*)
{
MyGui.Hide()
Sleep(50)
Send "^{Home}" ; 先頭へ移動
Sleep(100)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.show() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Goto_Tail(*)
{
MyGui.Hide()
Sleep(50)
Send "^{End}" ; 末尾へ移動
Sleep(100)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.show() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Zenkaku_space(*)
{
MyGui.Hide()
Sleep(50)
Send " "
Sleep(100)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.show() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Hankaku_space(*)
{
MyGui.Hide()
Sleep(50)
Send " "
Sleep(100)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.show() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Enter(*)
{
MyGui.Hide()
Sleep(50)
Send("{Enter}")
Sleep(100)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.show() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Tab_space(*)
{
MyGui.Hide()
Sleep(50)
Send("{Tab}")
Sleep(100)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.show() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
Back_space(*)
{
MyGui.Hide()
Sleep(50)
Send("{BS}")
Sleep(100)
Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
MyGui.show() ; Gui を表示する
;SetTimer(UpdateMenu, 5000)
}
;---画面リストアする(またメニューを表示する)-----
Win_1(*)
{
MyGui.Hide() ; メニュー消す (アクティブがエディタ画面に)
; Sleep(50) ; ちょっと待つ(速すぎるとアクティブが切り替わらない)
Send("#^{Left}#^{Left}#^{Left}")
; Sleep(50) ; ちょっと待つ
; Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
; MyGui.Restore() ; Guiメニューを表示する
; SetTimer(UpdateMenu, 5000)
}
Win_2(*)
{
; MyGui.Hide() ; メニュー消す (アクティブがエディタ画面に)
Sleep(50) ; ちょっと待つ(速すぎるとアクティブが切り替わらない)
Send("#^{Left}#^{Left}#^{Left}#^{Right}")
; Sleep(50) ; ちょっと待つ
; Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
; MyGui.Restore() ; Guiメニューを表示する
; SetTimer(UpdateMenu, 5000)
}
Win_3(*)
{
; MyGui.Hide() ; メニュー消す (アクティブがエディタ画面に)
Sleep(50) ; ちょっと待つ(速すぎるとアクティブが切り替わらない)
Send("#^{Right}#^{Right}#^{Right}#^{Left}")
; Sleep(50) ; ちょっと待つ
; Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
; MyGui.Restore() ; Guiメニューを表示する
; SetTimer(UpdateMenu, 5000)
}
Win_4(*)
{
; MyGui.Hide() ; メニュー消す (アクティブがエディタ画面に)
Sleep(50) ; ちょっと待つ(速すぎるとアクティブが切り替わらない)
Send("#^{Right}#^{Right}#^{Right}")
; Sleep(50) ; ちょっと待つ
; Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
; MyGui.Restore() ; Guiメニューを表示する
; SetTimer(UpdateMenu, 5000)
}
Win_Tab(*)
{
MyGui.Hide() ; メニュー消す (アクティブがエディタ画面に)
Sleep(50) ; ちょっと待つ(速すぎるとアクティブが切り替わらない)
Send("#{Tab}")
; Sleep(50) ; ちょっと待つ
; Title := WinGetTitle("A") ;アクティブ タイトル名を取得し Title へ格納
; MyGui.Restore() ; Guiメニューを表示する
; SetTimer(UpdateMenu, 5000)
}
TaskManager_Click(*)
{
MyGui.Destroy()
Run("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\System Tools\Task Manager.lnk")
}
Shutdown_click(*)
{
MyGui.Destroy()
func_shutdown()
}
}
func_shutdown()
{
MyGui := Gui(,"Shutdown")
MyGui.BackColor := "FF0000" ; 赤
MyGui.SetFont("s32") ; 大きなフォント
MyGui.Add("Text",, "Shutdown")
MyGui.Add("Button", " default", "OK").OnEvent("Click", OK_click) ; ;
MyGui.OnEvent("Escape", CloseWindow) ; [ESC]でダイアログを閉じる
MyGui.show() ; Gui を表示する
OK_Click(*)
{
Run("C:\Windows\system32\shutdown.exe /s /f /t 0")
return
}
CloseWindow(*)
{
MyGui.Destroy()
}
}
他にも、スタートメニューでは、起動しにくい、よく使うアプリを登録したり、 キー操作に該当するものを、ボタンで実行できるようにしたりなど、 利用方法は無限です。
GUIメニューを呼び出す方法
Autohotkeyのキー登録で、たとえば「Shift + F1」でGUIメニューを呼び出すように登録しておく。
+F1::
{
GUI_menu()
return
}
これでキーボードがあれば、Shift+F1で起動しますが、 キーボードなしの環境には、以下の
ジェスチャーで操作 torazaemon2016.hatenablog.jp
のTouchPanelGesturesを使って、

の、「③SIngleTap Shift+F1」と3本指でシングルタップとか、 一番下の「②↑→↓」のように2本指で上右下と、登録しておけば簡単に呼び出せます。
ぜひ使いやすいように、カスタマイズして、 「キーボードのないPC」でPCを使いこなしてください。
AutohotkeyとTouchPabelGestures、また以下の手書き文字認識アプリなどを導入して、SurfaceProやGOなどでPCをペンのみで操作する環境を構築してみてください。
手書き入力&音声入力でキーボードなしでも文章を入力することが快適に(&漢字を書いてボケ防止) torazaemon2016.hatenablog.jp