private static void CheckGlobalKeys(SKEvent skEvent) { if (skEvent.wm == 0x100) { switch (skEvent.paramL) { case 20: capslockChanged = !capslockChanged; return; case 0x15: kanaChanged = !kanaChanged; break; case 0x90: numlockChanged = !numlockChanged; return; case 0x91: scrollLockChanged = !scrollLockChanged; return; default: return; } } }
public virtual IntPtr Callback(int code, IntPtr wparam, IntPtr lparam) { NativeMethods.EVENTMSG eventmsg = Marshal.PtrToStructure <NativeMethods.EVENTMSG>(lparam); if (UnsafeNativeMethods.GetAsyncKeyState((int)Keys.Pause) != 0) { SendKeys.stopHook = true; } // switch (code) { case NativeMethods.HC_SKIP: if (!gotNextEvent) { break; } if (SendKeys.events != null && SendKeys.events.Count > 0) { SendKeys.events.Dequeue(); } SendKeys.stopHook = SendKeys.events == null || SendKeys.events.Count == 0; break; case NativeMethods.HC_GETNEXT: gotNextEvent = true; #if DEBUG Debug.Assert(SendKeys.events != null && SendKeys.events.Count > 0 && !SendKeys.stopHook, "HC_GETNEXT when queue is empty!"); #endif SKEvent evt = (SKEvent)SendKeys.events.Peek(); eventmsg.message = evt.wm; eventmsg.paramL = evt.paramL; eventmsg.paramH = evt.paramH; eventmsg.hwnd = evt.hwnd; eventmsg.time = SafeNativeMethods.GetTickCount(); Marshal.StructureToPtr(eventmsg, lparam, true); break; default: if (code < 0) { UnsafeNativeMethods.CallNextHookEx(new HandleRef(null, SendKeys.hhook), code, wparam, lparam); } break; } if (SendKeys.stopHook) { SendKeys.UninstallJournalingHook(); gotNextEvent = false; } return(IntPtr.Zero); }
private void CheckGlobalKeys(SKEvent skEvent) { if (skEvent.wm == WM_KEYDOWN) { switch (skEvent.paramL) { case 20: capslockChanged = !capslockChanged; return; case 21: kanaChanged = !kanaChanged; return; case 144: numlockChanged = !numlockChanged; return; case 145: scrollLockChanged = !scrollLockChanged; return; default: return; } } }
private void GetEvents(Queue <SKEvent> events, out Queue <SKEvent> keysDown, out Queue <SKEvent> keysUp) { keysDown = new Queue <SKEvent>(); keysUp = new Queue <SKEvent>(); SKEvent[] evs = events.ToArray(); for (int i = 0; i < evs.Length; i++) { SKEvent ev = evs[i]; if (ev.IsDown) { if (!keysDown.Contains(ev)) { keysDown.Enqueue(ev); } } ev = evs[evs.Length - i - 1]; if (!ev.IsDown) { if (!keysUp.Contains(ev)) { keysUp.Enqueue(ev); } } } }
private static bool IsExtendedKey(SKEvent skEvent) { if (((((skEvent.paramL != 0x26) && (skEvent.paramL != 40)) && ((skEvent.paramL != 0x25) && (skEvent.paramL != 0x27))) && (((skEvent.paramL != 0x21) && (skEvent.paramL != 0x22)) && ((skEvent.paramL != 0x24) && (skEvent.paramL != 0x23)))) && (skEvent.paramL != 0x2d)) { return(skEvent.paramL == 0x2e); } return(true); }
private bool IsExtendedKey(SKEvent skEvent) { if (((((skEvent.paramL != 38) && (skEvent.paramL != 40)) && ((skEvent.paramL != 37) && (skEvent.paramL != 39))) && (((skEvent.paramL != 33) && (skEvent.paramL != 34)) && ((skEvent.paramL != 36) && (skEvent.paramL != 35)))) && (skEvent.paramL != 45)) { return(skEvent.paramL == 46); } return(true); }
/// <summary> /// adds an event to our list of events for the hook /// </summary> private static void AddEvent(SKEvent skevent) { if (events == null) { events = new Queue(); } events.Enqueue(skevent); }
// For SendInput, these previous events that stick around if an Exception was // thrown could modify the state of the keyboard modifiers (alt, ctrl, shift). // We must send a KeyUp for those, JournalHook doesn't permanently set the state // so it's ok private static void AddCancelModifiersForPreviousEvents(Queue previousEvents) { if (previousEvents == null) { return; } bool shift = false; bool ctrl = false; bool alt = false; while (previousEvents.Count > 0) { SKEvent skEvent = (SKEvent)previousEvents.Dequeue(); bool isOn; if ((skEvent.wm == Interop.WindowMessages.WM_KEYUP) || (skEvent.wm == Interop.WindowMessages.WM_SYSKEYUP)) { isOn = false; } else if ((skEvent.wm == Interop.WindowMessages.WM_KEYDOWN) || (skEvent.wm == Interop.WindowMessages.WM_SYSKEYDOWN)) { isOn = true; } else { continue; } if (skEvent.paramL == (int)Keys.ShiftKey) { shift = isOn; } else if (skEvent.paramL == (int)Keys.ControlKey) { ctrl = isOn; } else if (skEvent.paramL == (int)Keys.Menu) { alt = isOn; } } if (shift) { AddEvent(new SKEvent(Interop.WindowMessages.WM_KEYUP, (int)Keys.ShiftKey, false, IntPtr.Zero)); } else if (ctrl) { AddEvent(new SKEvent(Interop.WindowMessages.WM_KEYUP, (int)Keys.ControlKey, false, IntPtr.Zero)); } else if (alt) { AddEvent(new SKEvent(Interop.WindowMessages.WM_SYSKEYUP, (int)Keys.Menu, false, IntPtr.Zero)); } }
public unsafe virtual IntPtr Callback(User32.HC nCode, IntPtr wparam, IntPtr lparam) { User32.EVENTMSG *eventmsg = (User32.EVENTMSG *)lparam; if (User32.GetAsyncKeyState((int)Keys.Pause) != 0) { s_stopHook = true; } switch (nCode) { case User32.HC.SKIP: if (_gotNextEvent) { if (s_events is not null && s_events.Count > 0) { s_events.Dequeue(); } s_stopHook = s_events is null || s_events.Count == 0; break; } break; case User32.HC.GETNEXT: _gotNextEvent = true; Debug.Assert( s_events is not null && s_events.Count > 0 && !s_stopHook, "HC_GETNEXT when queue is empty!"); SKEvent evt = (SKEvent)s_events.Peek(); eventmsg->message = evt.WM; eventmsg->paramL = evt.ParamL; eventmsg->paramH = evt.ParamH; eventmsg->hwnd = evt.HWND; eventmsg->time = Kernel32.GetTickCount(); break; default: if (nCode < 0) { User32.CallNextHookEx(s_hhook, nCode, wparam, lparam); } break; } if (s_stopHook) { UninstallJournalingHook(); _gotNextEvent = false; } return(IntPtr.Zero); }
private static void AddCancelModifiersForPreviousEvents(Queue previousEvents) { if (previousEvents != null) { bool flag = false; bool flag2 = false; bool flag3 = false; while (previousEvents.Count > 0) { bool flag4; SKEvent event2 = (SKEvent)previousEvents.Dequeue(); if ((event2.wm == 0x101) || (event2.wm == 0x105)) { flag4 = false; } else { if ((event2.wm != 0x100) && (event2.wm != 260)) { continue; } flag4 = true; } if (event2.paramL == 0x10) { flag = flag4; } else { if (event2.paramL == 0x11) { flag2 = flag4; continue; } if (event2.paramL == 0x12) { flag3 = flag4; } } } if (flag) { AddEvent(new SKEvent(0x101, 0x10, false, IntPtr.Zero)); } else if (flag2) { AddEvent(new SKEvent(0x101, 0x11, false, IntPtr.Zero)); } else if (flag3) { AddEvent(new SKEvent(0x105, 0x12, false, IntPtr.Zero)); } } }
private static bool IsExtendedKey(SKEvent skEvent) { return((skEvent.paramL == User32.VK.UP) || (skEvent.paramL == User32.VK.DOWN) || (skEvent.paramL == User32.VK.LEFT) || (skEvent.paramL == User32.VK.RIGHT) || (skEvent.paramL == User32.VK.PRIOR) || (skEvent.paramL == User32.VK.NEXT) || (skEvent.paramL == User32.VK.HOME) || (skEvent.paramL == User32.VK.END) || (skEvent.paramL == User32.VK.INSERT) || (skEvent.paramL == User32.VK.DELETE)); }
private static bool IsExtendedKey(SKEvent skEvent) { return((skEvent.paramL == NativeMethods.VK_UP) || (skEvent.paramL == NativeMethods.VK_DOWN) || (skEvent.paramL == NativeMethods.VK_LEFT) || (skEvent.paramL == NativeMethods.VK_RIGHT) || (skEvent.paramL == NativeMethods.VK_PRIOR) || (skEvent.paramL == NativeMethods.VK_NEXT) || (skEvent.paramL == NativeMethods.VK_HOME) || (skEvent.paramL == NativeMethods.VK_END) || (skEvent.paramL == NativeMethods.VK_INSERT) || (skEvent.paramL == NativeMethods.VK_DELETE)); }
private static void CheckGlobalKeys(SKEvent skEvent) { if (skEvent.wm == Interop.WindowMessages.WM_KEYDOWN) { switch (skEvent.paramL) { case (int)Keys.CapsLock: capslockChanged = !capslockChanged; break; case (int)Keys.NumLock: numlockChanged = !numlockChanged; break; case (int)Keys.Scroll: scrollLockChanged = !scrollLockChanged; break; case (int)Keys.KanaMode: kanaChanged = !kanaChanged; break; } } }
private void SendInput(byte[] oldKeyboardState, Queue <SKEvent> events) { int count; //AddCancelModifiersForPreviousEvents(previousEvents); INPUT[] pInputs = new INPUT[2]; pInputs[0].type = INPUT_KEYBOARD; pInputs[0].inputUnion.ki.dwExtraInfo = IntPtr.Zero; pInputs[0].inputUnion.ki.time = 0; pInputs[1].type = INPUT_KEYBOARD; pInputs[1].inputUnion.ki.wVk = 0; pInputs[1].inputUnion.ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE; pInputs[1].inputUnion.ki.dwExtraInfo = IntPtr.Zero; pInputs[1].inputUnion.ki.time = 0; int cbSize = Marshal.SizeOf(typeof(INPUT)); uint num2 = 0; lock (events) { bool flag = BlockInput(true); try { count = events.Count; ClearGlobalKeys(); for (int i = 0; i < count; i++) { SKEvent skEvent = (SKEvent)events.Dequeue(); pInputs[0].inputUnion.ki.dwFlags = 0; if (skEvent.wm == WM_CHAR) { int vk = pInputs[0].inputUnion.ki.wVk; pInputs[0].inputUnion.ki.wVk = 0; pInputs[0].inputUnion.ki.wScan = (short)MapVirtualKey(vk, 0 /* MAPVK_VK_TO_VSC */); // (short)skEvent.paramL; pInputs[0].inputUnion.ki.dwFlags = KEYEVENTF_UNICODE; pInputs[1].inputUnion.ki.wScan = (short)MapVirtualKey(vk, 0 /* MAPVK_VK_TO_VSC */); // (short)skEvent.paramL; num2 += SendInput(2, pInputs, cbSize) - 1; } else { //pInputs[0].inputUnion.ki.wScan = 0; pInputs[0].inputUnion.ki.wScan = (short)MapVirtualKey(skEvent.paramL, 0 /* MAPVK_VK_TO_VSC */); if ((skEvent.wm == WM_KEYUP) || (skEvent.wm == WM_SYSKEYUP)) { pInputs[0].inputUnion.ki.dwFlags |= KEYEVENTF_KEYUP; } if (IsExtendedKey(skEvent)) { pInputs[0].inputUnion.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; } pInputs[0].inputUnion.ki.wVk = (short)skEvent.paramL; num2 += SendInput(1, pInputs, cbSize); CheckGlobalKeys(skEvent); } Thread.Sleep(1); } ResetKeyboardUsingSendInput(cbSize); } finally { SetKeyboardState(oldKeyboardState); if (flag) { BlockInput(false); } } } if (num2 != count) { throw new System.ComponentModel.Win32Exception(); } }
// Uses User32 SendInput to send keystrokes private static void SendInput(byte[] oldKeyboardState, Queue previousEvents) { // Should be a No-Opt most of the time AddCancelModifiersForPreviousEvents(previousEvents); // SKEvents are sent as sent as 1 or 2 inputs // currentInput[0] represents the SKEvent // currentInput[1] is a KeyUp to prevent all identical WM_CHARs to be sent as one message NativeMethods.INPUT[] currentInput = new NativeMethods.INPUT[2]; // all events are Keyboard events currentInput[0].type = NativeMethods.INPUT_KEYBOARD; currentInput[1].type = NativeMethods.INPUT_KEYBOARD; // set KeyUp values for currentInput[1] currentInput[1].inputUnion.ki.wVk = (short)0; currentInput[1].inputUnion.ki.dwFlags = NativeMethods.KEYEVENTF_UNICODE | NativeMethods.KEYEVENTF_KEYUP; // initialize unused members currentInput[0].inputUnion.ki.dwExtraInfo = IntPtr.Zero; currentInput[0].inputUnion.ki.time = 0; currentInput[1].inputUnion.ki.dwExtraInfo = IntPtr.Zero; currentInput[1].inputUnion.ki.time = 0; // send each of our SKEvents using SendInput int INPUTSize = Marshal.SizeOf <NativeMethods.INPUT>(); // need these outside the lock below uint eventsSent = 0; int eventsTotal; // A lock here will allow multiple threads to SendInput at the same time. // This mimics the JournalHook method of using the message loop to mitigate // threading issues. There is still a theoretical thread issue with adding // to the events Queue (both JournalHook and SendInput), but we do not want // to alter the timings of the existing shipped behavior. I did not run into // problems with 2 threads on a multiproc machine lock (events.SyncRoot) { // block keyboard and mouse input events from reaching applications. bool blockInputSuccess = UnsafeNativeMethods.BlockInput(true); try { eventsTotal = events.Count; ClearGlobalKeys(); for (int i = 0; i < eventsTotal; i++) { SKEvent skEvent = (SKEvent)events.Dequeue(); currentInput[0].inputUnion.ki.dwFlags = 0; if (skEvent.wm == Interop.WindowMessages.WM_CHAR) { // for WM_CHAR, send a KEYEVENTF_UNICODE instead of a Keyboard event // to support extended ascii characters with no keyboard equivalent. // send currentInput[1] in this case currentInput[0].inputUnion.ki.wVk = (short)0; currentInput[0].inputUnion.ki.wScan = (short)skEvent.paramL; currentInput[0].inputUnion.ki.dwFlags = NativeMethods.KEYEVENTF_UNICODE; currentInput[1].inputUnion.ki.wScan = (short)skEvent.paramL; // call SendInput, increment the eventsSent but subtract 1 for the extra one sent eventsSent += UnsafeNativeMethods.SendInput(2, currentInput, INPUTSize) - 1; } else { // just need to send currentInput[0] for skEvent currentInput[0].inputUnion.ki.wScan = 0; // add KeyUp flag if we have a KeyUp if (skEvent.wm == Interop.WindowMessages.WM_KEYUP || skEvent.wm == Interop.WindowMessages.WM_SYSKEYUP) { currentInput[0].inputUnion.ki.dwFlags |= NativeMethods.KEYEVENTF_KEYUP; } // Sets KEYEVENTF_EXTENDEDKEY flag if necessary if (IsExtendedKey(skEvent)) { currentInput[0].inputUnion.ki.dwFlags |= NativeMethods.KEYEVENTF_EXTENDEDKEY; } currentInput[0].inputUnion.ki.wVk = (short)skEvent.paramL; // send only currentInput[0] eventsSent += UnsafeNativeMethods.SendInput(1, currentInput, INPUTSize); CheckGlobalKeys(skEvent); } // We need this slight delay here for Alt-Tab to work on Vista when the Aero theme // is running. Although this does not look good, a delay // here actually more closely resembles the old JournalHook that processes each // event individually in the hook callback. System.Threading.Thread.Sleep(1); } // reset the keyboard back to what it was before inputs were sent, SendInupt modifies // the global lights on the keyboard (caps, scroll..) so we need to call it again to // undo those changes ResetKeyboardUsingSendInput(INPUTSize); } finally { SetKeyboardState(oldKeyboardState); // unblock input if it was previously blocked if (blockInputSuccess) { UnsafeNativeMethods.BlockInput(false); } } } // check to see if we sent the number of events we're supposed to if (eventsSent != eventsTotal) { // calls Marshal.GetLastWin32Error and sets it in the exception throw new Win32Exception(); } }
private static void SendInput(byte[] oldKeyboardState, Queue previousEvents) { int count; AddCancelModifiersForPreviousEvents(previousEvents); System.Windows.Forms.NativeMethods.INPUT[] pInputs = new System.Windows.Forms.NativeMethods.INPUT[2]; pInputs[0].type = 1; pInputs[1].type = 1; pInputs[1].inputUnion.ki.wVk = 0; pInputs[1].inputUnion.ki.dwFlags = 6; pInputs[0].inputUnion.ki.dwExtraInfo = IntPtr.Zero; pInputs[0].inputUnion.ki.time = 0; pInputs[1].inputUnion.ki.dwExtraInfo = IntPtr.Zero; pInputs[1].inputUnion.ki.time = 0; int cbSize = Marshal.SizeOf(typeof(System.Windows.Forms.NativeMethods.INPUT)); uint num2 = 0; lock (events.SyncRoot) { bool flag = UnsafeNativeMethods.BlockInput(true); try { count = events.Count; ClearGlobalKeys(); for (int i = 0; i < count; i++) { SKEvent skEvent = (SKEvent)events.Dequeue(); pInputs[0].inputUnion.ki.dwFlags = 0; if (skEvent.wm == 0x102) { pInputs[0].inputUnion.ki.wVk = 0; pInputs[0].inputUnion.ki.wScan = (short)skEvent.paramL; pInputs[0].inputUnion.ki.dwFlags = 4; pInputs[1].inputUnion.ki.wScan = (short)skEvent.paramL; num2 += UnsafeNativeMethods.SendInput(2, pInputs, cbSize) - 1; } else { pInputs[0].inputUnion.ki.wScan = 0; if ((skEvent.wm == 0x101) || (skEvent.wm == 0x105)) { pInputs[0].inputUnion.ki.dwFlags |= 2; } if (IsExtendedKey(skEvent)) { pInputs[0].inputUnion.ki.dwFlags |= 1; } pInputs[0].inputUnion.ki.wVk = (short)skEvent.paramL; num2 += UnsafeNativeMethods.SendInput(1, pInputs, cbSize); CheckGlobalKeys(skEvent); } Thread.Sleep(1); } ResetKeyboardUsingSendInput(cbSize); } finally { SetKeyboardState(oldKeyboardState); if (flag) { UnsafeNativeMethods.BlockInput(false); } } } if (num2 != count) { throw new Win32Exception(); } }
private static void CheckGlobalKeys(SKEvent skEvent) { if (skEvent.wm == NativeMethods.WM_KEYDOWN) { switch (skEvent.paramL) { case (int)Keys.CapsLock: capslockChanged = !capslockChanged; break; case (int)Keys.NumLock: numlockChanged = !numlockChanged; break; case (int)Keys.Scroll: scrollLockChanged = !scrollLockChanged; break; case (int)Keys.KanaMode: kanaChanged = !kanaChanged; break; } } }
private static bool IsExtendedKey(SKEvent skEvent) { return (skEvent.paramL == NativeMethods.VK_UP) || (skEvent.paramL == NativeMethods.VK_DOWN) || (skEvent.paramL == NativeMethods.VK_LEFT) || (skEvent.paramL == NativeMethods.VK_RIGHT) || (skEvent.paramL == NativeMethods.VK_PRIOR) || (skEvent.paramL == NativeMethods.VK_NEXT) || (skEvent.paramL == NativeMethods.VK_HOME) || (skEvent.paramL == NativeMethods.VK_END) || (skEvent.paramL == NativeMethods.VK_INSERT) || (skEvent.paramL == NativeMethods.VK_DELETE); }
/// <include file='doc\SendKeys.uex' path='docs/doc[@for="SendKeys.AddEvent"]/*' /> /// <devdoc> /// adds an event to our list of events for the hook /// </devdoc> private static void AddEvent(SKEvent skevent) { if (events == null) { events = new Queue(); } events.Enqueue(skevent); }
private static void AddEvent(SKEvent skevent) { s_events ??= new Queue <SKEvent>(); s_events.Enqueue(skevent); }
private static bool IsExtendedKey(SKEvent skEvent) { if (((((skEvent.paramL != 0x26) && (skEvent.paramL != 40)) && ((skEvent.paramL != 0x25) && (skEvent.paramL != 0x27))) && (((skEvent.paramL != 0x21) && (skEvent.paramL != 0x22)) && ((skEvent.paramL != 0x24) && (skEvent.paramL != 0x23)))) && (skEvent.paramL != 0x2d)) { return (skEvent.paramL == 0x2e); } return true; }
// Uses User32 SendInput to send keystrokes private static void SendInput(byte[] oldKeyboardState) //, Queue previousEvents) { NativeMethods.INPUT[] currentInput = new NativeMethods.INPUT[1]; // all events are Keyboard events currentInput[0].type = NativeMethods.INPUT_KEYBOARD; // initialize unused members currentInput[0].inputUnion.ki.dwExtraInfo = IntPtr.Zero; currentInput[0].inputUnion.ki.time = 0; // send each of our SKEvents using SendInput int INPUTSize = Marshal.SizeOf(typeof(NativeMethods.INPUT)); // need these outside the lock below uint eventsSent = 0; int eventsTotal; // A lock here will allow multiple threads to SendInput at the same time. lock (events.SyncRoot) { // block keyboard and mouse input events from reaching applications. bool blockInputSuccess = UnsafeNativeMethods.BlockInput(true); try { eventsTotal = events.Count; for (int i = 0; i < eventsTotal; i++) { SKEvent skEvent = (SKEvent)events.Dequeue(); currentInput[0].inputUnion.ki.dwFlags = 0; // just need to send currentInput[0] for skEvent currentInput[0].inputUnion.ki.wScan = skEvent.sc; // add KeyUp flag if we have a KeyUp if (skEvent.wm == BaseUtils.Win32Constants.WM.KEYUP || skEvent.wm == BaseUtils.Win32Constants.WM.SYSKEYUP) { currentInput[0].inputUnion.ki.dwFlags |= NativeMethods.KEYEVENTF_KEYUP; } // Sets KEYEVENTF_EXTENDEDKEY flag if necessary if (skEvent.extkey) { currentInput[0].inputUnion.ki.dwFlags |= NativeMethods.KEYEVENTF_EXTENDEDKEY; } currentInput[0].inputUnion.ki.wVk = skEvent.vkey; //System.Diagnostics.Debug.WriteLine("Send " + currentInput[0].inputUnion.ki.wVk + " " + currentInput[0].inputUnion.ki.wScan.ToString("2X") + " " + currentInput[0].inputUnion.ki.dwFlags); // send only currentInput[0] eventsSent += UnsafeNativeMethods.SendInput(1, currentInput, INPUTSize); System.Threading.Thread.Sleep(skEvent.delay > 0 ? skEvent.delay : 1); } } finally { SetKeyboardState(oldKeyboardState); // unblock input if it was previously blocked if (blockInputSuccess) { UnsafeNativeMethods.BlockInput(false); } } } // check to see if we sent the number of events we're supposed to if (eventsSent != eventsTotal) { // calls Marshal.GetLastWin32Error and sets it in the exception throw new Win32Exception(); } }