Solved

Keyboard grabber in other applications

Posted on 1998-03-07
3
274 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
3 Comments
 
LVL 5

Expert Comment

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

Accepted Solution

by:
d003303 earned 100 total points
Comment Utility
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
Comment Utility
Slash/d003303,

Beautiful !

0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This video discusses moving either the default database or any database to a new volume.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

763 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

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now