Solved

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

Posted on 2008-06-11
12
944 Views
Last Modified: 2013-11-20
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
Comment
Question by:UdiRaz
  • 6
  • 6
12 Comments
 
LVL 19

Expert Comment

by:alb66
ID: 21766804
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
 

Author Comment

by:UdiRaz
ID: 21773032
Thanks for your response, but the code you suggested doesn't work. Only y is typed.
0
 
LVL 19

Expert Comment

by:alb66
ID: 21776808
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
 

Author Comment

by:UdiRaz
ID: 21787941
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
 
LVL 19

Expert Comment

by:alb66
ID: 21791289
Isn't there a Hindi keyboard?
0
 

Author Comment

by:UdiRaz
ID: 21791339
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 19

Expert Comment

by:alb66
ID: 21791394
0
 

Author Comment

by:UdiRaz
ID: 21791910
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
 
LVL 19

Accepted Solution

by:
alb66 earned 500 total points
ID: 21792482
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
 

Author Comment

by:UdiRaz
ID: 21792517
what is "the key repeat" ?
0
 
LVL 19

Expert Comment

by:alb66
ID: 21792694
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
 

Author Closing Comment

by:UdiRaz
ID: 31466249
thanks a lot !!!
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
no14 challenge 14 56
twoTwo  challenge 35 86
How to split this in C++ 4 76
Need some help with Microsoft Visual Studio C++ 2003 5 37
When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

707 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

11 Experts available now in Live!

Get 1:1 Help Now