-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMouse.cs
More file actions
312 lines (279 loc) · 10.5 KB
/
Mouse.cs
File metadata and controls
312 lines (279 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
using System.Text.Json;
using Gma.System.MouseKeyHook;
using System.Runtime.InteropServices;
namespace WinControlCenter
{
public interface IMouseApi : ISystemApi
{
bool IsEnabled { get; set; }
event EventHandler<object> StateChanged;
Task<object> GetStateAsync();
Task MoveMouseAsync(int deltaX, int deltaY);
Task ClickMouseAsync(string button);
Task ScrollMouseAsync(int delta);
}
public class MouseState
{
public int X { get; set; }
public int Y { get; set; }
public bool IsEnabled { get; set; }
public double Sensitivity { get; set; }
public double ScrollSensitivity { get; set; }
public double AccelerationFactor { get; set; }
public double MaxAcceleration { get; set; }
}
/// <summary>
/// Default mouse settings used throughout the application
/// </summary>
public static class MouseDefaults
{
public const double Sensitivity = 1.2;
public const double ScrollSensitivity = 4.0;
public const double AccelerationFactor = 1.5;
public const double MaxAcceleration = 3.0;
}
public class MouseFeatureHandler : WebSocketFeatureHandler
{
private readonly IMouseApi _mouseApi;
private readonly string _featureType = "mouse";
protected override string GetStateMessageType => $"get{_featureType}";
protected override string SetStateMessageType => _featureType;
public MouseFeatureHandler(WebServer webServer, IMouseApi mouseApi)
: base(webServer, "mouse")
{
_mouseApi = mouseApi;
_mouseApi.StateChanged += OnMouseStateChanged;
}
private void OnMouseStateChanged(object sender, object state) => _ = BroadcastStateAsync();
protected override Task<object> GetStateAsync() => _mouseApi.GetStateAsync();
protected override async Task HandleSetStateAsync(JsonElement valueElement)
{
if (valueElement.TryGetProperty("move", out var moveElement))
{
var deltaX = moveElement.GetProperty("x").GetInt32();
var deltaY = moveElement.GetProperty("y").GetInt32();
await _mouseApi.MoveMouseAsync(deltaX, deltaY);
}
if (valueElement.TryGetProperty("click", out var clickElement))
{
var button = clickElement.GetString();
await _mouseApi.ClickMouseAsync(button);
}
if (valueElement.TryGetProperty("scroll", out var scrollElement))
{
var delta = scrollElement.GetInt32();
await _mouseApi.ScrollMouseAsync(delta);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_mouseApi.StateChanged -= OnMouseStateChanged;
_mouseApi.Dispose();
}
base.Dispose(disposing);
}
}
public class MouseKeyHookManager : IMouseApi
{
private IKeyboardMouseEvents _globalHook;
private bool _isEnabled = true;
private readonly object _stateLock = new object();
private MouseState _currentState;
[DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
private const int MOUSEEVENTF_WHEEL = 0x0800;
public bool IsEnabled
{
get => _isEnabled;
set
{
if (_isEnabled != value)
{
_isEnabled = value;
if (_isEnabled)
{
_globalHook = Hook.GlobalEvents();
}
else
{
_globalHook?.Dispose();
_globalHook = null;
}
UpdateState();
}
}
}
public event EventHandler<object> StateChanged;
public MouseKeyHookManager()
{
_globalHook = Hook.GlobalEvents();
_currentState = new MouseState
{
X = 0,
Y = 0,
IsEnabled = true,
Sensitivity = MouseDefaults.Sensitivity,
ScrollSensitivity = MouseDefaults.ScrollSensitivity,
AccelerationFactor = MouseDefaults.AccelerationFactor,
MaxAcceleration = MouseDefaults.MaxAcceleration
};
InitializeMouseState();
}
private void InitializeMouseState()
{
try
{
var currentPosition = System.Windows.Forms.Cursor.Position;
_currentState = new MouseState
{
X = currentPosition.X,
Y = currentPosition.Y,
IsEnabled = true,
Sensitivity = MouseDefaults.Sensitivity,
ScrollSensitivity = MouseDefaults.ScrollSensitivity,
AccelerationFactor = MouseDefaults.AccelerationFactor,
MaxAcceleration = MouseDefaults.MaxAcceleration
};
UpdateState();
}
catch (Exception ex)
{
Logger.Log($"Failed to initialize mouse state: {ex.Message}");
}
}
private void UpdateState()
{
lock (_stateLock)
{
var currentPosition = System.Windows.Forms.Cursor.Position;
_currentState.X = currentPosition.X;
_currentState.Y = currentPosition.Y;
StateChanged?.Invoke(this, _currentState);
}
}
public Task<object> GetStateAsync()
{
try
{
return Task.FromResult<object>(_currentState);
}
catch (Exception ex)
{
Logger.Log($"Failed to get mouse state: {ex.Message}");
return Task.FromResult<object>(new MouseState());
}
}
public void UpdateSensitivitySettings(double sensitivity, double scrollSensitivity, double accelerationFactor, double maxAcceleration)
{
lock (_stateLock)
{
_currentState.Sensitivity = sensitivity;
_currentState.ScrollSensitivity = scrollSensitivity;
_currentState.AccelerationFactor = accelerationFactor;
_currentState.MaxAcceleration = maxAcceleration;
StateChanged?.Invoke(this, _currentState);
}
}
public MouseState GetMouseState()
{
try
{
var state = (MouseState)GetStateAsync().Result;
Logger.Log($"Getting mouse state: Sensitivity={state.Sensitivity}, ScrollSensitivity={state.ScrollSensitivity}, AccelerationFactor={state.AccelerationFactor}, MaxAcceleration={state.MaxAcceleration}");
return state;
}
catch (Exception ex)
{
Logger.Log($"Error getting mouse state: {ex.Message}");
return new MouseState
{
IsEnabled = false,
Sensitivity = MouseDefaults.Sensitivity,
ScrollSensitivity = MouseDefaults.ScrollSensitivity,
AccelerationFactor = MouseDefaults.AccelerationFactor,
MaxAcceleration = MouseDefaults.MaxAcceleration
};
}
}
public Task MoveMouseAsync(int deltaX, int deltaY)
{
if (_isEnabled)
{
var currentPosition = System.Windows.Forms.Cursor.Position;
var speed = Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
var acceleration = Math.Min(
1 + (speed / 50) * (_currentState.AccelerationFactor - 1),
_currentState.MaxAcceleration
);
var adjustedDeltaX = (int)(deltaX * _currentState.Sensitivity * acceleration);
var adjustedDeltaY = (int)(deltaY * _currentState.Sensitivity * acceleration);
System.Windows.Forms.Cursor.Position = new System.Drawing.Point(
currentPosition.X + adjustedDeltaX,
currentPosition.Y + adjustedDeltaY
);
}
return Task.CompletedTask;
}
public Task ClickMouseAsync(string button)
{
if (!_isEnabled) return Task.CompletedTask;
try
{
switch (button.ToLower())
{
case "left":
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Thread.Sleep(50); // Increased delay to prevent double-click interpretation
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
break;
case "right":
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
Thread.Sleep(50); // Increased delay for right click as well
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
break;
}
}
catch (Exception ex)
{
Logger.Log($"Error performing mouse click: {ex.Message}");
}
return Task.CompletedTask;
}
public Task ScrollMouseAsync(int delta)
{
if (!_isEnabled) return Task.CompletedTask;
try
{
var adjustedDelta = (int)(delta * _currentState.ScrollSensitivity);
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, adjustedDelta, 0);
}
catch (Exception ex)
{
Logger.Log($"Error performing mouse scroll: {ex.Message}");
}
return Task.CompletedTask;
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_globalHook?.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public static class MouseFactory
{
public static IMouseApi CreateMouseApi() => new MouseKeyHookManager();
}
}