public virtual void Dispatch(MouseInput e) { }
private void MouseInputHook_MouseInputReceived(object sender, MouseInput e) { #region Mouse 'Button State' Tracking ButtonState mouseButtonInfo = null; if (Mouse_Buttons.TryGetValue(e.WM, out mouseButtonInfo)) { var dateTimeNow = DateTime.Now; switch (e.WM) { case WinAPI.WM.MOUSEMOVE: if (mouseButtonInfo.IsDown && MuboxConfigSection.Default.Profiles.ActiveProfile.EnableMousePanningFix) { if ((int)e.Point.X != mouseButtonInfo.ClickX || (int)e.Point.Y != mouseButtonInfo.ClickY) { // TODO: screen bounds code may be incorrect for multimon, not properly tested var drawingPoint = new System.Drawing.Point(mouseButtonInfo.ClickX, mouseButtonInfo.ClickY); var screen = System.Windows.Forms.Screen.FromPoint(drawingPoint); var x = (ushort)Math.Ceiling((double)(mouseButtonInfo.ClickX) * (65536.0 / (double)screen.Bounds.Width)); var y = (ushort)Math.Ceiling((double)(mouseButtonInfo.ClickY) * (65536.0 / (double)screen.Bounds.Height)); var mouseinput = new Mubox.WinAPI.SendInputApi.INPUT { InputType = WinAPI.SendInputApi.InputType.INPUT_MOUSE, mi = new WinAPI.SendInputApi.MOUSEINPUT { dwExtraInfo = WinAPI.SendInputApi.GetMessageExtraInfo(), dx = x, dy = y, Flags = WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_MOVE | WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_ABSOLUTE, mouseData = 0, time = e.Time + 1, }, }; WinAPI.SendInputApi.SendInput(1, new Mubox.WinAPI.SendInputApi.INPUT[] { mouseinput, }, Marshal.SizeOf(mouseinput)); e.Handled = true; } else { e.Handled = true; } return; } break; case WinAPI.WM.LBUTTONDOWN: case WinAPI.WM.RBUTTONDOWN: case WinAPI.WM.MBUTTONDOWN: case WinAPI.WM.XBUTTONDOWN: if (!mouseButtonInfo.IsDown) { mouseButtonInfo.ClickX = (int)e.Point.X; mouseButtonInfo.ClickY = (int)e.Point.Y; mouseButtonInfo.IsClick = false; mouseButtonInfo.IsDoubleClick = // within buffer timestamp for a second down/up transition to be interpretted as a double-click (DateTime.Now.Ticks <= mouseButtonInfo.LastClickTimestamp.AddMilliseconds(Mubox.Configuration.MuboxConfigSection.Default.ClickBufferMilliseconds).Ticks) // and last click event was not also a double-click event && mouseButtonInfo.LastDoubleClickTimestamp != mouseButtonInfo.LastClickTimestamp; if (mouseButtonInfo.IsDoubleClick) { // translate message switch (e.WM) { case WinAPI.WM.LBUTTONDOWN: e.WM = WinAPI.WM.LBUTTONDBLCLK; break; case WinAPI.WM.RBUTTONDOWN: e.WM = WinAPI.WM.RBUTTONDBLCLK; break; case WinAPI.WM.MBUTTONDOWN: e.WM = WinAPI.WM.MBUTTONDBLCLK; break; case WinAPI.WM.XBUTTONDOWN: e.WM = WinAPI.WM.XBUTTONDBLCLK; break; } } mouseButtonInfo.LastDownTimestamp = dateTimeNow; } break; case WinAPI.WM.LBUTTONDBLCLK: case WinAPI.WM.MBUTTONDBLCLK: case WinAPI.WM.RBUTTONDBLCLK: case WinAPI.WM.XBUTTONDBLCLK: mouseButtonInfo.IsDoubleClick = true; break; case WinAPI.WM.LBUTTONUP: case WinAPI.WM.RBUTTONUP: case WinAPI.WM.MBUTTONUP: case WinAPI.WM.XBUTTONUP: if (mouseButtonInfo.IsDown) { mouseButtonInfo.IsClick = // within buffer timestamp for down/up transition to be interpretted as a 'click' gesture dateTimeNow.Ticks <= mouseButtonInfo.LastDownTimestamp.AddMilliseconds(Mubox.Configuration.MuboxConfigSection.Default.ClickBufferMilliseconds).Ticks; if (mouseButtonInfo.IsClick) { if (mouseButtonInfo.IsDoubleClick) { mouseButtonInfo.IsDoubleClick = false; mouseButtonInfo.LastDoubleClickTimestamp = dateTimeNow; } mouseButtonInfo.IsClick = false; mouseButtonInfo.LastClickTimestamp = dateTimeNow; } mouseButtonInfo.LastUpTimestamp = dateTimeNow; } break; } e.IsClickEvent = mouseButtonInfo.IsClick; e.IsDoubleClickEvent = mouseButtonInfo.IsDoubleClick; } #endregion Mouse 'Button State' Tracking if (!Mubox.Configuration.MuboxConfigSection.Default.EnableMouseCapture) { e.Handled = false; return; } Mubox.Extensions.ExtensionManager.Instance.OnMouseInputReceived(sender, e); ClientBase activeClient = ActiveClient; #region Mouse_RelativeMovement // one-time init if (e.WM == WinAPI.WM.MOUSEMOVE) { if (this.Mouse_RelativeMovement_LastX == double.MinValue) { this.Mouse_RelativeMovement_LastX = e.Point.X; this.Mouse_RelativeMovement_LastY = e.Point.Y; return; } // update for resolution changes every XX seconds if ((DateTime.Now.Ticks - Mouse_AbsoluteMovement_Screen_Resolution_UpdateTimestampTicks) > TimeSpan.FromSeconds(15).Ticks) { Mouse_Screen_OnResolutionChanged(); return; } } var shouldMulticastMouse = ShouldMulticastMouse(e); // track relative movement // TODO: except when the mouse moves TO the center of the screen or center of client area, some games do this to implement view pan // TODO: except when the mouse moves FROM the center of the screen, somce games do this to implement view pan int relX = (int)e.Point.X; int relY = (int)e.Point.Y; if (e.WM == WinAPI.WM.MOUSEMOVE) { relX -= (int)this.Mouse_RelativeMovement_LastX; relY -= (int)this.Mouse_RelativeMovement_LastY; this.Mouse_RelativeMovement_LastX += relX; if (this.Mouse_RelativeMovement_LastX <= 0) { this.Mouse_RelativeMovement_LastX = 0; } else if (this.Mouse_RelativeMovement_LastX >= Mouse_AbsoluteMovement_Screen_ResolutionX) { this.Mouse_RelativeMovement_LastX = Mouse_AbsoluteMovement_Screen_ResolutionX; } this.Mouse_RelativeMovement_LastY += relY; if (this.Mouse_RelativeMovement_LastY <= 0) { this.Mouse_RelativeMovement_LastY = 0; } else if (this.Mouse_RelativeMovement_LastY >= Mouse_AbsoluteMovement_Screen_ResolutionY) { this.Mouse_RelativeMovement_LastY = Mouse_AbsoluteMovement_Screen_ResolutionY; } } #endregion Mouse_RelativeMovement // send to client if (Mubox.Configuration.MuboxConfigSection.Default.IsCaptureEnabled && (activeClient != null)) { //if (!shouldMulticastMouse) //{ // e.Handled = !(activeClient.IsLocalAddress && (e.WM == Win32.WM.MOUSEMOVE)); // if (!activeClient.IsLocalAddress || e.WM != Win32.WM.MOUSEMOVE) // { // e.Point = new Point(relX, relY); // e.WindowStationHandle = activeClient.WindowStationHandle; // e.WindowHandle = activeClient.WindowHandle; // activeClient.Dispatch(e); // } //} //else { e.Handled = (e.WM != WinAPI.WM.MOUSEMOVE); var clients = shouldMulticastMouse ? GetCachedClients() : new[] { activeClient }; if (e.WM == WinAPI.WM.MOUSEMOVE) { // track mouse position TrackMousePositionClientRelative(e, activeClient, clients); // in the case of the 'active, local' client it is presumed that the mouse is correctly interacting with said client and thus is removed from the list of target clients, otherwise the client may be receiving double the number of mousemove events if (clients.Length > 0) { if (mouseButtonInfo.IsDown && MuboxConfigSection.Default.Profiles.ActiveProfile.EnableMousePanningFix) { clients = clients.Where(c => c.ClientId != activeClient.ClientId) .ToArray(); } } } foreach (ClientBase client in clients) { ForwardMouseEvent(e, client); } } } }
private void Process(MouseInput mouseInput) { // denormalize coordinates into client coordinates (we should always expect normalized coordinates, whether coordinates are absolute or relative) ushort x = (ushort)Math.Ceiling((double)(mouseInput.Point.X) * ((double)ClientWindowRect.Width / 65536.0)); ushort y = (ushort)Math.Ceiling((double)(mouseInput.Point.Y) * ((double)ClientWindowRect.Height / 65536.0)); var clientRelativeCoordinates = WinAPI.MACROS.MAKELPARAM(x, y); var wm = WinAPI.WM.USER; switch ((mouseInput.Flags | WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_ABSOLUTE) ^ WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_ABSOLUTE) { case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_MOVE: wm = WinAPI.WM.MOUSEMOVE; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_LEFTDOWN: //WinAPI.Cursor.SetCapture(ClientWindowHandle); wm = WinAPI.WM.LBUTTONDOWN; CurrentMK |= WinAPI.Windows.MK.MK_LBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_LEFTUP: //var priorCapture = WinAPI.Cursor.GetCapture(); //if (priorCapture == IntPtr.Zero) //{ // ("GetCapture Fail").LogWarn(); //} //else //{ // WinAPI.Cursor.ReleaseCapture(); //} wm = WinAPI.WM.LBUTTONUP; CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_LBUTTON) ^ WinAPI.Windows.MK.MK_LBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_RIGHTDOWN: //WinAPI.Cursor.SetCapture(ClientWindowHandle); wm = WinAPI.WM.RBUTTONDOWN; CurrentMK |= WinAPI.Windows.MK.MK_RBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_RIGHTUP: //var priorCapture = WinAPI.Cursor.GetCapture(); //if (priorCapture == IntPtr.Zero) //{ // ("GetCapture Fail").LogWarn(); //} //else //{ // WinAPI.Cursor.ReleaseCapture(); //} wm = WinAPI.WM.RBUTTONUP; CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_RBUTTON) ^ WinAPI.Windows.MK.MK_RBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_MIDDLEDOWN: wm = WinAPI.WM.MBUTTONDOWN; CurrentMK |= WinAPI.Windows.MK.MK_MBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_MIDDLEUP: wm = WinAPI.WM.MBUTTONUP; CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_MBUTTON) ^ WinAPI.Windows.MK.MK_MBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_XDOWN: wm = WinAPI.WM.XBUTTONDOWN; switch (WinAPI.MACROS.GET_XBUTTON_WPARAM(mouseInput.MouseData)) { case WinAPI.MACROS.XBUTTONS.XBUTTON1: CurrentMK |= WinAPI.Windows.MK.MK_XBUTTON1; break; case WinAPI.MACROS.XBUTTONS.XBUTTON2: CurrentMK |= WinAPI.Windows.MK.MK_XBUTTON2; break; } break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_XUP: wm = WinAPI.WM.XBUTTONUP; switch (WinAPI.MACROS.GET_XBUTTON_WPARAM(mouseInput.MouseData)) { case WinAPI.MACROS.XBUTTONS.XBUTTON1: CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_XBUTTON1) ^ WinAPI.Windows.MK.MK_XBUTTON1; break; case WinAPI.MACROS.XBUTTONS.XBUTTON2: CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_XBUTTON2) ^ WinAPI.Windows.MK.MK_XBUTTON2; break; } break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_WHEEL: case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_HWHEEL: wm = WinAPI.WM.MOUSEWHEEL; break; default: wm = mouseInput.WM; break; } WinAPI.Windows.PostMessage(ClientWindowHandle, wm, new UIntPtr(mouseInput.MouseData), new UIntPtr(clientRelativeCoordinates)); }
private void ForwardMouseEvent(MouseInput e, ClientBase clientBase) { MouseInput L_e = new MouseInput(); L_e.IsAbsolute = true; L_e.MouseData = e.MouseData; L_e.Point = L_e_Point; L_e.Time = e.Time; L_e.WindowDesktopHandle = clientBase.WindowDesktopHandle; L_e.WindowStationHandle = clientBase.WindowStationHandle; L_e.WindowHandle = clientBase.WindowHandle; L_e.WM = e.WM; clientBase.Dispatch(L_e); }
private static bool ShouldMulticastMouse(MouseInput e) { return ( ((Mubox.Configuration.MuboxConfigSection.Default.MouseMulticastMode == MouseMulticastModeType.Toggled) && WinAPI.IsToggled(WinAPI.VK.Capital)) || ((Mubox.Configuration.MuboxConfigSection.Default.MouseMulticastMode == MouseMulticastModeType.Pressed) && WinAPI.IsPressed(WinAPI.VK.Capital)) ); }
private static bool IsMouseInClientArea(MouseInput e, WinAPI.Windows.RECT calcRect) { return (calcRect.Left <= (int)e.Point.X && calcRect.Top <= (int)e.Point.Y) && (calcRect.Right >= (int)e.Point.X && calcRect.Bottom >= (int)e.Point.Y); }
private void TrackMousePositionClientRelative(MouseInput e, ClientBase activeClient, ClientBase[] clients) { ClientBase clientForCoordinateNormalization = activeClient; if (clientForCoordinateNormalization == null || !clientForCoordinateNormalization.IsLocalAddress || !IsMouseInClientArea(e, GetScreenRelativeClientRect(clientForCoordinateNormalization))) { // look for a local client which the mouse coordinates "belong to" and re-assign "clientForCoordinateNormalization" clientForCoordinateNormalization = null; foreach (var item in clients) { if (item.IsLocalAddress && IsMouseInClientArea(e, GetScreenRelativeClientRect(item))) { clientForCoordinateNormalization = item; break; } } } if (clientForCoordinateNormalization != null) { // track client-relative position this.L_e_Point = new Point( Math.Ceiling((double)(e.Point.X - clientForCoordinateNormalization.CachedScreenFromClientRect.Left) * (65536.0 / (double)clientForCoordinateNormalization.CachedScreenFromClientRect.Width)), Math.Ceiling((double)(e.Point.Y - clientForCoordinateNormalization.CachedScreenFromClientRect.Top) * (65536.0 / (double)clientForCoordinateNormalization.CachedScreenFromClientRect.Height))); } }
public override void Dispatch(MouseInput e) { #if DEBUG if (e.WM != WinAPI.WM.MOUSEMOVE) // reduce CPU cost of DEBUG logging { ("Dispatch(" + _displayName + ") " + Convert.ToString(e)).Log(); } #endif ServerTxPerformanceIncrement("MOUSE"); try { Send(e); base.Dispatch(e); } catch { Control.Network.Server.RemoveClient(this); } }