{I know this topic is kind of secret and nobody would like to get involved too 
much. I just guess if you can solve it you could sell it as well, so this can 
be somewhere on the limit of free information exchange.

Everybody knows that sending wm_char messages is not the proper way of 
simulating keyboard input. I read some old C code written by somebody from MS.
The code is called sendkeys.dll and describes how to send keys.
You need to start with a JournalPlaybackHook and send keyboard events to the 
system. That's ok, but the example was limited to English characters.
But there are characters not mapped on the keyboard so you need to emulate the 
Alt/nnnn sequences too where nnnn is a windows ansi code.

So you send a WM_Syskeydown with alt, then wm_syskeydown and wm_syskeyup pairs 
with the code and a final wm_keyup with alt. And it works perfectly in Notepad 
but not in Winword. You try on and you send some wm_syskeydown-s with alt just 
to get get closer to realyty when the user presses alt for a half of an hour 
before he finds the numpad. And Winword works fine but Wordpad (W95) not. And 
you start to think that you are crasy...

Here I include the code in question. Please tell me what is wrong with it or 
with me. One thing is for sure. I can not get a second level MS Develeoper 
Network membership just to figure it out.

I would be glad to get any pointer, but please don't tell me that I should not 
send wm_char because I may already know.

----------------------------------------------------}
Library SKTest;

Uses Win31,WinTypes,WinProcs,Strings,W_str;


Var
	I : byte;
	Events : Array[0..9,0..1] of TEventMsg;
	AltD,AltU : TEventMsg;
	TheText : Pchar;
	Current : Pchar;
	Phase: Integer;
	TheHook: Hhook;



Function GetNext(E : Peventmsg): Boolean;   {This is to prepare one event}
Begin				    {it gets called by JPBHook}
	Case Phase of
		0..4: E^:= AltD;    {from -16 to 4 send alt down}
		5: E^:= Events[0,0]; {events are prepared with numpad keys}
		6: E^:= Events[0,1]; { we always send four numpad strokes}
		7: E^:= Events[Ord(Current^)div 100,0]; {second digit}
		8: E^:= Events[Ord(Current^)div 100,1];
		9: E^:= Events[(Ord(Current^)div 10)mod 10,0];{third digit}
		10: E^:= Events[(Ord(Current^)div 10)mod 10,1];
		11: E^:= Events[Ord(Current^)mod 10,0];{fourth digit}
		12: E^:= Events[Ord(Current^)mod 10,1];
		13: E^:= AltU; {Alt Up}
	End;
	E^.Time:=GetTickCount;
	Inc(phase); {Next time next keystroke}
	If Phase >13 Then
	Begin
	   Phase:=-16;
           Inc(Current); {Next character}
	End
End;

Function JPBHook(Code : Integer;Wparam :Word;Lparam : Longint):Longint; 
Export; 		{This is the hook I set}
  Procedure UnHook;
    Begin
      UnhookWindowsHookEx(TheHook);
      StrDispose(Thetext);
      Thetext:=nil;
      TheHook:=0;
    End;

Begin
  If Code>=0 Then
  Begin
   JPBHook:=0;
   If TheHook>0 Then
   Case Code of
   HC_SKIP: If Current^=#0 Then UnHook;
   HC_GETNEXT:
     Begin
       GetNext(PeventMsg(Lparam));
       If Current^=#0 Then UnHook; {if it is the end of the string}
       Exit;
     End;
   HC_SYSMODALOFF: Unhook;
   HC_SYSMODALON:;
   End;
  End;
  JPBHook:=CallnextHookEx(TheHook,Code,Wparam,Lparam);
End;

Function SendKeys(S : PChar): Integer; Export;
  Var		{this is to send a string}
    Msg : TMsg;
  Begin
    If TheHook<>0 Then Exit;
    TheText:=StrNew(S);
    Current:=TheText;		{Current is a global ponter to the string}
    Phase:=0;			{phase is an index within sending one char.}
    TheHook:=SetWindowsHookEx(WH_JOURNALPLAYBACK,JPBHook,System.HInstance,0);
    If TheHook=0 Then
    Begin
	StrDispose(Thetext);
	Thetext:=nil;
    End;
    Repeat  {waiting for the hook to finish}
      Yield;
      Until TheHook=0;
    End;

Function InstallJPB: Integer; Export; {this prepares the event array}
Begin
  For i:=0 to 9 Do {numpad numbers}
  Begin
	Events[i,0].Message:=WM_SysKeyDown;
	Events[i,0].paramL:=vk_numpad0+i+$100*MapVirtualkey(vk_numpad0+i,0);
	Events[i,0].ParamH:=1;
	Events[i,1]:=Events[i,0];
	Events[i,1].Message:=WM_SysKeyup;
  End;
  AltD.Message:=WM_SysKeyDown;  {alt down and up}
  AltD.ParamL:=vk_menu+$100*MapVirtualkey(vk_menu,0);
  AltD.ParamH:=1;
  AltU:=AltD;
  AltU.message:=WM_KeyUp;
  Thetext:=nil;
  TheHook:=0;
End;

{author:
http://iap11.ethz.ch/users/szp/szp.htm}
