ttw_fmx_v10/utils/uKeyEvent.pas

319 lines
8.4 KiB
Plaintext

unit uKeyEvent;
interface
uses
System.SysUtils, System.Types, winapi.Windows, System.Classes, System.UITypes,
FMX.Types, FMX.Edit, FMX.Controls, FMX.Forms, FMX.Platform, FMX.ListBox;
type
TKE = class(TObject)
private
fEdit: TEdit;
Fcombo1: TComboBox;
Fcombo2: TComboBox;
Fcombo3: TComboBox;
procedure UpdateCombination;
function GetKeyPriority(const Key: string): Integer;
procedure ComboBoxChange(Sender: TObject);
function FindLastDuplicate(List: TStringList; StartIndex: Integer): Integer;
function StrToVirtualKey(const KeyStr: string): Word;
procedure InitializeComboBox(cb: TComboBox);
function CompareKeys(List: TStringList; Index1, Index2: Integer): Integer;
public
constructor Create( edt: TEdit; c1, c2, c3: TComboBox);
procedure SimulateKeyPress(const KeyCombo: string; Delay: Integer);
end;
const
KeyOrder: array[0..82] of string = (
// Ìîäèôèêàòîðû
'Control', 'Ctrl', 'Alt', 'Shift', 'Win',
// Ôóíêöèîíàëüíûå êëàâèøè
'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12',
// Ñïåöèàëüíûå êëàâèøè
'Esc', 'Tab', 'CapsLock', 'Enter', 'Space', 'Backspace', 'Delete', 'Insert',
'Home', 'End', 'PageUp', 'PageDown', 'PrintScreen', 'ScrollLock', 'Pause',
// Íàâèãàöèÿ
'Up', 'Down', 'Left', 'Right',
// Öèôðû
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
// Áóêâû
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
// Ñèìâîëû
'`', '-', '=', '[', ']', '\', ';', '''', ',', '.', '/'
);
implementation
var
SortingInstance: TKE;
function GlobalCompare(List: TStringList; Index1, Index2: Integer): Integer;
begin
if Assigned(SortingInstance) then
Result := SortingInstance.CompareKeys(List, Index1, Index2)
else
Result := 0;
end;
constructor TKE.Create( edt: TEdit; c1, c2, c3: TComboBox);
begin
inherited Create;
// Ïðîâåðêà íà âàëèäíîñòü êîìïîíåíòîâ
if not Assigned(edt) then
raise Exception.Create('TEdit is nil');
if not Assigned(c1) or not Assigned(c2) or not Assigned(c3) then
raise Exception.Create('ComboBox is nil');
fEdit := edt;
Fcombo1 := c1;
Fcombo2 := c2;
Fcombo3 := c3;
InitializeComboBox(Fcombo1);
InitializeComboBox(Fcombo2);
InitializeComboBox(Fcombo3);
Fcombo1.OnChange := ComboBoxChange;
Fcombo2.OnChange := ComboBoxChange;
Fcombo3.OnChange := ComboBoxChange;
end;
procedure TKE.InitializeComboBox(cb: TComboBox);
var
i: Integer;
begin
cb.Items.BeginUpdate;
try
cb.Items.Clear;
cb.Items.Add(''); // Ïóñòîé ýëåìåíò
for i := 0 to High(KeyOrder) do
cb.Items.Add(KeyOrder[i]);
finally
cb.Items.EndUpdate;
end;
cb.ItemIndex := 0;
end;
procedure TKE.ComboBoxChange(Sender: TObject);
begin
UpdateCombination;
end;
function TKE.GetKeyPriority(const Key: string): Integer;
var
I: Integer;
begin
for I := 0 to High(KeyOrder) do
if SameText(KeyOrder[I], Key) then
begin
Result := I;
Exit;
end;
Result := High(KeyOrder) + 1; // Äëÿ íåèçâåñòíûõ êëàâèø
end;
function TKE.FindLastDuplicate(List: TStringList; StartIndex: Integer): Integer;
var
I: Integer;
begin
Result := -1;
for I := List.Count-1 downto StartIndex+1 do
if SameText(List[StartIndex], List[I]) then
begin
Result := I;
Break;
end;
end;
function TKE.CompareKeys(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := GetKeyPriority(List[Index1]) - GetKeyPriority(List[Index2]);
end;
procedure TKE.UpdateCombination;
var
List: TStringList;
I: Integer;
TempStr: string;
begin
List := TStringList.Create;
try
// Ñîáèðàåì âûáðàííûå êëàâèøè
if Fcombo1.Text <> '' then List.Add(Fcombo1.Text);
if Fcombo2.Text <> '' then List.Add(Fcombo2.Text);
if Fcombo3.Text <> '' then List.Add(Fcombo3.Text);
// Óäàëåíèå äóáëèêàòîâ
I := 0;
while I < List.Count do
begin
if FindLastDuplicate(List, I) > I then
List.Delete(I)
else
Inc(I);
end;
// Ñîðòèðîâêà ñ èñïîëüçîâàíèåì ãëîáàëüíîé ïåðåìåííîé
SortingInstance := Self;
try
List.CustomSort(GlobalCompare);
finally
SortingInstance := nil;
end;
// Ôîðìèðîâàíèå ñòðîêè
TempStr := '';
for I := 0 to List.Count-1 do
begin
if TempStr <> '' then TempStr := TempStr + '+';
TempStr := TempStr + List[I];
end;
fEdit.Text := TempStr;
finally
List.Free;
end;
end;
function TKE.StrToVirtualKey(const KeyStr: string): Word;
begin
// Ìîäèôèêàòîðû
if SameText(KeyStr, 'Control') or SameText(KeyStr, 'Ctrl') then Exit(VK_CONTROL);
if SameText(KeyStr, 'Alt') then Exit(VK_MENU);
if SameText(KeyStr, 'Shift') then Exit(VK_SHIFT);
if SameText(KeyStr, 'Win') then Exit(VK_LWIN);
// Ôóíêöèîíàëüíûå êëàâèøè
if SameText(KeyStr, 'F1') then Exit(VK_F1);
if SameText(KeyStr, 'F2') then Exit(VK_F2);
if SameText(KeyStr, 'F3') then Exit(VK_F3);
if SameText(KeyStr, 'F4') then Exit(VK_F4);
if SameText(KeyStr, 'F5') then Exit(VK_F5);
if SameText(KeyStr, 'F6') then Exit(VK_F6);
if SameText(KeyStr, 'F7') then Exit(VK_F7);
if SameText(KeyStr, 'F8') then Exit(VK_F8);
if SameText(KeyStr, 'F9') then Exit(VK_F9);
if SameText(KeyStr, 'F10') then Exit(VK_F10);
if SameText(KeyStr, 'F11') then Exit(VK_F11);
if SameText(KeyStr, 'F12') then Exit(VK_F12);
// Ñïåöèàëüíûå êëàâèøè
if SameText(KeyStr, 'Esc') then Exit(VK_ESCAPE);
if SameText(KeyStr, 'Tab') then Exit(VK_TAB);
if SameText(KeyStr, 'CapsLock') then Exit(VK_CAPITAL);
if SameText(KeyStr, 'Enter') then Exit(VK_RETURN);
if SameText(KeyStr, 'Space') then Exit(VK_SPACE);
if SameText(KeyStr, 'Backspace') then Exit(VK_BACK);
if SameText(KeyStr, 'Delete') then Exit(VK_DELETE);
if SameText(KeyStr, 'Insert') then Exit(VK_INSERT);
if SameText(KeyStr, 'Home') then Exit(VK_HOME);
if SameText(KeyStr, 'End') then Exit(VK_END);
if SameText(KeyStr, 'PageUp') then Exit(VK_PRIOR);
if SameText(KeyStr, 'PageDown') then Exit(VK_NEXT);
if SameText(KeyStr, 'PrintScreen') then Exit(VK_SNAPSHOT);
if SameText(KeyStr, 'ScrollLock') then Exit(VK_SCROLL);
if SameText(KeyStr, 'Pause') then Exit(VK_PAUSE);
// Íàâèãàöèÿ
if SameText(KeyStr, 'Up') then Exit(VK_UP);
if SameText(KeyStr, 'Down') then Exit(VK_DOWN);
if SameText(KeyStr, 'Left') then Exit(VK_LEFT);
if SameText(KeyStr, 'Right') then Exit(VK_RIGHT);
// Áóêâû è öèôðû
if Length(KeyStr) = 1 then
begin
case KeyStr[1] of
'A'..'Z': Exit(Ord(UpCase(KeyStr[1])));
'0'..'9': Exit(Ord(KeyStr[1]));
'`': Exit(VK_OEM_3);
'-': Exit(VK_OEM_MINUS);
'=': Exit(VK_OEM_PLUS);
'[': Exit(VK_OEM_4);
']': Exit(VK_OEM_6);
'\': Exit(VK_OEM_5);
';': Exit(VK_OEM_1);
'''': Exit(VK_OEM_7);
',': Exit(VK_OEM_COMMA);
'.': Exit(VK_OEM_PERIOD);
'/': Exit(VK_OEM_2);
end;
end;
Result := 0; // Åñëè êëàâèøà íå ðàñïîçíàíà
end;
procedure TKE.SimulateKeyPress(const KeyCombo: string; Delay: Integer);
var
Parts: TArray<string>;
Inputs: array of TInput;
i, Index: Integer;
Key: Word;
KeyState: TKeyboardState;
begin
Parts := KeyCombo.Split(['+'], TStringSplitOptions.ExcludeEmpty);
SetLength(Inputs, Length(Parts) * 2); // Êàæäàÿ êëàâèøà: íàæàòèå è îòïóñêàíèå
Index := 0;
// Ñíà÷àëà ñîáèðàåì âñå ñîáûòèÿ íàæàòèÿ
for i := 0 to High(Parts) do
begin
Key := StrToVirtualKey(Parts[i].Trim);
if Key = 0 then Continue;
// Íàæàòèå êëàâèøè
Inputs[Index].Itype := INPUT_KEYBOARD;
Inputs[Index].ki.wVk := Key;
Inputs[Index].ki.dwFlags := 0;
Inputs[Index].ki.time := 0;
Inputs[Index].ki.wScan := 0;
Inputs[Index].ki.dwExtraInfo := 0;
Inc(Index);
end;
// Îòïðàâëÿåì íàæàòèÿ
if Index > 0 then
SendInput(Index, Inputs[0], SizeOf(TInput));
// Çàäåðæêà
Sleep(Delay);
// Òåïåðü ñîáèðàåì ñîáûòèÿ îòïóñêàíèÿ â îáðàòíîì ïîðÿäêå
for i := High(Parts) downto 0 do
begin
Key := StrToVirtualKey(Parts[i].Trim);
if Key = 0 then Continue;
// Îòïóñêàíèå êëàâèøè
Inputs[Index].Itype := INPUT_KEYBOARD;
Inputs[Index].ki.wVk := Key;
Inputs[Index].ki.dwFlags := KEYEVENTF_KEYUP;
Inputs[Index].ki.time := 0;
Inputs[Index].ki.wScan := 0;
Inputs[Index].ki.dwExtraInfo := 0;
Inc(Index);
end;
// Îòïðàâëÿåì îòïóñêàíèÿ
if Index > Length(Parts) then
SendInput(Index - Length(Parts), Inputs[Length(Parts)], SizeOf(TInput));
// Ïðèíóäèòåëüíî îáíîâëÿåì ñîñòîÿíèå êëàâèàòóðû
GetKeyboardState(KeyState);
SetKeyboardState(KeyState);
end;
end.