public void HandleKeyDown([NotNull] WirelessNetworkAddress source, RemoteKey key,
            [CanBeNull] TimeSpan? sensorTime)
        {
            Guard.NotNull(source, nameof(source));

            KeyCategory keyCategory = GetCategoryForKey(key);

            if (keyCategory != KeyCategory.CommandOnly && HasModifierDownThatMatchesEntryState(source))
            {
                int digit = GetDigitForKey(key);
                if (numberEntryState.AppendToNumber(digit))
                {
                    // ReSharper disable once PossibleInvalidOperationException
                    // Reason: Call to AppendToNumber() above guarantees that value is not null.
                    int number = numberEntryState.Number.Value;

                    if (number > 0)
                    {
                        bool isCurrentCompetitor = numberEntryState.Mode == NumberEntryMode.EnteringCurrentCompetitor;
                        var args = new CompetitorNumberSelectionEventArgs(number, isCurrentCompetitor);
                        NotifyDigitReceived?.Invoke(this, args);
                    }
                }
            }

            if (keyCategory == KeyCategory.CommandOnly ||
                (keyCategory == KeyCategory.DigitAndCommand && modifierStatePerDevice.IsEmpty(source)))
            {
                NotifyUnknownAction?.Invoke(this, new UnknownDeviceActionEventArgs(source, sensorTime, key));
            }
        }
        public void HandleModifierKeyUp([NotNull] WirelessNetworkAddress source, RemoteKeyModifier modifier)
        {
            Guard.NotNull(source, nameof(source));

            modifierStatePerDevice.EnsureNotDown(source, modifier);

            NumberEntryMode matchingEntryMode = GetMatchingEntryModeForModifier(modifier);

            if (numberEntryState.Mode == matchingEntryMode)
            {
                int? builtNumber = numberEntryState.Number;

                numberEntryState.ChangeMode(NumberEntryMode.None);

                bool isCurrentCompetitor = modifier == RemoteKeyModifier.EnterCurrentCompetitor;
                if (builtNumber == null || builtNumber == 0)
                {
                    var args = new CompetitorSelectionEventArgs(isCurrentCompetitor);
                    NotifyCompetitorSelectCanceled?.Invoke(this, args);
                }
                else
                {
                    var args = new CompetitorNumberSelectionEventArgs(builtNumber.Value, isCurrentCompetitor);
                    NotifyCompetitorSelected?.Invoke(this, args);
                }
            }
        }