From d6b2ac33aa6d5fd21c884f218c886c6fe256acfc Mon Sep 17 00:00:00 2001
From: Ac_K <Acoustik666@gmail.com>
Date: Wed, 23 Jun 2021 23:44:09 +0200
Subject: [PATCH] input: Fixes TouchPoint wrong attribute (#2390)

---
 .../Services/Hid/HidDevices/TouchDevice.cs    |  1 +
 .../Hid/HidDevices/Types/TouchPoint.cs        |  3 ++
 .../TouchScreen/TouchAttribute.cs             |  2 +-
 Ryujinx.Input/HLE/TouchScreenManager.cs       | 48 +++++++++++++++++--
 Ryujinx/Ui/MainWindow.cs                      | 14 ++++++
 Ryujinx/Ui/RendererWidgetBase.cs              | 35 +++-----------
 6 files changed, 71 insertions(+), 32 deletions(-)

diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
index 432a37e337..bb58ee517c 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
@@ -31,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
                     newState.Touches[i] = new TouchState
                     {
                         DeltaTime = newState.SamplingNumber,
+                        Attribute = pi.Attribute,
                         X = pi.X,
                         Y = pi.Y,
                         FingerId = (uint)i,
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
index d1172dd06b..457d2b0d01 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
@@ -1,7 +1,10 @@
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen;
+
 namespace Ryujinx.HLE.HOS.Services.Hid
 {
     public struct TouchPoint
     {
+        public TouchAttribute Attribute;
         public uint X;
         public uint Y;
         public uint DiameterX;
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs
index 8a8f9cc1e7..d2c5726a51 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs
@@ -3,7 +3,7 @@
 namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen
 {
     [Flags]
-    enum TouchAttribute : uint
+    public enum TouchAttribute : uint
     {
         None = 0,
         Start = 1 << 0,
diff --git a/Ryujinx.Input/HLE/TouchScreenManager.cs b/Ryujinx.Input/HLE/TouchScreenManager.cs
index ffa8eeacc5..579dcd7450 100644
--- a/Ryujinx.Input/HLE/TouchScreenManager.cs
+++ b/Ryujinx.Input/HLE/TouchScreenManager.cs
@@ -1,5 +1,6 @@
 using Ryujinx.HLE;
 using Ryujinx.HLE.HOS.Services.Hid;
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen;
 using System;
 
 namespace Ryujinx.Input.HLE
@@ -8,6 +9,7 @@ namespace Ryujinx.Input.HLE
     {
         private readonly IMouse _mouse;
         private Switch _device;
+        private bool _wasClicking;
 
         public TouchScreenManager(IMouse mouse)
         {
@@ -19,10 +21,35 @@ namespace Ryujinx.Input.HLE
             _device = device;
         }
 
-        public bool Update(bool isFocused, float aspectRatio = 0)
+        public bool Update(bool isFocused, bool isClicking = false, float aspectRatio = 0)
         {
-            if (!isFocused)
+            if (!isFocused || (!_wasClicking && !isClicking))
             {
+                // In case we lost focus, send the end touch.
+                if (_wasClicking && !isClicking)
+                {
+                    MouseStateSnapshot snapshot = IMouse.GetMouseStateSnapshot(_mouse);
+                    var touchPosition = IMouse.GetTouchPosition(snapshot.Position, _mouse.ClientSize, aspectRatio);
+
+                    TouchPoint currentPoint = new TouchPoint
+                    {
+                        Attribute = TouchAttribute.End,
+
+                        X = (uint)touchPosition.X,
+                        Y = (uint)touchPosition.Y,
+
+                        // Placeholder values till more data is acquired
+                        DiameterX = 10,
+                        DiameterY = 10,
+                        Angle = 90
+                    };
+
+                    _device.Hid.Touchscreen.Update(currentPoint);
+
+                }
+
+                _wasClicking = false;
+
                 _device.Hid.Touchscreen.Update();
 
                 return false;
@@ -30,11 +57,24 @@ namespace Ryujinx.Input.HLE
 
             if (aspectRatio > 0)
             {
-                var snapshot = IMouse.GetMouseStateSnapshot(_mouse);
+                MouseStateSnapshot snapshot = IMouse.GetMouseStateSnapshot(_mouse);
                 var touchPosition = IMouse.GetTouchPosition(snapshot.Position, _mouse.ClientSize, aspectRatio);
 
+                TouchAttribute attribute = TouchAttribute.None;
+
+                if (!_wasClicking && isClicking)
+                {
+                    attribute = TouchAttribute.Start;
+                }
+                else if (_wasClicking && !isClicking)
+                {
+                    attribute = TouchAttribute.End;
+                }
+
                 TouchPoint currentPoint = new TouchPoint
                 {
+                    Attribute = attribute,
+
                     X = (uint)touchPosition.X,
                     Y = (uint)touchPosition.Y,
 
@@ -46,6 +86,8 @@ namespace Ryujinx.Input.HLE
 
                 _device.Hid.Touchscreen.Update(currentPoint);
 
+                _wasClicking = isClicking;
+
                 return true;
             }
 
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index d0848012fb..50c5725f40 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -74,6 +74,8 @@ namespace Ryujinx.Ui
         public RendererWidgetBase RendererWidget;
         public InputManager InputManager;
 
+        public bool IsFocused;
+
         private static bool UseVulkan = false;
 
 #pragma warning disable CS0169, CS0649, IDE0044
@@ -157,6 +159,8 @@ namespace Ryujinx.Ui
 
             WindowStateEvent += WindowStateEvent_Changed;
             DeleteEvent      += Window_Close;
+            FocusInEvent     += MainWindow_FocusInEvent;
+            FocusOutEvent    += MainWindow_FocusOutEvent;
 
             _applicationLibrary.ApplicationAdded        += Application_Added;
             _applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
@@ -272,6 +276,16 @@ namespace Ryujinx.Ui
             _fullScreen.Label = args.Event.NewWindowState.HasFlag(Gdk.WindowState.Fullscreen) ? "Exit Fullscreen" : "Enter Fullscreen";
         }
 
+        private void MainWindow_FocusOutEvent(object o, FocusOutEventArgs args)
+        {
+            IsFocused = false;
+        }
+
+        private void MainWindow_FocusInEvent(object o, FocusInEventArgs args)
+        {
+            IsFocused = true;
+        }
+
         private void UpdateColumns()
         {
             foreach (TreeViewColumn column in _gameTable.Columns)
diff --git a/Ryujinx/Ui/RendererWidgetBase.cs b/Ryujinx/Ui/RendererWidgetBase.cs
index 4ba87a1b10..289b2dbf1a 100644
--- a/Ryujinx/Ui/RendererWidgetBase.cs
+++ b/Ryujinx/Ui/RendererWidgetBase.cs
@@ -37,7 +37,6 @@ namespace Ryujinx.Ui
 
         private bool _isActive;
         private bool _isStopped;
-        private bool _isFocused;
 
         private bool _toggleFullscreen;
         private bool _toggleDockedMode;
@@ -91,8 +90,6 @@ namespace Ryujinx.Ui
                           | EventMask.KeyPressMask
                           | EventMask.KeyReleaseMask));
 
-            Shown += Renderer_Shown;
-
             _exitEvent = new ManualResetEvent(false);
 
             _hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
@@ -124,16 +121,6 @@ namespace Ryujinx.Ui
             });
         }
 
-        private void Parent_FocusOutEvent(object o, Gtk.FocusOutEventArgs args)
-        {
-            _isFocused = false;
-        }
-
-        private void Parent_FocusInEvent(object o, Gtk.FocusInEventArgs args)
-        {
-            _isFocused = true;
-        }
-
         private void Renderer_Destroyed(object sender, EventArgs e)
         {
             ConfigurationState.Instance.HideCursorOnIdle.Event -= HideCursorStateChanged;
@@ -142,11 +129,6 @@ namespace Ryujinx.Ui
             Dispose();
         }
 
-        private void Renderer_Shown(object sender, EventArgs e)
-        {
-            _isFocused = ParentWindow.State.HasFlag(Gdk.WindowState.Focused);
-        }
-
         protected override bool OnMotionNotifyEvent(EventMotion evnt)
         {
             if (_hideCursorOnIdle)
@@ -341,10 +323,7 @@ namespace Ryujinx.Ui
 
             _isActive = true;
 
-            Gtk.Window parent = this.Toplevel as Gtk.Window;
-
-            parent.FocusInEvent += Parent_FocusInEvent;
-            parent.FocusOutEvent += Parent_FocusOutEvent;
+            Gtk.Window parent = Toplevel as Gtk.Window;
 
             Application.Invoke(delegate
             {
@@ -445,9 +424,9 @@ namespace Ryujinx.Ui
                 return false;
             }
 
-            if (_isFocused)
+            if ((Toplevel as MainWindow).IsFocused)
             {
-                Gtk.Application.Invoke(delegate
+                Application.Invoke(delegate
                 {
                     KeyboardStateSnapshot keyboard = _keyboardInterface.GetKeyboardStateSnapshot();
 
@@ -465,7 +444,7 @@ namespace Ryujinx.Ui
 
             NpadManager.Update();
 
-            if (_isFocused)
+            if ((Toplevel as MainWindow).IsFocused)
             {
                 KeyboardHotkeyState currentHotkeyState = GetHotkeyState();
 
@@ -481,10 +460,10 @@ namespace Ryujinx.Ui
             // Touchscreen
             bool hasTouch = false;
 
-            // Get screen touch position from left mouse click
-            if (_isFocused && (_inputManager.MouseDriver as GTK3MouseDriver).IsButtonPressed(MouseButton.Button1))
+            // Get screen touch position
+            if ((Toplevel as MainWindow).IsFocused)
             {
-                hasTouch = TouchScreenManager.Update(true, ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
+                hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as GTK3MouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat());
             }
 
             if (!hasTouch)