Solved

Keyboard grabber in other applications

Posted on 1998-03-07
3
280 Views
Last Modified: 2010-05-18
How can I trap keys pressed in others applications and write to a file?
0
Comment
Question by:narabe
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
3 Comments
 
LVL 5

Expert Comment

by:ronit051397
ID: 1360247
I think it has something to do with Hooking.
0
 
LVL 4

Accepted Solution

by:
d003303 earned 100 total points
ID: 1360248
Yo,

like ronit said, you have to use hooks. Here is a sample code that traps all characters that are generated from the keyboard (systemwide).
The first listing is a DLL source (hook procedures have to resist in a DLL), the second is a sample application that displays all chars in a TMemo. You can easily change it to write to a file.
I have commented nearly everything, so you should understand what the whole thing is doing.

///////////////////////////////
// hook library

// to be hooktest.dpr
library hooktest;

uses
  Windows,
  Messages;

// because the DLL is mapped in each process space the hook event originates,
// it is instanciated for each such process. All global variables for all
// instances are independent. So we cannot init the DLL and set parameters on
// runtime to communicate with the host application. Therefore we use constants.
//
// MainAppClassName is used by the hook procedure to send the catched char to
// the host application. MainAppClassName is equivalent to the class name of
// the TWinControl descendant instance that carries the message handler.
//
// MainAppMessageNumber defines the message number that is sent to the host
// application. It should be wm_User + n. MainAppMessageID is just to make
// sure the message is sent from the hook procedure, because wm_User + n
// can be used by anyone. Can be any value you like.
//
// If you change any of these values, DO NOT FORGET to change them also in
// the host application !!!

const
  MainAppClassName     = 'TSpyKeyHookWnd';
  MainAppMessageNumber = wm_User + 1;
  MainAppMessageID     = 123;

// these variables have to be in the DLL
// because the keyboard state depends on
// the process space. The DLL is mapped
//
// originates.
// For performance reasons, this variables
// are global.

var
  KeyState : TKeyboardState;
  CharCode : LPARAM;

function KeyHookProc(nCode: integer; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
begin
  // we shall to this refering to the Win32API documentation
  if(nCode < 0) then
   begin
     Result := CallNextHookEx(0, nCode, wp, lp);
   end
  else
   // here we go
   begin
     // we only react on a global KEYDOWN event, check bit 32 in lParam
     // otherwise a message will be sent when a key is pressed and
     // a second time when the key is released
     if (lp and (1 shl 31)) = 0 then
      begin
        // clean old value
        CharCode := 0;
        // get keyboard state (shift, shift lock, etc.)
        GetKeyboardState(KeyState);
        // if this function returns 0, no character is translated
        // e.g. when ALT or SHIFT is pressed. We only accept non-dead keys.
        // if 2 is returned, we have a multibyte system. I will not
        // support it here.
        if ToASCII(wp, HiWord(lp), KeyState, @CharCode, 0) = 1
         // send a message containing the translated char in lParam.
         // see the comment on top of the project for a description
         // on this function
         then PostMessage(FindWindow(MainAppClassName, nil), MainAppMessageNumber, MainAppMessageID, CharCode);
      end;
     // we shall to this refering to the Win32API documentation
     Result := CallNextHookEx(0, nCode, wp, lp);
   end;
end;

exports
  KeyHookProc;

begin
end.

///////////////////////////////
// demo application

// to be hookexe.dpr
program hookexe;

uses
  Forms,
  _hookexe in '_hookexe.pas' {SpyKeyHookWnd};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TSpyKeyHookWnd, SpyKeyHookWnd);
  Application.Run;
end.

// to be _hookexe.pas
unit _hookexe;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdCtrls;

// KeyHookDllName is the name of the DLL containing the hook procedure.
// Equivalent to the DLLs project name.
//
// KeyHookProc is the name of the hook procedure in the DLL.
//
// MainAppMessageNumber and MainAppMessageID -> See DLL source code.

const
  KeyHookDllName       = 'hooktest.dll';
  HookProcName         = 'KeyHookProc';
  MainAppMessageNumber = wm_User + 1;
  MainAppMessageID     = 123;

type
  TSpyKeyHookWnd = class(TForm)
    StatusBar1: TStatusBar;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    LibHandle,
    HHookProc : THandle;
    HookProc  : function(nCode: integer; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
    // this is the handler for the MainAppMessageNumber message
    procedure WMUser_KeyPressedGlobal(var Message : TMessage); message MainAppMessageNumber;
  public
    { Public declarations }
  end;

var
  SpyKeyHookWnd: TSpyKeyHookWnd;

implementation

{$R *.DFM}

procedure TSpyKeyHookWnd.WMUser_KeyPressedGlobal(var Message : TMessage);
var KeyBuf : array[0..1] of Char;
begin
  // check if message is sent from DLL
  if Message.wParam = MainAppMessageID then
   begin
     // clean structure
     FillChar(KeyBuf[0], 2, 0);
     // translate character from lParam
     KeyBuf[0] := Chr(LoByte(LoWord(Message.lParam)));
     // put it into the memo
     Memo1.SetSelTextBuf(KeyBuf);
   end;
end;

procedure TSpyKeyHookWnd.FormCreate(Sender: TObject);
var DllName : string;
begin
  // get full qualified path to the DLL, assuming it is in the
  // same directory as the host application
  DllName := ExtractFilePath(Application.ExeName) + KeyHookDllName;
  // load DLL
  LibHandle := LoadLibrary(PChar(DllName));
  if LibHandle <> 0 then
   begin
     // find hook procedure address
     @HookProc := GetProcAddress(LibHandle, HookProcName);
     if @HookProc <> nil
      // insert the hook procedure into the systems hook chain
      then HHookProc := SetWindowsHookEx(WH_KEYBOARD, HookProc, LibHandle, 0)
      else Application.MessageBox('Failed to get HookProc address', 'Error', mb_ok);
   end
  else Application.MessageBox('Failed to load DLL', 'Error', mb_ok);
end;

procedure TSpyKeyHookWnd.FormDestroy(Sender: TObject);
begin
  if LibHandle <> 0 then
   begin
     if HHookProc <> 0
      // remove the hook procedure from the systems hook chain
      then UnhookWindowsHookEx(HHookProc);
     // unload DLL
     FreeLibrary(LibHandle);
   end;
end;

end.

// to be hookexe.dfm
object SpyKeyHookWnd: TSpyKeyHookWnd
  Left = 208
  Top = 113
  Width = 325
  Height = 195
  Caption = 'Systemwide Keystrokes - here they are'
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Memo1: TMemo
    Left = 0
    Top = 0
    Width = 317
    Height = 168
    Align = alClient
    ReadOnly = True
    TabOrder = 0
  end
end

///////////////////////

Have fun,
Slash/d003303
0
 
LVL 7

Expert Comment

by:ahalya
ID: 1360249
Slash/d003303,

Beautiful !

0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
DBGrid or StringGrid ? 6 135
Wincontrol not (correctly) drawn 15 58
Problem working with dynamic array - help 2 48
Way to create an iPhone app for my customers 8 89
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…

734 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question