public void PressRelease(string name, int code, List <ManagedWrapper.Stroke> pressResult, List <ManagedWrapper.Stroke> releaseResult) { var actualResult = ScanCodeHelper.TranslateAhkCode((ushort)code, 1); AssertResults(pressResult, actualResult); actualResult = ScanCodeHelper.TranslateAhkCode((ushort)code, 0); AssertResults(releaseResult, actualResult); }
/// <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); } }
public void PressRelease(string name, List <Stroke> pressStrokes, List <Stroke> releaseStrokes, ExpectedResult pressResult, ExpectedResult releaseResult) { Debug.WriteLine($"\nTesting key {name}..."); Debug.WriteLine("Testing Press"); var expectedResult = pressResult; var actualResult = ScanCodeHelper.TranslateScanCodes(pressStrokes); AssertResult(actualResult, expectedResult); Debug.WriteLine("Testing Release"); expectedResult = releaseResult; actualResult = ScanCodeHelper.TranslateScanCodes(releaseStrokes); AssertResult(actualResult, expectedResult); Debug.WriteLine("OK!"); }
// 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); } } }
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"); }