I ❤️ Japan pic.twitter.com/aY5MvDqkbC
— Elon Musk (Parody) (@ElonMuskAOC) June 14, 2024
👍
👍
ひと工夫したので貼っておこー 
マウスジェスチャーで仮想デスクトップを切り替えたい。

MouseGestureL.ahk
https://hp.vector.co.jp/authors/VA018351/mglahk.html
「MouseGestureL.ahk Ver. 1.40 (2022/06/22)」リンクから「MGLahk140.zip」をダウンロードする。
2. ダウンロードした「MGLahk140.zip」を展開し、以下に格納します。
C:\tool\MGLahk140
└─Setup.vbs
└─ ・・・
※格納場所任意。
3. 「Setup.vbs」を実行し、「MouseGestureL.exe」を生成します。
C:\tool\MGLahk140
└─Setup.vbs
└─ ・・・
└─ MouseGestureL.exe
4. 生成した「MouseGestureL.exe」を実行します。
→タスクトレイに「MouseGestureL.ahk」が常駐します。
5. 「MouseGestureL.ahk」を右クリックし、「設定」を選択します。
6. マウスジェスチャーに「タスクビュー」のキーボード操作を割り当てます。
例:RB←

アクションスクリプト
;左デスクトップに移動
SendLevel 1
ctrl := GetKeyState("Ctrl")
shift := GetKeyState("Shift")
win := GetKeyState("LWin")
if (ctrl and shift and win) {
    Send,^+#{Left}
} else if (ctrl and shift) {
    Send,^+{Left}
} else if (ctrl and win) {
    Send,^#{Left}
} else {
    Send,^#{Right}
}RB← + Ctrl + Shift + Win:アクティブ画面を左デスクトップに移動して、左デスクトップに移動
RB← + Ctrl + Shift:アクティブ画面を左デスクトップに移動
RB← + Ctrl + Win:左デスクトップに移動
RB←:右デスクトップに移動
例:RB→

アクションスクリプト
;右デスクトップに移動
SendLevel 1
ctrl := GetKeyState("Ctrl")
shift := GetKeyState("Shift")
win := GetKeyState("LWin")
if (ctrl and shift and win) {
    Send,^+#{Right}
} else if (ctrl and shift) {
    Send,^+{Right}
} else if (ctrl and win) {
    Send,^#{Right}
} else {
    Send,^#{Left}
}RB→ + Ctrl + Shift + Win:アクティブ画面を右デスクトップに移動して、右デスクトップに移動
RB→ + Ctrl + Shift:アクティブ画面を右デスクトップに移動
RB→ + Ctrl + Win:右デスクトップに移動
RB→:左デスクトップに移動
上記のアクションスクリプトをそのままコピペする場合は読み飛ばしてください。
MouseGestureL.ahk も AutoHotkey で作成されています。
AutoHotkey 1.0:ASCII版
AutoHotkey 1.1:Unicode版
AutoHotkey 2.0:下位互換なし、レガシーシンタックス廃止版。
MouseGestureL.ahk は、AutoHotkey 1.1 で、「タスクビュー」は、AutoHotkey 2.0 で実行されています。
タスクビュー
https://kozawa.tokyo/?p=1262
通常、AutoHotkeyで生成したキーストロークは、AutoHotkeyでは処理されません。AutoHotkeyでAutoHotkeyのホットキーをトリガーするために、アクションスクリプトでSendする前にSendLevelの指定が必要となります。
SendLevel 1SendLevel
https://ahkscript.github.io/ja/docs/v2/lib/SendLevel.htm
下位互換はないですが、SendLevel、InputLevelまわりは互換ありです。
7. 「軌跡・ログ」タブで「ジェスチャーの軌跡を表示する」にチェックする。(任意)

8. 「その他」タブで「スタートアップに登録」する。管理者権限は不要です。(任意)
9. 「OK」ボタンをクリックする。
書き直したやつも貼っておこー 
Ctrl + Win + F1~F6キー:デスクトップ切り替え
Ctrl + Shift + F1~F6キー:アクティブ画面を指定のデスクトップに移動*
Ctrl + Shift + Win + F1~F6キー:アクティブ画面を指定のデスクトップに移動してデスクトップも移動*
Ctrl + Win + 左右キー:デスクトップ1と6を左右キーで移動*
Ctrl + Shift + 左右キー:アクティブ画面を隣のデスクトップに移動*
Ctrl + Shift + Win + 左右キー:アクティブ画面を隣のデスクトップに移動してデスクトップも移動*
*:機能追加
もうぐちゃぐちゃ。こんなの覚えてられん。これを覚えて使おうとする人おる?環境によっては、Ctrl + Shift + 左右キーあたりは他のソフトのホットキーと被るかもしれないので人によっては使えないのだろうなぁとは分かりつつも致し方なし。
#Requires AutoHotkey v2.0+
#SingleInstance Force
; ----------------------------------------
; define
; ----------------------------------------
PREV := "Prev"
NEXT := "Next"
OK := True
NG := False
VDA_PATH := "C:\tool\taskview\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")
MoveWindowToDesktopNumberProc := DllCall("GetProcAddress", "Ptr", hVirtualDesktopAccessor, "AStr", "MoveWindowToDesktopNumber", "Ptr")
; ----------------------------------------
; helper function
; ----------------------------------------
GetDesktopCount() {
    count := DllCall(GetDesktopCountProc, "Int")
    return count
}
GoToDesktopNumber(number) {
    if (number > GetDesktopCount())
        return
    ; Win + 左右キーのアニメーションに操作感を合わせるため、
    ; 移動前後に0.5秒の待ち時間を設定している(機能的には不要)
    Sleep 500
    DllCall(GoToDesktopNumberProc, "Int", number - 1)
    Sleep 500
}
GetCurrentDesktopNumber() {
    number := DllCall(GetCurrentDesktopNumberProc, "Int")
    number++ ; デスクトップ番号を1オリジンで指定するため + 1
    return number
}
MoveWindowToDesktopNumber(number) {
    WinWaitActive WinExist("A")
    retry := 0
    Loop
        try {
            activeHwnd := WinGetID("A")
            number-- ; dllには0オリジンで渡すため - 1
            DllCall(MoveWindowToDesktopNumberProc, "Ptr", activeHwnd, "Int", number, "Int")
            result := OK
            break
        } catch {
            Sleep 250
            result := NG
            retry++
        }
    until retry == 10
    return result
}
moveWindow(desktop) {
    current := GetCurrentDesktopNumber()
    max := GetDesktopCount()
    if (desktop == PREV) {
        if (current == 1) {
            result := MoveWindowToDesktopNumber(max)
        } else {
            result := MoveWindowToDesktopNumber(current - 1)
        }
    } else if (desktop == NEXT) {
        if (current == max) {
            result := MoveWindowToDesktopNumber(1)
        } else {
            result := MoveWindowToDesktopNumber(current + 1)
        }
    } else {
        result := MoveWindowToDesktopNumber(desktop)
    }
    return result
}
moveDesktop(desktop) {
    current := GetCurrentDesktopNumber()
    max := GetDesktopCount()
    if (desktop == PREV) {
        if (current == 1) {
            GoToDesktopNumber(max)
        } else {
            Send "^#{Left}"
        }
        KeyWait "Left"
    } else if (desktop == NEXT) {
        if (current == max) {
            GoToDesktopNumber(1)
        } else {
            Send "^#{Right}"
        }
        KeyWait "Right"
    } else {
        GoToDesktopNumber(desktop)
    }
}
moveWindowMoveDesktop(desktop) {
    result := moveWindow(desktop)
    if (result == OK)
        moveDesktop(desktop)
}
; ----------------------------------------
; main
; ----------------------------------------
; アクティブ画面移動
^+Left:: moveWindow(PREV)
^+Right:: moveWindow(NEXT)
^+F1:: moveWindow(1)
^+F2:: moveWindow(2)
^+F3:: moveWindow(3)
^+F4:: moveWindow(4)
^+F5:: moveWindow(5)
^+F6:: moveWindow(6)
; デスクトップ移動
^#Left:: moveDesktop(PREV)
^#Right:: moveDesktop(NEXT)
^#F1:: moveDesktop(1)
^#F2:: moveDesktop(2)
^#F3:: moveDesktop(3)
^#F4:: moveDesktop(4)
^#F5:: moveDesktop(5)
^#F6:: moveDesktop(6)
; アクティブ画面/デスクトップ移動
^#+Left:: moveWindowMoveDesktop(PREV)
^#+Right:: moveWindowMoveDesktop(NEXT)
^#+F1:: moveWindowMoveDesktop(1)
^#+F2:: moveWindowMoveDesktop(2)
^#+F3:: moveWindowMoveDesktop(3)
^#+F4:: moveWindowMoveDesktop(4)
^#+F5:: moveWindowMoveDesktop(5)
^#+F6:: moveWindowMoveDesktop(6)1.「taskview_ext_20240615.zip」ファイルを展開し、C:ドライブの直下に格納します。
C:\tool\taskview
└─taskview_ext.ahk
※格納場所固定。変更する場合は、ソース内のパス「VDA_PATH := “C:\tool\taskview\VirtualDesktopAccessor.dll”」を変更する必要がある。
2. 以下のサイトからDLLファイルをダウンロードします。
VirtualDesktopAccessor.dll
https://github.com/Ciantic/VirtualDesktopAccessor
リリースページの「VirtualDesktopAccessor.dll」をダウンロードする。
https://github.com/Ciantic/VirtualDesktopAccessor/releases
3. ダウンロードしたDLLファイルを同じフォルダに格納します。
C:\tool\taskview
├─taskview_ext.ahk
└─VirtualDesktopAccessor.dll
4. 「taskview_ext.ahk」を実行します。
フォルダごと削除するだけ。
デスクトップ1と6を左右キーで移動するときにアニメーションがない。
IVirtualDesktopManager インターフェイス (shobjidl_core.h)
https://learn.microsoft.com/ja-jp/windows/win32/api/shobjidl_core/nn-shobjidl_core-ivirtualdesktopmanager
「VirtualDesktopAccessor.dll」には、このインターフェイスでは実現できない機能が含まれているのなんで?どうやって作ってるんだろう?仮想デスクトップ周りって他にも公開情報あるのか?ググったけど見つからなかったので継続調査中・・・
ソースファイル、助かるーけど、COM周り、シェル周り、相変わらず難しい。Rustで書かれているので、これを機にRustも触ってみようかとインストールしてドキュメントをパラパラした。
ヒープメモリを使用する変数に所有権あるらしいな。所有権ムーブしたり変数の変更に制限をかけることで二重開放などなどが起こりえない言語仕様になってるとか、なっていないとか?メモリの管理というか、状態の管理で良くバグるのあるある。おかしな動作がパソコン再起動したら直るってそういうことですよねえ。
所有権を理解する
https://doc.rust-jp.rs/book-ja/ch04-00-understanding-ownership.html
25年、29年?何も変わらないWindows のデスクトップアプリの内部、一度公開されたインターフェイスは変わらないですねえ。
Win32 API のプログラミング リファレンス
https://learn.microsoft.com/ja-jp/windows/win32/api
いにしえのソースやドキュメントを見ながら酒飲んでるw 🥴

おもちゃツールを作ったので貼っておこー 

「Ctrl」+「Win」+「F1~F6」キーで離れたデスクトップに直接移動
; ----------------------------------------
;  prerequisites
;  display: 1 monitor only
;  os: Windows 11
;  virtual desktop: 1 - 6
; ----------------------------------------
WINCOUNT := 4
switchDesktop(desktopId) {
    winIds := WinGetList()
    Send "#{Tab}"
    WinWaitActive ("ahk_class XamlExplorerHostIslandWindow")
    Sleep 500
    count := 0
    Loop  {
        if count == 0 {
            if winIds.Length > WINCOUNT
                Send "{Tab}"
        } else {
            Send "{Right}"
        }
        count++
    } Until count == desktopId
    Send "{Enter}"
}   
^#F1::switchDesktop(1)
^#F2::switchDesktop(2)
^#F3::switchDesktop(3)
^#F4::switchDesktop(4)
^#F5::switchDesktop(5)
^#F6::switchDesktop(6)「Ctrl」+「Win」+「F1~F6」キーでデスクトップ切り替え
事前に仮想デスクトップが6つ作成されていることを想定している。
ディスプレイが2枚以上あると正しく動かないことが分かっている。「Win」+「Tab」キーを押下して、単純にTabキーを送り付けて最後にEnterキーを叩いているだけなのでディスプレイの枚数が増えると必ずバグる。
Send “{Tab}” を Send “{Tab x}” にしてTabキーの回数を修正すれば動くのだろうけど、そもそもマルチディスプレイ環境であれば、タスクビューでデスクトップを切り替えるような使い方はしないか。
あとは、実行時にタスクビューの画面が表示されてしまい宜しくない。
Linuxの仮想コンソールは、「Ctrl」+「Alt」+「F1~F6」キーで切り替えていた。昔のLinuxのGUIは、すぐに固まってしまい仮想コンソールからプロセスを落とすことがよくあった。
Linuxの仮想コンソールに倣い6つの仮想デスクトップを想定している。
Karabiner-Elementsの定義ファイルをバックアップしたので貼っておこー 
Ctrl + 矢印キー:矢印キー5回連打*
Ctrl + iキー :上キー*
Ctrl + kキー :下キー*
Ctrl + jキー :左キー*
Ctrl + lキー :右キー*
Ctrl + uキー :Homeキー*
Ctrl + oキー :Endキー*
Ctrl + hキー :BackSpace*
Alt + 1キー :アクティブ画面左寄せ
Alt + 2キー :アクティブ画面中央寄せ
Alt + 3キー :アクティブ画面右寄せ
Alt + qキー :アクティブ画面左上寄せ
Alt + aキー :アクティブ画面左下寄せ
Alt + wキー :アクティブ画面右上寄せ
Alt + sキー :アクティブ画面右下寄せ
Ctrl + F10 :音量ミュート
Ctrl + F11 :音量Down
Ctrl + F12 :音量UP
*:Karabinerで定義
https://karabiner-elements.pqrs.org

{
    "description": "Exchange control + arrow key to 5 arrow keys",
    "manipulators": [
        {
            "from": {
                "key_code": "right_arrow",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "right_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "right_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "right_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "right_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "right_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "left_arrow",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "left_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "left_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "left_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "left_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "left_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "up_arrow",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "up_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "up_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "up_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "up_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "up_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "down_arrow",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "down_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "down_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "down_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "down_arrow",
                    "modifiers": []
                },
                {
                    "key_code": "down_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        }
    ]
}{
    "description": "Exchange control + h key to backspace key",
    "manipulators": [
        {
            "from": {
                "key_code": "h",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "delete_or_backspace",
                    "modifiers": []
                }
            ],
            "type": "basic"
        }
    ]
}{
    "description": "Exchange control + ikjl key to arrow key",
    "manipulators": [
        {
            "from": {
                "key_code": "i",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "up_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "k",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "down_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "j",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "left_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "l",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "right_arrow",
                    "modifiers": []
                }
            ],
            "type": "basic"
        }
    ]
}{
    "description": "Exchange control + uo key to home end key",
    "manipulators": [
        {
            "from": {
                "key_code": "u",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "home",
                    "modifiers": []
                }
            ],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "o",
                "modifiers": {
                    "mandatory": [
                        "control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "end",
                    "modifiers": []
                }
            ],
            "type": "basic"
        }
    ]
}アクティブ画面の移動は、Rectangleを使っていた。
Hammerspoonでスクリプトを書くとAutoHotkeyと同じようなことができる。知らんけど。

https://support.apple.com/ja-jp/111999

だとよ。そろそろ壊れるかもしれない。
ここ何年かはこの2台でMacBook Proをメインで使ってきたけどトリグキーに移行する。トリグキーはまだ2か月ぐらいで長期間使えるかが怪しい。そして8年前のMacBook Proの方が未だにトリグキーより速い。
上記の構成でブログサイトを再構築するとMacBookが18分で完了するのにトリグキーは32分かかる。同じサイト資産を使って測定したのでトリグキーが遅いことは確定。何が足を引っ張っているのか分からないけど3万円だけのことはある。( ー`дー´)キリッ
最近の速いMacBookが欲しいなぁとは思うものの必要かというと必要はなくて遅いパソコンで問題ない用途でしか使用していない。YouTubeやNetflixの視聴がメインだからなあ…