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; 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.