⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hksend.pas

📁 Delphi 开发的的热键操作 很值得看的
💻 PAS
字号:
unit hkSend;

interface

uses
  SysUtils,
  Messages,
  Forms,
  Windows,
  Classes;

type
  TSendKeyError = (skNone, skFailSetHook, skInvalidToken, skUnknownError);

function SendKeys(S: String; Wait: Boolean): TSendKeyError;

implementation

type
  ESendKeyError = class(Exception);
  ESetHookError = class(ESendKeyError);
  EInvalidToken = class(ESendKeyError);

  TKeyDef = record
    Key : String;
    Code: UINT;
  end;

  TMessageList = class(TList)
  public
    destructor Destroy; override;
  end;

const
  MaxKeys = 43;
  ShiftKey = '+';
  ControlKey = '^';
  AltKey = '%';
  EnterKey = '~';

  KeyGroupOpen = '{';
  KeyGroupClose = '}';

  KeyTokens = '{}~%^+';

  KeyDefs : array[1..MaxKeys] of TKeyDef = (
   (Key: 'BACKSPACE'  ; Code: VK_BACK),
   (Key: 'BKSP'       ; Code: VK_BACK),
   (Key: 'BS'         ; Code: VK_BACK),
   (Key: 'CAPS'       ; Code: VK_CAPITAL),
   (Key: 'CAPSLOCK'   ; Code: VK_CAPITAL),
   (KEy: 'CLEAR'      ; Code: VK_CLEAR),
   (Key: 'DEL'        ; Code: VK_DELETE),
   (Key: 'DELETE'     ; Code: VK_DELETE),
   (Key: 'DOWN'       ; Code: VK_DOWN),
   (Key: 'END'        ; Code: VK_END),
   (Key: 'ENTER'      ; Code: VK_RETURN),
   (Key: 'ESC'        ; Code: VK_ESCAPE),
   (Key: 'ESCAPE'     ; Code: VK_ESCAPE),
   (Key: 'HOME'       ; Code: VK_HOME),
   (Key: 'INS'        ; Code: VK_INSERT),
   (Key: 'INSERT'     ; Code: VK_INSERT),
   (Key: 'LEFT'       ; Code: VK_LEFT),
   (Key: 'NUM'        ; Code: VK_NUMLOCK),
   (Key: 'NUMLOCK'    ; Code: VK_NUMLOCK),
   (Key: 'DOWN'       ; Code: VK_DOWN),
   (Key: 'PAGEDOWN'   ; Code: VK_NEXT),
   (Key: 'PGDN'       ; Code: VK_NEXT),
   (Key: 'PAGEUP'     ; Code: VK_PRIOR),
   (Key: 'PGUP'       ; Code: VK_PRIOR),
   (Key: 'RIGHT'      ; Code: VK_RIGHT),
   (Key: 'SCROLL'     ; Code: VK_SCROLL),
   (Key: 'SCROLLLOCK' ; Code: VK_SCROLL),
   (Key: 'PRINTSCREEN'; Code: VK_SNAPSHOT),
   (Key: 'PRTSC'      ; Code: VK_SNAPSHOT),
   (Key: 'TAB'        ; Code: VK_TAB),
   (Key: 'UP'         ; Code: VK_UP),
   (Key: 'F1'         ; Code: VK_F1),
   (Key: 'F2'         ; Code: VK_F2),
   (Key: 'F3'         ; Code: VK_F3),
   (Key: 'F4'         ; Code: VK_F4),
   (Key: 'F5'         ; Code: VK_F5),
   (Key: 'F6'         ; Code: VK_F6),
   (Key: 'F7'         ; Code: VK_F7),
   (Key: 'F8'         ; Code: VK_F8),
   (Key: 'F9'         ; Code: VK_F9),
   (Key: 'F10'        ; Code: VK_F10),
   (Key: 'F11'        ; Code: VK_F11),
   (Key: 'F12'        ; Code: VK_F12));

var
  bPlaying,
  bAltPressed,
  bControlPressed,
  bShiftPressed    : Boolean;
  Delay, CurDelay  : Integer;
  Event            : TEventMsg;
  MessageList      : TMessageList;
  iMsgCount        : Integer;
  HookHandle       : hHook;

destructor TMessageList.Destroy;
var
  i : Integer;
begin
  for i:=0 to Count-1 do
   Dispose(PEventMsg(Items[i]));
  inherited;
end;

procedure StopPlayback;
begin
  if bPlaying then UnhookWindowsHookEx(HookHandle);
  MessageList.Free;
  bPlaying := False;
end;

function Playback(nCode: Integer; wp: wParam; lp: lParam): Longint; stdcall; export;
begin
  Result := 0;
  case nCode of
    HC_SKIP:
     begin
       inc(iMsgCount);
       if iMsgCount>=MessageList.Count then
        StopPlayback
       else
        begin
          Event := TEventMsg(MessageList.Items[iMsgCount]^);
          CurDelay := Delay;
        end;
     end;
    HC_GETNEXT:
     begin
       with PEventMsg(lp)^ do
        begin
          Message := Event.Message;
          ParamL  := Event.ParamL;
          ParamH  := Event.ParamH;
          Time    := Event.Time;
          hWnd    := Event.hWnd;
        end;
        Result := CurDelay;
        CurDelay := 0;
     end;
    else
     begin
       Result := CallNextHookEx(HookHandle, nCode, wp, lp);
     end;
  end;
end;

procedure StartPlayback;
begin
  Event := TEventMsg(MessageList.Items[0]^);
  iMsgCount := 0;
  HookHandle := SetWindowsHookEx(WH_JOURNALPLAYBACK, @Playback, hInstance, 0);
  if HookHandle=0 then
   raise ESetHookError.Create('Could not set hook')
  else
   bPlaying := True;
end;

procedure MakeMessage(vKey, M: UINT);
var
  E: PEventMsg;
begin
  New(E);
  with E^ do
   begin
     Message := M;
     ParamL  := vKey;
     ParamH  := MapVirtualKey(vKey, 0);
     Time    := GetTickCount;
     hWnd    := 0;
   end;
  MessageList.Add(E);
end;

function FindKeyInArray(Key: String; var Code: UINT): Boolean;
var
  i : Integer;
begin
  Result := False;
  for i:=Low(KeyDefs) to High(KeyDefs) do
   if UpperCase(Key)=KeyDefs[i].Key then
    begin
      Code := KeyDefs[i].Code;
      Result := True;
      Exit;
    end;
end;

const
  vkKeySet = [VK_SPACE, Ord('A')..Ord('Z'), VK_MENU, VK_F1..VK_F12];

procedure SimulateKey(Code: UINT; Down: Boolean);
const
  KeyMsg: array[Boolean] of UINT = (WM_KEYUP, WM_KEYDOWN);
  SysMsg: array[Boolean] of UINT = (WM_SYSKEYUP, WM_SYSKEYDOWN);
begin
  if bAltPressed and (not bControlPressed) and (Code in vkKeySet) then
   MakeMessage(Code, SysMsg[Down])
  else
   MakeMessage(Code, KeyMsg[Down])
end;

procedure SimulateKeyPress(Code: UINT);
begin
  if bAltPressed then SimulateKey(VK_MENU, True);
  if bControlPressed then SimulateKey(VK_CONTROL, True);
  if bShiftPressed and not bControlPressed then SimulateKey(VK_SHIFT, True);
  SimulateKey(Code, True);
  SimulateKey(Code, False);
  if bShiftPressed and not bControlPressed then
   begin
     SimulateKey(VK_SHIFT, False);
     bShiftPressed := False;
   end;
  if bControlPressed then
   begin
     SimulateKey(VK_CONTROL, False);
     bControlPressed := False;
   end;
  if bAltPressed then
   begin
     SimulateKey(VK_MENU, False);
     bAltPressed := False;
   end;
end;

procedure NormalKeyPress(C: Char);
var
  KeyCode,
  Shift  : UINT;
begin
  KeyCode := vkKeyScan(C);
  Shift := HiByte(KeyCode);
  if (Shift and 1)=1 then bShiftPressed := True;
  if (Shift and 2)=2 then bControlPressed := True;
  if (Shift and 4)=4 then bAltPressed := True;
  SimulateKeyPress(LoByte(KeyCode))
end;

function CheckDelay(Token: String): Boolean;
begin
  Token := UpperCase(Token);
  Result := Pos('DELAY', Token)=1;
  if Result then
   begin
     Delete(Token, 1, 5);
     if (Length(Token)>0) and (Token[1]='=') then Delete(Token, 1, 1);
     Delay := StrToIntDef(Token, 0);
   end;
end;

procedure ProcessKey(S: String);
var
  Index  : Integer;
  Token  : String;
  KeyCode: UINT;
begin
  Index := 1;
  repeat
    case S[Index] of
      KeyGroupOpen:
       begin
         Token := '';
         inc(Index);
         while (Index<Length(S)) and (S[Index]<>KeyGroupClose) do
          begin
            Token := Token + S[Index];
            inc(Index);
            if (Length(Token)=12) and (S[Index]<>KeyGroupClose) then
             raise EInvalidToken.Create('No closing brace')
          end;
         if (Length(Token)=1) and (Pos(Token, KeyTokens)>0) then
          NormalKeyPress(Token[1])
         else if FindKeyInArray(Token, KeyCode) then
          SimulateKeyPress(KeyCode)
         else if not CheckDelay(Token) then
          raise EInvalidToken.Create('Invalid token');
       end;
      AltKey:
       bAltPressed := True;
      ControlKey:
       bControlPressed := True;
      ShiftKey:
       bShiftPressed := True;
      EnterKey:
       SimulateKeyPress(VK_RETURN);
      else
       NormalKeyPress(S[Index]);
    end;
    inc(Index);
  until Index > Length(S);
end;

function SendKeys(S: String; Wait: Boolean): TSendKeyError;
begin
  bAltPressed := False;
  bControlPressed := False;
  bShiftPressed := False;
  Result := skNone;
  Delay := 0;
  if bPlaying or (S='') then Exit;
  try
    MessageList := TMessageList.Create;
    ProcessKey(S);
    StartPlayback;
    if Wait then
     repeat
       Application.ProcessMessages;
     until bPlaying = False;
  except
   on E:ESendKeyError do
    begin
      MessageList.Free;
      if E is ESetHookError then
       Result := skFailSetHook
      else if E is EInvalidToken then
       Result := skInvalidToken;
    end
   else
    Result := skUnknownError;
  end;
end;

exports
   Playback;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -