Beispiel #1
0
        /// <summary>
        /// Send array of System.Window.Forms.Keys to client as keypresses.  Restores and activates window.
        /// </summary>
        /// <param name="client">Target client.</param>
        /// <param name="keys">System.Window.Forms.Keys to send.</param>
        /// <returns>True if all keys were successfully sent.</returns>
        public static bool SendKeys(int client, Keys[] keys)
        {
            if (keys.Length == 0) return false;
            ClientInfo ci;
            if (ClientInfoCollection.GetClient(client, out ci))
            {
                NativeMethods.INPUT[] inputs = new NativeMethods.INPUT[keys.Length * 2];
                NativeMethods.KEYBDINPUT kbi = new NativeMethods.KEYBDINPUT();

                if (!ci.PrepareWindowForInput())
                {
                    ci.DetachFromWindow();
                    return false;
                }

                for (int x = 0; x < keys.Length; x++)
                {
                    kbi.dwFlags = 0;
                    kbi.wVk = (ushort)keys[x];
                    inputs[x * 2].mkhi.ki = kbi;
                    inputs[x * 2].type = NativeMethods.INPUT_KEYBOARD;
                    kbi.dwFlags = NativeMethods.KEYEVENTF_KEYUP;
                    inputs[x * 2 + 1].mkhi.ki = kbi;
                    inputs[x * 2 + 1].type = NativeMethods.INPUT_KEYBOARD;
                }
                uint success = NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0]));
                ci.DetachFromWindow();
                return success == inputs.Length;
            }
            return false;
        }
Beispiel #2
0
        // 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(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.
            // 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 == NativeMethods.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 == NativeMethods.WM_KEYUP || skEvent.wm == NativeMethods.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.  See DevDiv bugs 23355.  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();
            }
        }
Beispiel #3
0
        private static void ResetKeyboardUsingSendInput(int INPUTSize)
        {
            // if the new state is the same, we don't need to do anything
            if (!(capslockChanged || numlockChanged || scrollLockChanged || kanaChanged))
            {
                return;
            }

            // INPUT struct for resetting the keyboard
            NativeMethods.INPUT[] keyboardInput = new NativeMethods.INPUT[2];

            keyboardInput[0].type = NativeMethods.INPUT_KEYBOARD;
            keyboardInput[0].inputUnion.ki.dwFlags = 0;

            keyboardInput[1].type = NativeMethods.INPUT_KEYBOARD;
            keyboardInput[1].inputUnion.ki.dwFlags = NativeMethods.KEYEVENTF_KEYUP;

            // SendInputs to turn on or off these keys.  Inputs are pairs because KeyUp is sent for each one
            if (capslockChanged)
            {
                keyboardInput[0].inputUnion.ki.wVk = NativeMethods.VK_CAPITAL;
                keyboardInput[1].inputUnion.ki.wVk = NativeMethods.VK_CAPITAL;
                UnsafeNativeMethods.SendInput(2, keyboardInput, INPUTSize);
            }

            if (numlockChanged)
            {
                keyboardInput[0].inputUnion.ki.wVk = NativeMethods.VK_NUMLOCK;
                keyboardInput[1].inputUnion.ki.wVk = NativeMethods.VK_NUMLOCK;
                UnsafeNativeMethods.SendInput(2, keyboardInput, INPUTSize);
            }

            if (scrollLockChanged)
            {
                keyboardInput[0].inputUnion.ki.wVk = NativeMethods.VK_SCROLL;
                keyboardInput[1].inputUnion.ki.wVk = NativeMethods.VK_SCROLL;
                UnsafeNativeMethods.SendInput(2, keyboardInput, INPUTSize);
            }

            if (kanaChanged)
            {
                keyboardInput[0].inputUnion.ki.wVk = NativeMethods.VK_KANA;
                keyboardInput[1].inputUnion.ki.wVk = NativeMethods.VK_KANA;
                UnsafeNativeMethods.SendInput(2, keyboardInput, INPUTSize);
            }
        }
        /// <summary>
        /// Send mouse click to relative position in the client window.
        /// </summary>
        /// <param name="client">Target client.</param>
        /// <param name="button">System.Windows.Forms.MouseButtons to click.</param>
        /// <param name="x">X position of point to click relative to client window's X position.</param>
        /// <param name="y">Y position of point to click relative to client window's Y position.</param>
        /// <param name="doubleClick">True for double click, false for single click.</param>
        /// <returns>True on success.</returns>
        public static bool SendMouseClick(int client, MouseButtons button, int x, int y, bool doubleClick)
        {
            ClientInfo ci;
            if (ClientInfoCollection.GetClient(client, out ci))
            {
                NativeMethods.INPUT[] inputs = new NativeMethods.INPUT[2];
                NativeMethods.MOUSEINPUT mi = new NativeMethods.MOUSEINPUT();
                inputs[0].type = NativeMethods.INPUT_MOUSE;
                inputs[1].type = NativeMethods.INPUT_MOUSE;
                mi.dx = 0;
                mi.dy = 0;
                switch (button)
                {
                    case MouseButtons.None:
                        return false;
                    case MouseButtons.Left:
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_LEFTDOWN;
                        inputs[0].mkhi.mi = mi;
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_LEFTUP;
                        inputs[1].mkhi.mi = mi;
                        break;
                    case MouseButtons.Right:
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_RIGHTDOWN;
                        inputs[0].mkhi.mi = mi;
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_RIGHTUP;
                        inputs[1].mkhi.mi = mi;
                        break;
                    case MouseButtons.Middle:
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_MIDDLEDOWN;
                        inputs[0].mkhi.mi = mi;
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_MIDDLEUP;
                        inputs[1].mkhi.mi = mi;
                        break;
                    case MouseButtons.XButton1:
                        mi.mouseData = NativeMethods.XBUTTON1;
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_XDOWN;
                        inputs[0].mkhi.mi = mi;
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_XUP;
                        inputs[1].mkhi.mi = mi;
                        break;
                    case MouseButtons.XButton2:
                        mi.mouseData = NativeMethods.XBUTTON2;
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_XDOWN;
                        inputs[0].mkhi.mi = mi;
                        mi.dwFlags = NativeMethods.MOUSEEVENTF_XUP;
                        inputs[1].mkhi.mi = mi;
                        break;
                }

                if (!ci.PrepareWindowForInput())
                {
                    ci.DetachFromWindow();
                    return false;
                }

                NativeMethods.WINDOWPLACEMENT wp = new NativeMethods.WINDOWPLACEMENT();
                if (NativeMethods.GetWindowPlacement(ci.WindowHandle, ref wp))
                {
                    /*int screenX = wp.rcNormalPosition.X + x;
                    int screenY = wp.rcNormalPosition.Y + y;
                    int absX = (screenX * 65536 / Screen.PrimaryScreen.Bounds.Width);
                    int absY = (screenY * 65536 / Screen.PrimaryScreen.Bounds.Height);
                    inputs[0].mkhi.mi.dx = absX;
                    inputs[1].mkhi.mi.dx = absX;
                    inputs[0].mkhi.mi.dy = absY;
                    inputs[1].mkhi.mi.dy = absY;*/

                    // using this method because absolute position is always off by a pixel or 2

                    if (!NativeMethods.SetCursorPos(x + wp.rcNormalPosition.X, y + wp.rcNormalPosition.Y)) return false;
                }
                else return false;

                uint success = NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0]));
                if (doubleClick && success == inputs.Length)
                {
                    success = NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0]));
                }
                ci.DetachFromWindow();
                return success == inputs.Length;
            }
            return false;
        }