Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 989
  • Last Modified:

How to simulate two WM_CHAR upon a button key when hooking those messages?

Hi,
I have a hook dll ( code snippet below ). I would like to generate to characters upon a press of a single button. This sample tries to generate 'x' and 'y' upon pressing 'z'. For some reason, only the second char is typed.

Thanks
Udi Raz
// HookDll.cpp
//
// This is the DLL which sets a hook which
//      substitutes the letter 'y' when the user types
//      the letter 'x'
//
 
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
 
HINSTANCE   hMod;
HHOOK       hHook;
bool        g_ignoreChar;
 
BOOL APIENTRY DllMain(  HANDLE hModule, 
                        DWORD  ul_reason_for_call, 
                        LPVOID lpReserved)
{
    hMod	= (HINSTANCE) hModule;
    g_ignoreChar = false;
    return TRUE;
}
 
#ifdef __cplusplus
extern "C" {
#endif
 
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
	LRESULT ret = 0;
 
	if (code == HC_ACTION)
	{
		MSG * pMsg = (MSG *) lParam;
 
		switch( pMsg->message )
		{
		case WM_KEYDOWN:
			if (pMsg->wParam == 'Z')
			{
				g_ignoreChar = true;
				pMsg->wParam  = 'x';
				pMsg->message = WM_CHAR;
				CallNextHookEx(hHook, code, wParam, lParam);
				pMsg->wParam  = 'y';
				return CallNextHookEx(hHook, code, wParam, lParam);
										}
			break;
		case WM_KEYUP:
			if (pMsg->wParam == 'Z')
				return 0;
			else
				break;
		case WM_CHAR:
			if ( g_ignoreChar == true)
			{
				g_ignoreChar = false;
				return 0;
			}
			else
				break;
		}
	}
 
	return(CallNextHookEx(hHook, code, wParam, lParam));
}
 
__declspec(dllexport) BOOL SetHook(DWORD threadId)
{
    hHook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, hMod, threadId);
 
    return(hHook ? TRUE : FALSE);
}
 
__declspec(dllexport) void ClearHook(void)
{
    if (hHook)
    {
        UnhookWindowsHookEx(hHook);
        hHook = 0;
    }
}
 
#ifdef __cplusplus
}
#endif

Open in new window

0
UdiRaz
Asked:
UdiRaz
  • 6
  • 6
1 Solution
 
alb66Commented:
Try to handle it int the WM_CHAR case:

                case WM_CHAR:
                        if (pMsg->wParam == 'Z')
                        {
                                pMsg->wParam  = 'x';
                                CallNextHookEx(hHook, code, wParam, lParam);
                                pMsg->wParam  = 'y';
                                return CallNextHookEx(hHook, code, wParam, lParam);
0
 
UdiRazAuthor Commented:
Thanks for your response, but the code you suggested doesn't work. Only y is typed.
0
 
alb66Commented:
It seems to me that your strategy is wrong.
Calling CallNextHookEx doesn't produce any effect, unless there is another hook in the hook chain.
You simply modify the message two times and, of course, the second modify (y) win.

I think that you should create a second message.
Try the following.
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
	LRESULT ret = 0;
 
	if (code == HC_ACTION)
	{
		MSG * pMsg = (MSG *) lParam;
 
		switch( pMsg->message )
		{
		case WM_CHAR:
			if ( pMsg->wParam == 'Z' )
			{
				pMsg->wParam  = 'x';
				CallNextHookEx(hHook, code, wParam, lParam);
 
				if ( wParam == 0 )
					::PostMessage( pMsg->hwnd, WM_CHAR, 'y', pMsg->lParam );				
				
				return TRUE;
			}
			break;
		}
	}
 
	return(CallNextHookEx(hHook, code, wParam, lParam));
}

Open in new window

0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
UdiRazAuthor Commented:
alb66 : thanks for your help, But I still have some problems:
1. your example works well on word document. On notepad, I had to remove the line if ( wParam == 0 )

2. I have to explain my motivation is this feature : In real life, I am replacing Hindi characters. Unfortunatly, Unlike english ,there are some hindi letters that are made of more then one character. What I do to replace the original key stroke with the characters I want is to hook the WM_KEYDOWN, simulate some WM_CHAR messages and don't pass the next WM_CHAR and WM_KEYUP. So I tried to modify your example to type x and y upon WM_KEYDOWN of 'Z'. The code snippet below works on notepad, doesn't work on word
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
	LRESULT ret = 0;
 
	if (code == HC_ACTION)
	{
		MSG * pMsg = (MSG *) lParam;
 
		switch( pMsg->message )
		{
		case WM_KEYDOWN:
			if (pMsg->wParam == 'Z')
			{
				g_ignoreChar = true;
				::SendMessage( pMsg->hwnd, WM_CHAR, 'y', pMsg->lParam );
				pMsg->wParam  = 'x';
				pMsg->message = WM_CHAR;
			}
			break;
		case WM_KEYUP:
			if (pMsg->wParam == 'Z')
				return 0;
			else
				break;
		case WM_CHAR:
			if ( g_ignoreChar == true)
			{
				g_ignoreChar = false;
				return 0;
			}
			else
				break;
		}
	}
 
	return(CallNextHookEx(hHook, code, wParam, lParam));
}

Open in new window

0
 
alb66Commented:
Isn't there a Hindi keyboard?
0
 
UdiRazAuthor Commented:
There is a hindi keyboard layout. You can add hindi like any other language. The thing is that there are several layouts for hindi and microsoft supports only one. Our clients would like a different layout and that is why I am trying to simulate it.

It is working well when I am subclassing a window withing my application.
It is working well when I am subcalssing other process windows using a hook dll with WH_CALLWNDPROC hook to hook WM_SETFOCUS of a window and then SetWindowLong(hEdit, GWL_WNDPROC, (LONG) pOldWndProc) to subclass the window

It is not working on word document and this is a problem for me.
It is working on word document also when I hook GETMESSAGE and catch WM_KEYDOWN, WM_KEYUP and WM_CHAR but only for replacing a single character.

I must make it work on word and the only problem I have simplified to how send two WM_CHAR messages upon a single WM_KEYDOWN message. Word ignore the PostMessage.

Thanks
0
 
alb66Commented:
0
 
UdiRazAuthor Commented:
I can't create a custom layout since win32 apis such as SetThreadLocale, LoadKeyboardLayout, ActivateKeyboardLayout does not work with the locale id that the new layout. Funny thing is that GetKeyboardLayout does return a new HKL.

Anyway, I will still have to stragle the windows messages and inject my own characters.
Can you please try to send two ( english ) character upon a single WM_KEYDOWN ?

Thanks in advance
0
 
alb66Commented:
The code attached works well in Word, notepad, VS and a sample MFC application.

It doesn't manage the key repeat. If you comment the bEnabled test it also manage the repeat , but it doesn't works in word (word receive 5 WM_CHAR message every WM_KEYDOWN  !?!?!? - very strange - !?!?!? ).

Anyway, in my opinion, a custom keyboard layout is the best solution. Modifying messages via a global hook is a very intrusive programming tecnique, and I don't exclude that you may encounter some other drawbacks.
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
	static bool bEnabled = true;
 
	if (code == HC_ACTION)
	{
		MSG * pMsg = (MSG *) lParam;
 
		switch( pMsg->message )
		{
		case WM_KEYDOWN:
			if (pMsg->wParam == 'Z')
			{
				pMsg->message = WM_NULL;
				
				if (( pMsg->lParam & 0xFFFF ) == 1 && bEnabled )
				{
					::PostMessage( pMsg->hwnd, WM_CHAR, 'x', pMsg->lParam );
					::PostMessage( pMsg->hwnd, WM_CHAR, 'y', pMsg->lParam );
 
					bEnabled = false;
				}
			}
			break;
 
		case WM_KEYUP:
			if (pMsg->wParam == 'Z')
			{
				bEnabled = true;
 
				pMsg->message = WM_NULL;
			}
		}
	}
 
	return(CallNextHookEx(hHook, code, wParam, lParam));
}

Open in new window

0
 
UdiRazAuthor Commented:
what is "the key repeat" ?
0
 
alb66Commented:
Usually when you press a key, the character is automatically repeated until you release the key. In my solution the charater is written only one time; I do that because of the Word strange behavior.
0
 
UdiRazAuthor Commented:
thanks a lot !!!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

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.

  • 6
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now