AutoHotKey-Hacks

Bsp. 2 : Tastaturlayout (bei Laptops) anpassen (extended version)

Aber: Der obige Code soll natürlich nur dann laufen, wenn ich auch direkt an dieser Laptop-Tastatur sitze. Die meiste Zeit arbeite ich mit einer externen Tastatur, d.h. da wäre dieser Tasten-Tausch hinderlich. Es wäre gut, das Skript würde nun erkennen, an welcher Tastatur ich sitze.

Gelöst habe ich das dadurch, dass ich eine Tastenkombination definiert habe, die das Script selbst neu läd. Beim Laden wird dann geschaut, ob meine externe Tastatur erkannt wird oder nicht, und abhängig davon wird das obige Tasten-Remapping gemacht oder eben nicht.

Ich will darauf gar nicht im Detail eingehen, sondern zeige den Code vor allem deshalb, um die Mächtigkeit von AutoHotkey zu demonstrieren:

; --- Konfiguration ---
MyExternalKeyboardId := "b35b_REV"
global ExternalKeyboardBool := false


; --- Initialisierung ---
try {
    o := HidListObj()

    ; Checken, ob ein Keyboard-Name den String enthält
    for keyboard in o.Keyboard {
        if InStr(keyboard.Name, MyExternalKeyboardId) {
            global ExternalKeyboardBool := true
            break
        }
    }
} catch {
    MsgBox("Fehler beim Auslesen der Hardware-Liste.", "Fehler", 16)
}

; --- Benutzerbestätigung ---
MsgTitle := "AutoHotkey gestartet"
MsgText := ExternalKeyboardBool ? "Externes Keyboard gefunden!`n`nPasst das?" :
    "KEIN externes Keyboard gefunden...`n`nPasst das?"
Result := MsgBox(MsgText, MsgTitle, 32 + 4) ; Icon Frage + Ja/No

if (Result = "No") {
    global ExternalKeyboardBool := !ExternalKeyboardBool
    MsgBox("OK, Einstellung geändert...", "Keyboard geändert", "Iconi T1")
}

; --- Hotkeys ---

; Skript neu laden
^!r:: Reload()

; Die Direktive #HotIf sorgt dafür, dass die Hotkeys NUR dann aktiv sind,
; wenn die Bedingung (KEIN externes Keyboard) erfüllt ist.
; Das spart die manuellen Checks in jedem Hotkey.

#HotIf !ExternalKeyboardBool
PgUp::Home
PgDn::End
Home::PgUp
End::PgDn

+PgUp::+Home
+PgDn::+End
+Home::+PgUp
+End::+PgDn

; Backspace Fix für defekte Taste
$BackSpace:: {
    Send("{BackSpace Down}")
    Sleep(70)
    Send("{BackSpace Up}")
}

; Globaler Ersatz für Backspace
PrintScreen::BackSpace

#HotIf


/************************************************************************
 * FUNKTIONEN
 ************************************************************************/

/**
 * Erstellt ein Objekt mit allen HID-Geräten
 * Basiert auf: https://www.autohotkey.com/boards/viewtopic.php?p=58347#p58347
 */
HidListObj() {
    F := { Mouse: [], Keyboard: [], HID: [] }
    B := Map(0, "Mouse", 1, "Keyboard", 2, "HID")

    iCount := 0
    ; Erste Abfrage für die Anzahl der Geräte
    DllCall("GetRawInputDeviceList", "Ptr", 0, "UInt*", &iCount, "UInt", A_PtrSize * 2)

    if (iCount = 0)
        return F

    uHIDList := Buffer(iCount * (A_PtrSize * 2))
    DllCall("GetRawInputDeviceList", "Ptr", uHIDList, "UInt*", &iCount, "UInt", A_PtrSize * 2)

    loop iCount {
        offset := (A_Index - 1) * (A_PtrSize * 2)
        hDevice := NumGet(uHIDList, offset, "Ptr")
        Type := NumGet(uHIDList, offset + A_PtrSize, "UInt")

        TypeName := B.Has(Type) ? B[Type] : "HID"

        deviceInfo := {}
        deviceInfo.Handle := hDevice

        ; Gerätename abrufen
        iLength := 0
        DllCall("GetRawInputDeviceInfo", "Ptr", hDevice, "UInt", 0x20000007, "Ptr", 0, "UInt*", &iLength)
        if (iLength > 0) {
            nameBuf := Buffer((iLength + 1) * 2)
            DllCall("GetRawInputDeviceInfo", "Ptr", hDevice, "UInt", 0x20000007, "Ptr", nameBuf, "UInt*", &iLength)
            deviceInfo.Name := StrGet(nameBuf)
        }

        ; Geräteinfo abrufen
        iLength := 0
        DllCall("GetRawInputDeviceInfo", "Ptr", hDevice, "UInt", 0x2000000b, "Ptr", 0, "UInt*", &iLength)
        if (iLength > 0) {
            uInfo := Buffer(iLength)
            NumPut("UInt", iLength, uInfo)
            DllCall("GetRawInputDeviceInfo", "Ptr", hDevice, "UInt", 0x2000000b, "Ptr", uInfo, "UInt*", &iLength)

            if (Type = 0) { ; Mouse
                deviceInfo.ID := NumGet(uInfo, 8, "UInt")
                deviceInfo.Buttons := NumGet(uInfo, 12, "UInt")
            } else if (Type = 1) { ; Keyboard
                deviceInfo.KBType := NumGet(uInfo, 8, "UInt")
                deviceInfo.KeysTotal := NumGet(uInfo, 28, "UInt")
            } else if (Type = 2) { ; HID
                deviceInfo.VendorID := NumGet(uInfo, 8, "UInt")
                deviceInfo.ProductID := NumGet(uInfo, 12, "UInt")
            }
        }

        F.%TypeName%.Push(deviceInfo)
    }
    return F
}

Bsp. 3: Defekte Taste “reparieren”

Im Lauf der Jahre hat die Backspace-Taste meiner Laptop-Tastatur etwas gelitten. Sie hat angefangen, nicht nur ein einziges Zeichen zu löschen, wenn man sie drückt, sondern sie hat mehrfach ausgelöst. Durch ein “Debouncing” hat sich das leicht reparieren lassen:

; Backspace Fix für defekte Taste:
$BackSpace:: {
    Send("{BackSpace Down}")
    Sleep(70)
    Send("{BackSpace Up}")
}

Was hier passiert: Beim Drücken der Backspace-Taste wird zunächst das Herunterdrücken der Taste gesendet, dann wird für 70ms gewartet, und danach wird das Loslassen der Taste gesendet. Das hat geholfen, um das Problem zu beheben. Definitiv günstiger als eine neue Tastatur.

Eine Alternative wäre, einfach statt der Backspace-Taste eine andere Taste zu verwenden, z.B. die “Druck”- bzw. “Print”-Taste, die bei meinem Laptop praktischerweise direkt darüber liegt:

PrintScreen::BackSpace

Bsp. 4: Steuern von Heimautomation

Wenn du Dinge in deinem Zuhause automatisiert hast und dafür z.B. MQTT nutzt, dann könnte so etwas interessant sein. Du installierst dir lokal Mosquitto und kannst dann ganz einfach per AutoHotkey und Tastenkombinationen bestimmte Aktionen auslösen. Das könnte z.B. so aussehen, um eine Lampe ein- und auszuschalten:

^!l::  ; Strg+Alt+L
{
    RunWait '"C:\Tools\mosquitto\mosquitto_pub.exe"'
        . ' -h 192.168.1.10'
        . ' -p 1883'
        . ' -u "deinUser"'
        . ' -P "deinPasswort"'
        . ' -t "home/schreibtisch/licht"'
        . ' -m "TOGGLE"'
    , , "Hide"
}

Bsp. 4: AutoHotkey selbst automatisieren

Bei mir sind die AutoHotkey-Sachen in zwei Skripte aufgeteilt. Jedes davon muss beim Systemstart gestartet werden. Das macht AutoHotkey nicht von sich aus, man muss da selbst eine Autostart-Verknüpfung anlegen. Das meinte ich oben damit, dass die Benutzung etwas holprig ist.

Wenn man diesen Code oben in jedes Skript packt spart man sich das. Denn der Code erzeugt automatisch einen Autostart-Link zu dem jeweiligen Skript, wenn noch keiner vorhanden ist:

; --- Autostart-Verknüpfung erstellen ---
; Erstellt automatisch eine Verknüpfung im Autostart-Ordner für das aktuelle Skript
A_StartupShortcut := A_Startup "\" StrReplace(A_ScriptName, ".ahk", ".lnk")
if !FileExist(A_StartupShortcut) {
    FileCreateShortcut(A_ScriptFullPath, A_StartupShortcut)
    MsgBox("Autostart-Verknüpfung für " A_ScriptName " wurde erstellt!", "Autostart", "Iconi")
}

So, das waren ein paar Anwendungsideen für AutoHotkey von mir. Vielleicht inspiriert es dich ja, auch bei dir ein paar Arbeitsabläufe eleganter zu lösen und auf dem Weg dahin noch ein bisschen Spaß beim Basteln mit Code zu haben.

0 Reaktionen auf “AutoHotKey-Hacks

  1. Daniel Weber

    Keine Ahnung, warum ich das mit dem "Bloggen"* jetzt wieder angefangen habe, aber irgendwie muss es.

    *Die Anführungszeichen müssen sein, denn ich das ist egtl. ein zu großes Wort dafür.

    #blog #bloggen #wordpress

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert