public void When_notify_action_operation_is_received_it_must_raise_event_for_action()
        {
            // Arrange
            var deviceAddress              = new WirelessNetworkAddress("AABBCC");
            const RawDeviceKeys inputKeys  = RawDeviceKeys.Key1OrPlaySoundA;
            TimeSpan            sensorTime = TimeSpan.FromMilliseconds(3456);

            using var testRunner = new CirceUsbLoopbackTestRunner <DeviceAction>();

            testRunner.RemoteSessionManager.ConnectionStateChanged += (_, e) =>
            {
                if (e.State == ControllerConnectionState.Connected)
                {
                    testRunner.Connection.Send(new NotifyActionOperation(deviceAddress)
                    {
                        InputKeys  = inputKeys,
                        SensorTime = sensorTime
                    });
                }
            };

            testRunner.RemoteSessionManager.DeviceActionReceived += (_, e) => testRunner.SignalSucceeded(e.Argument);

            // Act
            bool succeeded = testRunner.Start();

            // Assert
            succeeded.Should().Be(true, "<USB loopback cable must be connected and COM port must be correct.>");
            testRunner.Result.ShouldNotBeNull();
            testRunner.Result.DeviceAddress.Should().Be(deviceAddress);
            testRunner.Result.InputKeys.Should().Be(inputKeys);
            testRunner.Result.SensorTime.Should().Be(sensorTime);
        }
        private void ProcessRawKeysDown([NotNull] WirelessNetworkAddress source, RawDeviceKeys rawKeysDown,
            [CanBeNull] TimeSpan? sensorTime)
        {
            RawDeviceKeys precedingKeysDown = GetPrecedingKeysDownForDevice(source);

            RaiseModifierDownEvents(source, rawKeysDown, precedingKeysDown, sensorTime);

            RaiseKeyDownEvents(source, rawKeysDown, precedingKeysDown, sensorTime);

            RaiseKeyUpEvents(source, rawKeysDown, precedingKeysDown, sensorTime);

            RaiseModifierUpEvents(source, rawKeysDown, precedingKeysDown, sensorTime);

            precedingRawKeysDownPerDevice[source] = rawKeysDown;
        }
 public static RawDeviceKeys Push(this RawDeviceKeys source, RawDeviceKeys key)
 {
     return(source | key);
 }
 public static RawDeviceKeys Release(this RawDeviceKeys source, RawDeviceKeys key)
 {
     return(source & ~key);
 }
        private void RaiseModifierDownEvents([NotNull] WirelessNetworkAddress source, RawDeviceKeys rawKeysDown,
            RawDeviceKeys precedingKeysDown, [CanBeNull] TimeSpan? sensorTime)
        {
            foreach (KeyValuePair<RawDeviceKeys, RemoteKeyModifier> entry in ModifierKeyTranslationTable)
            {
                ChangeType changeType = GetChangeForKey(entry.Key, rawKeysDown, precedingKeysDown);
                if (changeType == ChangeType.Down)
                {
                    Log.Debug($"ModifierKeyDown of {entry.Value} from {source}");

                    var args = new RemoteKeyModifierEventArgs(source, entry.Value, sensorTime);
                    ModifierKeyDown?.Invoke(this, args);
                }
            }
        }
        private static ChangeType GetChangeForKey(RawDeviceKeys targetKey, RawDeviceKeys rawKeysDown,
            RawDeviceKeys precedingKeysDown)
        {
            RawDeviceKeys lastKeyValue = precedingKeysDown & targetKey;
            RawDeviceKeys thisKeyValue = rawKeysDown & targetKey;

            bool hasChanged = (lastKeyValue ^ thisKeyValue) != 0;

            return !hasChanged ? ChangeType.None : thisKeyValue != 0 ? ChangeType.Down : ChangeType.Up;
        }
        private void HandleKeyChange(RawDeviceKeys keyChanged, bool isKeyDownEvent)
        {
            if (isKeyDownEvent)
            {
                keysDown |= keyChanged;
            }
            else
            {
                keysDown &= ~keyChanged;
            }

            KeysDownChanged?.Invoke(this, new EventArgs<RawDeviceKeys>(keysDown));
        }
        private string GetButtonText(RawDeviceKeys key)
        {
            bool hasCore = (Features & RemoteEmulatorFeatures.CoreKeys) != 0;
            bool hasNumeric = (Features & RemoteEmulatorFeatures.NumericKeys) != 0;
            bool hasTimer = (Features & RemoteEmulatorFeatures.TimerKeys) != 0;
            bool inEntry = InDigitEntryMode;

            switch (key)
            {
                case RawDeviceKeys.Key1OrPlaySoundA:
                    return hasNumeric && (!hasCore || inEntry) ? "1" : (hasCore ? "Sound A" : string.Empty);
                case RawDeviceKeys.Key2OrPassIntermediate:
                    return hasNumeric && (!hasTimer || inEntry) ? "2" : (hasTimer ? "Intermediate" : string.Empty);
                case RawDeviceKeys.Key3OrToggleElimination:
                    return hasNumeric && (!hasCore || inEntry) ? "3" : (hasCore ? "E" : string.Empty);
                case RawDeviceKeys.Key4:
                    return hasNumeric ? "4" : string.Empty;
                case RawDeviceKeys.Key5OrDecreaseRefusals:
                    return hasNumeric && (!hasCore || inEntry) ? "5" : (hasCore ? "R-" : string.Empty);
                case RawDeviceKeys.Key6OrIncreaseRefusals:
                    return hasNumeric && (!hasCore || inEntry) ? "6" : (hasCore ? "R+" : string.Empty);
                case RawDeviceKeys.Key7:
                    return hasNumeric ? "7" : string.Empty;
                case RawDeviceKeys.Key8OrDecreaseFaults:
                    return hasNumeric && (!hasCore || inEntry) ? "8" : (hasCore ? "F-" : string.Empty);
                case RawDeviceKeys.Key9OrIncreaseFaults:
                    return hasNumeric && (!hasCore || inEntry) ? "9" : (hasCore ? "F+" : string.Empty);
                case RawDeviceKeys.EnterCurrentCompetitor:
                    return hasNumeric ? "Current" : string.Empty;
                case RawDeviceKeys.EnterNextCompetitor:
                    return hasNumeric ? "Next" : string.Empty;
                case RawDeviceKeys.Key0OrMuteSound:
                    return hasNumeric && (!hasCore || inEntry) ? "0" : (hasCore ? "Mute" : string.Empty);
                case RawDeviceKeys.PassFinish:
                    return hasTimer ? "Finish" : string.Empty;
                case RawDeviceKeys.PassStart:
                    return hasTimer ? "Start" : string.Empty;
                case RawDeviceKeys.ResetRun:
                    return hasCore ? "Reset" : string.Empty;
                case RawDeviceKeys.Ready:
                    return hasCore ? "Ready" : string.Empty;
                default:
                    throw new InvalidOperationException($"No text available for key {key}.");
            }
        }
 public static RawDeviceKeys Push(this RawDeviceKeys source, RawDeviceKeys key)
 {
     return source | key;
 }
 public static RawDeviceKeys Release(this RawDeviceKeys source, RawDeviceKeys key)
 {
     return source & ~key;
 }