![]() |
SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Hallo DP-Mitglieder,
vor einigen Tagen bestand bei mir Bedarf, Tastatureingaben zu simulieren, wofür die Windows-Funktion ![]() Ich lege am einfachsten mit einem Beispiel los. Notepad starten:
Delphi-Quellcode:
Jeder der mit SendInput schon mal gearbeitet hat, wird wissen, was das für eine Vereinfachung mit sich bringt. Desweiteren wird der Caps-Lock-Zustand in der Methode Flush neutralisiert, soll heißen, dass im obigen Beispiel auch wirklich 'cmd' und nicht 'CMD' gesendet wird, wenn der Benutzer die Feststelltaste (wohl aus versehen) aktiviert hat.
uses SendInputHelper;
with TSendInputHelper.Create do begin AddShortCut([ssWin], 'r'); // [Win] + [R] AddDelay(100); // Verzögerung in ms AddText('cmd', TRUE); // TRUE = AppendReturn Flush; // Erst hier werden die zuvor hinzugefügten // Eingaben gebündelt abgesetzt. Free; end; Ich weiß, es ist eigentlich kein "richtiges" Projekt, doch ich sehe es einfach mal als eines an und habe es auch bei sourceforge veröffentlicht: ![]() Dort ist auch ein umfangreicheres Beispiel (auch compiliert) dabei. mfg |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Vielen Dank, Wladimir....
|
Ein weiteres Beispiel
Liste der Anhänge anzeigen (Anzahl: 1)
Habe soeben ein minimalistisches Beispiel erstellt, mit dem das Windows Flip 3D aktiviert und für 2 Sekunden durch die geöffneten Fenster geflippt wird:
Delphi-Quellcode:
mfg
program WindowsFlip;
{$APPTYPE CONSOLE} uses SysUtils, Windows, SendInputHelper; var cc:Integer; begin with TSendInputHelper.Create do begin AddShift([ssWin], TRUE, FALSE); for cc:=1 to 20 do begin AddVirtualKey(VK_TAB, TRUE, FALSE); AddDelay(100); end; AddVirtualKey(VK_TAB, FALSE, TRUE); AddVirtualKey(VK_ESCAPE); AddShift([ssWin], FALSE, TRUE); Flush; Free; end; end. |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Gute Arbeit 8-)
Als Dankeschön noch eine kleine Erweiterung. zum Hintergrund: Die aktuelle Implementation kann nur Zeichen schicken, die es auch im aktuell eingestellten Keyboard Layout gibt. D.h. auf einem deutschen Keyboard kannst du kein الله أكبر ausgeben. Das ist uns aufgefallen, als ein TerminalDiensteClient mit englischem Tastaturlayout ein Ö schicken wollte. Mit der Erweiterung ist das kein Problem mehr. Ein nicht unicodefähiges Control erhält dann die Ansi Entsprechung des Zeichens. wie man die Klasse erweitern kann:
Delphi-Quellcode:
P.S. ich hab hier WideChar genommen, damit es auch vor D2009 funzt.
class function TSendInputHelper.GetUnicode(SendChar: WideChar; Press,
Release: Boolean): TInputArray; const KEYEVENTF_UNICODE = 4; var ScanCode:Word absolute SendChar; KeyDown, KeyUp:TInput; begin KeyDown.Itype:=INPUT_KEYBOARD; KeyDown.ki.wVk:=0; KeyDown.ki.wScan:=ScanCode; KeyDown.ki.dwFlags:=KEYEVENTF_UNICODE; KeyDown.ki.time:=0; KeyDown.ki.dwExtraInfo:=GetMessageExtraInfo; KeyUp:=KeyDown; KeyUp.ki.dwFlags:=KeyUp.ki.dwFlags or KEYEVENTF_KEYUP; SetLength(Result, 0); if Press and Release then begin SetLength(Result, 2); Result[0]:=KeyDown; Result[1]:=KeyUp; end else if Press then begin SetLength(Result, 1); Result[0]:=KeyDown; end else if Release then begin SetLength(Result, 1); Result[0]:=KeyUp; end; end; procedure TSendInputHelper.AddUnicodeChar(SendChar: WideChar; Press, Release: Boolean); var Inputs:TInputArray; begin Inputs:=GetUnicode(SendChar, Press, Release); if Assigned(Inputs) then AddRange(Inputs); end; |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Hallo MarcoWarm,
sorry, dass ich erst jetzt antworte. Das Forum hat mir keine Benachrichtigung geschickt, dass ich ein Antwort erhalten hab. Hab es nur per Zufall entdeckt. Zitat:
Die Erweiterung werde ich gerne demnächst übernehmen. Vielen Dank dafür. |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
deinen Code habe ich als Basis genommen und den Support für Unicode eingebunden. Es läuft jetzt transparent ab, die Klassenmethode TSendInputHelper.GetChar überprüft nun ob das Zeichen ein Unicode-Char ist und leitet den Aufruf ggf. auf TSendInputHelper.GetUnicodeChar um. Dadurch werden alle Methoden, die auf GetChar basieren, automatisch Unicode kompatibel und eine separate AddUnicode Methode wird überflüssig. Ich weiß, dadurch bin ich nicht Abwärtskompatibel zu < Delphi 2009, aber das interessiert mich ehrlich gesagt nicht ;) (think only forward) Die Änderungen sind auf der ![]() |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Hi Wladi,
danke für's einbauen (wir haben es erstmal ungetestet in unsere produktive Umgebung übernommen ;-) ein kleiner Hinweis noch. Für alle D2009 Nutzer wäre es schön, wenn du
Delphi-Quellcode:
als konstante definieren würdest ... das bringt unsere alte Windows.pas nicht mit :-(
KEYEVENTF_UNICODE = 4;
Gruß Marco |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Hi Marco,
die Konstante ist drin. Die Änderung wurde ins SVN-Repository gecommitted. Leider kann ich im Moment keine Dateien releasen, da sourceforge vor ein paar Tagen gehackt wurde und der File-Release-Dienst deaktiviert wurde. Hole ich aber in ein paar Tagen nach. mfg |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
vielen Dank :-D
|
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Hallo Waldemar,
vielen Dank für TSendInputHelper! Ich habe eine Frage: Man kann zwar alle möglichen Schriftzeichen senden, die nicht auf der Tastatur vorhanden sind, z.B.:
Delphi-Quellcode:
Wenn ich jedoch ein "é" senden möchte, so funktioniert es nicht:
IH.AddText('Das ist ein Test üöäÜÖÄß!"§$%&/()=?\|~', True);
IH.AddText('Привет! Cześć! 你好! !שלום', TRUE);
Delphi-Quellcode:
IH.AddText('é', True); // Kleiner lateinischer Buchstabe E mit Akut
Wie kann ich dieses Zeichen senden? |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Wird ein Fehler gemeldet? Wenn ja welcher?
|
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
Ich habe eine Tastatur mit deutschem Layout. Windows 7 x64 SP1 Deutsch |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
|
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
SendInputHelper hat ein Problem: Es verwendet TShiftState als Klassenmitglied. Das führt zu Problemen mit anderen Klassen, welche System.Classes.TShiftState verwenden.
Wie kann man dieses Problem lösen? |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Eine Möglichkeit wäre, dass man SendInputHelper in der uses-Klausel VOR System.Classes einfügt. Aber dann funktionieren alle SendInputHelper Methoden nicht mehr, welche einen TShiftState Parameter verwenden, z.B.:
Delphi-Quellcode:
procedure TSendInputHelper.AddShortCut(ShiftState:TShiftState; ShortChar:Char);
Ein verzwicktes Problem! Wie könnte man es lösen? |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Ein möglicher Workaround: Eine eigene Bridge- oder Worker-Unit erzeugen, in der die SendInputHelper-Aufrufe gekapselt werden, z.B.:
Delphi-Quellcode:
Zusätzlich sollte noch in SendInputHelper.pas TShiftState durch TSIHShiftState ersetzt werden.
unit SIHWorker;
interface uses SendInputHelper; procedure SendShortCut(DummyShiftState: Integer; ShortChar: Char); implementation var SIH: TSendInputHelper; procedure SendShortCut(DummyShiftState: Integer; ShortChar: Char); begin case DummyShiftState of 1: SIH.AddShortCut([ssShift], ShortChar); 2: SIH.AddShortCut([ssCtrl], ShortChar); 3: SIH.AddShortCut([ssAlt], ShortChar); end; SIH.Flush; end; { Todo: weitere SendInputHelper-Aufrufe } initialization SIH := TSendInputHelper.Create; finalization SIH.Free; end. Jetzt kann man die Methoden von SendInputHelper indirekt über SIHWorker aufrufen und braucht so SendInputHelper nicht mehr in anderen Units zu deklarieren (was zu den besagten Fehlern führen würde). |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Nachdem ich eine Lösung für das TShiftState-Problem aufgezeigt habe, habe ich jetzt endlich den Fehler gefunden, bei dem keine Akzentzeichen (z.B. éèáà usw.) ausgegeben wurden. Ich habe jetzt die Delphi XE3 IDE zum Debuggen verwendet, und die stürzt im Debug-Modus nicht ab, obwohl AQtime installiert ist! ;-)
Delphi-Quellcode:
Der Fehler liegt darin, dass Waldemar die Unicode-Zeichenbehandlung erst ab Ord(SendChar) = 255 angesetzt hat. Akzentzeichen wie é sind jedoch auf einer deutschen Tastatur mit den Umschalttasten Shift/Ctrl/Alt(/AltGr) nicht erreichbar (und nur diese sind im Rückgabewert von VkKeyScan kodiert), deshalb hat das nachfolgende VkKeyScan(SendChar) immer einen falschen ScanCode von 65535 (!) ergeben, wodurch natürlich kein Zeichen gesendet wurde. Die deutschen Umlaute sind zwar auch 8-bittig kodiert (haben also einen ASCII-Wert im Bereich 128-255), sind jedoch mit den Umschalttasten auf einer deutschen Tastatur erreichbar und liefern deshalb bei VkKeyScan einen korrekten Wert zurück. Bei Verwendung einer US-Tastatur würde VkKeyScan aber auch bei den deutschen Umlauten einen falschen Wert zurückgeben. Es ist also richtig, bei VkKeyScan vom kleinsten gemeinsamen Nenner - nämlich 7-bit ASCII - auszugehen!
if not((Ord(SendChar) > 0) and (Ord(SendChar) < 127)) then // war: 255
begin Result := GetUnicodeChar(SendChar, Press, Release); Exit; end; |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Verbesserung: SendInputHelper-Methoden, die kein TShiftState als Parameter übergeben, können von außen direkt über die Objekt-Variable SIH aufgerufen werden. Deshalb muss die Objekt-Variable SIH im Interface-Teil deklariert werden!
Delphi-Quellcode:
unit SIHWorker;
interface uses SendInputHelper; procedure SendShortCutChar(DummyShiftState: Integer; ShortChar: Char); var SIH: TSendInputHelper; implementation procedure SendShortCutChar(DummyShiftState: Integer; ShortChar: Char); begin case DummyShiftState of 1: SIH.AddShortCut([ssShift], ShortChar); 2: SIH.AddShortCut([ssCtrl], ShortChar); 3: SIH.AddShortCut([ssAlt], ShortChar); end; SIH.Flush; end; (* SendInputHelper-Methoden, die kein TShiftState als Parameter übergeben, können von außen direkt über die Objekt-Variable SIH aufgerufen werden. Deshalb muss die Objekt-Variable SIH im Interface-Teil deklariert werden! *) initialization SIH := TSendInputHelper.Create; finalization SIH.Free; end. |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Nach so viele Jahre :thumb:
Danke |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
sicherlich ist es nach all den Jahren nicht mehr relevant, aber ich wollte hier mal erwähnen, das dieser Fehler jetzt beseitigt ist. Auch habe ich das Set TShiftState nach TSIHShiftState umbenannt, damit es keine Namenskonflikte mit anderen Bibliotheken geben kann. Das Repository befindet sich schon seit einigen Jahren auf GitHub: ![]() |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
|
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
DANKE nochmals für SendInputHelper - einfach nützlich und genial!
|
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
|
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
Es sind solche Programmierer wie Waldemar Derr, die mit ihrer ausgezeichneten Arbeit Delphi voranbringen! |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Wenn beim Add oder Flush eine Exception auftreten könnte, dann würde noch der Ressourcenschutzblock fehlen.
Delphi-Quellcode:
with TSendInputHelper.Create do
try AddShortCut([ssWin], 'r'); // [Win] + [R] AddDelay(100); // Verzögerung in ms AddText('cmd', TRUE); // TRUE = AppendReturn Flush; // Erst hier werden die zuvor hinzugefügten Eingaben gebündelt abgesetzt. finally Free; end; Wenn du das auf einen Record umschreibst und z.B. intern nur dynamische Arrays (anstatt objekte/Pointer/Listen) verwendets, OK, ein Interface statt Class ginge auch, aber warum komplizierter. :angle2: dann kann man auf Create und Free verzichten, also wie eine einfach Variable benutzten und dann vergessen. (wie Integer, TPoint oder String+StringHelper) PS, dann ginge auch sowas wie Ducktyping. (überall jeweils Self als Result zurückgegeben)
Delphi-Quellcode:
TSendInputHelper.Create.AddShortCut([ssWin], 'r').AddDelay(100).AddText('cmd', TRUE).Flush;
Ja, Dank Custom-Managed-Records kann man nun auch in Records eigentlich alles benutzen, so lange ein Record nur sein eigenens Zeugs nutzt und man beim Kopieren von Variablen alle Inhalte, anstatt nur die Referenzen kopiert, oder man für Objekte/Pointer sich eine Referenzzählung baut (geht, aber macht kein Spaß, da es keine Record-Vererbung gibt und Generics hier kaum nutzbar sind). Warum eigentlich .Flush und nicht .Send ? |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Zitat:
|
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
z.B. statt TList<> und TStringList verwende ich zunehmend lieber ein TArray<String>, sowie eben Records anstatt Klassen. (sind teilweise einfacher als die doppelte Deklaration eines Interfaces)
und dennoch kann man so von der automatischen Speicherverwaltung profitieren. (seit den Custom-Managed-Records sind nun auch die letzten Probleme mit "unsicheren" Typen behebbar, also Pointer und Objekte innerhalb des Reocrds, sowie die einfachen dynamischen Arrays, welchen leider seit Jahrzehnten das CopyOnWrite fehlt, entgegen z.B. einem String, der intern auch nur ein aufgemotztes Char-Array ist, aber bei Welchem das CopyOnWrite funktioniert)
Delphi-Quellcode:
type
TMyRecord = record private FList: TArray<Integer>; public class function Create: TMyRecord; static; function Add(a: Integer): TMyRecord: function Send; function Clear; end; class function TMyRecord.Create: TMyRecord; begin Result := Self; end; function TMyRecord.Add(a: Integer): TMyRecord: begin FList := FList + [a]; end; function TMyRecord.Send; begin // mach was mit FList end; function TMyRecord.Clear; begin FList := []; // oder FList := nil; oder SetLength(FList, 0); end; TMyRecord.Create.Add(123).Add(456).Send; var R: TMyRecord; R.Add(123); R.Add(456); R.Send; R.Clear; // damit die 123 und 456 verschwinden (oder beim Send, z.B. via Parameter, nach dem Senden automatisch leeren lassen) R.Add(789); R.Send; R.Add(123).Add(456).Send; R.Clear; R.Add(789).Send;
Delphi-Quellcode:
bzw.
type
TSendInputHelper = record private FData: TArray<TInput>; // oder eben dein TInputArray class function MergeInputs(InputsBatch: array of TInputArray): TInputArray; static; public class function ConvertShiftState(ClassesShiftState: System.Classes.TShiftState): TSIHShiftState; static; ... procedure AddShift(ShiftState: TSIHShiftState; Press, Release: Boolean); overload; procedure AddShift(ShiftState: System.Classes.TShiftState; Press, Release: Boolean); overload; ... end;
Delphi-Quellcode:
---
function AddShift(ShiftState: TSIHShiftState; Press, Release: Boolean): TSendInputHelper; overload;
function AddShift(ShiftState: System.Classes.TShiftState; Press, Release: Boolean): TSendInputHelper; overload; ... end;
Delphi-Quellcode:
gibt es nicht, da es leider keine Recordvererbung gibt. :cry:
protected
Sinnvoll ist somit eh nur
Delphi-Quellcode:
und
private
Delphi-Quellcode:
.
public
Delphi-Quellcode:
können nur müssen
class function
Delphi-Quellcode:
sein, wodurch es dann auch kein Self gibt. (ohne Vererbung gibt es in einer Funktion eh immer nur den einen "Klassen"-Typ)
static
Delphi-Quellcode:
class function ConvertShiftState(ClassesShiftState: System.Classes.TShiftState): TSIHShiftState; static;
Das in TMyRecord.Add, nennt sich "string-like Operator", sowie Insert und Delete gibt es auch seit 'ner Weile. ![]() Ebenso weitere Array-Helper (unit System.Generics.Collections)
Delphi-Quellcode:
BinarySearch geht aber nur für sortierte Arrays.
FList := [456, 123, 789];
TArray.Sort<Integer>(FList); if TArray.BinarySearch<Integer>(FList, 456, idx) then ShowMessage(idx.ToString); // = '1' Für TArray<String> gäbe es auch ![]() ![]() Constructoren für Record sind zu praktisch, aber die müssen leider immer Parameter besitzen (vermutlich eine kranke Kompatibilität zu C++ oder so), aber
Delphi-Quellcode:
Das alte TPoint kennst'e doch noch?
type
TMyRecord = record constructor Create; // [dcc32 Fehler] E2394 Parameterlose Konstruktoren sind für Record-Typen nicht zulässig constructor Create(Value: Integer); constructor Create(Values: array of Integer); overload; // bzw. (Values: TArray<Integer>) end; TMyRecord = record class function Create: TMyRecord; static; // der Bugfix für den E2394 end;
Delphi-Quellcode:
neu sieht es so aus
TPoint = record
X: Integer; Y: Integer; end;
Delphi-Quellcode:
TPoint = record
X: FixedInt; Y: FixedInt; public constructor Create(P : TPoint); overload; constructor Create(const X, Y : Integer); overload; //operator overloads class operator Equal(const Lhs, Rhs : TPoint) : Boolean; class operator NotEqual(const Lhs, Rhs : TPoint): Boolean; class operator Add(const Lhs, Rhs : TPoint): TPoint; class operator Subtract(const Lhs, Rhs : TPoint): TPoint; class operator Implicit(Value: TSmallPoint): TPoint; class operator Explicit(Value: TPoint): TSmallPoint; class function PointInCircle(const Point, Center: TPoint; const Radius: Integer): Boolean; static; inline; /// <summary> Zero point having values of (0, 0). </summary> class function Zero: TPoint; inline; static; function Distance(const P2 : TPoint) : Double; procedure SetLocation(const X, Y : Integer); overload; procedure SetLocation(const P : TPoint); overload; procedure Offset(const DX, DY : Integer); overload; procedure Offset(const Point: TPoint); overload; function Add(const Point: TPoint): TPoint; function Subtract(const Point: TPoint): TPoint; function IsZero : Boolean; function Angle(const APoint: TPoint): Single; end;
Delphi-Quellcode:
Viele Records haben keinen Constructor und Delphi generiert auch (noch) keinen Standard-Constructor. :cry:
var Demo: TArray<TPoint>; // oder : array of TPoint;
Demo := [TPoint.Create(1, 2), TPoint.Create(3, 4)]; Demo := Demo + [TPoint.Create(5, 6)]; Insert(TPoint.Create(7, 8), Demo, 3); TInput leider auch, aber das kann man noch nachrüsten:
Delphi-Quellcode:
type
TInputHelper = record helper for TInput constructor Create(P: TMouseInput); overload; constructor Create(P: TKeybdInput); overload; constructor Create(P: THardwareInput); overload; end; // bzw. TInputHelper = record helper for TInput constructor Create(dx, dy: LongInt; mouseData, dwFlags: DWORD); overload; //constructor Create(dx, dy: LongInt; mouseData, dwFlags, time: DWORD; dwExtraInfo: ULONG_PTR); overload; constructor Create(wVk, wScan: WORD; dwFlags: DWORD); overload; //constructor Create(wVk, wScan: WORD; dwFlags, time: DWORD; dwExtraInfo: ULONG_PTR); overload; //constructor Create(P: THardwareInput); overload; end; PS: Record-Helper für sowas wie Enum und Set geht noch nicht so, aber man könnte sich einen Record mit AutoCasts basteln. Also TShiftStateEx als Parameter für deine Funktionen. Dann brauchst'e das Overload nicht mehr, da sich die beiden Sets größtenteils automatisch von und dahin casten, bei Zuweisung := , sowie bei Übergabe an den Parameter. Zu geil wäre es natürlich, wenn man stattdessen TSIHShiftState so anpassen könnte, dass TShiftState zuweisungskompatibel würde. (aber sowas erwarte ich frühestens im nächsten Jahrtausend von Embarcadero)
Delphi-Quellcode:
TShiftStateEx = record
private FState: TSIHShiftState; function GetShiftState: TShiftState; // Result := TShiftState(FState - ssWin); procedure SetShiftState(Value: TShiftState); // FState := TSIHShiftState(Value); public class operator Implicit(a: TSIHShiftState): TShiftStateEx; // Result.FState := a; -> entspricht TheRecord := SIHShiftState; class operator Implicit(a: TShiftState): TShiftStateEx; // Result.FState := TSIHShiftState(a); -> entspricht TheRecord := ShiftState; class operator Implicit(a: TShiftStateEx): TShiftState; // Result := TShiftState(a.FState - ssWin); -> entspricht ShiftState := TheRecord; class operator Explicit(a: TShiftStateEx): TSIHShiftState; // Result := a.FState; -> entspricht SIHShiftState := TSIHShiftState(TheRecord); // Und noch ein paar kleine Hilfsfunktionen, falls man nicht alles direkt über harte oder implizite Casts machen will: property AsShiftState: TShiftState read GetShiftState write SetShiftState; property AsSIHShiftState: TSIHShiftState read FState write FState; function HasMenu: Boolean; // Result := ssWin in FState; end;
Delphi-Quellcode:
// anstatt
procedure AddShift(ShiftState: TSIHShiftState; Press, Release: Boolean); overload; procedure AddShift(ShiftState: System.Classes.TShiftState; Press, Release: Boolean); overload; procedure AddShortCut(ShiftState: TSIHShiftState; ShortChar: Char); overload; procedure AddShortCut(ShiftState: TSIHShiftState; ShortVK: Word); overload; procedure AddShortCut(ShiftState: System.Classes.TShiftState; ShortChar: Char); overload; procedure AddShortCut(ShiftState: System.Classes.TShiftState; ShortVK: Word); overload; // nur noch procedure AddShift(ShiftState: TShiftStateEx; Press, Release: Boolean); overload; procedure AddShortCut(ShiftState: TShiftStateEx; ShortChar: Char); overload; procedure AddShortCut(ShiftState: TShiftStateEx; ShortVK: Word); overload; |
AW: SendInputHelper - Ein Wrapper, der den Umgang mit SendInput vereinfacht
Hi Himitsu,
vielen Dank für dein ausführliches Feedback. Wenn du magst, kannst du einen PullRequest erstellen. Ich würde dich natürlich in den Credits aufführen. Sonst weiß ich nicht, wann ich dazu komme, dies einzubauen... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:27 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz