home *** CD-ROM | disk | FTP | other *** search
/ BUG 15 / BUGCD1998_06.ISO / desktop / hotkey / hotkey95.exe / Source / hkSend.pas < prev    next >
Pascal/Delphi Source File  |  1998-02-13  |  7KB  |  300 lines

  1. unit hkSend;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils,
  7.   Messages,
  8.   Windows,
  9.   Classes;
  10.  
  11. type
  12.   TSendKeyError = (skNone, skFailSetHook, skInvalidToken, skUnknownError);
  13.  
  14. function SendKeys(S: String): TSendKeyError;
  15.  
  16. implementation
  17.  
  18. type
  19.   ESendKeyError = class(Exception);
  20.   ESetHookError = class(ESendKeyError);
  21.   EInvalidToken = class(ESendKeyError);
  22.  
  23.   TKeyDef = record
  24.     Key : String;
  25.     Code: UINT;
  26.   end;
  27.  
  28.   TMessageList = class(TList)
  29.   public
  30.     destructor Destroy; override;
  31.   end;
  32.  
  33. const
  34.   MaxKeys = 41;
  35.   ShiftKey = '+';
  36.   ControlKey = '^';
  37.   AltKey = '%';
  38.   EnterKey = '~';
  39.   KeyGroupOpen = '{';
  40.   KeyGroupClose = '}';
  41.  
  42.   KeyDefs : array[1..MaxKeys] of TKeyDef = (
  43.    (Key: 'BACKSPACE' ; Code: VK_BACK),
  44.    (Key: 'BKSP'      ; Code: VK_BACK),
  45.    (Key: 'BS'        ; Code: VK_BACK),
  46.    (Key: 'CAPS'      ; Code: VK_CAPITAL),
  47.    (Key: 'CAPSLOCK'  ; Code: VK_CAPITAL),
  48.    (KEy: 'CLEAR'     ; Code: VK_CLEAR),
  49.    (Key: 'DEL'       ; Code: VK_DELETE),
  50.    (Key: 'DELETE'    ; Code: VK_DELETE),
  51.    (Key: 'DOWN'      ; Code: VK_DOWN),
  52.    (Key: 'END'       ; Code: VK_END),
  53.    (Key: 'ENTER'     ; Code: VK_RETURN),
  54.    (Key: 'ESC'       ; Code: VK_ESCAPE),
  55.    (Key: 'ESCAPE'    ; Code: VK_ESCAPE),
  56.    (Key: 'HOME'      ; Code: VK_HOME),
  57.    (Key: 'INS'       ; Code: VK_INSERT),
  58.    (Key: 'INSERT'    ; Code: VK_INSERT),
  59.    (Key: 'LEFT'      ; Code: VK_LEFT),
  60.    (Key: 'NUM'       ; Code: VK_NUMLOCK),
  61.    (Key: 'NUMLOCK'   ; Code: VK_NUMLOCK),
  62.    (Key: 'DOWN'      ; Code: VK_DOWN),
  63.    (Key: 'PAGEDOWN'  ; Code: VK_NEXT),
  64.    (Key: 'PGDN'      ; Code: VK_NEXT),
  65.    (Key: 'PAGEUP'    ; Code: VK_PRIOR),
  66.    (Key: 'PGUP'      ; Code: VK_PRIOR),
  67.    (Key: 'RIGHT'     ; Code: VK_RIGHT),
  68.    (Key: 'SCROLL'    ; Code: VK_SCROLL),
  69.    (Key: 'SCROLLLOCK'; Code: VK_SCROLL),
  70.    (Key: 'TAB'       ; Code: VK_TAB),
  71.    (Key: 'UP'        ; Code: VK_UP),
  72.    (Key: 'F1'        ; Code: VK_F1),
  73.    (Key: 'F2'        ; Code: VK_F2),
  74.    (Key: 'F3'        ; Code: VK_F3),
  75.    (Key: 'F4'        ; Code: VK_F4),
  76.    (Key: 'F5'        ; Code: VK_F5),
  77.    (Key: 'F6'        ; Code: VK_F6),
  78.    (Key: 'F7'        ; Code: VK_F7),
  79.    (Key: 'F8'        ; Code: VK_F8),
  80.    (Key: 'F9'        ; Code: VK_F9),
  81.    (Key: 'F10'       ; Code: VK_F10),
  82.    (Key: 'F11'       ; Code: VK_F11),
  83.    (Key: 'F12'       ; Code: VK_F12));
  84.  
  85. var
  86.   bPlaying,
  87.   bAltPressed,
  88.   bControlPressed,
  89.   bShiftPressed    : Boolean;
  90.   Event            : TEventMsg;
  91.   MessageList      : TMessageList;
  92.   iMsgCount        : Integer;
  93.   HookHandle       : hHook;
  94.  
  95. destructor TMessageList.Destroy;
  96. var
  97.   i : Integer;
  98. begin
  99.   for i:=0 to Count-1 do
  100.    Dispose(PEventMsg(Items[i]));
  101.   inherited;
  102. end;
  103.  
  104. procedure StopPlayback;
  105. begin
  106.   if bPlaying then UnhookWindowsHookEx(HookHandle);
  107.   MessageList.Free;
  108.   bPlaying := False;
  109. end;
  110.  
  111. function Playback(nCode: Integer; wp: wParam; lp: lParam): Longint; stdcall; export;
  112. begin
  113.   Result := 0;
  114.   case nCode of
  115.     HC_SKIP:
  116.      begin
  117.        inc(iMsgCount);
  118.        if iMsgCount>=MessageList.Count then
  119.         StopPlayback
  120.        else
  121.         Event := TEventMsg(MessageList.Items[iMsgCount]^);
  122.      end;
  123.     HC_GETNEXT:
  124.      begin
  125.        with PEventMsg(lp)^ do
  126.         begin
  127.           Message := Event.Message;
  128.           ParamL  := Event.ParamL;
  129.           ParamH  := Event.ParamH;
  130.           Time    := Event.Time;
  131.           hWnd    := Event.hWnd;
  132.         end;
  133.      end;
  134.     else
  135.      begin
  136.        Result := CallNextHookEx(HookHandle, nCode, wp, lp);
  137.      end;
  138.   end;
  139. end;
  140.  
  141. procedure StartPlayback;
  142. begin
  143.   Event := TEventMsg(MessageList.Items[0]^);
  144.   iMsgCount := 0;
  145.   HookHandle := SetWindowsHookEx(WH_JOURNALPLAYBACK, @Playback, hInstance, 0);
  146.   if HookHandle=0 then
  147.    raise ESetHookError.Create('Could not set hook')
  148.   else
  149.    bPlaying := True;
  150. end;
  151.  
  152. procedure MakeMessage(vKey, M: UINT);
  153. var
  154.   E: PEventMsg;
  155. begin
  156.   New(E);
  157.   with E^ do
  158.    begin
  159.      Message := M;
  160.      ParamL  := vKey;
  161.      ParamH  := MapVirtualKey(ParamL, 0);
  162.      Time    := GetTickCount;
  163.      hWnd    := 0;
  164.    end;
  165.   MessageList.Add(E);
  166. end;
  167.  
  168. function FindKeyInArray(Key: String; var Code: UINT): Boolean;
  169. var
  170.   i : Integer;
  171. begin
  172.   Result := False;
  173.   for i:=Low(KeyDefs) to High(KeyDefs) do
  174.    if UpperCase(Key)=KeyDefs[i].Key then
  175.     begin
  176.       Code := KeyDefs[i].Code;
  177.       Result := True;
  178.       Exit;
  179.     end;
  180. end;
  181.  
  182. procedure SimulateKey(Code: UINT; Down: Boolean);
  183. const
  184.   KeyMsg: array[Boolean] of UINT = (WM_KEYUP, WM_KEYDOWN);
  185.   SysMsg: array[Boolean] of UINT = (WM_SYSKEYUP, WM_SYSKEYDOWN);
  186. begin
  187.   if (bAltPressed and (not bControlPressed) and (Code in [Ord('A')..Ord('Z')])) or (Code=VK_MENU) then
  188.    MakeMessage(Code, SysMsg[Down])
  189.   else
  190.    MakeMessage(Code, KeyMsg[Down])
  191. end;
  192.  
  193. procedure SimulateKeyPress(Code: UINT);
  194. begin
  195.   if bAltPressed then SimulateKey(VK_MENU, True);
  196.   if bControlPressed then SimulateKey(VK_CONTROL, True);
  197.   if bShiftPressed and not bControlPressed then SimulateKey(VK_SHIFT, True);
  198.   SimulateKey(Code, True);
  199.   SimulateKey(Code, False);
  200.   if bShiftPressed and not bControlPressed then
  201.    begin
  202.      SimulateKey(VK_SHIFT, False);
  203.      bShiftPressed := False;
  204.    end;
  205.   if bControlPressed then
  206.    begin
  207.      SimulateKey(VK_CONTROL, False);
  208.      bControlPressed := False;
  209.    end;
  210.   if bAltPressed then
  211.    begin
  212.      SimulateKey(VK_MENU, False);
  213.      bAltPressed := False;
  214.    end;
  215. end;
  216.  
  217. procedure NormalKeyPress(C: Char);
  218. var
  219.   KeyCode,
  220.   Shift  : UINT;
  221. begin
  222.   KeyCode := vkKeyScan(C);
  223.   Shift := HiByte(KeyCode);
  224.   if (Shift and 1)=1 then bShiftPressed := True;
  225.   if (Shift and 2)=2 then bControlPressed := True;
  226.   if (Shift and 4)=4 then bAltPressed := True;
  227.   SimulateKeyPress(LoByte(KeyCode))
  228. end;
  229.  
  230. procedure ProcessKey(S: String);
  231. var
  232.   Index  : Integer;
  233.   Token  : String;
  234.   KeyCode: UINT;
  235. begin
  236.   Index := 1;
  237.   repeat
  238.     case S[Index] of
  239.       KeyGroupOpen:
  240.        begin
  241.          Token := '';
  242.          inc(Index);
  243.          while (Index<Length(S)) and (S[Index]<>KeyGroupClose) do
  244.           begin
  245.             Token := Token + S[Index];
  246.             inc(Index);
  247.             if (Length(Token)=12) and (S[Index]<>KeyGroupClose) then
  248.              raise EInvalidToken.Create('No closing brace')
  249.           end;
  250.          if (Token='{') or (Token='}') then
  251.           NormalKeyPress(Token[1])
  252.          else if not FindKeyInArray(Token, KeyCode) then
  253.           raise EInvalidToken.Create('Invalid token');
  254.          SimulateKeyPress(KeyCode);
  255.        end;
  256.       AltKey:
  257.        bAltPressed := True;
  258.       ControlKey:
  259.        bControlPressed := True;
  260.       ShiftKey:
  261.        bShiftPressed := True;
  262.       EnterKey:
  263.        SimulateKeyPress(VK_RETURN);
  264.       else
  265.        NormalKeyPress(S[Index]);
  266.     end;
  267.     inc(Index);
  268.   until Index > Length(S);
  269. end;
  270.  
  271. function SendKeys(S: String): TSendKeyError;
  272. begin
  273.   bAltPressed := False;
  274.   bControlPressed := False;
  275.   bShiftPressed := False;
  276.   Result := skNone;
  277.   if bPlaying or (S='') then Exit;
  278.   try
  279.     MessageList := TMessageList.Create;
  280.     ProcessKey(S);
  281.     StartPlayback;
  282.   except
  283.    on E:ESendKeyError do
  284.     begin
  285.       MessageList.Free;
  286.       if E is ESetHookError then
  287.        Result := skFailSetHook
  288.       else if E is EInvalidToken then
  289.        Result := skInvalidToken;
  290.     end
  291.    else
  292.     Result := skUnknownError;
  293.   end;
  294. end;
  295.  
  296. exports
  297.    Playback;
  298.  
  299. end.
  300.