(10 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 5: Zeile 5:
[[file:desktop-suite.ahk für Windows 10 IoT 2021 LTSC.png|frameless|upright=3.0|link=https://schwarzatal.org/images/3/36/Desktop-suite.ahk_f%C3%BCr_Windows_10_IoT_2021_LTSC.png|desktop-suite.ahk für Windows 10 IoT 2021 LTSC - Screenshot]]
[[file:desktop-suite.ahk für Windows 10 IoT 2021 LTSC.png|frameless|upright=3.0|link=https://schwarzatal.org/images/3/36/Desktop-suite.ahk_f%C3%BCr_Windows_10_IoT_2021_LTSC.png|desktop-suite.ahk für Windows 10 IoT 2021 LTSC - Screenshot]]


Dieses Script ist speziell für [[Windows#Windows_10_IoT_Enterprise_LTSC_2021|Windows 10 IoT 2021 LTSC]]. Wenn man es mit einer Anderen Windows Version nutzen will, muss man es für die jeweilige Version überarbeiten. Und man benötigt auch die entsprechende [[Windows#Autohotkey|AutoHotKey]] Version, welche zur jeweiligen Windows Version passt.
Dieses Script ist speziell für [[Windows#Windows_10_IoT_Enterprise_LTSC_2021|Windows 10 IoT 2021 LTSC]]. Wenn man es mit einer Anderen Windows Version nutzen will, muss man es für die jeweilige Version überarbeiten. Und man benötigt auch die entsprechende VirtualDesktopAccessor.dll Version, welche zur jeweiligen Windows Version passt.




Zeile 94: Zeile 94:


=== Schritt 1: AutoHotkey v2 installieren ===
=== Schritt 1: AutoHotkey v2 installieren ===
Lade AutoHotkey '''v2''' von der offiziellen Seite '''autohotkey.com''' herunter und installiere es. Achte darauf, dass es wirklich '''v2''' ist — v1-Skripte und v2-Skripte sind nicht kompatibel, und dieses Skript läuft ausschließlich unter v2 (die erste Zeile <code>#Requires AutoHotkey v2.0</code> sorgt dafür, dass es sich bei einer falschen Version gar nicht erst startet). Wähle bei der Installation die Standardoption „UX / v2".
Lade AutoHotkey '''v2''' von der offiziellen Seite '''[https://www.autohotkey.com/ autohotkey.com]''' herunter und installiere es. Achte darauf, dass es wirklich '''v2''' ist — v1-Skripte und v2-Skripte sind nicht kompatibel, und dieses Skript läuft ausschließlich unter v2 (die erste Zeile <code>#Requires AutoHotkey v2.0</code> sorgt dafür, dass es sich bei einer falschen Version gar nicht erst startet). Wähle bei der Installation die Standardoption „UX / v2".


=== Schritt 2: VirtualDesktopAccessor.dll besorgen ===
=== Schritt 2: VirtualDesktopAccessor.dll besorgen ===
Die Desktop-Leiste steuert die virtuellen Windows-Desktops über eine Hilfsbibliothek namens '''VirtualDesktopAccessor.dll'''. Diese ist nicht Teil von AutoHotkey und muss separat geladen werden. Sie stammt aus dem quelloffenen Projekt '''VirtualDesktopAccessor''' von ''Ciantic'' auf GitHub.
Die Desktop-Leiste steuert die virtuellen Windows-Desktops über eine Hilfsbibliothek namens '''[https://github.com/Ciantic/VirtualDesktopAccessor/releases/ VirtualDesktopAccessor.dll]''' (Windows 10 binary, final
). Diese ist nicht Teil von AutoHotkey und muss separat geladen werden. Sie stammt aus dem quelloffenen Projekt '''[https://github.com/Ciantic/VirtualDesktopAccessor VirtualDesktopAccessor ]''' von ''[https://github.com/Ciantic Ciantic]'' auf GitHub.


Wichtig dabei: Diese DLL spricht interne Windows-Schnittstellen an, die sich zwischen Windows-Versionen unterscheiden. Lade daher die Version, die zu '''deinem Windows''' passt (Windows 10 bzw. Windows 11, ggf. für deinen konkreten Build). Nimmst du die falsche, startet das Skript zwar, aber das Umschalten der Desktops funktioniert nicht oder stürzt ab.
Wichtig dabei: Diese DLL spricht interne Windows-Schnittstellen an, die sich zwischen Windows-Versionen unterscheiden. Lade daher die Version, die zu '''deinem Windows''' passt (Windows 10 bzw. Windows 11, ggf. für deinen konkreten Build). Nimmst du die falsche, startet das Skript zwar, aber das Umschalten der Desktops funktioniert nicht oder stürzt ab.


Da die DLL Fenster über Windows-interne APIs verschiebt, gilt hier dieselbe Vorsicht wie bei jedem Fremd-Download: Lade sie nur aus der offiziellen GitHub-Quelle des Projekts, nicht von Drittseiten.
Da die DLL Fenster über Windows-interne APIs verschiebt, gilt hier dieselbe Vorsicht wie bei jedem Fremd-Download: Lade sie nur aus der offiziellen GitHub-Quelle des Projekts, nicht von Drittseiten.
[[file:Desktop-suite.ahk für Windows 10 IoT 2021 LTSC - VirtualDesktopAccessor.png|frameless|upright=3.0|link=]]


=== Schritt 3: DLL an den richtigen Ort legen ===
=== Schritt 3: DLL an den richtigen Ort legen ===
Zeile 749: Zeile 752:


</pre>
</pre>
== Start über eine Verknüpfung statt über die Dateizuordnung ==
Standardmäßig wird <code>vdesk.ahk</code> per Doppelklick bzw. über die Autostart-
Verknüpfung auf die '''Skriptdatei''' gestartet. Windows entscheidet dabei anhand der
Dateizuordnung, welcher Interpreter zum Zug kommt. Das ist ein Sicherheitsrisko, da Jemand der weiß das sie das Tool nutzen, sie vl. dazu bringen kann, ein bösartiges Script auszuführen.
Sauberer ist es, die Verknüpfung direkt auf den 64-Bit-Interpreter zeigen zu lassen und
das Skript nur als Parameter zu übergeben.
=== Autostart-Verknüpfung umstellen ===
# <code>Win+R</code> → <code>shell:startup</code> → Enter
# Rechtsklick auf die vorhandene desktop-suite-Verknüpfung → ''Eigenschaften''
# Feld '''Ziel''' auf folgenden Wert ändern (Anführungszeichen sind wegen der Leerzeichen im Pfad zwingend):
#: <code>"C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe" "C:\Tools\desktop-suite.ahk"</code>
# Feld '''Ausführen in''' auf <code>C:\Tools</code> setzen
# Mit ''OK'' bestätigen
Zeigte die alte Verknüpfung direkt auf die <code>.ahk</code>-Datei, lässt sich das Ziel
unter Umständen nicht bearbeiten – dann die Verknüpfung löschen und über
''Rechtsklick → Neu → Verknüpfung'' mit obiger Zeile neu anlegen.
==== Pfad der EXE prüfen ====
{| class="wikitable"
! Variante !! Pfad
|-
| AutoHotkey v2, aktueller Installer || <code>C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe</code>
|-
| Ältere oder portable v2-Installation || <code>C:\Program Files\AutoHotkey\AutoHotkey64.exe</code>
|}
'''Ausdrücklich nicht verwenden:''' <code>AutoHotkey32.exe</code> (32-Bit, inkompatibel
zur DLL) und <code>AutoHotkey.exe</code> (nur Launcher).
==== Ergebnis kontrollieren ====
Laufendes Skript beenden (Rechtsklick auf das Tray-Symbol → ''Exit''), dann die
Verknüpfung doppelklicken. Danach prüfen:
* Im Task-Manager muss der Prozess '''<code>AutoHotkey64.exe</code>''' heißen.
* Das Panel erscheint in der Taskleiste, <code>Win+2</code> wechselt den Desktop.
Erst wenn das funktioniert, mit dem nächsten Schritt weitermachen.
=== Dateizuordnung für .ahk entfernen ===
{{Achtung|Erst durchführen, wenn der Start über die Verknüpfung nachweislich
funktioniert. Ohne Zuordnung lassen sich <code>.ahk</code>-Dateien nicht mehr per
Doppelklick starten – das ist hier gewollt, muss aber allen Beteiligten klar sein.}}
Über ''Einstellungen → Apps → Standard-Apps'' lässt sich eine Zuordnung nur ''ändern'',
nicht ''entfernen''. Zwei saubere Wege:
==== Variante A: über das AutoHotkey-Setup (bevorzugt) ====
# Das Installationsprogramm von AutoHotkey v2 erneut starten (bzw. ''Systemsteuerung → Programme → AutoHotkey → Ändern'')
# Die Option zum Registrieren bzw. Wiederherstellen der Dateizuordnung deaktivieren – je nach Version heißt sie ''Add 'Run Script''' bzw. wird über die Schaltfläche ''UnInstall file association'' im Dash angeboten.
AutoHotkey v2 bringt dafür das '''Dash''' mit (Startmenü → ''AutoHotkey Dash'' →
''Launch settings'' →
''Run all scripts with a specific interpreter"). Und z.B. Notepad++ wählen.
==== Variante B: manuell in der Registry ====
Vorher die betroffenen Schlüssel exportieren (Rechtsklick → ''Exportieren''), damit sich
der Zustand zurückholen lässt.
Zu löschen sind:
{| class="wikitable"
! Schlüssel !! Bedeutung
|-
| <code>HKEY_CLASSES_ROOT\.ahk</code> || Verknüpft die Endung mit der ProgID
|-
| <code>HKEY_CLASSES_ROOT\AutoHotkeyScript</code> || Definiert die Aktionen (''Open'', ''Run Script'', ''Edit'', ''Compile'')
|-
| <code>HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ahk</code> || Benutzerspezifische Auswahl (''UserChoice''), überstimmt die Einträge oben
|}
Der letzte Schlüssel ist der wichtigste: Solange <code>UserChoice</code> existiert, wirkt
er, auch wenn <code>HKEY_CLASSES_ROOT\.ahk</code> bereits weg ist. Er ist
schreibgeschützt – der '''Unterschlüssel''' <code>UserChoice</code> lässt sich aber als
Ganzes löschen. Anschließend abmelden und wieder anmelden oder den Explorer neu
starten.
==== Ergebnis kontrollieren ====
* Doppelklick auf <code>C:\Tools\vdesk.ahk</code> muss den Dialog ''Wie soll diese Datei geöffnet werden?'' zeigen – dort '''ohne''' Auswahl abbrechen und keinesfalls den Haken ''Immer diese App verwenden'' setzen.
* Die Autostart-Verknüpfung muss weiterhin funktionieren.
* Nach der nächsten Anmeldung erneut prüfen, ob das Panel erscheint.
Zum manuellen Neustart des Skripts ab jetzt immer die '''Verknüpfung''' verwenden, nicht
die <code>.ahk</code>-Datei.
<br><br><br><br>


Script und Anleitung erstellt mit Claude Opus 4.8 und Claude Fabel 5.
Script und Anleitung erstellt mit Claude Opus 4.8 und Claude Fabel 5.
Die einzelnen Funktionen "Vritual Desktop Managemant" und "TilingWM" waren zuvor einzelnen Scripts welche mit Opus 4.8 ausgearbeitet wurden, und am Ende wurden diese mit Fabel 5 zusammengeführt und um die Dark/Light-Mode umschaltung erweitert.
Die einzelnen Funktionen "Virtual Desktop Managemant" und "Tiling-WM" waren zuvor einzelnen Scripte welche mit Opus 4.8 ausgearbeitet wurden, und am Ende wurden diese mit Fabel 5 zusammengeführt und um die Dark/Light-Mode Umschaltung erweitert.

Aktuelle Version vom 20. Juli 2026, 14:08 Uhr

Hauptseite > Technik > EDV > Windows > Windows 10 IoT 2021 LTSC


desktop-suite.ahk für Windows 10 IoT 2021 LTSC - Screenshot

Dieses Script ist speziell für Windows 10 IoT 2021 LTSC. Wenn man es mit einer Anderen Windows Version nutzen will, muss man es für die jeweilige Version überarbeiten. Und man benötigt auch die entsprechende VirtualDesktopAccessor.dll Version, welche zur jeweiligen Windows Version passt.


Anleitung: Desktop-Suite

Was ist das?

Ein AutoHotkey-v2-Skript, das drei Dinge in einem bündelt: eine Desktop-Leiste in der Taskleiste zum Anzeigen und Wechseln der virtuellen Windows-Desktops, ein Autotile, das Fenster automatisch in Spalten oder einem Quad-Layout anordnet, und einen Dark/Light-Umschalter für das Windows-Farbschema. Dazu kommt ein Always-on-Top-Schalter für einzelne Fenster.

Voraussetzungen

Du brauchst AutoHotkey v2 (installiert) und die VirtualDesktopAccessor.dll unter C:\Tools\VirtualDesktopAccessor.dll. Liegt die DLL woanders, passe die Zeile DllPath := ... ganz oben im Skript an. Ohne die DLL startet das Skript nicht (es meldet sich mit einer Fehlermeldung).

Starten

Doppelklick auf desktop-suite.ahk. Es erscheint das grüne AHK-Symbol im Infobereich und links neben der Uhr die Desktop-Leiste mit den nummerierten Knöpfen. Soll das Skript bei jedem Windows-Start mitlaufen: Win+Rshell:startup → Enter, und eine Verknüpfung der Datei in diesen Ordner legen.

Nach jeder Änderung am Skript: Rechtsklick aufs AHK-Symbol im Infobereich → Reload Script.

Virtuelle Desktops

Die Leiste zeigt alle Desktops als Knöpfe; der aktive leuchtet blau. Klick auf einen Knopf wechselt dorthin. Legst du in Windows Desktops an oder löscht welche (Win+Tab), passt sich die Leiste automatisch an. Bei Vollbild-Anwendungen (Videos, Spiele) blendet sie sich selbst aus.

Kürzel Wirkung
Win + 1…9 zu Desktop 1–9 wechseln
Win + Shift + 1…9 aktives Fenster dorthin schicken, du bleibst hier
Win + Alt + 1…9 Fenster verschieben und mitspringen
Win + 0 Desktop-Leiste ein-/ausblenden

Autotile

Das Autotile ordnet alle „normalen" Fenster des Bildschirms automatisch an — minimierte Fenster, Dialoge und Fenster auf anderen Desktops bleiben unberührt. Solange es an ist, fügen sich neu geöffnete Fenster von selbst ein und geschlossene machen Platz.

Kürzel Wirkung
Strg + Shift + Win + Z Autotile an, Layout Spalten (alle nebeneinander)
Strg + Shift + Win + J Autotile an, Layout Quad (links eine große Hälfte, Rest rechts gestapelt — bei 3 Fenstern: halb + zwei Viertel)
Strg + Shift + Win + Y Autotile aus
Strg + Shift + Win + N aktives Fenster eine Position weiterschieben
Strg + Shift + Win + B aktives Fenster eine Position zurückschieben

Tipp: Im Quad-Layout bestimmt die Position 1 den großen Platz links — mit N/B schiebst du das gewünschte Fenster dorthin. Die Abstände lassen sich oben im Skript über GAP_INNER und GAP_OUTER ändern.

Dark/Light umschalten

Kürzel Wirkung
Strg + Shift + Win + O Windows-Farbschema zwischen Dunkel und Hell umschalten

Schaltet App- und System-Theme gleichzeitig um; Taskleiste, Explorer und die meisten Apps wechseln sofort. Ein kurzes Tooltip zeigt den neuen Zustand. Einzelne Programme mit eigener Theme-Einstellung (z. B. Browser auf „festes Theme") folgen ihrer eigenen Einstellung — stelle sie dort auf „System", wenn sie mitwechseln sollen.

Always on Top

Kürzel Wirkung
Strg + Alt + T aktives Fenster immer im Vordergrund halten (an/aus)
Shift + Rechtsklick auf eine Titelleiste dasselbe für das angeklickte Fenster

Wenn etwas klemmt

Reagieren die Kürzel nicht, prüfe, ob das Skript läuft (grünes Symbol im Infobereich) und ob du wirklich alle drei Modifier hältst (erst Strg+Shift+Win gedrückt halten, dann den Buchstaben). Meldet das Skript beim Start die fehlende DLL, stimmt der Pfad in DllPath nicht. Und wenn sich Fenster beim Kacheln überlappen, sind es meist zu viele für Spalten — dann aufs Quad wechseln (J) oder Fenster auf mehrere virtuelle Desktops verteilen.





Installation

Schritt 1: AutoHotkey v2 installieren

Lade AutoHotkey v2 von der offiziellen Seite autohotkey.com herunter und installiere es. Achte darauf, dass es wirklich v2 ist — v1-Skripte und v2-Skripte sind nicht kompatibel, und dieses Skript läuft ausschließlich unter v2 (die erste Zeile #Requires AutoHotkey v2.0 sorgt dafür, dass es sich bei einer falschen Version gar nicht erst startet). Wähle bei der Installation die Standardoption „UX / v2".

Schritt 2: VirtualDesktopAccessor.dll besorgen

Die Desktop-Leiste steuert die virtuellen Windows-Desktops über eine Hilfsbibliothek namens VirtualDesktopAccessor.dll (Windows 10 binary, final ). Diese ist nicht Teil von AutoHotkey und muss separat geladen werden. Sie stammt aus dem quelloffenen Projekt VirtualDesktopAccessor von Ciantic auf GitHub.

Wichtig dabei: Diese DLL spricht interne Windows-Schnittstellen an, die sich zwischen Windows-Versionen unterscheiden. Lade daher die Version, die zu deinem Windows passt (Windows 10 bzw. Windows 11, ggf. für deinen konkreten Build). Nimmst du die falsche, startet das Skript zwar, aber das Umschalten der Desktops funktioniert nicht oder stürzt ab.

Da die DLL Fenster über Windows-interne APIs verschiebt, gilt hier dieselbe Vorsicht wie bei jedem Fremd-Download: Lade sie nur aus der offiziellen GitHub-Quelle des Projekts, nicht von Drittseiten.

Schritt 3: DLL an den richtigen Ort legen

Das Skript erwartet die DLL standardmäßig unter:

C:\Tools\VirtualDesktopAccessor\VirtualDesktopAccessor.dll

Lege den Ordner C:\Tools\VirtualDesktopAccessor\ an und kopiere die DLL hinein. Wenn du sie lieber woanders ablegen willst, öffne das Skript im Editor und passe ganz oben die Zeile

DllPath  := "C:\Tools\VirtualDesktopAccessor\VirtualDesktopAccessor.dll"

auf deinen tatsächlichen Pfad an.

Schritt 4: Skript speichern

Speichere den Skript-Text als Datei mit der Endung .ahk, zum Beispiel desktop-suite.ahk. Achte beim Speichern im Editor darauf, als Dateityp „Alle Dateien" zu wählen, damit nicht versehentlich desktop-suite.ahk.txt daraus wird. Als Speicherort eignet sich ein fester Ordner wie C:\Tools\ oder dein Benutzerordner — von dort läuft es dauerhaft.

Bevor du es zum ersten Mal startest: Öffne die Datei einmal per Rechtsklick → Öffnen mit → Editor und lies sie durch. Ein Doppelklick würde das Skript sofort ausführen — das ist bei .ahk-Dateien immer so, sobald AutoHotkey installiert ist, und der Grund, warum man fremde Skripte grundsätzlich erst liest.

Schritt 5: Erster Start

Doppelklick auf desktop-suite.ahk. Zwei Dinge sollten passieren: Im Infobereich (rechts unten bei der Uhr) erscheint das grüne AutoHotkey-Symbol, und links neben der Uhr taucht die Desktop-Leiste mit den nummerierten Knöpfen auf.

Kommt stattdessen die Meldung „VirtualDesktopAccessor.dll nicht gefunden", stimmt der Pfad aus Schritt 3 nicht. Kommt gar nichts, prüfe, ob wirklich AutoHotkey v2 (nicht v1) installiert ist.

Schritt 6: Automatisch beim Anmelden starten (optional)

Damit die Suite bei jedem Windows-Start mitläuft: Drücke Win + R, gib shell:startup ein und bestätige. Es öffnet sich der Autostart-Ordner. Lege dort eine Verknüpfung zu deiner .ahk-Datei ab (Rechtsklick auf die Datei → Verknüpfung erstellen, dann die Verknüpfung in den Autostart-Ordner ziehen). Ab dem nächsten Anmelden startet die Suite automatisch.

Aktualisieren des Skripts

Wenn du etwas am Skript änderst, wird die laufende Version dadurch nicht automatisch neu geladen. Rechtsklick auf das grüne AutoHotkey-Symbol im Infobereich → Reload Script, dann läuft die neue Fassung.

Deinstallieren

Zum Beenden: Rechtsklick auf das AutoHotkey-Symbol → Exit. Soll es nicht mehr automatisch starten, lösche die Verknüpfung aus dem shell:startup-Ordner. Das Skript selbst und die DLL kannst du einfach löschen; es hinterlässt keine Systemänderungen — mit einer Ausnahme: Der Dark/Light-Umschalter verändert deine Windows-Theme-Einstellung, aber das ist dieselbe Einstellung, die du auch normal über die Windows-Einstellungen jederzeit zurücksetzen kannst.


#Requires AutoHotkey v2.0
#SingleInstance Force
CoordMode "Mouse", "Screen"

; ╔══════════════════════════════════════════════════════════════╗
; ║  Desktop-Suite:                                              ║
; ║   1) Virtuelle-Desktop-Leiste in der Taskleiste (vdesk)      ║
; ║   2) Autotile — Spalten / Quad                               ║
; ║   3) Dark/Light-Umschalter                                   ║
; ╚══════════════════════════════════════════════════════════════╝
;
;  ── Virtuelle Desktops ──────────────────────────────────────
;    Win+1..9          Desktop wechseln
;    Win+Shift+1..9    aktives Fenster dorthin schicken (du bleibst)
;    Win+Alt+1..9      Fenster verschieben UND mitspringen
;    Win+0             Desktop-Leiste ein/aus
;
;  ── Autotile (Strg+Shift+Win + Buchstabe) ───────────────────
;    Strg+Shift+Win+Z  Autotile AN, Layout Spalten
;    Strg+Shift+Win+J  Autotile AN, Layout Quad (links halb, Rest rechts)
;    Strg+Shift+Win+Y  Autotile AUS
;    Strg+Shift+Win+N  aktives Fenster eine Position weiter
;    Strg+Shift+Win+B  aktives Fenster eine Position zurueck
;
;  ── Sonstiges ───────────────────────────────────────────────
;    Strg+Shift+Win+O  Windows Dark/Light umschalten
;    Strg+Alt+T        Always on Top fuer aktives Fenster
;    Shift+Rechtsklick auf Titelleiste  ->  Always on Top

; ══════════════════════════════════════════════════════════════
; ══  TEIL 1: VIRTUELLE-DESKTOP-LEISTE                        ══
; ══════════════════════════════════════════════════════════════

; ══ Einstellungen (Leiste) ═══════════════════════════════════
DllPath  := "C:\Tools\VirtualDesktopAccessor.dll"
BTN_W    := 28            ; Breite pro Button
BTN_H    := 26            ; Hoehe
GAP      := 2             ; Abstand zwischen Buttons
PAD      := 14            ; Abstand zum Infobereich (Uhr/Icons)
COL_BG   := 0x1F1F1F      ; Panel-Hintergrund (Taskleistenton)
COL_ON   := 0x0A84FF      ; aktiver Desktop
COL_OFF  := 0x3A3A3A      ; inaktive Desktops
AUTOHIDE := true          ; Panel bei Vollbild automatisch ausblenden
; ═════════════════════════════════════════════════════════════

hDll := DllCall("LoadLibrary", "Str", DllPath, "Ptr")
if !hDll {
    MsgBox "VirtualDesktopAccessor.dll nicht gefunden:`n" DllPath
    ExitApp
}
pGoTo    := DllCall("GetProcAddress", "Ptr", hDll, "AStr", "GoToDesktopNumber", "Ptr")
pMove    := DllCall("GetProcAddress", "Ptr", hDll, "AStr", "MoveWindowToDesktopNumber", "Ptr")
pCurrent := DllCall("GetProcAddress", "Ptr", hDll, "AStr", "GetCurrentDesktopNumber", "Ptr")
pCount   := DllCall("GetProcAddress", "Ptr", hDll, "AStr", "GetDesktopCount", "Ptr")
pPin     := DllCall("GetProcAddress", "Ptr", hDll, "AStr", "PinWindow", "Ptr")

DeskCount()   => DllCall(pCount, "Int")
DeskCurrent() => DllCall(pCurrent, "Int") + 1

; ══ Kernfunktionen ═══════════════════════════════════════════
VDGo(n) {
    global pGoTo
    if (n > DeskCount()) {
        Flash("Desktop " n " existiert nicht")
        return
    }
    DllCall(pGoTo, "Int", n - 1)
}

MoveWin(n, follow := false) {
    global pMove, pGoTo, LastWin
    if (n > DeskCount()) {
        Flash("Desktop " n " existiert nicht")
        return
    }
    hwnd := WinExist("A")
    if (hwnd = PanelHwnd())
        hwnd := LastWin
    if !hwnd
        return
    DllCall(pMove, "Ptr", hwnd, "Int", n - 1)
    if follow
        DllCall(pGoTo, "Int", n - 1)
    else
        Flash("-> Desktop " n)
}

; kleines Overlay (gemeinsam fuer alle Teile)
Flash(txt) {
    ToolTip txt
    SetTimer () => ToolTip(), -900
}

; ══ Panel ════════════════════════════════════════════════════
global Panel := "", Tabs := [], LastCount := 0, LastCur := 0
global LastWin := 0, LastPos := "", Visible := true, Manual := true

PanelHwnd() => Panel ? Panel.Hwnd : 0
PanelWidth(cnt) => cnt * BTN_W + (cnt - 1) * GAP + 2 * GAP

TabClick(n, *) {
    VDGo(n)
}

BuildPanel(cnt) {
    global Panel, Tabs, BTN_W, BTN_H, GAP, COL_BG, COL_OFF, pPin
    global LastCur, LastPos, Visible

    if Panel
        Panel.Destroy()
    Tabs := []

    Panel := Gui("-Caption +ToolWindow +AlwaysOnTop +E0x08000000 -DPIScale")
    Panel.BackColor := COL_BG
    Panel.MarginX := 0, Panel.MarginY := 0

    Loop cnt {
        Panel.SetFont("s10 Bold cFFFFFF", "Segoe UI")
        c := Panel.Add("Text", Format("x{} y{} w{} h{} Center Background{:06X}"
                                    , GAP + (A_Index-1)*(BTN_W+GAP), GAP
                                    , BTN_W, BTN_H - 2*GAP, COL_OFF), A_Index)
        c.OnEvent("Click", TabClick.Bind(A_Index))
        Tabs.Push(c)
    }

    Panel.Show(Format("NoActivate Hide w{} h{}", PanelWidth(cnt), BTN_H))
    DllCall(pPin, "Ptr", Panel.Hwnd)          ; auf allen Desktops sichtbar
    LastPos := ""
    Place(cnt)
    Visible := false
    LastCur := 0
    Refresh(true)
}

Place(cnt) {
    global Panel, BTN_H, PAD, LastPos

    hTray := WinExist("ahk_class Shell_TrayWnd")
    if !hTray
        return
    WinGetPos &tx, &ty, &tw, &th, "ahk_id " hTray

    w := PanelWidth(cnt)
    x := tx + tw - 300 - w                      ; Fallback

    hNotify := DllCall("FindWindowEx", "Ptr", hTray, "Ptr", 0
                     , "Str", "TrayNotifyWnd", "Ptr", 0, "Ptr")
    if hNotify {
        r := Buffer(16, 0)
        DllCall("GetWindowRect", "Ptr", hNotify, "Ptr", r)
        x := NumGet(r, 0, "Int") - w - PAD      ; links vom Infobereich
    }
    y := ty + (th - BTN_H) // 2

    pos := x "," y
    if (pos = LastPos)
        return
    LastPos := pos

    ; SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE
    DllCall("SetWindowPos", "Ptr", Panel.Hwnd, "Ptr", 0
          , "Int", x, "Int", y, "Int", 0, "Int", 0, "UInt", 0x0015)
}

Raise() {
    global Panel
    ; SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE, HWND_TOPMOST
    DllCall("SetWindowPos", "Ptr", Panel.Hwnd, "Ptr", -1
          , "Int", 0, "Int", 0, "Int", 0, "Int", 0, "UInt", 0x0013)
}

; ── Vollbild-Erkennung ───────────────────────────────────────
; Wie die Shell: aktives Fenster deckt den ganzen Monitor ab
; und ist weder Desktop noch Taskleiste.
IsFullscreen() {
    hwnd := WinExist("A")
    if !hwnd || (hwnd = PanelHwnd())
        return false

    cls := WinGetClass(hwnd)
    if (cls = "WorkerW" || cls = "Progman" || cls = "Shell_TrayWnd")
        return false

    r := Buffer(16, 0)
    if !DllCall("GetWindowRect", "Ptr", hwnd, "Ptr", r)
        return false
    wx := NumGet(r, 0, "Int"), wy := NumGet(r, 4, "Int")
    wr := NumGet(r, 8, "Int"), wb := NumGet(r, 12, "Int")

    ; Monitor unter diesem Fenster (MONITOR_DEFAULTTONEAREST)
    hMon := DllCall("MonitorFromWindow", "Ptr", hwnd, "UInt", 2, "Ptr")
    mi := Buffer(40, 0)
    NumPut("UInt", 40, mi, 0)
    if !DllCall("GetMonitorInfo", "Ptr", hMon, "Ptr", mi)
        return false
    mx := NumGet(mi, 4, "Int"), my := NumGet(mi, 8, "Int")
    mr := NumGet(mi, 12, "Int"), mb := NumGet(mi, 16, "Int")

    return (wx <= mx) && (wy <= my) && (wr >= mr) && (wb >= mb)
}

SetVisible(show) {
    global Panel, Visible
    if (show = Visible)
        return
    Visible := show
    if show {
        Panel.Show("NoActivate")
        Raise()
    } else
        Panel.Hide()
}

Paint(idx, active) {
    global Tabs, COL_ON, COL_OFF
    c := Tabs[idx]
    c.SetFont(active ? "s10 Bold cFFFFFF" : "s10 Norm cA0A0A0", "Segoe UI")
    c.Opt("+Background" Format("{:06X}", active ? COL_ON : COL_OFF))
    c.Redraw()
}

Refresh(force := false) {
    global Tabs, LastCur, LastCount, LastWin, Panel
    global AUTOHIDE, Manual, Visible

    if (h := WinExist("A")) && (h != PanelHwnd())
        LastWin := h

    cnt := DeskCount()
    if (cnt != LastCount) {
        LastCount := cnt
        BuildPanel(cnt)
        return
    }

    ; sichtbar = manuell an UND (kein Autohide ODER kein Vollbild)
    SetVisible(Manual && (!AUTOHIDE || !IsFullscreen()))
    if !Visible
        return

    Place(cnt)
    Raise()

    cur := DeskCurrent()
    if (cur = LastCur && !force)
        return
    LastCur := cur

    Loop Tabs.Length
        Paint(A_Index, A_Index = cur)

    ; RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN | RDW_UPDATENOW
    DllCall("RedrawWindow", "Ptr", Panel.Hwnd, "Ptr", 0, "Ptr", 0, "UInt", 0x0185)
}

LastCount := DeskCount()
BuildPanel(LastCount)
SetTimer Refresh, 250

; ══════════════════════════════════════════════════════════════
; ══  TEIL 2: AUTOTILE (Spalten / Quad)                       ══
; ══════════════════════════════════════════════════════════════

; ══ Einstellungen (Autotile) ═════════════════════════════════
global GAP_INNER := 8         ; Abstand zwischen Fenstern (px)
global GAP_OUTER := 8         ; Abstand zum Bildschirmrand (px)
global Layout    := "columns" ; Startlayout: "columns" oder "grid"
; ═════════════════════════════════════════════════════════════

global AutoTile := false, LastSig := "", Tiling := false
global TileOrder := []

; ══ Fenster-Filter: was darf gekachelt werden? ═══════════════
IsManageable(hwnd) {
    try {
        if !hwnd
            return false
        if !DllCall("IsWindowVisible", "Ptr", hwnd)
            return false

        ; auf anderem virtuellen Desktop / versteckt (UWP) -> ueberspringen
        cloaked := 0
        DllCall("dwmapi\DwmGetWindowAttribute", "Ptr", hwnd
              , "UInt", 14, "Int*", &cloaked, "UInt", 4)   ; DWMWA_CLOAKED
        if cloaked
            return false

        if (WinGetTitle(hwnd) = "")
            return false
        if (WinGetMinMax(hwnd) = -1)                        ; minimiert
            return false

        style := WinGetStyle(hwnd)
        ex    := WinGetExStyle(hwnd)

        if (ex & 0x80)                                      ; WS_EX_TOOLWINDOW
            return false
        ; Fenster mit Owner (Dialoge/Popups) raus, ausser echte AppWindows
        owner := DllCall("GetWindow", "Ptr", hwnd, "UInt", 4, "Ptr")  ; GW_OWNER
        if (owner && !(ex & 0x40000))                       ; WS_EX_APPWINDOW
            return false
        ; nur groessenveraenderbare Fenster kacheln (fixe Dialoge floaten lassen)
        if !(style & 0x40000)                               ; WS_THICKFRAME
            return false

        static skip := Map("Progman",1, "WorkerW",1, "Shell_TrayWnd",1
                         , "Shell_SecondaryTrayWnd",1, "Windows.UI.Core.CoreWindow",1)
        if skip.Has(WinGetClass(hwnd))
            return false

        return true
    }
    return false
}

MonOf(hwnd) => DllCall("MonitorFromWindow", "Ptr", hwnd, "UInt", 2, "Ptr") ; NEAREST

; Arbeitsbereich eines Monitors (ohne Taskleiste)
WorkArea(hMon) {
    mi := Buffer(40, 0), NumPut("UInt", 40, mi, 0)
    DllCall("GetMonitorInfo", "Ptr", hMon, "Ptr", mi)
    return {l: NumGet(mi,20,"Int"), t: NumGet(mi,24,"Int")
          , r: NumGet(mi,28,"Int"), b: NumGet(mi,32,"Int")}
}

; DWM-Rahmenversatz: echter Fensterrahmen vs. sichtbare Kante
FrameOffsets(hwnd) {
    ow := Buffer(16,0), fw := Buffer(16,0)
    DllCall("GetWindowRect", "Ptr", hwnd, "Ptr", ow)
    if DllCall("dwmapi\DwmGetWindowAttribute", "Ptr", hwnd
             , "UInt", 9, "Ptr", fw, "UInt", 16)            ; EXTENDED_FRAME_BOUNDS
        return {l:0, t:0, r:0, b:0}
    return { l: NumGet(fw,0,"Int") - NumGet(ow,0,"Int")
           , t: NumGet(fw,4,"Int") - NumGet(ow,4,"Int")
           , r: NumGet(ow,8,"Int") - NumGet(fw,8,"Int")
           , b: NumGet(ow,12,"Int") - NumGet(fw,12,"Int") }
}

; Fenster an sichtbarer Zielposition platzieren (Versatz rausgerechnet)
PlaceWindow(hwnd, x, y, w, h) {
    try {
        if (WinGetMinMax(hwnd) = 1)                          ; maximiert -> erst normal
            WinRestore(hwnd)
        o := FrameOffsets(hwnd)
        DllCall("SetWindowPos", "Ptr", hwnd, "Ptr", 0
              , "Int", x - o.l, "Int", y - o.t
              , "Int", w + o.l + o.r, "Int", h + o.t + o.b
              , "UInt", 0x14)                                ; NOZORDER | NOACTIVATE
    }
}

; ══ Layouts ══════════════════════════════════════════════════
LayColumns(n, a) {
    global GAP_INNER, GAP_OUTER
    rects := []
    L := a.l+GAP_OUTER, T := a.t+GAP_OUTER, R := a.r-GAP_OUTER, B := a.b-GAP_OUTER
    colW := (R - L - (n-1)*GAP_INNER) / n
    Loop n {
        cx := L + (A_Index-1)*(colW+GAP_INNER)
        rects.Push({x:Round(cx), y:T, w:Round(colW), h:B-T})
    }
    return rects
}

; "Quad": erstes Fenster = linke Haelfte (Master),
; die restlichen gestapelt in der rechten Haelfte.
;   2 Fenster -> zwei Haelften
;   3 Fenster -> links halb, rechts zwei Viertel
;   4 Fenster -> links halb, rechts drei Zeilen
LayGrid(n, a) {
    global GAP_INNER, GAP_OUTER
    rects := []
    if (n = 0)
        return rects
    L := a.l+GAP_OUTER, T := a.t+GAP_OUTER, R := a.r-GAP_OUTER, B := a.b-GAP_OUTER
    totalW := R - L, totalH := B - T
    if (n = 1) {
        rects.Push({x:L, y:T, w:totalW, h:totalH})
        return rects
    }
    masterW := (totalW - GAP_INNER) / 2
    rects.Push({x:L, y:T, w:Round(masterW), h:totalH})   ; Master links
    stackN := n - 1
    stackX := L + masterW + GAP_INNER
    stackW := totalW - masterW - GAP_INNER
    rowH   := (totalH - (stackN-1)*GAP_INNER) / stackN
    Loop stackN {
        ry := T + (A_Index-1)*(rowH+GAP_INNER)
        rects.Push({x:Round(stackX), y:Round(ry), w:Round(stackW), h:Round(rowH)})
    }
    return rects
}

; ══ Reihenfolge stabil halten ════════════════════════════════
; Bestehende Fenster behalten ihren Platz, neue kommen ans Ende,
; geschlossene fallen raus.
RebuildOrder() {
    global TileOrder
    managed := Map()
    for h in WinGetList()
        if IsManageable(h)
            managed[h] := true
    kept := []
    for h in TileOrder
        if managed.Has(h) {
            kept.Push(h), managed.Delete(h)
        }
    for h in WinGetList()                                    ; neue anhaengen
        if managed.Has(h) {
            kept.Push(h), managed.Delete(h)
        }
    TileOrder := kept
}

; Set-Signatur (sortiert) -> nur bei Fensterwechsel neu kacheln,
; nicht bei jedem Fokuswechsel
ManagedSig() {
    s := ""
    for h in WinGetList()
        if IsManageable(h)
            s .= h "`n"
    return Sort(RTrim(s, "`n"), "N")
}

; ══ Kernaktion ═══════════════════════════════════════════════
Tile() {
    global TileOrder, Tiling, Layout
    if Tiling
        return
    Tiling := true
    try {
        RebuildOrder()
        groups := Map()                                      ; nach Monitor gruppieren
        for h in TileOrder {
            m := MonOf(h)
            if !groups.Has(m)
                groups[m] := []
            groups[m].Push(h)
        }
        for m, list in groups {
            wa := WorkArea(m)
            n  := list.Length
            rects := (Layout = "grid") ? LayGrid(n, wa) : LayColumns(n, wa)
            Loop n
                PlaceWindow(list[A_Index], rects[A_Index].x, rects[A_Index].y
                                         , rects[A_Index].w, rects[A_Index].h)
        }
    }
    Tiling := false
}

; ══ Fenster tauschen (monitor-lokal, mit Umlauf) ═════════════
SwapFocused(dir) {
    global TileOrder
    hwnd := WinExist("A")
    if !hwnd || !IsManageable(hwnd)
        return
    RebuildOrder()
    hMon := MonOf(hwnd)
    subIdx := []                                             ; Indizes dieses Monitors
    for i, h in TileOrder
        if (MonOf(h) = hMon)
            subIdx.Push(i)
    if (subIdx.Length < 2)
        return
    p := 0
    for k, i in subIdx
        if (TileOrder[i] = hwnd) {
            p := k
            break
        }
    if !p
        return
    q := Mod(p - 1 + dir + subIdx.Length, subIdx.Length) + 1   ; mit Umlauf
    a := subIdx[p], b := subIdx[q]
    tmp := TileOrder[a], TileOrder[a] := TileOrder[b], TileOrder[b] := tmp
    Tile()
    WinActivate(hwnd)
}

; ══ Auto-Retile-Schleife ═════════════════════════════════════
TileTick() {
    global AutoTile, LastSig, Tiling
    if !AutoTile || Tiling
        return
    if ((s := ManagedSig()) != LastSig) {
        LastSig := s
        Tile()
    }
}

; ══ Steuerung ════════════════════════════════════════════════
StartTiling(mode) {
    global Layout, AutoTile, LastSig
    Layout := mode
    AutoTile := true
    LastSig := ManagedSig()
    Tile()
    SetTimer TileTick, 350            ; ab jetzt automatisch nachkacheln
    Flash("Autotile AN — " (mode = "grid" ? "Quad" : "Spalten"))
}

StopTiling() {
    global AutoTile
    AutoTile := false
    SetTimer TileTick, 0
    Flash("Autotile AUS")
}

; ══════════════════════════════════════════════════════════════
; ══  TEIL 3: DARK/LIGHT-UMSCHALTER                           ══
; ══════════════════════════════════════════════════════════════
; Schaltet App- UND System-Theme um und benachrichtigt alle
; laufenden Programme (kein Neustart/Abmelden noetig).
ToggleTheme() {
    key := "HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
    cur := 1
    try cur := RegRead(key, "AppsUseLightTheme")
    val := cur ? 0 : 1                                   ; 0 = Dark, 1 = Light
    try {
        RegWrite val, "REG_DWORD", key, "AppsUseLightTheme"
        RegWrite val, "REG_DWORD", key, "SystemUsesLightTheme"
    } catch {
        Flash("Theme-Umschaltung fehlgeschlagen (Registry)")
        return
    }
    ; WM_SETTINGCHANGE an alle Fenster -> Apps uebernehmen sofort
    DllCall("SendMessageTimeout", "Ptr", 0xFFFF, "UInt", 0x1A
          , "Ptr", 0, "Str", "ImmersiveColorSet"
          , "UInt", 2, "UInt", 500, "Ptr*", 0)           ; SMTO_ABORTIFHUNG
    Flash(val ? "Theme: LIGHT" : "Theme: DARK")
}

; ══════════════════════════════════════════════════════════════
; ══  TEIL 4: ALWAYS ON TOP                                   ══
; ══════════════════════════════════════════════════════════════
ToggleAOT(hwnd := 0) {
    if !hwnd
        hwnd := WinExist("A")
    if !hwnd
        return
    isTop := WinGetExStyle(hwnd) & 0x8      ; WS_EX_TOPMOST
    WinSetAlwaysOnTop -1, hwnd
    Flash(isTop ? "Always on Top: AUS" : "Always on Top: AN")
}

OverTitleBar() {
    MouseGetPos &mx, &my, &win
    if !win
        return false
    lp := ((my & 0xFFFF) << 16) | (mx & 0xFFFF)
    return SendMessage(0x0084, 0, lp, , "ahk_id " win) = 2   ; WM_NCHITTEST -> HTCAPTION
}

; ══════════════════════════════════════════════════════════════
; ══  TASTEN                                                  ══
; ══════════════════════════════════════════════════════════════

; ── Desktop-Leiste ein/aus (Notausgang) ──────────────────────
#0:: {
    global Manual
    Manual := !Manual
    Flash("Desktop-Leiste: " (Manual ? "AN" : "AUS"))
    Refresh(true)
}

; ── Desktop wechseln ─────────────────────────────────────────
#1::VDGo(1)
#2::VDGo(2)
#3::VDGo(3)
#4::VDGo(4)
#5::VDGo(5)
#6::VDGo(6)
#7::VDGo(7)
#8::VDGo(8)
#9::VDGo(9)

; ── Fenster verschieben (du bleibst) ─────────────────────────
#+1::MoveWin(1)
#+2::MoveWin(2)
#+3::MoveWin(3)
#+4::MoveWin(4)
#+5::MoveWin(5)
#+6::MoveWin(6)
#+7::MoveWin(7)
#+8::MoveWin(8)
#+9::MoveWin(9)

; ── Fenster verschieben UND mitspringen ──────────────────────
#!1::MoveWin(1, true)
#!2::MoveWin(2, true)
#!3::MoveWin(3, true)
#!4::MoveWin(4, true)
#!5::MoveWin(5, true)
#!6::MoveWin(6, true)
#!7::MoveWin(7, true)
#!8::MoveWin(8, true)
#!9::MoveWin(9, true)

; ── Autotile (Strg+Shift+Win + Buchstabe) ────────────────────
^+#z::StartTiling("columns")   ; Spalten  – Autotile an
^+#j::StartTiling("grid")      ; Quad     – Autotile an
^+#y::StopTiling()             ; alles aus
^+#n::SwapFocused(1)           ; aktives Fenster eine Position weiter
^+#b::SwapFocused(-1)          ; ... und zurueck

; ── Dark/Light ───────────────────────────────────────────────
^+#o::ToggleTheme()            ; Strg+Shift+Win+O

; ── Always on Top ────────────────────────────────────────────
^!t::ToggleAOT()               ; Strg+Alt+T

#HotIf OverTitleBar()
+RButton:: {
    MouseGetPos , , &win
    ToggleAOT(win)
}
#HotIf

Start über eine Verknüpfung statt über die Dateizuordnung

Standardmäßig wird vdesk.ahk per Doppelklick bzw. über die Autostart- Verknüpfung auf die Skriptdatei gestartet. Windows entscheidet dabei anhand der Dateizuordnung, welcher Interpreter zum Zug kommt. Das ist ein Sicherheitsrisko, da Jemand der weiß das sie das Tool nutzen, sie vl. dazu bringen kann, ein bösartiges Script auszuführen.

Sauberer ist es, die Verknüpfung direkt auf den 64-Bit-Interpreter zeigen zu lassen und das Skript nur als Parameter zu übergeben.

Autostart-Verknüpfung umstellen

  1. Win+Rshell:startup → Enter
  2. Rechtsklick auf die vorhandene desktop-suite-Verknüpfung → Eigenschaften
  3. Feld Ziel auf folgenden Wert ändern (Anführungszeichen sind wegen der Leerzeichen im Pfad zwingend):
    "C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe" "C:\Tools\desktop-suite.ahk"
  4. Feld Ausführen in auf C:\Tools setzen
  5. Mit OK bestätigen

Zeigte die alte Verknüpfung direkt auf die .ahk-Datei, lässt sich das Ziel unter Umständen nicht bearbeiten – dann die Verknüpfung löschen und über Rechtsklick → Neu → Verknüpfung mit obiger Zeile neu anlegen.

Pfad der EXE prüfen

Variante Pfad
AutoHotkey v2, aktueller Installer C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe
Ältere oder portable v2-Installation C:\Program Files\AutoHotkey\AutoHotkey64.exe

Ausdrücklich nicht verwenden: AutoHotkey32.exe (32-Bit, inkompatibel zur DLL) und AutoHotkey.exe (nur Launcher).

Ergebnis kontrollieren

Laufendes Skript beenden (Rechtsklick auf das Tray-Symbol → Exit), dann die Verknüpfung doppelklicken. Danach prüfen:

  • Im Task-Manager muss der Prozess AutoHotkey64.exe heißen.
  • Das Panel erscheint in der Taskleiste, Win+2 wechselt den Desktop.

Erst wenn das funktioniert, mit dem nächsten Schritt weitermachen.

Dateizuordnung für .ahk entfernen

Vorlage:Achtung

Über Einstellungen → Apps → Standard-Apps lässt sich eine Zuordnung nur ändern, nicht entfernen. Zwei saubere Wege:

Variante A: über das AutoHotkey-Setup (bevorzugt)

  1. Das Installationsprogramm von AutoHotkey v2 erneut starten (bzw. Systemsteuerung → Programme → AutoHotkey → Ändern)
  2. Die Option zum Registrieren bzw. Wiederherstellen der Dateizuordnung deaktivieren – je nach Version heißt sie Add 'Run Script' bzw. wird über die Schaltfläche UnInstall file association im Dash angeboten.

AutoHotkey v2 bringt dafür das Dash mit (Startmenü → AutoHotkey DashLaunch settingsRun all scripts with a specific interpreter"). Und z.B. Notepad++ wählen.

Variante B: manuell in der Registry

Vorher die betroffenen Schlüssel exportieren (Rechtsklick → Exportieren), damit sich der Zustand zurückholen lässt.

Zu löschen sind:

Schlüssel Bedeutung
HKEY_CLASSES_ROOT\.ahk Verknüpft die Endung mit der ProgID
HKEY_CLASSES_ROOT\AutoHotkeyScript Definiert die Aktionen (Open, Run Script, Edit, Compile)
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ahk Benutzerspezifische Auswahl (UserChoice), überstimmt die Einträge oben

Der letzte Schlüssel ist der wichtigste: Solange UserChoice existiert, wirkt er, auch wenn HKEY_CLASSES_ROOT\.ahk bereits weg ist. Er ist schreibgeschützt – der Unterschlüssel UserChoice lässt sich aber als Ganzes löschen. Anschließend abmelden und wieder anmelden oder den Explorer neu starten.

Ergebnis kontrollieren

  • Doppelklick auf C:\Tools\vdesk.ahk muss den Dialog Wie soll diese Datei geöffnet werden? zeigen – dort ohne Auswahl abbrechen und keinesfalls den Haken Immer diese App verwenden setzen.
  • Die Autostart-Verknüpfung muss weiterhin funktionieren.
  • Nach der nächsten Anmeldung erneut prüfen, ob das Panel erscheint.

Zum manuellen Neustart des Skripts ab jetzt immer die Verknüpfung verwenden, nicht die .ahk-Datei.






Script und Anleitung erstellt mit Claude Opus 4.8 und Claude Fabel 5. Die einzelnen Funktionen "Virtual Desktop Managemant" und "Tiling-WM" waren zuvor einzelnen Scripte welche mit Opus 4.8 ausgearbeitet wurden, und am Ende wurden diese mit Fabel 5 zusammengeführt und um die Dark/Light-Mode Umschaltung erweitert.