I am trying to develop a software which will take a keyboard input, consume the input and return some other character inexchange of the typed input. For example, if i type: "abcd" and define exchange rule as any russian alphabet then i would expect output开发者_JS百科 as: "ский".
The code I am using is as follows:
namespace hook_form
{
public partial class Form1 : Form
{
//Keyboard API constants
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SYSKEYUP = 0x0105;
private const int WM_SYSKEYDOWN = 0x0104;
private HookHandlerDelegate proc;
private IntPtr hookID = IntPtr.Zero;
private delegate IntPtr HookHandlerDelegate(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
private struct KBDLLHOOKSTRUCT
{
public int vkCode;
int scanCode;
public int flags;
int time;
int dwExtraInfo;
}
private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
{
bool AllowKey = false;
switch (lParam.vkCode)
{
case (65|97|66|98): // key codes for "a/b/c/d" etc. goes here
//Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key
AllowKey = true;
SendKeys.Send("\u0997"); // code for russian letters here....
break;
}
MessageBox.Show(lParam.vkCode.ToString());
if (AllowKey == false)
return (System.IntPtr)1;
return CallNextHookEx(hookID, nCode, wParam, ref lParam);
}
#region DllImports
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
HookHandlerDelegate lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
private void buttonStart_Click(object sender, EventArgs e)
{
proc = new HookHandlerDelegate(HookCallback);
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
hookID = SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private void btnEnd_Click(object sender, EventArgs e)
{
UnhookWindowsHookEx(hookID);
}
}
}
I get output as: "aсbкcиdй", i mean typed letters (english) are not consumed by the code(i mean they should not appear in output) even though i returned (System.IntPtr)1
.
I think it is a problem of unhooking. Can anyone help me to solve this problem ?
If not possible, then can anyone refer me any open source software which uses keyboard hook?
Try not calling CallNextHookEx
for events that you want to swallow.
Edit: So one problem that I see is that a key press generates two messages WM_KEYDOWN and WM_KEYUP. You are injecting the new keyboard message for both cases, duplicating it. The example at Tim Barrass' link show how to do this better. This does not fully explain the behavior that you are seeing, though.
How about sending a backspace key press before sending the new character that you want?
AllowKey = true;
SendKeys.Send("{BS}");
SendKeys.Send("\u0997"); // code for russian letters here....
break;
精彩评论