From 51e23ef201d24486bbd65706ca7525c697accbeb Mon Sep 17 00:00:00 2001 From: Lorf Date: Mon, 21 Oct 2024 18:43:24 +0200 Subject: [PATCH 1/3] Added some simulated mouse events to fix a focus change issue primarily noticed with text inputs --- .../GameServices/Input/Mouse/MouseHandler.cs | 65 +++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs b/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs index 6c3b60d36..c1ac1ba2a 100644 --- a/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs +++ b/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs @@ -1,6 +1,7 @@ using System; using System.Windows.Forms; using Blish_HUD.Controls; +using Blish_HUD.Controls.Extern; using Blish_HUD.Input.WinApi; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; @@ -45,6 +46,8 @@ private set { private bool _cursorIsVisible = true; + private bool _recentlyEnabled = false; + /// /// Indicates if the hardware mouse is currently visible. When false, /// this typically indicates that the user is rotating their camera or in action @@ -160,20 +163,74 @@ public void Update() { // Handle mouse events blocked by the mouse hook if (_mouseEvent != null) { - if (HandleHookedMouseEvent(_mouseEvent) && this.CursorIsVisible) { - GameService.Graphics.SpriteScreen.TriggerMouseInput(_mouseEvent.EventType, this.State); + if(_recentlyEnabled) { + _recentlyEnabled = false; + SimulateNonCapturePressedEvent(_mouseEvent); } + HandleMouseEvent(_mouseEvent); _mouseEvent = null; } } + /// + /// Meant to simulate missing parts of mouse events (LeftMouseButtonPressed and RightMouseButtonPressed) in case the mouse hook just got enabled. This was not an issue prior to a fix for issue #768 as e.g. the base Control just always operated with the release event. + /// Now that the event handling there requires a prime state setup by the respective pressed event this logic exists to simulate said event. This saves us from having to pass down a special case flag to all handlers and aims to keep behaviour consistent since + /// there will always be a press and release event and not sometimes just half of it. + /// + /// Current mouse event that we need to simulate the missing part for given its one of the 2 cases we even want to handle + private void SimulateNonCapturePressedEvent(MouseEventArgs mouseEvent) { + // no need to worry about PositionRaw as it will be the same as the simulated event + // no need to worry about CameraDragging as it will be the same as the simulated event + // ActiveControl is not changed by the mouse event so we also dont have to worry about that one either + + // need to modify the State but it's basically just a copy with changed mouse states + + // we don't necessarily have to check the previous mouse state here as an additional security as this can only be happening on the enable / disable chain right now + // -> the previous state may also be a dangling leftover + + if (_mouseEvent.EventType == MouseEventType.LeftMouseButtonReleased) { + var tmpState = this.State; + this.State = new MouseState(tmpState.X, + tmpState.Y, + tmpState.ScrollWheelValue, + Microsoft.Xna.Framework.Input.ButtonState.Pressed, + tmpState.MiddleButton, + tmpState.RightButton, + tmpState.XButton1, + tmpState.XButton2); + // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. + HandleMouseEvent(new MouseEventArgs(MouseEventType.LeftMouseButtonPressed, mouseEvent.PointX, mouseEvent.PointY, mouseEvent.MouseData, mouseEvent.Flags, mouseEvent.Time, mouseEvent.Extra)); + this.State = tmpState; + } else if (_mouseEvent.EventType == MouseEventType.RightMouseButtonReleased) { + var tmpState = this.State; + this.State = new MouseState(tmpState.X, + tmpState.Y, + tmpState.ScrollWheelValue, + tmpState.LeftButton, + tmpState.MiddleButton, + Microsoft.Xna.Framework.Input.ButtonState.Pressed, + tmpState.XButton1, + tmpState.XButton2); + // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. + HandleMouseEvent(new MouseEventArgs(MouseEventType.RightMouseButtonPressed, mouseEvent.PointX, mouseEvent.PointY, mouseEvent.MouseData, mouseEvent.Flags, mouseEvent.Time, mouseEvent.Extra)); + this.State = tmpState; + } + } + + private void HandleMouseEvent(MouseEventArgs mouseEvent) { + if (HandleHookedMouseEvent(mouseEvent) && this.CursorIsVisible) { + GameService.Graphics.SpriteScreen.TriggerMouseInput(mouseEvent.EventType, this.State); + } + } + public void OnEnable() { - /* NOOP */ + _recentlyEnabled = true; } public void OnDisable() { - /* NOOP */ + // shouldn't be needed even but can't hurt to tidy up a little + _recentlyEnabled = false; } public void UnsetActiveControl() { From 7c14b5d9450e7cb741815dceea1dc77a8c2dcb90 Mon Sep 17 00:00:00 2001 From: Lorf Date: Mon, 21 Oct 2024 18:57:13 +0200 Subject: [PATCH 2/3] Slight bit of commentary --- .../GameServices/Input/Mouse/MouseHandler.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs b/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs index c1ac1ba2a..3305f5244 100644 --- a/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs +++ b/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs @@ -1,7 +1,6 @@ using System; using System.Windows.Forms; using Blish_HUD.Controls; -using Blish_HUD.Controls.Extern; using Blish_HUD.Input.WinApi; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; @@ -174,20 +173,21 @@ public void Update() { } /// - /// Meant to simulate missing parts of mouse events (LeftMouseButtonPressed and RightMouseButtonPressed) in case the mouse hook just got enabled. This was not an issue prior to a fix for issue #768 as e.g. the base Control just always operated with the release event. - /// Now that the event handling there requires a prime state setup by the respective pressed event this logic exists to simulate said event. This saves us from having to pass down a special case flag to all handlers and aims to keep behaviour consistent since + /// Meant to simulate missing parts of mouse events (LeftMouseButtonPressed and RightMouseButtonPressed) in case the mouse hook just got enabled. This was not an "issue" prior to a fix for issue #768 as e.g. the base control just always operated with the release event. + /// Now that the event handling there requires a primed state setup by the respective pressed event this logic exists to simulate said event. This saves us from having to pass down a special case flag to the handlers and aims to keep behaviour consistent since /// there will always be a press and release event and not sometimes just half of it. /// /// Current mouse event that we need to simulate the missing part for given its one of the 2 cases we even want to handle private void SimulateNonCapturePressedEvent(MouseEventArgs mouseEvent) { + // What state keeping do we need to even mess with? (Considering public fields of this class accessed by other methods in the handler chain) // no need to worry about PositionRaw as it will be the same as the simulated event // no need to worry about CameraDragging as it will be the same as the simulated event - // ActiveControl is not changed by the mouse event so we also dont have to worry about that one either + // ActiveControl is not changed by the mouse event so we also dont have to worry about that one either (targets of the events may choose to alter this as necessary but that is normal behaviour then) - // need to modify the State but it's basically just a copy with changed mouse states + // need to modify the State but it's basically just a copy with changed mouse button pressed states // we don't necessarily have to check the previous mouse state here as an additional security as this can only be happening on the enable / disable chain right now - // -> the previous state may also be a dangling leftover + // -> the previous state may also be a dangling leftover so it should even be safer to ignore it if (_mouseEvent.EventType == MouseEventType.LeftMouseButtonReleased) { var tmpState = this.State; @@ -199,7 +199,7 @@ private void SimulateNonCapturePressedEvent(MouseEventArgs mouseEvent) { tmpState.RightButton, tmpState.XButton1, tmpState.XButton2); - // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. + // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. (both seem to always be 0 right now?) HandleMouseEvent(new MouseEventArgs(MouseEventType.LeftMouseButtonPressed, mouseEvent.PointX, mouseEvent.PointY, mouseEvent.MouseData, mouseEvent.Flags, mouseEvent.Time, mouseEvent.Extra)); this.State = tmpState; } else if (_mouseEvent.EventType == MouseEventType.RightMouseButtonReleased) { @@ -212,7 +212,7 @@ private void SimulateNonCapturePressedEvent(MouseEventArgs mouseEvent) { Microsoft.Xna.Framework.Input.ButtonState.Pressed, tmpState.XButton1, tmpState.XButton2); - // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. + // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. (both seem to always be 0 right now?) HandleMouseEvent(new MouseEventArgs(MouseEventType.RightMouseButtonPressed, mouseEvent.PointX, mouseEvent.PointY, mouseEvent.MouseData, mouseEvent.Flags, mouseEvent.Time, mouseEvent.Extra)); this.State = tmpState; } @@ -229,7 +229,7 @@ public void OnEnable() { } public void OnDisable() { - // shouldn't be needed even but can't hurt to tidy up a little + // shouldn't be needed but can't hurt to tidy up a little _recentlyEnabled = false; } From 75a2ced572b9846a135be7b8ad46179b494ace6d Mon Sep 17 00:00:00 2001 From: Lorf Date: Mon, 21 Oct 2024 19:04:17 +0200 Subject: [PATCH 3/3] Removed some dangling references instead of accessing the args --- Blish HUD/GameServices/Input/Mouse/MouseHandler.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs b/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs index 3305f5244..953cda3cc 100644 --- a/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs +++ b/Blish HUD/GameServices/Input/Mouse/MouseHandler.cs @@ -189,8 +189,8 @@ private void SimulateNonCapturePressedEvent(MouseEventArgs mouseEvent) { // we don't necessarily have to check the previous mouse state here as an additional security as this can only be happening on the enable / disable chain right now // -> the previous state may also be a dangling leftover so it should even be safer to ignore it - if (_mouseEvent.EventType == MouseEventType.LeftMouseButtonReleased) { - var tmpState = this.State; + var tmpState = this.State; + if (mouseEvent.EventType == MouseEventType.LeftMouseButtonReleased) { this.State = new MouseState(tmpState.X, tmpState.Y, tmpState.ScrollWheelValue, @@ -201,9 +201,7 @@ private void SimulateNonCapturePressedEvent(MouseEventArgs mouseEvent) { tmpState.XButton2); // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. (both seem to always be 0 right now?) HandleMouseEvent(new MouseEventArgs(MouseEventType.LeftMouseButtonPressed, mouseEvent.PointX, mouseEvent.PointY, mouseEvent.MouseData, mouseEvent.Flags, mouseEvent.Time, mouseEvent.Extra)); - this.State = tmpState; - } else if (_mouseEvent.EventType == MouseEventType.RightMouseButtonReleased) { - var tmpState = this.State; + } else if (mouseEvent.EventType == MouseEventType.RightMouseButtonReleased) { this.State = new MouseState(tmpState.X, tmpState.Y, tmpState.ScrollWheelValue, @@ -214,8 +212,8 @@ private void SimulateNonCapturePressedEvent(MouseEventArgs mouseEvent) { tmpState.XButton2); // currently unsure if the MouseData and Flags contained any additional information about the button state maybe requires some bitmagic .. (both seem to always be 0 right now?) HandleMouseEvent(new MouseEventArgs(MouseEventType.RightMouseButtonPressed, mouseEvent.PointX, mouseEvent.PointY, mouseEvent.MouseData, mouseEvent.Flags, mouseEvent.Time, mouseEvent.Extra)); - this.State = tmpState; } + this.State = tmpState; } private void HandleMouseEvent(MouseEventArgs mouseEvent) {