Reputation: 503
I'm running into a weird problem. I have a WinForms application that opens another program (billing system emulator), sets it as a child window and then disables it. This works fine, the user cannot send any keys to the that child window, and the winforms application does its thing, sending commands to the child window.
However, it's been discovered that pushing the shift or control, even if the winforms application doesn't have focus, causes an error in the billing system emulator as they aren't valid keys. Users have taken to not using the shift or control keys while the winforms app runs but that's obviously not a practical solution.
My attempted solution was:
OnKeyDown
in the winforms application to stop those keys.That however still doesn't solve the problem of the shift and alt keys being sent to the child window when the winforms app is not in focus. I can stop shift and alt globally while the winforms app is running but I don't think that is valid. So I need to somehow in the global hook stop the keypress
for the winforms app and its children but allow globally. Any ideas/thoughts?
This is my code.
Upvotes: 3
Views: 1512
Reputation: 63317
I took a look at the only constructor of the globalKeyboardHook
and looks like it is designed only for global hook. You can add another overload to hook into the current running module only like this:
class globalKeyboardHook {
[DllImport("kernel32")]
private static extern int GetCurrentThreadId();
[DllImport("user32")]
private static extern IntPtr SetWindowsHookEx(int hookType, KeyBoardProc proc, IntPtr moduleHandle, int threadId);
[DllImport("user32")]
private static extern int CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);
public globalKeyboardHook(bool currentModuleOnly){
if(currentModuleOnly){
proc = KeyBoardCallback;
//WH_KEYBOARD = 0x2
hhook = SetWindowsHookEx(2, proc, IntPtr.Zero, GetCurrentThreadId());
} else hook();
}
public delegate int KeyBoardProc(int nCode, IntPtr wParam, IntPtr lParam);
public int KeyBoardCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0) {
Keys key = (Keys)wParam;
var lp = lParam.ToInt64();
//your own handling with the key
if ((lp >> 31) == 0)//Key down
{
//your own code ...
} else { //Key up
//your own code ...
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
KeyBoardProc proc;
//other code ...
}
//then use the new overload constructor instead of the parameterless constructor:
globalHook = new globalKeyboardHook(true);
NOTE: You can implement your own KeyDown
and KeyUp
event based on what I posted above (the comment your own code ...
). After some searching I understand that the WH_KEYBOARD_LL
supports global hook only while the WH_KEYBOARD
is for thread hook
only. That should be what you want instead of the WH_KEYBOARD_LL
.
BTW, I doubt that the IMessageFilter
which can be registered/added by your application can be used in this case. It also supports a PreFilterMessage
method helping you to intercept any key and mouse messages at the application-level
. You should try searching on that, it's easy to follow.
Upvotes: 0
Reputation: 39122
I don't think there's a good answer for your scenario... =\
Here's a hack you can try. It will "release" Control/Shift if they are down, then you send your message afterwards:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int extraInfo);
[DllImport("user32.dll")]
static extern short MapVirtualKey(int wCode, int wMapType);
private void button1_Click(object sender, EventArgs e)
{
if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
{
keybd_event((int)Keys.ShiftKey, (byte)MapVirtualKey((int)Keys.ShiftKey, 0), 2, 0); // Shift Up
}
if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
{
keybd_event((int)Keys.ControlKey, (byte)MapVirtualKey((int)Keys.ControlKey, 0), 2, 0); // Control Up
}
// ... now try sending your message ...
}
This obviously isn't foolproof.
Upvotes: 2