diff --git a/.gitignore b/.gitignore
index 426d76d..84c2f88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+.vscode
+
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
diff --git a/MapTP.App/InspectorWindow.xaml.cs b/MapTP.App/InspectorWindow.xaml.cs
index 9edb28a..e195913 100644
--- a/MapTP.App/InspectorWindow.xaml.cs
+++ b/MapTP.App/InspectorWindow.xaml.cs
@@ -31,23 +31,23 @@ public partial class InspectorWindow : Window
public _TriggerEvent MainWindow_Start;
public _TriggerEvent MainWindow_Turtle;
- private readonly int X,Y, eX, eY;
+ private readonly int X, Y, eX, eY;
public InspectorWindow(int X, int Y, int eX, int eY)
{
InitializeComponent();
- this.X= X;
- this.Y= Y;
- this.eX= eX;
- this.eY= eY;
+ this.X = X;
+ this.Y = Y;
+ this.eX = eX;
+ this.eY = eY;
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
- this.LocationChanged+= OnTransformChanged;
+ this.LocationChanged += OnTransformChanged;
this.SizeChanged += OnTransformChanged;
- this.DpiRatio=ScreenManager.GetDpiRatio(this);
+ this.DpiRatio = ScreenManager.GetDpiRatio(this);
this.Loaded += OnLoaded;
}
@@ -67,12 +67,14 @@ private void OnTransformChanged(object sender, EventArgs e)
var y = (int)(this.Top * DpiRatio);
var ex = (int)((this.Left + this.width) * DpiRatio);
var ey = (int)((this.Top + this.height) * DpiRatio);
- if (x >= 0 && y >= 0 && ex <= ScreenManager.GetScreenWidth() && ey <= ScreenManager.GetScreenHeight()) {
- TitleBar.Background = new SolidColorBrush(Color.FromArgb(0x33,0xff,0xff,0xff));
- SendScreenArea(x, y, ex, ey);
+ if (x >= 0 && y >= 0 && ex <= ScreenManager.GetScreenWidth() && ey <= ScreenManager.GetScreenHeight())
+ {
+ TitleBar.Background = new SolidColorBrush(Color.FromArgb(0x33, 0xff, 0xff, 0xff));
+ SendScreenArea(x, y, ex, ey);
}
- else {
- TitleBar.Background = new SolidColorBrush(Color.FromArgb(0x33,0xff,0x00,0x00));
+ else
+ {
+ TitleBar.Background = new SolidColorBrush(Color.FromArgb(0x33, 0xff, 0x00, 0x00));
}
}
@@ -102,8 +104,8 @@ private void StartButtonClick(object sender, RoutedEventArgs e)
{
MainWindow_Start(sender, e);
}
- this.StopButton.Visibility=Visibility.Visible;
- this.StartButton.Visibility=Visibility.Collapsed;
+ this.StopButton.Visibility = Visibility.Visible;
+ this.StartButton.Visibility = Visibility.Collapsed;
}
private void StopButtonClick(object sender, RoutedEventArgs e)
@@ -112,8 +114,8 @@ private void StopButtonClick(object sender, RoutedEventArgs e)
{
MainWindow_Stop(sender, e);
}
- this.StopButton.Visibility=Visibility.Collapsed;
- this.StartButton.Visibility=Visibility.Visible;
+ this.StopButton.Visibility = Visibility.Collapsed;
+ this.StartButton.Visibility = Visibility.Visible;
}
}
diff --git a/MapTP.App/MainWindow.xaml b/MapTP.App/MainWindow.xaml
index c4112aa..36e9cf7 100644
--- a/MapTP.App/MainWindow.xaml
+++ b/MapTP.App/MainWindow.xaml
@@ -101,6 +101,7 @@
+
@@ -114,6 +115,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MapTP.App/MainWindow.xaml.cs b/MapTP.App/MainWindow.xaml.cs
index c677f2f..3d43189 100644
--- a/MapTP.App/MainWindow.xaml.cs
+++ b/MapTP.App/MainWindow.xaml.cs
@@ -155,22 +155,23 @@ private void TrayCBClick(object sender, RoutedEventArgs e)
}
}
- private void TrayShowWindowClick(object sender, RoutedEventArgs e) {
+ private void TrayShowWindowClick(object sender, RoutedEventArgs e)
+ {
TrayShowMenuItem.IsEnabled = false;
- this.Visibility= Visibility.Visible;
+ this.Visibility = Visibility.Visible;
this.ShowInTaskbar = true;
}
private void TurtleCBClick(object sender, RoutedEventArgs e)
{
- this.turtle=TurtleCB.IsChecked.Value;
+ this.turtle = TurtleCB.IsChecked.Value;
}
private void InspectorButtonClick(object sender, RoutedEventArgs e)
{
if (started) StopButtonClick(new object(), new RoutedEventArgs());
- var w= new InspectorWindow(scsx, scsy, scex, scey);
-
+ var w = new InspectorWindow(scsx, scsy, scex, scey);
+
w.SendScreenArea = ReceiveScreenArea;
w.MainWindow_Start = StartButtonClick;
w.MainWindow_Stop = StopButtonClick;
@@ -199,7 +200,7 @@ private void SuggestButtonClick(object sender, RoutedEventArgs e)
{
Tpey.Text = TouchpadSizeY.ToString();
var width = ((int)Math.Floor((double)TouchpadSizeY / ScreenSizeY * ScreenSizeX));
- var margin=(TouchpadSizeX - width)/2;
+ var margin = (TouchpadSizeX - width) / 2;
Tpsx.Text = margin.ToString();
Tpex.Text = (width + margin).ToString();
}
@@ -224,8 +225,8 @@ private void OnMinButtonClick(object sender, RoutedEventArgs e)
this.Visibility = Visibility.Hidden;
this.ShowInTaskbar = false;
TrayShowMenuItem.IsEnabled = true;
- new ToastContentBuilder()
- .AddText("MapTP is hidden to the taskbar tray!").Show();
+ new ToastContentBuilder()
+ .AddText("MapTP is hidden to the taskbar tray!").Show();
}
else WindowState = WindowState.Minimized;
}
@@ -234,7 +235,7 @@ private void OnCloseButtonClick(object sender, RoutedEventArgs e)
{
if (HideCB.IsChecked.Value)
{
- var r=MessageBox.Show("Are you sure to close MapTP?\n(use minimize to hide MapTP into tray icon)", "Closing MapTP", MessageBoxButton.YesNo, MessageBoxImage.Question);
+ var r = MessageBox.Show("Are you sure to close MapTP?\n(use minimize to hide MapTP into tray icon)", "Closing MapTP", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (r != MessageBoxResult.Yes) return;
}
Close();
@@ -459,6 +460,8 @@ private void InitConfig()
{
ConfigXmlSerializer.Serialize(writer, config);
}
+ // load defaults into UI
+ LoadSensitivityFromConfig();
calibrated = false;
}
else
@@ -487,12 +490,14 @@ private void InitConfig()
Scex.Text = config.scex.ToString();
Scey.Text = config.scey.ToString();
TurtleCB.IsChecked = config.Turtle;
- turtle=config.Turtle;
+ turtle = config.Turtle;
TrayCB.IsChecked = config.Tray;
HideCB.IsChecked = config.HideToTray;
ReceiveTouchpadSize(config.TouchpadSizeX, config.TouchpadSizeY);
ConfigScreenMapUpdate(config);
ConfigTouchpadMapUpdate(config);
+ // Load sensitivity UI/values
+ LoadSensitivityFromConfig();
}
}
@@ -550,6 +555,9 @@ private void SaveConfig()
config.Turtle = TurtleCB.IsChecked.Value;
config.Tray = TrayCB.IsChecked.Value;
config.HideToTray = HideCB.IsChecked.Value;
+ config.TapTimeMs = TapDurationThresholdMs;
+ config.TapMoveXAbs = TapMovementThresholdXAbs;
+ config.TapMoveYAbs = TapMovementThresholdYAbs;
using (StreamWriter writer = new StreamWriter(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\cn.enita.MapTP\\config.xml"))
{
@@ -564,7 +572,54 @@ private void OnWindowCloses(object sender, System.ComponentModel.CancelEventArgs
return;
}
+ // Tap/Drag detection state (improves separating discrete taps from drags)
private bool lastTip;
+ private DateTime fingerDownTime;
+ private int fingerStartAbsX, fingerStartAbsY; // starting absolute (0..65535) mapped coordinates
+ private bool mouseDownSent; // whether we already issued a real left down (drag scenario)
+ private int TapDurationThresholdMs = 180; // max duration to still count as a tap before auto-convert to drag
+ private int TapMovementThresholdXAbs = 600; // movement threshold in absolute coordinate units (~2% of65535 width)
+ private int TapMovementThresholdYAbs = 600; // movement threshold in absolute coordinate units (~2% of65535 width)
+
+ // Allow user to apply sensitivity changes from UI
+ private void OnApplySensitivityClick(object sender, RoutedEventArgs e)
+ {
+ var tapTimeBox = this.FindName("TapTimeBox") as System.Windows.Controls.TextBox;
+ var tapMoveXBox = this.FindName("TapMoveXBox") as System.Windows.Controls.TextBox;
+ var tapMoveYBox = this.FindName("TapMoveYBox") as System.Windows.Controls.TextBox;
+
+ if (tapTimeBox != null && int.TryParse(tapTimeBox.Text, out var t))
+ TapDurationThresholdMs = Math.Max(50, Math.Min(800, t));
+ if (tapMoveXBox != null && int.TryParse(tapMoveXBox.Text, out var mx))
+ TapMovementThresholdXAbs = Math.Max(50, Math.Min(8000, mx));
+ if (tapMoveYBox != null && int.TryParse(tapMoveYBox.Text, out var my))
+ TapMovementThresholdYAbs = Math.Max(50, Math.Min(8000, my));
+
+ if (config != null)
+ {
+ config.TapTimeMs = TapDurationThresholdMs;
+ config.TapMoveXAbs = TapMovementThresholdXAbs;
+ config.TapMoveYAbs = TapMovementThresholdYAbs;
+ SaveConfig();
+ }
+ }
+
+ // Load sensitivity values from config into fields and UI
+ private void LoadSensitivityFromConfig()
+ {
+ if (config == null) return;
+ TapDurationThresholdMs = config.TapTimeMs <= 0 ? 180 : config.TapTimeMs;
+ TapMovementThresholdXAbs = config.TapMoveXAbs <= 0 ? 600 : config.TapMoveXAbs;
+ TapMovementThresholdYAbs = config.TapMoveYAbs <= 0 ? 600 : config.TapMoveYAbs;
+
+ var tapTimeBox = this.FindName("TapTimeBox") as System.Windows.Controls.TextBox;
+ var tapMoveXBox = this.FindName("TapMoveXBox") as System.Windows.Controls.TextBox;
+ var tapMoveYBox = this.FindName("TapMoveYBox") as System.Windows.Controls.TextBox;
+
+ if (tapTimeBox != null) tapTimeBox.Text = TapDurationThresholdMs.ToString();
+ if (tapMoveXBox != null) tapMoveXBox.Text = TapMovementThresholdXAbs.ToString();
+ if (tapMoveYBox != null) tapMoveYBox.Text = TapMovementThresholdYAbs.ToString();
+ }
///
/// This method is for processing touchpad inputs
@@ -586,38 +641,73 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b
{
foreach (var x in digitizerData.Contacts)
{
- if (x.Identifier == 0) // limiting ContactId(Identifier) to 0 is to read the first finger
+ if (x.Identifier == 0) // limiting ContactId(Identifier) to0 is to read the first finger
{
- var curTip = x.IsButtonDown.Value;
+ var curTip = x.IsButtonDown.Value; // finger touching surface
if (started)
{
try
{
int X, Y;
X = (tpsx <= x.X ?
- (tpex >= x.X ?
- (int)Math.Floor((((decimal)(x.X - tpsx) / tpgx * scgx) + scsx) / ScreenSizeX * 65535)
- : (int)Math.Floor((decimal)scex / ScreenSizeX * 65535))
+ (tpex >= x.X ?
+ (int)Math.Floor((((decimal)(x.X - tpsx) / tpgx * scgx) + scsx) / ScreenSizeX * 65535)
+ : (int)Math.Floor((decimal)scex / ScreenSizeX * 65535))
: (int)Math.Floor((decimal)scsx / ScreenSizeX * 65535));
Y = (tpsy <= x.Y ?
- (tpey >= x.Y ?
- (int)Math.Floor((((decimal)(x.Y - tpsy) / tpgy * scgy) + scsy) / ScreenSizeY * 65535)
- : (int)Math.Floor((decimal)scey / ScreenSizeY * 65535))
+ (tpey >= x.Y ?
+ (int)Math.Floor((((decimal)(x.Y - tpsy) / tpgy * scgy) + scsy) / ScreenSizeY * 65535)
+ : (int)Math.Floor((decimal)scey / ScreenSizeY * 65535))
: (int)Math.Floor((decimal)scsy / ScreenSizeY * 65535));
+
+ // Always move pointer (for visual feedback)
mouseProcessor.MoveCursor(X, Y);
+
+ // Enhanced tap vs drag logic only when turtle mode is enabled (click simulation enabled)
if (turtle)
{
- if (lastTip != curTip)
+ if (!lastTip && curTip)
+ {
+ // Finger just touched: start possible tap
+ fingerDownTime = DateTime.UtcNow;
+ fingerStartAbsX = X;
+ fingerStartAbsY = Y;
+ mouseDownSent = false; // not yet a drag
+ }
+ else if (lastTip && curTip)
+ {
+ // Finger is still down; decide if we should convert to drag
+ if (!mouseDownSent)
+ {
+ double elapsed = (DateTime.UtcNow - fingerDownTime).TotalMilliseconds;
+ int deltaAbsX = Math.Abs(X - fingerStartAbsX);
+ int deltaAbsY = Math.Abs(Y - fingerStartAbsY);
+ if (elapsed > TapDurationThresholdMs ||
+ deltaAbsX > TapMovementThresholdXAbs ||
+ deltaAbsY > TapMovementThresholdYAbs)
+ {
+ // Became a drag: send down now
+ mouseProcessor.MouseDown();
+ mouseDownSent = true;
+ }
+ }
+ }
+ else if (lastTip && !curTip)
{
- if (curTip)
+ // Finger lifted
+ if (!mouseDownSent)
{
+ // Treat as discrete tap: emit down+up quickly
mouseProcessor.MouseDown();
+ mouseProcessor.MouseUp();
}
else
{
+ // End drag
mouseProcessor.MouseUp();
}
- }
+ mouseDownSent = false;
+ }
}
}
catch (Exception e)
@@ -625,18 +715,9 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b
HandyControl.Controls.MessageBox.Show(e.ToString());
}
}
- lastTip = curTip;
+ lastTip = curTip; // update last state after processing
}
}
- /*
- foreach (TouchpadContact x in Touchpad.Handler.ParseInput(lParam))
- {
- if (x.ContactId == 0) // limiting ContactId to 0 is to read the first finger
- {
- InputX = x.X;
- InputY = x.Y;
- }
- }*/
}
break;
@@ -680,7 +761,16 @@ public class Config
[XmlElement("turtle")]
public bool Turtle;
- public Config(int scsx, int tpsx, int scsy, int tpsy, int scex, int tpex, int tpey, int scey, int touchpadSizeX, int touchpadSizeY, bool tray, bool hideToTray, bool turtle)
+ // New: tap/drag sensitivity options
+ [XmlElement("tap-time-ms")]
+ public int TapTimeMs;
+ [XmlElement("tap-move-x-abs")]
+ public int TapMoveXAbs;
+ [XmlElement("tap-move-y-abs")]
+ public int TapMoveYAbs;
+
+ public Config(int scsx, int tpsx, int scsy, int tpsy, int scex, int tpex, int tpey, int scey, int touchpadSizeX, int touchpadSizeY, bool tray, bool hideToTray, bool turtle,
+ int tapTimeMs, int tapMoveXAbs, int tapMoveYAbs)
{
this.scsx = scsx;
this.tpsx = tpsx;
@@ -695,8 +785,11 @@ public Config(int scsx, int tpsx, int scsy, int tpsy, int scex, int tpex, int tp
Tray = tray;
HideToTray = hideToTray;
Turtle = turtle;
+ TapTimeMs = tapTimeMs;
+ TapMoveXAbs = tapMoveXAbs;
+ TapMoveYAbs = tapMoveYAbs;
}
- public Config() : this(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, true, false)
+ public Config() : this(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, true, false, 180, 600, 600)
{ }
}
}
\ No newline at end of file
diff --git a/MapTP.App/MouseProcessor.cs b/MapTP.App/MouseProcessor.cs
index 611aa06..dd528ba 100644
--- a/MapTP.App/MouseProcessor.cs
+++ b/MapTP.App/MouseProcessor.cs
@@ -63,29 +63,88 @@ struct MOUSEINPUT
[DllImport("user32.dll")]
static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
- //[DllImport("user32.dll")]
- //private static extern int SetCursorPos(int x, int y);
+ // Useful constants for readability
+ const uint INPUT_MOUSE = 0;
+ const uint MOUSEEVENTF_MOVE = 0x0001;
+ const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
+ const uint MOUSEEVENTF_LEFTUP = 0x0004;
+ const uint MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000; // May be ignored on older Windows
+ const uint MOUSEEVENTF_VIRTUALDESK = 0x4000;
+ const uint MOUSEEVENTF_ABSOLUTE = 0x8000;
#endregion
+
+ // Simple smoothing to improve perceived pointer stability
+ private int _lastRawX = -1;
+ private int _lastRawY = -1;
+ private int _lastOutX = -1;
+ private int _lastOutY = -1;
+
+ // Public knobs (can be wired to settings later if needed)
+ public bool EnableSmoothing { get; set; } = true;
+
+ // range: 0..1. closer to 0 -> smoother/slower, closer to 1 -> snappier
+ public double SmoothFactor { get; set; } = 0.35;
+
+ // Deadzone in normalized absolute units (0..65535). Small deltas are ignored.
+ public int Deadzone { get; set; } = 1;
+
public void MoveCursor(int x, int y)
{
- //SetCursorPos(x, y);
+ // Remember raw (requested) position
+ int rawX = x;
+ int rawY = y;
+
+ // Initialize last values on first call
+ if (_lastOutX < 0 || _lastOutY < 0)
+ {
+ _lastRawX = rawX;
+ _lastRawY = rawY;
+ _lastOutX = rawX;
+ _lastOutY = rawY;
+ }
+
+ // Early out if movement is within deadzone (reduces jitter)
+ if (Math.Abs(rawX - _lastRawX) <= Deadzone && Math.Abs(rawY - _lastRawY) <= Deadzone)
+ {
+ _lastRawX = rawX;
+ _lastRawY = rawY;
+ return;
+ }
+
+ int outX = rawX;
+ int outY = rawY;
+
+ if (EnableSmoothing)
+ {
+ // Exponential moving average
+ double a = Math.Min(1.0, Math.Max(0.0, SmoothFactor));
+ outX = (int)Math.Round(_lastOutX + (rawX - _lastOutX) * a);
+ outY = (int)Math.Round(_lastOutY + (rawY - _lastOutY) * a);
+ }
+
INPUT[] _input = new INPUT[1];
_input[0] = new INPUT
{
- type = 0, // INPUT_MOUSE
+ type = INPUT_MOUSE,
mkhi = new MOUSEKEYBDHARDWAREINPUT
{
mi = new MOUSEINPUT
{
- dx = x,
- dy = y,
+ dx = outX,
+ dy = outY,
mouseData = 0,
- dwFlags = 0x8000 | 0x0001 | 0x4000, // MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVEMENT | MOUSEEVENTF_VIRTUALDESK
+ // Absolute movement across the virtual desktop; avoid OS coalescing if possible
+ dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK | MOUSEEVENTF_MOVE_NOCOALESCE,
time = 0 // Windows will provide this
}
}
};
SendInput((uint)1, _input, Marshal.SizeOf(typeof(INPUT)));
+
+ _lastRawX = rawX;
+ _lastRawY = rawY;
+ _lastOutX = outX;
+ _lastOutY = outY;
return;
}
@@ -95,7 +154,7 @@ public void MouseDown()
INPUT[] _input = new INPUT[1];
_input[0] = new INPUT
{
- type = 0, // INPUT_MOUSE
+ type = INPUT_MOUSE, // INPUT_MOUSE
mkhi = new MOUSEKEYBDHARDWAREINPUT
{
mi = new MOUSEINPUT
@@ -103,7 +162,7 @@ public void MouseDown()
dx = 0,
dy = 0,
mouseData = 0,
- dwFlags = 0x0002, // MOUSEEVENTF_LEFTDOWN
+ dwFlags = MOUSEEVENTF_LEFTDOWN, // MOUSEEVENTF_LEFTDOWN
time = 0 // Windows will provide this
}
}
@@ -117,7 +176,7 @@ public void MouseUp()
INPUT[] _input = new INPUT[1];
_input[0] = new INPUT
{
- type = 0, // INPUT_MOUSE
+ type = INPUT_MOUSE, // INPUT_MOUSE
mkhi = new MOUSEKEYBDHARDWAREINPUT
{
mi = new MOUSEINPUT
@@ -125,7 +184,7 @@ public void MouseUp()
dx = 0,
dy = 0,
mouseData = 0,
- dwFlags = 0x0004, // MOUSEEVENTF_LEFTUP
+ dwFlags = MOUSEEVENTF_LEFTUP, // MOUSEEVENTF_LEFTUP
time = 0 // Windows will provide this
}
}