I need to detect when a user presses Ctrl+V(regardless of window focus - my app will likely be minimised) but I must not stop the actual paste operation.
I have tried a few things: (I am successfully binding to keystrokes with RegisterHotKey)
I have:
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x312)
hotKey();
base.WndProc(ref m);
}
and I've tried the following:
void hotKey()
{
SendKeys.SendWait("^v"); //just puts 'v' instead of clipboard contents
}
and
void hotKey()
{
SendKeys.SendWait(ClipBoard.GetText());
/* This works, but since Ctrl is still down, it triggers
* all the shortcut keys for the app, e.g. if the keyboard
* contains 's' then instead of putting 's' in the app, it
* calls Ctrl+S which makes the app think the user wants
* to save.
*/
}
Currently the only working solution I have is to bind to something different, e.g. Ctrl+B and then call SendKeys.SendWait("^v");
however this isn't ideal.
An ideal solution would be if my window didn't intercept the keystroke in the first place, just reacted.
You can do this by leveraging hooks using SetWindowsHookEx().
HHOOK WINAPI SetWindowsHookEx(
__in int idHook,
__in HOOKPROC lpfn,
__in HINSTANCE hMod,
__in DWORD dwThreadId
);
Basically, you can set up a low-level keyboard hook:
_hookHandle = SetWindowsHookEx(
WH_KEYBOARD_LL,
KbHookProc, // Your keyboard handler
(IntPtr)0,
0); // Set up system-wide hook.
to capture system-wide keyboard events. But it also allows you to make those keyboard events pass through to other apps. For your particular case, you can define KbHookProc
as:
private static int KbHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0) // This means we can intercept the event.
{
var hookStruct = (KbLLHookStruct)Marshal.PtrToStructure(
lParam,
typeof(KbLLHookStruct));
// Quick check if Ctrl key is down.
// See GetKeyState() doco for more info about the flags.
bool ctrlDown =
GetKeyState(VK_LCONTROL) != 0 ||
GetKeyState(VK_RCONTROL) != 0;
if (ctrlDown && hookStruct.vkCode == 0x56) // Ctrl+V
{
// Replace this with your custom action.
Clipboard.SetText("Hi");
}
}
// Pass to other keyboard handlers. Makes the Ctrl+V pass through.
return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
}
I coded a quick and dirty WinForms app to illustrate this. For the full code listing, see http://pastebin.com/uCSvqwb4.