Skip to content

SubscribeKey Extended for v1 #100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions AHK v1/Lib/AutoHotInterception.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -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){
Expand Down Expand Up @@ -261,4 +267,4 @@ class AutoHotInterception {
this.parent.Instance.RemoveContextCallback(this.id)
}
}
}
}
32 changes: 32 additions & 0 deletions C#/AutoHotInterception/DeviceHandlers/DeviceHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ abstract class DeviceHandler : IDeviceHandler

// Holds MappingOptions for individual mouse button / keyboard key subscriptions
protected ConcurrentDictionary<ushort, MappingOptions> SingleButtonMappings = new ConcurrentDictionary<ushort, MappingOptions>();
protected ConcurrentDictionary<ushort, MappingOptions> SingleButtonMappingsEx = new ConcurrentDictionary<ushort, MappingOptions>();
// If all mouse buttons or keyboard keys are subscribed, this holds the mapping options
protected MappingOptions AllButtonsMapping;

Expand Down Expand Up @@ -42,6 +43,21 @@ public void SubscribeSingleButton(ushort code, MappingOptions mappingOptions)
_isFiltered = true;
}

/// <summary>
/// Subscribes to a single key or button of this device
/// </summary>
/// <param name="code">The ScanCode (keyboard) or Button Code (mouse) for the key or button</param>
/// <param name="mappingOptions">Options for the subscription (block, callback to fire etc)</param>
public void SubscribeSingleButtonEx(ushort code, MappingOptions mappingOptions)
{
SingleButtonMappingsEx.TryAdd(code, mappingOptions);
if (!mappingOptions.Concurrent && !WorkerThreads.ContainsKey(code))
{
WorkerThreads.TryAdd(code, new WorkerThread());
}
_isFiltered = true;
}

/// <summary>
/// Unsubscribes from a single key or button of this device
/// </summary>
Expand All @@ -58,6 +74,22 @@ public void UnsubscribeSingleButton(ushort code)
DisableFilterIfNeeded();
}

/// <summary>
/// Unsubscribes from a single key or button of this device
/// </summary>
/// <param name="code">The ScanCode (keyboard) or Button Code (mouse) for the key or button</param>
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();
}

/// <summary>
/// Subscribes to all keys or buttons of this device
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions C#/AutoHotInterception/DeviceHandlers/IDeviceHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ interface IDeviceHandler
/// <param name="mappingOptions">Options for the subscription (block, callback to fire etc)</param>
void SubscribeSingleButton(ushort code, MappingOptions mappingOptions);

/// <summary>
/// Subscribes to a single key or button of this device
/// </summary>
/// <param name="code">The ScanCode (keyboard) or Button Code (mouse) for the key or button</param>
/// <param name="mappingOptions">Options for the subscription (block, callback to fire etc)</param>
void SubscribeSingleButtonEx(ushort code, MappingOptions mappingOptions);

/// <summary>
/// Unsubscribes from a single key or button of this device
/// </summary>
Expand Down
28 changes: 26 additions & 2 deletions C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public override void DisableFilterIfNeeded()
{
if (AllButtonsMapping == null
&& SingleButtonMappings.Count == 0
&& SingleButtonMappingsEx.Count == 0
&& ContextCallback == null)
{
_isFiltered = false;
Expand Down Expand Up @@ -56,6 +57,7 @@ public override void ProcessStroke(List<ManagedWrapper.Stroke> 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;
Expand All @@ -65,8 +67,16 @@ public override void ProcessStroke(List<ManagedWrapper.Stroke> 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)
{
Expand All @@ -82,7 +92,14 @@ public override void ProcessStroke(List<ManagedWrapper.Stroke> 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
{
Expand All @@ -94,7 +111,14 @@ public override void ProcessStroke(List<ManagedWrapper.Stroke> 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
{
Expand Down
40 changes: 39 additions & 1 deletion C#/AutoHotInterception/Manager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,27 @@ public void SubscribeKey(int id, ushort code, bool block, dynamic callback, bool
SetThreadState(true);
}

/// <summary>
/// Subscribes to a Keyboard key
/// </summary>
/// <param name="id">The ID of the Keyboard</param>
/// <param name="code">The ScanCode of the key</param>
/// <param name="block">Whether or not to block the key</param>
/// <param name="callback">The callback to fire when the key changes state</param>
/// <param name="concurrent">Whether or not to execute callbacks concurrently</param>
/// <returns></returns>
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);
}

/// <summary>
/// Unsubscribe from a keyboard key
/// </summary>
Expand All @@ -103,6 +124,23 @@ public void UnsubscribeKey(int id, ushort code)
SetThreadState(true);
}

/// <summary>
/// Unsubscribe from a keyboard key
/// </summary>
/// <param name="id">The id of the keyboard</param>
/// <param name="code">The Scancode of the key</param>
public void UnsubscribeKeyEx(int id, ushort code)
{
HelperFunctions.IsValidDeviceId(false, id);
SetFilterState(false);

var handler = DeviceHandlers[id];
handler.UnsubscribeSingleButton(code);

SetFilterState(true);
SetThreadState(true);
}

/// <summary>
/// Subscribe to all keys on a keyboard
/// </summary>
Expand Down Expand Up @@ -583,4 +621,4 @@ private static void PollThread(object obj)
}
#endregion
}
}
}
5 changes: 5 additions & 0 deletions C#/TestApp/KeyboardKeyTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ public KeyboardKeyTester(TestDevice device, AhkKey key, bool block = false)
if (devId == 0) return;

im.SubscribeKey(devId, 0x2, block, new Action<int>(OnKeyEvent));
im.SubscribeKeyEx(devId, 0x3, block, new Action<int,ushort>(OnKeyEventEx));
}

public void OnKeyEvent(int value)
{
Console.WriteLine($"State: {value}");
}
public void OnKeyEventEx(int value, ushort code)
{
Console.WriteLine($"State: {value} Code: {code}");
}

}
}