
最終更新: 2024-03-10
TL; DR
Windowsでカスタムキーマップを使う場合は AutoHotkeyで
- レジストリの変更が必要なキーもある
内容
- 音量上げ下げ
- 仮想デスクトップの移動
- Alacritty + Vimで発生するペーストの問題
前情報
私は現在Linux → Windowsへの移行中である。
Linuxでは気軽に設定できた内容もWindowsでは難しいことも多い。
この辺はおそらくOSの設計思想がよく現れていて、整理するとこんな感じ
Linux:
- すべてはファイル
- つまり設定は平文で保存される
- ユーザーが変更可能で、変更に対する責任もユーザーが負う
Windows:
- 色々な管理方式が混在
- ファイル・レジストリ・ポリシーなど
- ファイル以外はバイナリ(Windowsから読めるデータベース)
- ユーザーが気軽に変更することは想定されない
- 変更には専用のインターフェイス(つまりアプリケーション)が必要
- 色々な管理方式が混在
つまりWindowsはクソ
「ユーザーが安易に変更できない」というのはITリテラシーの低い職場などで、規格を統一する際などは便利なのかもしれない。 Linuxの方が圧倒的にスクリプトキディに悪用され易いし(防ぐ方法はあってもかなり面倒そう)。
何がしたいか
次のような挙動をさせたい
- Windows Key + L: 右の仮想デスクトップへ移動
- Windows Key + Shift + L: ウィンドウを右の仮想デスクトップへ移動
- Windows Key + H: 左の仮想デスクトップへ移動
- Windows Key + Shift + H: ウィンドウを左の仮想デスクトップへ移動
「Win3 - 🐱🐱🐱」と 「Win4 - 🐱🐱🐱🐱」を行き来している。
前準備 - “Win + L”の解除
今回 Win + L に割当を追加する。元々はWindowのLock機能が割り当てられており、割当を解除するには、レジストリを編集する必要がある。 レジストリの以下を変更すれば良い。
- キー:
\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableLockWorkstation
- 値: 1
System
フォルダは存在しなかったので新規に作成する必要があった。
AutoHotkeyの基本設定 - 音量上げ下げを例に
Windowsにおいて、キーマッピングを変更するには AutoHotkey を使うものらしい。
例えば、次のようなマッピングを行うには
- F4: 音量を下げる
- F5: 音量を上げる
こうする。 SoundBeep
はフィードバック音
#Requires AutoHotkey v2.0+
#SingleInstance Force
; Volume Up/Down
F5::
{
SoundSetVolume "+5"
SoundBeep 825, 200
}
F4::
{
SoundSetVolume "-5"
SoundBeep 660, 200
}
F3::{
IsMuted := SoundGetMute()
if IsMuted {
SoundSetMute false
SoundBeep 660, 200
} else {
SoundSetMute true
}
}
※ バージョンが1系と2系でかなり文法が違うので注意
※ AutoHotkeyがインストールされていればダブルクリックで起動できるはず
例えば、次の場所に配置するとスタートアップ時に読み込んでくれる。
/mnt/c/Users/{ユーザ名}/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/default.ahk
AutoHotkeyでDLLを読む - 仮想デスクトップの移動
今回はウィンドウの移動を実現したいのだが、“現在のウィンドウを横に移動させる機能”は元々存在しない。
運良く、DLL1を開発してくれている人がいるので、それに乗っかる。
https://github.com/Ciantic/VirtualDesktopAccessor (幸いAHKの2系にも対応している)
ということで
#Requires AutoHotkey v2.0+
#SingleInstance Force ; The script will Reload if launched while already running
SetWorkingDir(A_ScriptDir)
; Path to the DLL, relative to the script
VDA_PATH := A_AppData . "\AutoHotkey\VirtualDesktopAccessor.dll"
hVirtualDesktopAccessor := DllCall("LoadLibrary", "Str", VDA_PATH, "Ptr")
GetDesktopCountProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "GetDesktopCount", "Ptr")
GoToDesktopNumberProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "GoToDesktopNumber", "Ptr")
GetCurrentDesktopNumberProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "GetCurrentDesktopNumber", "Ptr")
IsWindowOnCurrentVirtualDesktopProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "IsWindowOnCurrentVirtualDesktop", "Ptr")
IsWindowOnDesktopNumberProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "IsWindowOnDesktopNumber", "Ptr")
MoveWindowToDesktopNumberProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "MoveWindowToDesktopNumber", "Ptr")
IsPinnedWindowProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "IsPinnedWindow", "Ptr")
GetDesktopNameProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "GetDesktopName", "Ptr")
SetDesktopNameProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "SetDesktopName", "Ptr")
CreateDesktopProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "CreateDesktop", "Ptr")
RemoveDesktopProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "RemoveDesktop", "Ptr")
; On change listeners
RegisterPostMessageHookProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "RegisterPostMessageHook", "Ptr")
UnregisterPostMessageHookProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "UnregisterPostMessageHook", "Ptr")
; Util Func
GetDesktopCount() {
global GetDesktopCountProc
count := DllCall(GetDesktopCountProc, "Int")
return count
}
MoveCurrentWindowToDesktop(number) {
global MoveWindowToDesktopNumberProc, GoToDesktopNumberProc
activeHwnd := WinGetID("A")
DllCall(MoveWindowToDesktopNumberProc, "Ptr", activeHwnd, "Int", number, "Int")
}
SetDesktopName(num, name) {
global SetDesktopNameProc
OutputDebug(name)
name_utf8 := Buffer(1024, 0)
StrPut(name, name_utf8, "UTF-8")
ran := DllCall(SetDesktopNameProc, "Int", num, "Ptr", name_utf8, "Int")
return ran
}
; Main Func
MoveCurrentWindowToPrevDesktop() {
global GetCurrentDesktopNumberProc, GoToDesktopNumberProc
current := DllCall(GetCurrentDesktopNumberProc, "Int")
last_desktop := GetDesktopCount() - 1
; If current desktop is 0, do nothing
if (current != 0) {
MoveCurrentWindowToDesktop(current - 1)
}
return
}
MoveCurrentWindowToNextDesktop() {
global GetCurrentDesktopNumberProc, GoToDesktopNumberProc
current := DllCall(GetCurrentDesktopNumberProc, "Int")
last_desktop := GetDesktopCount() - 1
; If current desktop is last, do nothing
if (current != last_desktop) {
MoveCurrentWindowToDesktop(current + 1)
}
return
}
SetDesktopName(0, "Win1 - 🐱")
SetDesktopName(1, "Win2 - 🐱🐱")
SetDesktopName(2, "Win3 - 🐱🐱🐱")
SetDesktopName(3, "Win4 - 🐱🐱🐱🐱")
; “Win + H”を“Win + Ctrl + LeftArrow”にマッピング
#h::#^Left
; “Win + L”を“Win + Ctrl + RightArrow”にマッピング
#l::#^Right
; “Win + Shift + H”を“現在のウィンドウを左のデスクトップに移動した上で、左のデスクトップに移動”にマッピング
#+h::
{
Send "#^{Left}"
MoveCurrentWindowToPrevDesktop()
}
; “Win + Shift + L”を“現在のウィンドウを右のデスクトップに移動した上で、右のデスクトップに移動”にマッピング
#+l::
{
Send "#^{Right}"
MoveCurrentWindowToNextDesktop()
}
VirtualDesktopAccessorのDLL本体は
ユーザーディレクトリ/AppData/Roaming/AutoHotkey
以下に配置する想定VDA_PATH := A_AppData . "\AutoHotkey\VirtualDesktopAccessor.dll"
コマンドの特殊キーとかの割当てはこんな感じ
# Windowsキー ^ Ctrl + Shift ! Alt F1~F24 ファンクションキー Space スペース Tab Tab Enter Enter BS Backspace Del Delete Left,Right,Up,Down ←→↑↓の矢印キー
以下の2つの関数は現在のアクティブウィンドウを移動する関数なので、アクティブウィンドウが存在しない場合はエラーが出る (まぁ別に良いか)。
MoveCurrentWindowToPrevDesktop
MoveCurrentWindowToNextDesktop
Alacritty + Vimで発生するペーストの問題
改行を含むテキストをWindows側でクリップボードにコピーして、WSL内のAlacritty内のVimに貼り付けると、余計な改行が発生する。
解消方法は https://github.com/alacritty/alacritty/issues/2324#issuecomment-1672990131 にある通り、
元のテキスト)
a
b
c
貼り付けた場合のテキスト)
a
b
c
これを解消する際にAutoHotkeyが使える。利便性のためにalacritty.tomlに次を追加
[window]
title = "alacritty"
dynamic_title = false
AutoHotkeyに次を追加。
#HotIf WinActive("alacritty")
^+v::
{
A_Clipboard := StrReplace(A_Clipboard, "`r`n", "`n")
Send("^+v")
}
return
#HotIf
Alacrittyの場合のみクリップボードを編集してCLRFをLFに変換している。
脚注
DLL (Dynamic Link Libarary) というのはWindowsにおける外部プログラムであり、何でもできる。