mirror of
https://github.com/evilC/AutoHotInterception.git
synced 2024-11-05 06:00:39 +00:00
commit
b86494316a
@ -55,18 +55,18 @@ namespace AutoHotInterception.Helpers
|
|||||||
return stroke;
|
return stroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Dictionary<int, ButtonState> ButtonStateLookupTable = new Dictionary<int, ButtonState>()
|
private static readonly Dictionary<int, ButtonState> StrokeFlagToButtonState = new Dictionary<int, ButtonState>()
|
||||||
{
|
{
|
||||||
{ 1, new ButtonState{Button = 0, State = 1} },
|
{ 1, new ButtonState{Button = 0, State = 1, Flag = 1} }, // LMB Press
|
||||||
{ 2, new ButtonState{Button = 0, State = 0} },
|
{ 2, new ButtonState{Button = 0, State = 0, Flag = 2} }, // LMB Release
|
||||||
{ 4, new ButtonState{Button = 1, State = 1} },
|
{ 4, new ButtonState{Button = 1, State = 1, Flag = 4} }, // RMB Press
|
||||||
{ 8, new ButtonState{Button = 1, State = 0} },
|
{ 8, new ButtonState{Button = 1, State = 0, Flag = 8} }, // RMB Release
|
||||||
{ 16, new ButtonState{Button = 2, State = 1} },
|
{ 16, new ButtonState{Button = 2, State = 1, Flag = 16} }, // MMB Press
|
||||||
{ 32, new ButtonState{Button = 2, State = 0} },
|
{ 32, new ButtonState{Button = 2, State = 0, Flag = 32} }, // MMB Release
|
||||||
{ 64, new ButtonState{Button = 3, State = 1} },
|
{ 64, new ButtonState{Button = 3, State = 1, Flag = 64} }, // XB1 Press
|
||||||
{ 128, new ButtonState{Button = 3, State = 0} },
|
{ 128, new ButtonState{Button = 3, State = 0, Flag = 128} }, // XB1 Release
|
||||||
{ 256, new ButtonState{Button = 4, State = 1} },
|
{ 256, new ButtonState{Button = 4, State = 1, Flag = 256} }, // XB2 Press
|
||||||
{ 512, new ButtonState{Button = 4, State = 0} },
|
{ 512, new ButtonState{Button = 4, State = 0, Flag = 512} } // XB2 Release
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ButtonState[] MouseStrokeToButtonStates(ManagedWrapper.Stroke stroke)
|
public static ButtonState[] MouseStrokeToButtonStates(ManagedWrapper.Stroke stroke)
|
||||||
@ -75,7 +75,7 @@ namespace AutoHotInterception.Helpers
|
|||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
var buttonStates = new List<ButtonState>();
|
var buttonStates = new List<ButtonState>();
|
||||||
foreach (var buttonState in ButtonStateLookupTable)
|
foreach (var buttonState in StrokeFlagToButtonState)
|
||||||
{
|
{
|
||||||
if (state < buttonState.Key) break;
|
if (state < buttonState.Key) break;
|
||||||
if ((state & buttonState.Key) != buttonState.Key) continue;
|
if ((state & buttonState.Key) != buttonState.Key) continue;
|
||||||
@ -91,7 +91,8 @@ namespace AutoHotInterception.Helpers
|
|||||||
new ButtonState
|
new ButtonState
|
||||||
{
|
{
|
||||||
Button = 5,
|
Button = 5,
|
||||||
State = (stroke.mouse.rolling < 0 ? -1 : 1)
|
State = (stroke.mouse.rolling < 0 ? -1 : 1),
|
||||||
|
Flag = 0x400
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -101,7 +102,8 @@ namespace AutoHotInterception.Helpers
|
|||||||
new ButtonState
|
new ButtonState
|
||||||
{
|
{
|
||||||
Button = 6,
|
Button = 6,
|
||||||
State = (stroke.mouse.rolling < 0 ? -1 : 1)
|
State = (stroke.mouse.rolling < 0 ? -1 : 1),
|
||||||
|
Flag = 0x800
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -165,6 +167,7 @@ namespace AutoHotInterception.Helpers
|
|||||||
{
|
{
|
||||||
public ushort Button { get; set; }
|
public ushort Button { get; set; }
|
||||||
public int State { get; set; }
|
public int State { get; set; }
|
||||||
|
public ushort Flag { get; set; } // Preserve original flag, so it can be removed from stroke
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KeyboardState
|
public class KeyboardState
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using AutoHotInterception.Helpers;
|
using AutoHotInterception.Helpers;
|
||||||
using static AutoHotInterception.Helpers.HelperFunctions;
|
using static AutoHotInterception.Helpers.HelperFunctions;
|
||||||
@ -601,79 +602,147 @@ namespace AutoHotInterception
|
|||||||
|
|
||||||
while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
|
while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
|
||||||
{
|
{
|
||||||
//Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}");
|
if (!isMonitoredMouse) continue;
|
||||||
var block = false;
|
|
||||||
if (isMonitoredMouse)
|
var moveRemoved = false;
|
||||||
|
var hasMove = false;
|
||||||
|
var x = stroke.mouse.x;
|
||||||
|
var y = stroke.mouse.y;
|
||||||
|
//Debug.WriteLine($"AHK| Stroke Seen. State = {stroke.mouse.state}, Flags = {stroke.mouse.flags}, x={x}, y={y}");
|
||||||
|
// Process Mouse Buttons
|
||||||
|
if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i))
|
||||||
{
|
{
|
||||||
if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i))
|
var btnStates = MouseStrokeToButtonStates(stroke);
|
||||||
|
foreach (var btnState in btnStates)
|
||||||
{
|
{
|
||||||
// Mouse Button
|
if (!_mouseButtonMappings[i].ContainsKey(btnState.Button)) continue;
|
||||||
//Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}");
|
|
||||||
var btnStates = MouseStrokeToButtonStates(stroke);
|
hasSubscription = true;
|
||||||
foreach (var btnState in btnStates)
|
var mapping = _mouseButtonMappings[i][btnState.Button];
|
||||||
|
|
||||||
|
var state = btnState;
|
||||||
|
|
||||||
|
if (mapping.Concurrent)
|
||||||
|
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State));
|
||||||
|
else if (_workerThreads.ContainsKey(i) &&
|
||||||
|
_workerThreads[i].ContainsKey(btnState.Button))
|
||||||
|
_workerThreads[i][btnState.Button]?.Actions
|
||||||
|
.Add(() => mapping.Callback(state.State));
|
||||||
|
if (mapping.Block)
|
||||||
{
|
{
|
||||||
if (_mouseButtonMappings[i].ContainsKey(btnState.Button))
|
// Remove the event for this button from the stroke, leaving other button events intact
|
||||||
|
stroke.mouse.state -= btnState.Flag;
|
||||||
|
// If we are removing a mouse wheel event, then set rolling to 0 if no mouse wheel event left
|
||||||
|
if (btnState.Flag == 0x400 || btnState.Flag == 0x800)
|
||||||
{
|
{
|
||||||
hasSubscription = true;
|
if ((stroke.mouse.state & 0x400) != 0x400 && (stroke.mouse.state & 0x800) != 0x800)
|
||||||
var mapping = _mouseButtonMappings[i][btnState.Button];
|
{
|
||||||
if (mapping.Block) block = true;
|
//Debug.WriteLine("AHK| Removing rolling flag from stroke");
|
||||||
|
stroke.mouse.rolling = 0;
|
||||||
var state = btnState;
|
}
|
||||||
|
|
||||||
if (mapping.Concurrent)
|
|
||||||
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State));
|
|
||||||
else if (_workerThreads.ContainsKey(i) &&
|
|
||||||
_workerThreads[i].ContainsKey(btnState.Button))
|
|
||||||
_workerThreads[i][btnState.Button]?.Actions
|
|
||||||
.Add(() => mapping.Callback(state.State));
|
|
||||||
}
|
}
|
||||||
|
//Debug.WriteLine($"AHK| Removing flag {btnState.Flag} from stoke, leaving state {stroke.mouse.state}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Debug.WriteLine($"AHK| Leaving flag {btnState.Flag} in stroke");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Console.WriteLine($"AHK| Mouse {i} seen - button {btnState.Button}, state: {stroke.mouse.state}, rolling: {stroke.mouse.rolling}");
|
|
||||||
}
|
|
||||||
else if ((stroke.mouse.flags & (ushort) ManagedWrapper.MouseFlag.MouseMoveAbsolute) ==
|
|
||||||
(ushort) ManagedWrapper.MouseFlag.MouseMoveAbsolute
|
|
||||||
&& _mouseMoveAbsoluteMappings.ContainsKey(i))
|
|
||||||
{
|
|
||||||
// Absolute Mouse Move
|
|
||||||
hasSubscription = true;
|
|
||||||
var mapping = _mouseMoveAbsoluteMappings[i];
|
|
||||||
if (mapping.Block) block = true;
|
|
||||||
|
|
||||||
var x = stroke.mouse.x;
|
|
||||||
var y = stroke.mouse.y;
|
|
||||||
if (mapping.Concurrent)
|
|
||||||
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
|
|
||||||
else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(7))
|
|
||||||
_workerThreads[i][7]?.Actions.Add(() => mapping.Callback(x, y));
|
|
||||||
}
|
|
||||||
else if ((stroke.mouse.flags & (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative) ==
|
|
||||||
(ushort) ManagedWrapper.MouseFlag.MouseMoveRelative
|
|
||||||
&& _mouseMoveRelativeMappings.ContainsKey(i))
|
|
||||||
{
|
|
||||||
// Relative Mouse Move
|
|
||||||
hasSubscription = true;
|
|
||||||
var mapping = _mouseMoveRelativeMappings[i];
|
|
||||||
if (mapping.Block) block = true;
|
|
||||||
|
|
||||||
var x = stroke.mouse.x;
|
|
||||||
var y = stroke.mouse.y;
|
|
||||||
if (mapping.Concurrent)
|
|
||||||
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
|
|
||||||
else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(8))
|
|
||||||
_workerThreads[i][8]?.Actions.Add(() => mapping.Callback(x, y));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this key had no subscriptions, but Context Mode is set for this mouse...
|
// Process Relative Mouse Move
|
||||||
// ... then set the Context before sending the button
|
if ((stroke.mouse.flags & (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative) == (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative)
|
||||||
if (!hasSubscription && hasContext) _contextCallbacks[i](1); // Set Context
|
{
|
||||||
if (!block) ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
|
if (x != 0 || y != 0)
|
||||||
// If we are processing Context Mode, then Unset the context variable after sending the button
|
{
|
||||||
if (!hasSubscription && hasContext) _contextCallbacks[i](0);
|
hasMove = true;
|
||||||
|
if (_mouseMoveRelativeMappings.ContainsKey(i))
|
||||||
|
{
|
||||||
|
var mapping = _mouseMoveRelativeMappings[i];
|
||||||
|
hasSubscription = true;
|
||||||
|
//var debugStr = $"AHK| Mouse stroke has relative move of {x}, {y}...";
|
||||||
|
|
||||||
|
if (mapping.Concurrent)
|
||||||
|
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
|
||||||
|
else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(8))
|
||||||
|
_workerThreads[i][8]?.Actions.Add(() => mapping.Callback(x, y));
|
||||||
|
if (mapping.Block)
|
||||||
|
{
|
||||||
|
moveRemoved = true;
|
||||||
|
//debugStr += "Blocking";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//debugStr += "Not Blocking";
|
||||||
|
}
|
||||||
|
//Debug.WriteLine(debugStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Process Absolute Mouse Move
|
||||||
|
else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) == (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute)
|
||||||
|
{
|
||||||
|
if (x != 0 || y != 0)
|
||||||
|
{
|
||||||
|
hasMove = true;
|
||||||
|
if (_mouseMoveAbsoluteMappings.ContainsKey(i))
|
||||||
|
{
|
||||||
|
var mapping = _mouseMoveAbsoluteMappings[i];
|
||||||
|
hasSubscription = true;
|
||||||
|
//var debugStr = $"AHK| Mouse stroke has absolute move of {x}, {y}...";
|
||||||
|
|
||||||
|
if (mapping.Concurrent)
|
||||||
|
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y));
|
||||||
|
else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(7))
|
||||||
|
_workerThreads[i][7]?.Actions.Add(() => mapping.Callback(x, y));
|
||||||
|
if (mapping.Block)
|
||||||
|
{
|
||||||
|
moveRemoved = true;
|
||||||
|
//debugStr += "Blocking";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//debugStr += "Not Blocking";
|
||||||
|
}
|
||||||
|
//Debug.WriteLine(debugStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward on the stroke if required
|
||||||
|
if (hasSubscription)
|
||||||
|
{
|
||||||
|
// Subscription mode
|
||||||
|
// If the stroke has a move that was not removed, OR it has remaining button events, then forward on the stroke
|
||||||
|
if ((hasMove && !moveRemoved) || stroke.mouse.state != 0)
|
||||||
|
{
|
||||||
|
//Debug.WriteLine($"AHK| Sending stroke. State = {stroke.mouse.state}. hasMove={hasMove}, moveRemoved={moveRemoved}");
|
||||||
|
ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Everything removed from stroke, do not forward
|
||||||
|
//Debug.WriteLine("AHK| Mouse stroke now empty, not forwarding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (hasContext)
|
||||||
|
{
|
||||||
|
// Context Mode - forward stroke with context wrapping
|
||||||
|
_contextCallbacks[i](1);
|
||||||
|
ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
|
||||||
|
_contextCallbacks[i](0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No subscription or context mode - forward on
|
||||||
|
//Debug.WriteLine($"AHK| Sending stroke. State = {stroke.mouse.state}. hasMove={hasMove}, moveRemoved={moveRemoved}");
|
||||||
|
ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
|
||||||
|
}
|
||||||
|
//Debug.WriteLine($"AHK| ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToDo: Can this sleep be removed? Will removing it consume a lot of CPU? It will certainly make updates only happen once every ~10ms, which is too slow for mice polling @ 1khz
|
||||||
Thread.Sleep(10);
|
Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -5,12 +5,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
- Add option to filter key presses and only show key releases
|
|
||||||
### Changed
|
### Changed
|
||||||
### Deprecated
|
### Deprecated
|
||||||
### Removed
|
### Removed
|
||||||
### Fixed
|
### Fixed
|
||||||
- GUI layout made more robust
|
|
||||||
|
## [0.4.3] - 2019-06-10 **EXPERIMENTAL TEST RELEASE**
|
||||||
|
- Fixed issue #39
|
||||||
|
Almost complete rewrite of mouse polling code
|
||||||
|
Multiple event types (Movement, mouse button events) supported per update ("stroke") of the mouse
|
||||||
|
It is now possible to block a button or movement, but leave unblocked events unblocked
|
||||||
|
Previously, a stroke was either blocked or not - if any one part of the stroke was blocked, it was all blocked
|
||||||
|
- [Monitor script] GUI layout made more robust
|
||||||
|
- [Monitor script] Add option to filter key presses and only show key releases
|
||||||
|
|
||||||
## [0.4.2] - 2019-06-08
|
## [0.4.2] - 2019-06-08
|
||||||
- Fixed issue #37
|
- Fixed issue #37
|
||||||
|
Loading…
Reference in New Issue
Block a user