Powershell-Skript für Tastenkombinationen?

cleanercode  27.04.2024, 10:44

Bitte nochmal auf deutsch.

motipo123 
Fragesteller
 27.04.2024, 20:04

hab ich

1 Antwort

Ich hätte gern 100€ 😅

Im Ernst, wir geben hier Hilfe zur Selbsthilfe und erledigen keine Auftragsarbeiten.

Powershell für sich alleine kann sowas nicht. Wir müssen auf eine Funktion der SystemAPI zurückgreifen.

Im folgenden polle ich einfach stumpf alle 40 Millisekunden ob die gewünschten (Auslöser)Tasten gedrückt sind.

Auf globale Tastenkombie warten:

#https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate
$signature = @'
    [DllImport("user32.dll", CharSet=CharSet.Auto)] 
    public static extern short GetAsyncKeyState(int virtualKeyCode); 
'@
$API = Add-Type -MemberDefinition $signature -Name 'Keypress' -Namespace API -PassThru


#https://learn.microsoft.com/de-de/windows/win32/inputdev/virtual-key-codes
#Tastenkombie festlegen
$InitiatorKey = 0xA4 #VK_LMENU (ALT)
$SecondKey = [byte][char]$('X').ToUpper()  #Taste X


#most significant Bit und the least significant Bit:
#Echtzeitstatus: Taste wird gedrückt gehalten (0x8000) MSB
#Die Taste ist gerade vom losgelassenen zum gedrückten Zustand übergegangen (0x0001) LSB
$significantBits = 0x8001  #MSB and LSB


 #polle alle 40 Millisekunden die definierten Tasten
do {Start-Sleep -Milliseconds 40} until (
    (($API::GetAsyncKeyState($InitiatorKey) -band $significantBits) -ne 0 ) -band #bis $InitiatorKey (hier ALT-Taste) gedückt wird
    ($API::GetAsyncKeyState($SecondKey)  -ne 0) #und auch $SecondKey (hier X)
)


Write-Host 'ALT+X wurde  gedrueckt' -fo green

Polling ist natürlich nicht unbedingt Resoucenfreundlich. Das Zweite Manko, wäre, dass die abzufragende Tastenkombination nicht von einer anderen Anwendung definiert sein darf! Ist dies der Fall, wäre es ein Lotteriespiel, wer die Tasten als erstes erkennt.

Die Alternative wäre ein KeyboardHook Allerdings birgt ein solcher Eingriff in die Ereigniskette auch die Gefahr, dass dieser von der AV-Software als Keylogger moniert wird. Zudem ist es wesentlich mehr Aufwand.

Was letztlich passieren soll, ist das generieren von Tastendrücken mit der Methode SendWait() der Klasse System.Windows.Forms.SendKeys. Beacht, das es der Methode egal ist wer gesendeten Tasten empfängt. Das Fenster , welches den Focus hat, verarbeitet sie (oder auch nicht).

Tastedrücke senden:
Add-Type -AssemblyName 'System.Windows.Forms'
#https://learn.microsoft.com/de-de/dotnet/api/system.windows.forms.sendkeys?view=windowsdesktop-8.0
$WSK = [System.Windows.Forms.SendKeys]
#Tastenbuffer  leeren (falls noch  was drin ist)
$WSK::Flush()
Start-Sleep -Milliseconds 1000 #wichtig!!!, Flush()  ist  asynchron, gib etwas Zeit ,  bis etwas in  den Tastaturpuffer schreibst,  sonst  wird  es   von  Flusch  "geressen"


#liste der (Send)Tastencode Definitionen: https://learn.microsoft.com/de-de/dotnet/api/system.windows.forms.sendkeys?view=windowsdesktop-8.0#remarks
$WSK::SendWait('blah und &blub {Enter}') #sende  eine Textzeile + ENTER
$WSK::SendWait('^+stestdatei.txt{Enter}') #sende CTRL+SHIFT+S  und eien Dateinamen und ENTER (entspräche im Notepad dem Speichern unter Dialog)

oder:

Add-Type -AssemblyName 'System.Windows.Forms'
$WSK = [System.Windows.Forms.SendKeys]
$WSK::Flush()
Start-Sleep -Milliseconds 1000 


#mehre zu sendende Strings einzeln in einem Array definieren...
$KeysToSend = @(
    'Muh und Miff {Enter}', #text schreiben
    '^+s', #Speichern unter...-dialog öffnen
    'testdatei.txt{Enter}' #...ausfüllen
    '%{F4}' #Programm beenden
)


#...und   die  Elemente via ForEach  verarbeiten
$KeysToSend|
    ForEach-Object{
        $WSK::SendWait($_)
        Start-Sleep 1 #optional Pause zwischen den  zu sendenden  Strings
    }
noch mal alles beisammen:

demo.ps1

 $signature = '[DllImport("user32.dll", CharSet=CharSet.Auto)]  public static extern short GetAsyncKeyState(int virtualKeyCode);'
$API = Add-Type -MemberDefinition $signature -Name 'Keypress' -Namespace API -PassThru
$InitiatorKey = 0xA4
$SecondKey = [byte][char]$('X').ToUpper()
$significantBits = 0x8001


do {Start-Sleep -Milliseconds 40} until (
    (($API::GetAsyncKeyState($InitiatorKey) -band $significantBits) -ne 0 ) -band  ($API::GetAsyncKeyState($SecondKey)  -ne 0)
)


Add-Type -AssemblyName 'System.Windows.Forms'
$WSK = [System.Windows.Forms.SendKeys]
$WSK::Flush()
Start-Sleep -Milliseconds 1000
$WSK::SendWait('blah und &blub {Enter}'
$WSK::SendWait('^+stestdatei.txt{Enter}')

Letztlich sind solche "Spielereien" eine ziemlich unsichere Angelegenheit, weil die verwendeten Methoden keinerlei Kontrolle über ihre Umgebung haben. Sowas nenne ich Blindflug.

Die WindowsTaste Kann man weder Lesen noch Senden !!!

Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren