You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
4.8 KiB
C#
129 lines
4.8 KiB
C#
using AutoHotInterception.Helpers;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
|
|
namespace AutoHotInterception.DeviceHandlers
|
|
{
|
|
abstract class DeviceHandler : IDeviceHandler
|
|
{
|
|
protected dynamic ContextCallback;
|
|
|
|
protected IntPtr DeviceContext;
|
|
protected int DeviceId;
|
|
protected bool _isFiltered { get; set; }
|
|
|
|
// Holds MappingOptions for individual mouse button / keyboard key subscriptions
|
|
protected ConcurrentDictionary<ushort, MappingOptions> SingleButtonMappings = new ConcurrentDictionary<ushort, MappingOptions>();
|
|
// If all mouse buttons or keyboard keys are subscribed, this holds the mapping options
|
|
protected MappingOptions AllButtonsMapping;
|
|
|
|
protected readonly ConcurrentDictionary<ushort, WorkerThread> WorkerThreads = new ConcurrentDictionary<ushort, WorkerThread>();
|
|
protected WorkerThread DeviceWorkerThread;
|
|
|
|
public DeviceHandler(IntPtr deviceContext, int deviceId)
|
|
{
|
|
DeviceContext = deviceContext;
|
|
DeviceId = deviceId;
|
|
}
|
|
|
|
/// <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 SubscribeSingleButton(ushort code, MappingOptions mappingOptions)
|
|
{
|
|
SingleButtonMappings.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>
|
|
/// <param name="code">The ScanCode (keyboard) or Button Code (mouse) for the key or button</param>
|
|
public void UnsubscribeSingleButton(ushort code)
|
|
{
|
|
if (!SingleButtonMappings.ContainsKey(code)) return;
|
|
SingleButtonMappings.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>
|
|
/// <param name="mappingOptions">Options for the subscription (block, callback to fire etc)</param>
|
|
public void SubscribeAllButtons(MappingOptions mappingOptions)
|
|
{
|
|
AllButtonsMapping = mappingOptions;
|
|
if (!mappingOptions.Concurrent && DeviceWorkerThread == null)
|
|
{
|
|
DeviceWorkerThread = new WorkerThread();
|
|
}
|
|
_isFiltered = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribes from a SubscribeAll for this device
|
|
/// </summary>
|
|
public void UnsubscribeAllButtons()
|
|
{
|
|
if (AllButtonsMapping == null) return;
|
|
// Stop DeviceWorkerThread
|
|
if (!AllButtonsMapping.Concurrent && DeviceWorkerThread != null)
|
|
{
|
|
DeviceWorkerThread.Dispose();
|
|
DeviceWorkerThread = null;
|
|
}
|
|
AllButtonsMapping = null;
|
|
DisableFilterIfNeeded();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables Context Mode for this device
|
|
/// </summary>
|
|
/// <param name="callback">The callback to call when input happens</param>
|
|
public void SetContextCallback(dynamic callback)
|
|
{
|
|
ContextCallback = callback;
|
|
_isFiltered = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes Context Mode for this device
|
|
/// </summary>
|
|
public void RemoveContextCallback()
|
|
{
|
|
ContextCallback = null;
|
|
DisableFilterIfNeeded();
|
|
}
|
|
|
|
// ToDo: Why is this IDeviceHandler.IsFiltered() and other Interface methods aren't?
|
|
public int IsFiltered()
|
|
{
|
|
return Convert.ToInt32(_isFiltered);
|
|
}
|
|
|
|
/// <summary>
|
|
/// After doing an UnsubscribeButton, UnsubscribeAll, or RemoveContext, this method will be called
|
|
/// If no more subscriptions are present, it should remove the filter for this device
|
|
/// </summary>
|
|
public abstract void DisableFilterIfNeeded();
|
|
|
|
/// <summary>
|
|
/// Process an incoming stroke, or a pair of extended keycode strokes
|
|
/// </summary>
|
|
/// <param name="strokes">The stroke(s) to process</param>
|
|
public abstract void ProcessStroke(List<ManagedWrapper.Stroke> strokes);
|
|
}
|
|
}
|