mirror of
https://github.com/evilC/AutoHotInterception.git
synced 2024-11-16 21:25:46 +00:00
Manager can subscribe to all keyboard keys
This commit is contained in:
parent
9b558f98c2
commit
3577f5a920
@ -17,9 +17,12 @@ namespace AutoHotInterception
|
|||||||
// Used by IsMonitoredDevice, which is handed to Interception as a "Predicate".
|
// Used by IsMonitoredDevice, which is handed to Interception as a "Predicate".
|
||||||
private readonly ConcurrentDictionary<int, bool> _filteredDevices = new ConcurrentDictionary<int, bool>();
|
private readonly ConcurrentDictionary<int, bool> _filteredDevices = new ConcurrentDictionary<int, bool>();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>> _keyboardMappings =
|
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>> _keyboardKeyMappings =
|
||||||
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>>();
|
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>>();
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<int, MappingOptions> _keyboardMappings =
|
||||||
|
new ConcurrentDictionary<int, MappingOptions>();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>> _mouseButtonMappings =
|
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>> _mouseButtonMappings =
|
||||||
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>>();
|
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>>();
|
||||||
|
|
||||||
@ -33,6 +36,8 @@ namespace AutoHotInterception
|
|||||||
// Makes sure the events are handled synchronously and with a FIFO order.
|
// Makes sure the events are handled synchronously and with a FIFO order.
|
||||||
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>> _workerThreads =
|
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>> _workerThreads =
|
||||||
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>>();
|
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>>();
|
||||||
|
private readonly ConcurrentDictionary<int, WorkerThread> _deviceWorkerThreads =
|
||||||
|
new ConcurrentDictionary<int, WorkerThread>();
|
||||||
|
|
||||||
private readonly MultimediaTimer _timer;
|
private readonly MultimediaTimer _timer;
|
||||||
private readonly int _pollRate = 1;
|
private readonly int _pollRate = 1;
|
||||||
@ -82,10 +87,10 @@ namespace AutoHotInterception
|
|||||||
HelperFunctions.IsValidDeviceId(false, id);
|
HelperFunctions.IsValidDeviceId(false, id);
|
||||||
SetFilterState(false);
|
SetFilterState(false);
|
||||||
|
|
||||||
if (!_keyboardMappings.ContainsKey(id))
|
if (!_keyboardKeyMappings.ContainsKey(id))
|
||||||
_keyboardMappings.TryAdd(id, new ConcurrentDictionary<ushort, MappingOptions>());
|
_keyboardKeyMappings.TryAdd(id, new ConcurrentDictionary<ushort, MappingOptions>());
|
||||||
|
|
||||||
_keyboardMappings[id].TryAdd(code,
|
_keyboardKeyMappings[id].TryAdd(code,
|
||||||
new MappingOptions {Block = block, Concurrent = concurrent, Callback = callback});
|
new MappingOptions {Block = block, Concurrent = concurrent, Callback = callback});
|
||||||
|
|
||||||
if (!concurrent)
|
if (!concurrent)
|
||||||
@ -102,17 +107,33 @@ namespace AutoHotInterception
|
|||||||
SetThreadState(true);
|
SetThreadState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SubscribeKeyboard(int id, bool block, dynamic callback, bool concurrent = false)
|
||||||
|
{
|
||||||
|
HelperFunctions.IsValidDeviceId(false, id);
|
||||||
|
SetFilterState(false);
|
||||||
|
|
||||||
|
_keyboardMappings.TryAdd(id, new MappingOptions { Block = block, Concurrent = concurrent, Callback = callback });
|
||||||
|
if (!concurrent)
|
||||||
|
{
|
||||||
|
_deviceWorkerThreads.TryAdd(id, new WorkerThread());
|
||||||
|
_deviceWorkerThreads[id].Start();
|
||||||
|
}
|
||||||
|
SetDeviceFilterState(id, true);
|
||||||
|
SetFilterState(true);
|
||||||
|
SetThreadState(true);
|
||||||
|
}
|
||||||
|
|
||||||
public void UnsubscribeKey(int id, ushort code)
|
public void UnsubscribeKey(int id, ushort code)
|
||||||
{
|
{
|
||||||
HelperFunctions.IsValidDeviceId(false, id);
|
HelperFunctions.IsValidDeviceId(false, id);
|
||||||
SetFilterState(false);
|
SetFilterState(false);
|
||||||
|
|
||||||
if (_keyboardMappings.TryGetValue(id, out var thisDevice))
|
if (_keyboardKeyMappings.TryGetValue(id, out var thisDevice))
|
||||||
{
|
{
|
||||||
thisDevice.TryRemove(code, out _);
|
thisDevice.TryRemove(code, out _);
|
||||||
if (thisDevice.Count == 0)
|
if (thisDevice.Count == 0)
|
||||||
{
|
{
|
||||||
_keyboardMappings.TryRemove(id, out _);
|
_keyboardKeyMappings.TryRemove(id, out _);
|
||||||
SetDeviceFilterState(id, false);
|
SetDeviceFilterState(id, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -482,7 +503,7 @@ namespace AutoHotInterception
|
|||||||
private bool DeviceHasBindings(int id)
|
private bool DeviceHasBindings(int id)
|
||||||
{
|
{
|
||||||
if (id < 11)
|
if (id < 11)
|
||||||
return _keyboardMappings.ContainsKey(id);
|
return _keyboardKeyMappings.ContainsKey(id);
|
||||||
|
|
||||||
return _mouseButtonMappings.ContainsKey(id)
|
return _mouseButtonMappings.ContainsKey(id)
|
||||||
|| _mouseMoveRelativeMappings.ContainsKey(id)
|
|| _mouseMoveRelativeMappings.ContainsKey(id)
|
||||||
@ -509,7 +530,24 @@ namespace AutoHotInterception
|
|||||||
// If this is not a monitored keyboard, skip.
|
// If this is not a monitored keyboard, skip.
|
||||||
// This check should not really be needed as the IsMonitoredDevice() predicate should only match monitored keyboards...
|
// This check should not really be needed as the IsMonitoredDevice() predicate should only match monitored keyboards...
|
||||||
// ... but in case it does, we want to ignore this bit and pass the input through
|
// ... but in case it does, we want to ignore this bit and pass the input through
|
||||||
if (isMonitoredKeyboard && _keyboardMappings.ContainsKey(i))
|
if (isMonitoredKeyboard)
|
||||||
|
{
|
||||||
|
var isKeyMapping = false; // True if this is a mapping to a single key, else it would be a mapping to a whole device
|
||||||
|
var processedState = HelperFunctions.KeyboardStrokeToKeyboardState(stroke);
|
||||||
|
var code = processedState.Code;
|
||||||
|
var state = processedState.State;
|
||||||
|
MappingOptions mapping = null;
|
||||||
|
|
||||||
|
if (_keyboardMappings.ContainsKey(i))
|
||||||
|
{
|
||||||
|
mapping = _keyboardMappings[i];
|
||||||
|
}
|
||||||
|
else if (_keyboardKeyMappings.ContainsKey(i) && _keyboardKeyMappings[i].ContainsKey(code))
|
||||||
|
{
|
||||||
|
isKeyMapping = true;
|
||||||
|
mapping = _keyboardKeyMappings[i][code];
|
||||||
|
}
|
||||||
|
if (mapping != null)
|
||||||
{
|
{
|
||||||
// Process Subscription Mode
|
// Process Subscription Mode
|
||||||
|
|
||||||
@ -517,7 +555,6 @@ namespace AutoHotInterception
|
|||||||
|
|
||||||
// Begin translation of incoming key code, state, extended flag etc...
|
// Begin translation of incoming key code, state, extended flag etc...
|
||||||
var processMappings = true;
|
var processMappings = true;
|
||||||
var processedState = HelperFunctions.KeyboardStrokeToKeyboardState(stroke);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -529,20 +566,36 @@ namespace AutoHotInterception
|
|||||||
processMappings = false;
|
processMappings = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var code = processedState.Code;
|
|
||||||
var state = processedState.State;
|
|
||||||
|
|
||||||
// Code and state now normalized, proceed with checking for subscriptions...
|
// Code and state now normalized, proceed with checking for subscriptions...
|
||||||
if (processMappings && _keyboardMappings[i].ContainsKey(code))
|
if (processMappings)
|
||||||
{
|
{
|
||||||
hasSubscription = true;
|
hasSubscription = true;
|
||||||
var mapping = _keyboardMappings[i][code];
|
|
||||||
if (mapping.Block) block = true;
|
if (mapping.Block) block = true;
|
||||||
if (mapping.Concurrent)
|
if (mapping.Concurrent)
|
||||||
|
{
|
||||||
|
if (isKeyMapping)
|
||||||
|
{
|
||||||
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state));
|
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state));
|
||||||
else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(code))
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(code, state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isKeyMapping)
|
||||||
|
{
|
||||||
_workerThreads[i][code]?.Actions.Add(() => mapping.Callback(state));
|
_workerThreads[i][code]?.Actions.Add(() => mapping.Callback(state));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_deviceWorkerThreads[i]?.Actions.Add(() => mapping.Callback(code, state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the key was blocked by Subscription Mode, then move on to next key...
|
// If the key was blocked by Subscription Mode, then move on to next key...
|
||||||
|
32
C#/TestApp/KeyboardKeyTester.cs
Normal file
32
C#/TestApp/KeyboardKeyTester.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AutoHotInterception;
|
||||||
|
|
||||||
|
namespace TestApp
|
||||||
|
{
|
||||||
|
public class KeyboardKeyTester
|
||||||
|
{
|
||||||
|
public KeyboardKeyTester()
|
||||||
|
{
|
||||||
|
var im = new Manager();
|
||||||
|
|
||||||
|
var devId = im.GetKeyboardId(0x03EB, 0xFF02);
|
||||||
|
|
||||||
|
if (devId == 0) return;
|
||||||
|
|
||||||
|
im.SubscribeKey(devId, 0x1, false, new Action<int>(value =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"State: {value}");
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnKeyEvent(int value)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"State: {value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -22,5 +22,10 @@ namespace TestApp
|
|||||||
Console.WriteLine($"State: {value}");
|
Console.WriteLine($"State: {value}");
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnKeyEvent(int value)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"State: {value}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ namespace TestApp
|
|||||||
{
|
{
|
||||||
private static void Main()
|
private static void Main()
|
||||||
{
|
{
|
||||||
var mt = new MouseTester();
|
//var mt = new MouseTester();
|
||||||
//var kt = new KeyboardTester();
|
var kt = new KeyboardKeyTester();
|
||||||
//var tt = new TabletTester();
|
//var tt = new TabletTester();
|
||||||
var mon = new MonitorTester();
|
//var mon = new MonitorTester();
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="KeyboardTester.cs" />
|
<Compile Include="KeyboardTester.cs" />
|
||||||
|
<Compile Include="KeyboardKeyTester.cs" />
|
||||||
<Compile Include="MonitorTester.cs" />
|
<Compile Include="MonitorTester.cs" />
|
||||||
<Compile Include="MouseTester.cs" />
|
<Compile Include="MouseTester.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user