Hello there. I'm new here and I want to ask help to you on solving this problem. I'm trying to detect which character is produced whenever the user presses a key. For this, I'm using the ToUnicodeEx function, which translates the specified virtual-key code and keyboard state to the corresponding Unicode character, inside a keyboard system wide hook. However, every time the user presses dead keys, such as the ones producing '¨', '~' or '´', strange things happen. Here is sample code of the first version:

Code:
private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
	//indicates if any of underlaing events set e.Handled flag
	bool handled = false;

	if (nCode >= 0)
	{
		//read structure KeyboardHookStruct at lParam
		KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
		//raise KeyDown
		if (s_KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
		{
			Keys keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
			KeyEventArgs e = new KeyEventArgs(keyData);
			s_KeyDown.Invoke(null, e);
			handled = e.Handled;
		}

		// raise KeyPress
		if (s_KeyPress != null && wParam == WM_KEYDOWN)
		{
			bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
			bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

			byte[] keyState = new byte[256];
			GetKeyboardState(keyState);
			System.Text.StringBuilder sbString = new System.Text.StringBuilder();
			IntPtr HKL = GetKeyboardLayout(0);

			switch (ToUnicodeEx((uint)MyKeyboardHookStruct.VirtualKeyCode,
				(uint)MyKeyboardHookStruct.ScanCode,
				keyState,
				sbString,
				5,
				(uint)MyKeyboardHookStruct.Flags,
				HKL))
			{
				case 1:
					char key = sbString.ToString()[0];
					if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
					KeyPressEventArgs e = new KeyPressEventArgs(key);
					s_KeyPress.Invoke(null, e);
					handled = handled || e.Handled;
					break;
			}
		}

		// raise KeyUp
		if (s_KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
		{
			Keys keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
			KeyEventArgs e = new KeyEventArgs(keyData);
			s_KeyUp.Invoke(null, e);
			handled = handled || e.Handled;
		}

	}

	//if event handled in application do not handoff to other listeners
	if (handled)
		return -1;

	//forward to other application
	return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam);
}
(I know the sample code I'm posting is C#, but it is really easy to read and the question here is about the ToUnicodeEx WinAPI call.)

With this code I faced the following problem: Whenever I tried to type "á" in notepad, which requires '´' to be pressed before 'a', the result would be "´´a". Although the captured character by ToUnicodeEx was 'á', I can't admit that my application prevents the user from using characters such as 'á'.

So, I worked around this problem by avoiding ToUnicodeEx to be called whenever a dead key is pressed. This way, I can avoid the ToUnicodeEx function from messing with the keyboard state. Here is the current version code:

Code:
private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
	//indicates if any of underlaing events set e.Handled flag
	bool handled = false;

	if (nCode >= 0)
	{
		//read structure KeyboardHookStruct at lParam
		KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
		//raise KeyDown
		if (s_KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
		{
			Keys keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
			KeyEventArgs e = new KeyEventArgs(keyData);
			s_KeyDown.Invoke(null, e);
			handled = e.Handled;
		}

		// raise KeyPress
		if (s_KeyPress != null && wParam == WM_KEYDOWN)
		{
			bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
			bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

			byte[] keyState = new byte[256];
			GetKeyboardState(keyState);
			System.Text.StringBuilder sbString = new System.Text.StringBuilder();
			IntPtr HKL = GetKeyboardLayout(0);

			if (!IsDeadKey((uint)MyKeyboardHookStruct.VirtualKeyCode))
			{
				switch (ToUnicodeEx((uint)MyKeyboardHookStruct.VirtualKeyCode,
					(uint)MyKeyboardHookStruct.ScanCode,
					keyState,
					sbString,
					5,
					(uint)MyKeyboardHookStruct.Flags,
					HKL))
				{
					case 1:
						char key = sbString.ToString()[0];
						if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
						KeyPressEventArgs e = new KeyPressEventArgs(key);
						s_KeyPress.Invoke(null, e);
						handled = handled || e.Handled;
						break;
				}
			}
		}

		// raise KeyUp
		if (s_KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
		{
			Keys keyData = (Keys)MyKeyboardHookStruct.VirtualKeyCode;
			KeyEventArgs e = new KeyEventArgs(keyData);
			s_KeyUp.Invoke(null, e);
			handled = handled || e.Handled;
		}

	}

	//if event handled in application do not handoff to other listeners
	if (handled)
		return -1;

	//forward to other application
	return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam);
}

static bool IsDeadKey(uint key)
{
	if ((MapVirtualKey(key, 2) & 2147483648) == 2147483648)
	{
		return true;
	}
	else
	{
		return false;
	}
}
I though this solution would solve my problem, but I was wrong. The result has improved, but it's not quite what I wanted. Now, typing 'á' in notepad results in 'a'. Notice that the accent '´' is missing.

Does anyone know how to work around this issue? My current method already captures the correct character, but prevents the user from producing characters with accents or diacritics. I think the KeyboardHookProc method just need a few changes, but I can't figure them out.

Thanks in advance.

PS: I tried the solution described in the following link: http://social.msdn.microsoft.com/For...1-33c7ccea735c. However, the result is quite the same as in my current version. That code only erases the keyboard buffer, which deletes the accents, therefore not allowing the user to use them.