Manager can subscribe to all keyboard keys

feature/SubscribeAll
Clive Galway 5 years ago
parent 9b558f98c2
commit 3577f5a920

@ -17,9 +17,12 @@ namespace AutoHotInterception
// 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, ConcurrentDictionary<ushort, MappingOptions>> _keyboardMappings =
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>> _keyboardKeyMappings =
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>>();
private readonly ConcurrentDictionary<int, MappingOptions> _keyboardMappings =
new ConcurrentDictionary<int, MappingOptions>();
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>> _mouseButtonMappings =
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, MappingOptions>>();
@ -33,6 +36,8 @@ namespace AutoHotInterception
// Makes sure the events are handled synchronously and with a FIFO order.
private readonly ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>> _workerThreads =
new ConcurrentDictionary<int, ConcurrentDictionary<ushort, WorkerThread>>();
private readonly ConcurrentDictionary<int, WorkerThread> _deviceWorkerThreads =
new ConcurrentDictionary<int, WorkerThread>();
private readonly MultimediaTimer _timer;
private readonly int _pollRate = 1;
@ -82,10 +87,10 @@ namespace AutoHotInterception
HelperFunctions.IsValidDeviceId(false, id);
SetFilterState(false);
if (!_keyboardMappings.ContainsKey(id))
_keyboardMappings.TryAdd(id, new ConcurrentDictionary<ushort, MappingOptions>());
if (!_keyboardKeyMappings.ContainsKey(id))
_keyboardKeyMappings.TryAdd(id, new ConcurrentDictionary<ushort, MappingOptions>());
_keyboardMappings[id].TryAdd(code,
_keyboardKeyMappings[id].TryAdd(code,
new MappingOptions {Block = block, Concurrent = concurrent, Callback = callback});
if (!concurrent)
@ -102,17 +107,33 @@ namespace AutoHotInterception
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)
{
HelperFunctions.IsValidDeviceId(false, id);
SetFilterState(false);
if (_keyboardMappings.TryGetValue(id, out var thisDevice))
if (_keyboardKeyMappings.TryGetValue(id, out var thisDevice))
{
thisDevice.TryRemove(code, out _);
if (thisDevice.Count == 0)
{
_keyboardMappings.TryRemove(id, out _);
_keyboardKeyMappings.TryRemove(id, out _);
SetDeviceFilterState(id, false);
}
}
@ -482,7 +503,7 @@ namespace AutoHotInterception
private bool DeviceHasBindings(int id)
{
if (id < 11)
return _keyboardMappings.ContainsKey(id);
return _keyboardKeyMappings.ContainsKey(id);
return _mouseButtonMappings.ContainsKey(id)
|| _mouseMoveRelativeMappings.ContainsKey(id)
@ -509,39 +530,71 @@ namespace AutoHotInterception
// If this is not a monitored keyboard, skip.
// 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
if (isMonitoredKeyboard && _keyboardMappings.ContainsKey(i))
if (isMonitoredKeyboard)
{
// Process Subscription Mode
#region KeyCode, State, Extended Flag translation
// Begin translation of incoming key code, state, extended flag etc...
var processMappings = true;
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;
#endregion
if (processedState.Ignore)
if (_keyboardMappings.ContainsKey(i))
{
// Set flag to stop Context Mode from firing
hasSubscription = true;
// Set flag to indicate disable mapping processing
processMappings = false;
mapping = _keyboardMappings[i];
}
else if (_keyboardKeyMappings.ContainsKey(i) && _keyboardKeyMappings[i].ContainsKey(code))
{
isKeyMapping = true;
mapping = _keyboardKeyMappings[i][code];
}
if (mapping != null)
{
// Process Subscription Mode
var code = processedState.Code;
var state = processedState.State;
#region KeyCode, State, Extended Flag translation
// Code and state now normalized, proceed with checking for subscriptions...
if (processMappings && _keyboardMappings[i].ContainsKey(code))
{
hasSubscription = true;
var mapping = _keyboardMappings[i][code];
if (mapping.Block) block = true;
if (mapping.Concurrent)
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state));
else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(code))
_workerThreads[i][code]?.Actions.Add(() => mapping.Callback(state));
// Begin translation of incoming key code, state, extended flag etc...
var processMappings = true;
#endregion
if (processedState.Ignore)
{
// Set flag to stop Context Mode from firing
hasSubscription = true;
// Set flag to indicate disable mapping processing
processMappings = false;
}
// Code and state now normalized, proceed with checking for subscriptions...
if (processMappings)
{
hasSubscription = true;
if (mapping.Block) block = true;
if (mapping.Concurrent)
{
if (isKeyMapping)
{
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state));
}
else
{
ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(code, state));
}
}
else
{
if (isKeyMapping)
{
_workerThreads[i][code]?.Actions.Add(() => mapping.Callback(state));
}
else
{
_deviceWorkerThreads[i]?.Actions.Add(() => mapping.Callback(code, state));
}
}
}
}
}

@ -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}");
}));
}
public void OnKeyEvent(int value)
{
Console.WriteLine($"State: {value}");
}
}
}

@ -7,10 +7,10 @@ namespace TestApp
{
private static void Main()
{
var mt = new MouseTester();
//var kt = new KeyboardTester();
//var mt = new MouseTester();
var kt = new KeyboardKeyTester();
//var tt = new TabletTester();
var mon = new MonitorTester();
//var mon = new MonitorTester();
Console.ReadLine();
}
}

@ -43,6 +43,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="KeyboardTester.cs" />
<Compile Include="KeyboardKeyTester.cs" />
<Compile Include="MonitorTester.cs" />
<Compile Include="MouseTester.cs" />
<Compile Include="Program.cs" />

Loading…
Cancel
Save