| |
| using System; |
| using System.Net; |
| using System.Runtime.InteropServices; |
| using System.Text; |
| using System.Windows.Forms; |
| |
| namespace RemoteView.PageHandlers |
| { |
| class ClickPageHandler : PageHandler |
| { |
| private Screen[] screens = Screen.AllScreens; |
| |
| /// <summary> |
| /// Act upon clicks received from application. |
| /// Input parsing is robust, trying to work even if problems are present in requesting string. |
| /// </summary> |
| /// <param name="response">server response</param> |
| /// <param name="uri">tokenized URI</param> |
| /// <returns></returns> |
| public override byte[] handleRequest(HttpListenerResponse response, string[] uri) |
| { |
| // must have 5 tokens |
| if (uri.Length != 6) |
| { |
| response.Redirect("/"); |
| return Encoding.UTF8.GetBytes("<html><body>Error...</body></html>"); |
| } |
| |
| int x, y; |
| try |
| { |
| y = Convert.ToInt16(uri[4]); |
| x = Convert.ToInt16(uri[5]); |
| } |
| catch |
| { |
| // parameter error, redirect to home |
| response.Redirect("/"); |
| return Encoding.UTF8.GetBytes("<html><body>Error...</body></html>"); |
| } |
| |
| int screen = getRequestedScreenDevice(uri, screens); |
| |
| // check bounds |
| Screen device = screens[screen]; |
| if (x < 0 || x >= device.Bounds.Width || y < 0 || y >= device.Bounds.Height) |
| { |
| response.Redirect("/"); |
| return Encoding.UTF8.GetBytes("<html><body>Error...</body></html>"); |
| } |
| |
| // grab the first character |
| switch (uri[3][0]) |
| { |
| case 'l': |
| // left click |
| ClickLeftMouseButton(x, y); |
| break; |
| case 'd': |
| break; |
| case 'r': |
| ClickRightMouseButton(x, y); |
| break; |
| default: |
| // error, redirect to home |
| response.Redirect("/"); |
| return Encoding.UTF8.GetBytes("<html><body>Error...</body></html>"); |
| } |
| |
| // request a refresh by redirecting to the homepage |
| response.Redirect("/home/" + screen); |
| return Encoding.UTF8.GetBytes("<html><body>Redirecting...</body></html>"); |
| } |
| |
| enum SystemMetric |
| { |
| SM_CXSCREEN = 0, |
| SM_CYSCREEN = 1, |
| } |
| |
| #region http://stackoverflow.com/questions/8021954/sendinput-doesnt-perform-click-mouse-button-unless-i-move-cursor |
| |
| [DllImport("user32.dll")] |
| static extern int GetSystemMetrics(SystemMetric smIndex); |
| |
| [DllImport("user32.dll", SetLastError = true)] |
| static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize); |
| |
| [StructLayout(LayoutKind.Sequential)] |
| struct HARDWAREINPUT |
| { |
| public int uMsg; |
| public short wParamL; |
| public short wParamH; |
| } |
| |
| [StructLayout(LayoutKind.Sequential)] |
| struct KEYBDINPUT |
| { |
| public ushort wVk; |
| public ushort wScan; |
| public uint dwFlags; |
| public uint time; |
| public IntPtr dwExtraInfo; |
| } |
| |
| [StructLayout(LayoutKind.Explicit)] |
| struct MouseKeybdhardwareInputUnion |
| { |
| [FieldOffset(0)] |
| public MouseInputData mi; |
| |
| [FieldOffset(0)] |
| public KEYBDINPUT ki; |
| |
| [FieldOffset(0)] |
| public HARDWAREINPUT hi; |
| } |
| |
| [StructLayout(LayoutKind.Sequential)] |
| struct INPUT |
| { |
| public SendInputEventType type; |
| public MouseKeybdhardwareInputUnion mkhi; |
| } |
| |
| [Flags] |
| enum MouseEventFlags : uint |
| { |
| MOUSEEVENTF_MOVE = 0x0001, |
| MOUSEEVENTF_LEFTDOWN = 0x0002, |
| MOUSEEVENTF_LEFTUP = 0x0004, |
| MOUSEEVENTF_RIGHTDOWN = 0x0008, |
| MOUSEEVENTF_RIGHTUP = 0x0010, |
| MOUSEEVENTF_MIDDLEDOWN = 0x0020, |
| MOUSEEVENTF_MIDDLEUP = 0x0040, |
| MOUSEEVENTF_XDOWN = 0x0080, |
| MOUSEEVENTF_XUP = 0x0100, |
| MOUSEEVENTF_WHEEL = 0x0800, |
| MOUSEEVENTF_VIRTUALDESK = 0x4000, |
| MOUSEEVENTF_ABSOLUTE = 0x8000 |
| } |
| |
| enum SendInputEventType : int |
| { |
| InputMouse, |
| InputKeyboard, |
| InputHardware |
| } |
| |
| struct MouseInputData |
| { |
| public int dx; |
| public int dy; |
| public uint mouseData; |
| public MouseEventFlags dwFlags; |
| public uint time; |
| public IntPtr dwExtraInfo; |
| } |
| |
| int CalculateAbsoluteCoordinateX(int x) |
| { |
| return (x * 65536) / GetSystemMetrics(SystemMetric.SM_CXSCREEN); |
| } |
| |
| int CalculateAbsoluteCoordinateY(int y) |
| { |
| return (y * 65536) / GetSystemMetrics(SystemMetric.SM_CYSCREEN); |
| } |
| |
| public void ClickLeftMouseButton(int x, int y) |
| { |
| INPUT mouseInput = new INPUT(); |
| mouseInput.type = SendInputEventType.InputMouse; |
| mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x); |
| mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y); |
| mouseInput.mkhi.mi.mouseData = 0; |
| |
| mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE | MouseEventFlags.MOUSEEVENTF_ABSOLUTE; |
| SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); |
| |
| mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN; |
| SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); |
| |
| mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP; |
| SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); |
| } |
| |
| public void ClickRightMouseButton(int x, int y) |
| { |
| INPUT mouseInput = new INPUT(); |
| mouseInput.type = SendInputEventType.InputMouse; |
| mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x); |
| mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y); |
| mouseInput.mkhi.mi.mouseData = 0; |
| |
| mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE | MouseEventFlags.MOUSEEVENTF_ABSOLUTE; |
| SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); |
| |
| mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN; |
| SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); |
| |
| mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP; |
| SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); |
| } |
| #endregion |
| |
| } |
| } |