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.
AutoHotInterception/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs

126 lines
4.6 KiB
C#

using AutoHotInterception.Helpers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
namespace AutoHotInterception.DeviceHandlers
{
class KeyboardHandler : DeviceHandler
{
public KeyboardHandler(IntPtr deviceContext, int deviceId) : base (deviceContext, deviceId)
{
}
/// <summary>
/// Called when we are removing a Subscription or Context Mode
/// If there are no other subscriptions, and Context Mode is disabled, turn the filter off
/// </summary>
public override void DisableFilterIfNeeded()
{
if (AllButtonsMapping == null
&& SingleButtonMappings.Count == 0
&& ContextCallback == null)
{
_isFiltered = false;
}
}
#region Input Synthesis
/// <summary>
/// Sends a keyboard key event
/// </summary>
/// <param name="code">The ScanCode to send</param>
/// <param name="state">The State to send (1 = pressed, 0 = released)</param>
public void SendKeyEvent(ushort code, int state)
{
var strokes = ScanCodeHelper.TranslateAhkCode(code, state);
for (int i = 0; i < strokes.Count; i++)
{
var stroke = strokes[i];
ManagedWrapper.Send(DeviceContext, DeviceId, ref stroke, 1);
}
}
#endregion
// ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
public override void ProcessStroke(List<ManagedWrapper.Stroke> strokes)
{
var hasSubscription = false;
var hasContext = ContextCallback != null;
// Process any waiting input for this keyboard
var block = false;
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 processedState = ScanCodeHelper.TranslateScanCodes(strokes);
var code = processedState.Code;
var state = processedState.State;
MappingOptions mapping = null;
// If there is a mapping to this specific key, then use that ...
if (SingleButtonMappings.ContainsKey(code))
{
isKeyMapping = true;
mapping = SingleButtonMappings[code];
}
// ... otherwise, if there is a mapping to the whole keyboard, use that
else if (AllButtonsMapping != null)
{
mapping = AllButtonsMapping;
}
if (mapping != null)
{
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
{
//mapping.Callback(code, state);
if (isKeyMapping)
{
WorkerThreads[code]?.Actions.Add(() => mapping.Callback(state));
}
else
{
DeviceWorkerThread?.Actions.Add(() => mapping.Callback(code, state));
}
}
}
// If the key was blocked by Subscription Mode, then move on to next key...
if (block) return;
// If this key had no subscriptions, but Context Mode is set for this keyboard...
// ... then set the Context before sending the key
if (!hasSubscription && hasContext) ContextCallback(1);
// Pass the key(s) through to the OS.
for (int i = 0; i < strokes.Count; i++)
{
var stroke = strokes[i];
ManagedWrapper.Send(DeviceContext, DeviceId, ref stroke, 1);
}
// If we are processing Context Mode, then Unset the context variable after sending the key
if (!hasSubscription && hasContext) ContextCallback(0);
}
}
}
}