private void PollThread() { var stroke = new ManagedWrapper.Stroke(); while (true) { for (var i = 1; i < 11; i++) { while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); FireKeyboardCallback(i, stroke); } } for (var i = 11; i < 21; i++) { while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); FireMouseCallback(i, stroke); } } Thread.Sleep(10); } }
/// <summary> /// Sends Absolute Mouse Movement /// Note: Newing up a stroke seems to make Absolute input be relative to main monitor /// Calling Send on an actual stroke from an Absolute device results in input relative to all monitors /// </summary> /// <param name="id"></param> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public void SendMouseMoveAbsolute(int id, int x, int y) { IsValidDeviceId(true, id); var stroke = new ManagedWrapper.Stroke { mouse = { x = x, y = y, flags = (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute } }; ManagedWrapper.Send(_deviceContext, id, ref stroke, 1); }
/// <summary> /// Sends Relative Mouse Movement /// </summary> /// <param name="id"></param> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public void SendMouseMoveRelative(int id, int x, int y) { HelperFunctions.IsValidDeviceId(true, id); var stroke = new ManagedWrapper.Stroke { mouse = { x = x, y = y, flags = (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative } }; ManagedWrapper.Send(_deviceContext, id, ref stroke, 1); }
/// <summary> /// Sends a keyboard key event /// </summary> /// <param name="id">The ID of the Keyboard to send as</param> /// <param name="code">The ScanCode to send</param> /// <param name="state">The State to send (1 = pressed, 0 = released)</param> public void SendKeyEvent(int id, ushort code, int state) { IsValidDeviceId(false, id); var st = 1 - state; var stroke = new ManagedWrapper.Stroke(); if (code > 255) { code -= 256; st += 2; } stroke.key.code = code; stroke.key.state = (ushort)st; ManagedWrapper.Send(_deviceContext, id, ref stroke, 1); }
public void DoPoll(object sender, EventArgs e) { var stroke = new ManagedWrapper.Stroke(); var keyEvents = new List <KeyEvent>(); while (ManagedWrapper.Receive(_deviceContext, _filteredDevice, ref stroke, 1) > 0) { keyEvents.Add(new KeyEvent { Code = stroke.key.code, State = stroke.key.state }); ManagedWrapper.Send(_deviceContext, _filteredDevice, ref stroke, 1); } if (keyEvents.Count > 0) { _callback(keyEvents.ToArray()); } }
/// <summary> /// Sends a keyboard key event /// </summary> /// <param name="id">The ID of the Keyboard to send as</param> /// <param name="code">The ScanCode to send</param> /// <param name="state">The State to send (1 = pressed, 0 = released)</param> public void SendKeyEvent(int id, ushort code, int state) { HelperFunctions.IsValidDeviceId(false, id); var st = 1 - state; var stroke = new ManagedWrapper.Stroke(); if (code > 255) { code -= 256; if (code != 54) // RShift has > 256 code, but state is 0/1 { st += 2; } } stroke.key.code = code; stroke.key.state = (ushort)st; ManagedWrapper.Send(_deviceContext, id, ref stroke, 1); }
private void PollThread() { ManagedWrapper.SetFilter(_deviceContext, IsMonitoredDevice, ManagedWrapper.Filter.All); int deviceId1; int deviceId2; var stroke1 = new ManagedWrapper.Stroke(); var stroke2 = new ManagedWrapper.Stroke(); while (true) { var strokes = new List <ManagedWrapper.Stroke>(); if (ManagedWrapper.Receive(_deviceContext, deviceId1 = ManagedWrapper.WaitWithTimeout(_deviceContext, 10), ref stroke1, 1) > 0) { strokes.Add(stroke1); if (deviceId1 < 11) { if (ManagedWrapper.Receive(_deviceContext, deviceId2 = ManagedWrapper.WaitWithTimeout(_deviceContext, 0), ref stroke2, 1) > 0) { strokes.Add(stroke2); } } if (!_block) { for (int i = 0; i < strokes.Count; i++) { var stroke = strokes[i]; ManagedWrapper.Send(_deviceContext, _deviceId, ref stroke, 1); } } // Use array for callback, as the callback may be AHK code, and dealing with arrays in AHK is way simpler that Lists var keyEvents = new KeyEvent[strokes.Count]; for (int i = 0; i < strokes.Count; i++) { var s = strokes[i]; keyEvents[i] = new KeyEvent { Code = s.key.code, State = s.key.state }; } _callback(keyEvents); } } }
// ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html private void DoPoll(object sender, EventArgs e) { _pollThreadRunning = true; var stroke = new ManagedWrapper.Stroke(); // Iterate through all Keyboards for (var i = 1; i < 11; i++) { var isMonitoredKeyboard = IsMonitoredDevice(i) == 1; var hasSubscription = false; var hasContext = _contextCallbacks.ContainsKey(i); // Process any waiting input for this keyboard while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { var block = false; // 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) { 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; if (_keyboardMappings.ContainsKey(i)) { mapping = _keyboardMappings[i]; } else if (_keyboardKeyMappings.ContainsKey(i) && _keyboardKeyMappings[i].ContainsKey(code)) { isKeyMapping = true; mapping = _keyboardKeyMappings[i][code]; } if (mapping != null) { // Process Subscription Mode #region KeyCode, State, Extended Flag translation // 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)); } } } } } // If the key was blocked by Subscription Mode, then move on to next key... if (block) { continue; } // 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) { _contextCallbacks[i](1); } // Pass the key through to the OS. ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); // If we are processing Context Mode, then Unset the context variable after sending the key if (!hasSubscription && hasContext) { _contextCallbacks[i](0); } } } // Process Mice for (var i = 11; i < 21; i++) { var isMonitoredMouse = IsMonitoredDevice(i) == 1; var hasSubscription = false; var hasContext = _contextCallbacks.ContainsKey(i); while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { if (!isMonitoredMouse) { continue; } var moveRemoved = false; var hasMove = false; var x = stroke.mouse.x; var y = stroke.mouse.y; //Debug.WriteLine($"AHK| Stroke Seen. State = {stroke.mouse.state}, Flags = {stroke.mouse.flags}, x={x}, y={y}"); // Process mouse movement if (x != 0 || y != 0) { hasMove = true; // Process Absolute Mouse Move if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) == (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) { if (_mouseMoveAbsoluteMappings.ContainsKey(i)) { var mapping = _mouseMoveAbsoluteMappings[i]; hasSubscription = true; //var debugStr = $"AHK| Mouse stroke has absolute move of {x}, {y}..."; if (mapping.Concurrent) { ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y)); } else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(7)) { _workerThreads[i][7]?.Actions.Add(() => mapping.Callback(x, y)); } if (mapping.Block) { moveRemoved = true; stroke.mouse.x = 0; stroke.mouse.y = 0; //debugStr += "Blocking"; } else { //debugStr += "Not Blocking"; } //Debug.WriteLine(debugStr); } } // Process Relative Mouse Move //else if ((stroke.mouse.flags & (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative) == (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative) / flag is 0, so always true! else { if (_mouseMoveRelativeMappings.ContainsKey(i)) { var mapping = _mouseMoveRelativeMappings[i]; hasSubscription = true; //var debugStr = $"AHK| Mouse stroke has relative move of {x}, {y}..."; if (mapping.Concurrent) { ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y)); } else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(8)) { _workerThreads[i][8]?.Actions.Add(() => mapping.Callback(x, y)); } if (mapping.Block) { moveRemoved = true; stroke.mouse.x = 0; stroke.mouse.y = 0; //debugStr += "Blocking"; } else { //debugStr += "Not Blocking"; } //Debug.WriteLine(debugStr); } } } var isMouseButtonsMapping = _mouseButtonsMappings.ContainsKey(i); // Process Mouse Buttons - do this AFTER mouse movement, so that absolute mode has coordinates available at the point that the button callback is fired if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i) || isMouseButtonsMapping) { var btnStates = HelperFunctions.MouseStrokeToButtonStates(stroke); foreach (var btnState in btnStates) { if (!isMouseButtonsMapping && !_mouseButtonMappings[i].ContainsKey(btnState.Button)) { continue; } hasSubscription = true; MappingOptions mapping = null; if (isMouseButtonsMapping) { mapping = _mouseButtonsMappings[i]; } else { mapping = _mouseButtonMappings[i][btnState.Button]; } var state = btnState; if (mapping.Concurrent) { if (isMouseButtonsMapping) { ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(btnState.Button, state.State)); } else { ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State)); } } else { if (isMouseButtonsMapping) { _deviceWorkerThreads[i]?.Actions .Add(() => mapping.Callback(btnState.Button, state.State)); } else { _workerThreads[i][btnState.Button]?.Actions .Add(() => mapping.Callback(state.State)); } } if (mapping.Block) { // Remove the event for this button from the stroke, leaving other button events intact stroke.mouse.state -= btnState.Flag; // If we are removing a mouse wheel event, then set rolling to 0 if no mouse wheel event left if (btnState.Flag == 0x400 || btnState.Flag == 0x800) { if ((stroke.mouse.state & 0x400) != 0x400 && (stroke.mouse.state & 0x800) != 0x800) { //Debug.WriteLine("AHK| Removing rolling flag from stroke"); stroke.mouse.rolling = 0; } } //Debug.WriteLine($"AHK| Removing flag {btnState.Flag} from stoke, leaving state {stroke.mouse.state}"); } else { //Debug.WriteLine($"AHK| Leaving flag {btnState.Flag} in stroke"); } } } // Forward on the stroke if required if (hasSubscription) { // Subscription mode // If the stroke has a move that was not removed, OR it has remaining button events, then forward on the stroke if ((hasMove && !moveRemoved) || stroke.mouse.state != 0) { //Debug.WriteLine($"AHK| Sending stroke. State = {stroke.mouse.state}. hasMove={hasMove}, moveRemoved={moveRemoved}"); ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); } else { // Everything removed from stroke, do not forward //Debug.WriteLine("AHK| Mouse stroke now empty, not forwarding"); } } else if (hasContext) { // Context Mode - forward stroke with context wrapping _contextCallbacks[i](1); ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); _contextCallbacks[i](0); } else { // No subscription or context mode - forward on //Debug.WriteLine($"AHK| Sending stroke. State = {stroke.mouse.state}. hasMove={hasMove}, moveRemoved={moveRemoved}"); ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); } //Debug.WriteLine($"AHK| "); } } _pollThreadRunning = false; }
private void PollThread() { var stroke = new ManagedWrapper.Stroke(); while (_pollThreadRunning) { for (var i = 1; i < 11; i++) { while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); var processedState = KeyboardStrokeToKeyboardState(stroke); if (processedState.Ignore) { FireKeyboardCallback(i, new KeyboardCallback { Id = i, Code = stroke.key.code, State = stroke.key.state, Info = "Ignored - showing raw values" }); } else { FireKeyboardCallback(i, new KeyboardCallback { Id = i, Code = processedState.Code, State = processedState.State, Info = stroke.key.code > 255 ? "Extended" : "" }); } } } for (var i = 11; i < 21; i++) { while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); if (stroke.mouse.state != 0) { // Mouse Button var btnState = MouseStrokeToButtonState(stroke); FireMouseCallback(new MouseCallback { Id = i, Code = btnState.Button, State = btnState.State, Info = "Mouse Button" }); } else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) == (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) { // Absolute Mouse Move FireMouseCallback(new MouseCallback { Id = i, X = stroke.mouse.x, Y = stroke.mouse.y, Info = "Absolute Move" }); } else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative) == (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative) { // Relative Mouse Move FireMouseCallback(new MouseCallback { Id = i, X = stroke.mouse.x, Y = stroke.mouse.y, Info = "Relative Move" }); } //FireMouseCallback(i, stroke); } } Thread.Sleep(10); } }
// ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html private void PollThread() { ManagedWrapper.Stroke stroke = new ManagedWrapper.Stroke(); while (true) { // Iterate through all Keyboards for (var i = 1; i < 11; i++) { var isMonitoredKeyboard = IsMonitoredDevice(i) == 1; var hasSubscription = false; var hasContext = _contextCallbacks.ContainsKey(i); // Process any waiting input for this keyboard while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { var block = false; // 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)) { // Process Subscription Mode var code = stroke.key.code; var state = stroke.key.state; #region KeyCode, State, Extended Flag translation // Begin translation of incoming key code, state, extended flag etc... var processMappings = true; if (code == 54) { // Interception seems to report Right Shift as 54 / 0x36 with state 0/1... // ... this code is normally unused (Alt-SysRq according to linked page) ... // ... and AHK uses 54 + 256 = 310 (0x36 + 0x100 = 0x136)... // ... so change the code, but leave the state as 0/1 code = 310; } // If state is shifted up by 2 (1 or 2 instead of 0 or 1), then this is an "Extended" key code if (state > 1) { if (code == 42) { // Shift (42/0x2a) with extended flag = the key after this one is extended. // Example case is Delete (The one above the arrow keys, not on numpad)... // ... this generates a stroke of 0x2a (Shift) with *extended flag set* (Normal shift does not do this)... // ... followed by 0x53 with extended flag set. // We do not want to fire subsriptions for the extended shift, but *do* want to let the key flow through... // ... so that is handled here. // When the extended key (Delete in the above example) subsequently comes through... // ... it will have code 0x53, which we shift to 0x153 (Adding 256 Dec) to signify extended version... // ... as this is how AHK behaves with GetKeySC() // Set flag to stop Context Mode from firing hasSubscription = true; // Set flag to indicate disable mapping processing processMappings = false; } else { // Extended flag set // Shift code up by 256 (0x100) to signify extended code code += 256; state -= 2; } } #endregion // 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; } ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(1 - state)); } } // If the key was blocked by Subscription Mode, then move on to next key... if (block) { continue; } // 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) { _contextCallbacks[i](1); } // Pass the key through to the OS. ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); // If we are processing Context Mode, then Unset the context variable after sending the key if (!hasSubscription && hasContext) { _contextCallbacks[i](0); } } } // Process Mice for (var i = 11; i < 21; i++) { var isMonitoredMouse = IsMonitoredDevice(i) == 1; var hasSubscription = false; var hasContext = _contextCallbacks.ContainsKey(i); while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}"); var block = false; if (isMonitoredMouse) { if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i)) { // Mouse Button //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}"); var btnState = StrokeStateToButtonState(stroke); if (_mouseButtonMappings[i].ContainsKey(btnState.Button)) { hasSubscription = true; var mapping = _mouseButtonMappings[i][btnState.Button]; if (mapping.Block) { block = true; } var state = btnState; ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State)); } //Console.WriteLine($"AHK| Mouse {i} seen - button {btnState.Button}, state: {stroke.mouse.state}, rolling: {stroke.mouse.rolling}"); } else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) == (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute && _mouseMoveAbsoluteMappings.ContainsKey(i)) { // Absolute Mouse Move hasSubscription = true; var mapping = _mouseMoveAbsoluteMappings[i]; if (mapping.Block) { block = true; } var x = stroke.mouse.x; var y = stroke.mouse.y; ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y)); } else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative) == (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative && _mouseMoveRelativeMappings.ContainsKey(i)) { // Relative Mouse Move hasSubscription = true; var mapping = _mouseMoveRelativeMappings[i]; if (mapping.Block) { block = true; } var x = stroke.mouse.x; var y = stroke.mouse.y; ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y)); } } // If this key had no subscriptions, but Context Mode is set for this mouse... // ... then set the Context before sending the button if (!hasSubscription && hasContext) { // Set Context _contextCallbacks[i](1); } if (!(block)) { ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); } // If we are processing Context Mode, then Unset the context variable after sending the button if (!hasSubscription && hasContext) { // Unset Context _contextCallbacks[i](0); } } } Thread.Sleep(10); } }
private void FireMouseCallback(int id, ManagedWrapper.Stroke stroke) { ThreadPool.QueueUserWorkItem(threadProc => _mouseCallback(id, stroke.mouse.state, stroke.mouse.flags, stroke.mouse.rolling, stroke.mouse.x, stroke.mouse.y, stroke.mouse.information)); }
private void FireKeyboardCallback(int id, ManagedWrapper.Stroke stroke) { ThreadPool.QueueUserWorkItem(threadProc => _keyboardCallback(id, stroke.key.state, stroke.key.code, stroke.key.information)); }
// ScanCode notes: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html private void PollThread() { var stroke = new ManagedWrapper.Stroke(); while (_pollThreadRunning) { // Iterate through all Keyboards for (var i = 1; i < 11; i++) { var isMonitoredKeyboard = IsMonitoredDevice(i) == 1; var hasSubscription = false; var hasContext = _contextCallbacks.ContainsKey(i); // Process any waiting input for this keyboard while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { var block = false; // 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)) { // Process Subscription Mode #region KeyCode, State, Extended Flag translation // Begin translation of incoming key code, state, extended flag etc... var processMappings = true; var processedState = KeyboardStrokeToKeyboardState(stroke); #endregion if (processedState.Ignore) { // Set flag to stop Context Mode from firing hasSubscription = true; // Set flag to indicate disable mapping processing processMappings = false; } var code = processedState.Code; var state = processedState.State; // 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)); } } } // If the key was blocked by Subscription Mode, then move on to next key... if (block) { continue; } // 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) { _contextCallbacks[i](1); } // Pass the key through to the OS. ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); // If we are processing Context Mode, then Unset the context variable after sending the key if (!hasSubscription && hasContext) { _contextCallbacks[i](0); } } } // Process Mice for (var i = 11; i < 21; i++) { var isMonitoredMouse = IsMonitoredDevice(i) == 1; var hasSubscription = false; var hasContext = _contextCallbacks.ContainsKey(i); while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0) { //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}"); var block = false; if (isMonitoredMouse) { if (stroke.mouse.state != 0 && _mouseButtonMappings.ContainsKey(i)) { // Mouse Button //Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}"); var btnStates = MouseStrokeToButtonStates(stroke); foreach (var btnState in btnStates) { if (_mouseButtonMappings[i].ContainsKey(btnState.Button)) { hasSubscription = true; var mapping = _mouseButtonMappings[i][btnState.Button]; if (mapping.Block) { block = true; } var state = btnState; if (mapping.Concurrent) { ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(state.State)); } else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(btnState.Button)) { _workerThreads[i][btnState.Button]?.Actions .Add(() => mapping.Callback(state.State)); } } } //Console.WriteLine($"AHK| Mouse {i} seen - button {btnState.Button}, state: {stroke.mouse.state}, rolling: {stroke.mouse.rolling}"); } else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute) == (ushort)ManagedWrapper.MouseFlag.MouseMoveAbsolute && _mouseMoveAbsoluteMappings.ContainsKey(i)) { // Absolute Mouse Move hasSubscription = true; var mapping = _mouseMoveAbsoluteMappings[i]; if (mapping.Block) { block = true; } var x = stroke.mouse.x; var y = stroke.mouse.y; if (mapping.Concurrent) { ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y)); } else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(7)) { _workerThreads[i][7]?.Actions.Add(() => mapping.Callback(x, y)); } } else if ((stroke.mouse.flags & (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative) == (ushort)ManagedWrapper.MouseFlag.MouseMoveRelative && _mouseMoveRelativeMappings.ContainsKey(i)) { // Relative Mouse Move hasSubscription = true; var mapping = _mouseMoveRelativeMappings[i]; if (mapping.Block) { block = true; } var x = stroke.mouse.x; var y = stroke.mouse.y; if (mapping.Concurrent) { ThreadPool.QueueUserWorkItem(threadProc => mapping.Callback(x, y)); } else if (_workerThreads.ContainsKey(i) && _workerThreads[i].ContainsKey(8)) { _workerThreads[i][8]?.Actions.Add(() => mapping.Callback(x, y)); } } } // If this key had no subscriptions, but Context Mode is set for this mouse... // ... then set the Context before sending the button if (!hasSubscription && hasContext) { _contextCallbacks[i](1); // Set Context } if (!block) { ManagedWrapper.Send(_deviceContext, i, ref stroke, 1); } // If we are processing Context Mode, then Unset the context variable after sending the button if (!hasSubscription && hasContext) { _contextCallbacks[i](0); } } } Thread.Sleep(10); } }
private static void PollThread(object obj) { var token = (CancellationToken)obj; //Debug.WriteLine($"AHK| Poll Thread Started"); _pollThreadRunning = true; int stroke1DeviceId; int stroke2DeviceId; while (!token.IsCancellationRequested) { var stroke = new ManagedWrapper.Stroke(); // While no input happens, this loop will exit every 10ms to allow us to check if cancellation has been requested // WaitWithTimeout is used with a timeout of 10ms instead of Wait, so that when we eg use SetState to turn the thread off... // ... any input which was filtered and is waiting to be processed can be processed (eg lots of mouse moves buffered) if (ManagedWrapper.Receive(DeviceContext, stroke1DeviceId = ManagedWrapper.WaitWithTimeout(DeviceContext, 10), ref stroke, 1) > 0) { var strokes = new List <ManagedWrapper.Stroke>(); strokes.Add(stroke); if (stroke1DeviceId < 11) { //Debug.WriteLine($"Stroke 1: {RenderStroke(stroke)}"); // If this is a keyboard stroke, then keep performing more Receives immediately with a timeout of 0... // ... this is to check whether an extended stroke is waiting. // Unfortunately, at this point, it's entirely possible that two single-stroke keys end up in strokes... // ... or even 3 strokes or more (eg one single-stroke key followed by a two-stroke key) //while ((stroke2DeviceId = ManagedWrapper.WaitWithTimeout(DeviceContext, 0)) == stroke1DeviceId) while ((stroke2DeviceId = ManagedWrapper.WaitWithTimeout(DeviceContext, 0)) != 0) { ManagedWrapper.Receive(DeviceContext, stroke2DeviceId, ref stroke, 1); strokes.Add(stroke); //Debug.WriteLine($"Stroke {strokes.Count}: {RenderStroke(stroke)}"); } // Loop through the list checking the first 2 indexes for valid "two-code" key combinations. // If no combo is found, send index 0 on its way, remove it off the top of the list, repeat while (strokes.Count > 0) { if (strokes.Count >= 2 && ScanCodeHelper.IsDoubleScanCode(new List <ManagedWrapper.Stroke> { strokes[0], strokes[1] })) { DeviceHandlers[stroke1DeviceId].ProcessStroke(new List <ManagedWrapper.Stroke> { strokes[0], strokes[1] }); strokes.RemoveRange(0, 2); } else { DeviceHandlers[stroke1DeviceId].ProcessStroke(new List <ManagedWrapper.Stroke> { strokes[0] }); strokes.RemoveAt(0); } } } else { DeviceHandlers[stroke1DeviceId].ProcessStroke(strokes); } } } _pollThreadRunning = false; //Debug.WriteLine($"AHK| Poll Thread Ended"); }
private static string RenderStroke(ManagedWrapper.Stroke stroke) { return($"key code: {stroke.key.code}, key state: {stroke.key.state}, mouse x/y: {stroke.mouse.x}, {stroke.mouse.y}"); }