From 37dd5b9855287fde89d52d74621aecdad6239f2c Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 29 Mar 2023 21:54:32 -0500 Subject: [PATCH 1/6] Update KeyboardHandler.cs --- .../DeviceHandlers/KeyboardHandler.cs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs b/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs index 106610c..80509ab 100644 --- a/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs +++ b/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs @@ -21,6 +21,7 @@ public override void DisableFilterIfNeeded() { if (AllButtonsMapping == null && SingleButtonMappings.Count == 0 + && SingleButtonMappingsEx.Count == 0 && ContextCallback == null) { _isFiltered = false; @@ -56,6 +57,7 @@ public override void ProcessStroke(List strokes) if (_isFiltered) { var isKeyMapping = false; // True if this is a mapping to a single key, else it would be a mapping to a whole device + var useExtendedCallback = false; var processedState = ScanCodeHelper.TranslateScanCodes(strokes); var code = processedState.Code; var state = processedState.State; @@ -65,8 +67,16 @@ public override void ProcessStroke(List strokes) if (SingleButtonMappings.ContainsKey(code)) { isKeyMapping = true; + useExtendedCallback = false; mapping = SingleButtonMappings[code]; } + // If there is an mapping (via SubscribeKeyEx) to this specific key, then use that ... + if (SingleButtonMappingsEx.ContainsKey(code)) + { + isKeyMapping = true; + useExtendedCallback = true; + mapping = SingleButtonMappingsEx[code]; + } // ... otherwise, if there is a mapping to the whole keyboard, use that else if (AllButtonsMapping != null) { @@ -82,7 +92,14 @@ public override void ProcessStroke(List strokes) { if (isKeyMapping) { - ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state)); + if (useExtendedCallback) + { + ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state, code)); + } + else + { + ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state)); + } } else { @@ -94,7 +111,14 @@ public override void ProcessStroke(List strokes) //mapping.Callback(code, state); if (isKeyMapping) { - WorkerThreads[code]?.Actions.Add(() => mapping.Callback(state)); + if (useExtendedCallback) + { + WorkerThreads[code]?.Actions.Add(() => mapping.Callback(state, code)); + } + else + { + WorkerThreads[code]?.Actions.Add(() => mapping.Callback(state)); + } } else { From a077e648c841aaf655e259efcf3333573866bee0 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 29 Mar 2023 21:55:14 -0500 Subject: [PATCH 2/6] Update IDeviceHandler.cs --- C#/AutoHotInterception/DeviceHandlers/IDeviceHandler.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/C#/AutoHotInterception/DeviceHandlers/IDeviceHandler.cs b/C#/AutoHotInterception/DeviceHandlers/IDeviceHandler.cs index b3caa60..5424919 100644 --- a/C#/AutoHotInterception/DeviceHandlers/IDeviceHandler.cs +++ b/C#/AutoHotInterception/DeviceHandlers/IDeviceHandler.cs @@ -19,6 +19,13 @@ interface IDeviceHandler /// Options for the subscription (block, callback to fire etc) void SubscribeSingleButton(ushort code, MappingOptions mappingOptions); + /// + /// Subscribes to a single key or button of this device + /// + /// The ScanCode (keyboard) or Button Code (mouse) for the key or button + /// Options for the subscription (block, callback to fire etc) + void SubscribeSingleButtonEx(ushort code, MappingOptions mappingOptions); + /// /// Unsubscribes from a single key or button of this device /// From 22dc040d501e3cd8e73bd1dadbbcea17031878ce Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 29 Mar 2023 21:56:35 -0500 Subject: [PATCH 3/6] Update DeviceHandler.cs --- .../DeviceHandlers/DeviceHandler.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/C#/AutoHotInterception/DeviceHandlers/DeviceHandler.cs b/C#/AutoHotInterception/DeviceHandlers/DeviceHandler.cs index c48f97f..50a3795 100644 --- a/C#/AutoHotInterception/DeviceHandlers/DeviceHandler.cs +++ b/C#/AutoHotInterception/DeviceHandlers/DeviceHandler.cs @@ -15,6 +15,7 @@ abstract class DeviceHandler : IDeviceHandler // Holds MappingOptions for individual mouse button / keyboard key subscriptions protected ConcurrentDictionary SingleButtonMappings = new ConcurrentDictionary(); + protected ConcurrentDictionary SingleButtonMappingsEx = new ConcurrentDictionary(); // If all mouse buttons or keyboard keys are subscribed, this holds the mapping options protected MappingOptions AllButtonsMapping; @@ -42,6 +43,21 @@ public void SubscribeSingleButton(ushort code, MappingOptions mappingOptions) _isFiltered = true; } + /// + /// Subscribes to a single key or button of this device + /// + /// The ScanCode (keyboard) or Button Code (mouse) for the key or button + /// Options for the subscription (block, callback to fire etc) + public void SubscribeSingleButtonEx(ushort code, MappingOptions mappingOptions) + { + SingleButtonMappingsEx.TryAdd(code, mappingOptions); + if (!mappingOptions.Concurrent && !WorkerThreads.ContainsKey(code)) + { + WorkerThreads.TryAdd(code, new WorkerThread()); + } + _isFiltered = true; + } + /// /// Unsubscribes from a single key or button of this device /// @@ -58,6 +74,22 @@ public void UnsubscribeSingleButton(ushort code) DisableFilterIfNeeded(); } + /// + /// Unsubscribes from a single key or button of this device + /// + /// The ScanCode (keyboard) or Button Code (mouse) for the key or button + public void UnsubscribeSingleButtonEx(ushort code) + { + if (!SingleButtonMappingsEx.ContainsKey(code)) return; + SingleButtonMappingsEx.TryRemove(code, out var mappingOptions); + if (!mappingOptions.Concurrent && WorkerThreads.ContainsKey(code)) + { + WorkerThreads[code].Dispose(); + WorkerThreads.TryRemove(code, out _); + } + DisableFilterIfNeeded(); + } + /// /// Subscribes to all keys or buttons of this device /// From 2c7d9babd45f8c62b3217f1c5364fee074d9b7d3 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 29 Mar 2023 21:57:09 -0500 Subject: [PATCH 4/6] Update Manager.cs --- C#/AutoHotInterception/Manager.cs | 40 ++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/C#/AutoHotInterception/Manager.cs b/C#/AutoHotInterception/Manager.cs index 3a6a500..0665d8b 100644 --- a/C#/AutoHotInterception/Manager.cs +++ b/C#/AutoHotInterception/Manager.cs @@ -86,6 +86,27 @@ public void SubscribeKey(int id, ushort code, bool block, dynamic callback, bool SetThreadState(true); } + /// + /// Subscribes to a Keyboard key + /// + /// The ID of the Keyboard + /// The ScanCode of the key + /// Whether or not to block the key + /// The callback to fire when the key changes state + /// Whether or not to execute callbacks concurrently + /// + public void SubscribeKeyEx(int id, ushort code, bool block, dynamic callback, bool concurrent = false) + { + HelperFunctions.IsValidDeviceId(false, id); + SetFilterState(false); + + var handler = DeviceHandlers[id]; + handler.SubscribeSingleButtonEx(code, new MappingOptions { Block = block, Concurrent = concurrent, Callback = callback }); + + SetFilterState(true); + SetThreadState(true); + } + /// /// Unsubscribe from a keyboard key /// @@ -103,6 +124,23 @@ public void UnsubscribeKey(int id, ushort code) SetThreadState(true); } + /// + /// Unsubscribe from a keyboard key + /// + /// The id of the keyboard + /// The Scancode of the key + public void UnsubscribeKeyEx(int id, ushort code) + { + HelperFunctions.IsValidDeviceId(false, id); + SetFilterState(false); + + var handler = DeviceHandlers[id]; + handler.UnsubscribeSingleButton(code); + + SetFilterState(true); + SetThreadState(true); + } + /// /// Subscribe to all keys on a keyboard /// @@ -583,4 +621,4 @@ private static void PollThread(object obj) } #endregion } -} \ No newline at end of file +} From 503da542fd29b944068b8fae786b9ffbebebe117 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 29 Mar 2023 22:00:49 -0500 Subject: [PATCH 5/6] Update KeyboardKeyTester.cs --- C#/TestApp/KeyboardKeyTester.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/C#/TestApp/KeyboardKeyTester.cs b/C#/TestApp/KeyboardKeyTester.cs index 912cd8f..c17238d 100644 --- a/C#/TestApp/KeyboardKeyTester.cs +++ b/C#/TestApp/KeyboardKeyTester.cs @@ -16,12 +16,17 @@ public KeyboardKeyTester(TestDevice device, AhkKey key, bool block = false) if (devId == 0) return; im.SubscribeKey(devId, 0x2, block, new Action(OnKeyEvent)); + im.SubscribeKeyEx(devId, 0x3, block, new Action(OnKeyEventEx)); } public void OnKeyEvent(int value) { Console.WriteLine($"State: {value}"); } + public void OnKeyEventEx(int value, ushort code) + { + Console.WriteLine($"State: {value} Code: {code}"); + } } } From 63d1225b83c678020465037285753d07732f1e02 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 29 Mar 2023 22:08:18 -0500 Subject: [PATCH 6/6] Update AutoHotInterception.ahk --- AHK v1/Lib/AutoHotInterception.ahk | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/AHK v1/Lib/AutoHotInterception.ahk b/AHK v1/Lib/AutoHotInterception.ahk index 9bde5ba..efa5827 100644 --- a/AHK v1/Lib/AutoHotInterception.ahk +++ b/AHK v1/Lib/AutoHotInterception.ahk @@ -166,7 +166,13 @@ class AutoHotInterception { ; ---------------------- Subscription Mode ---------------------- SubscribeKey(id, code, block, callback, concurrent := false) { - this.Instance.SubscribeKey(id, code, block, callback, concurrent) + switch callback.MaxParams + { + case 1: + this.Instance.SubscribeKey(id, code, block, callback, concurrent) + case 2: + this.Instance.SubscribeKeyEx(id, code, block, callback, concurrent) + } } UnsubscribeKey(id, code){ @@ -261,4 +267,4 @@ class AutoHotInterception { this.parent.Instance.RemoveContextCallback(this.id) } } -} \ No newline at end of file +}