/// <summary>
        /// Registers the given view on this thread.
        /// </summary>
        internal void RegisterView(IInputEnabledView view)
        {
            view.EnsureNotNull(nameof(view));

            _commandQueue.Enqueue(() =>
            {
                var inputHandlers = InputHandlerFactory.CreateInputHandlersForView(view);
                if (inputHandlers == null)
                {
                    return;
                }
                if (inputHandlers.Count == 0)
                {
                    return;
                }

                // Deregister old input handlers if necessary
                if (_viewInputHandlers.ContainsKey(view))
                {
                    var oldList = _viewInputHandlers[view];

                    foreach (var actOldInputHandler in oldList)
                    {
                        actOldInputHandler.Stop();
                    }
                    _viewInputHandlers.Remove(view);
                }

                // Register new ones
                _viewInputHandlers[view] = inputHandlers;

                foreach (var actInputHandler in inputHandlers)
                {
                    actInputHandler.Start(view);
                }
            });
        }
        protected override void OnTick(EventArgs eArgs)
        {
            base.OnTick(eArgs);

            if (!GraphicsCore.IsLoaded)
            {
                return;
            }

            // Query for all input handlers on first tick
            if (_globalInputHandlers == null)
            {
                _globalInputHandlers = InputHandlerFactory.CreateInputHandlersForGlobal() ?? new List <IInputHandler>(0);
                foreach (var actInputHandler in _globalInputHandlers)
                {
                    actInputHandler.Start(null);
                }
            }

            // Execute all commands within the command queue
            if (_commandQueue.Count > 0)
            {
                var prevCount = _commandQueue.Count;
                var actIndex  = 0;
                while (actIndex < prevCount &&
                       _commandQueue.TryDequeue(out var actCommand))
                {
                    actCommand();
                    actIndex++;
                }
            }

            // Gather all input data
            var expectedStateCount = _lastInputFrame?.CountStates ?? 6;

            // Create new InputFrame object or reuse an old one
            if (_recoveredInputFrames.TryDequeue(out var newInputFrame))
            {
                newInputFrame.Reset(expectedStateCount, s_singleFrameDuration);
            }
            else
            {
                newInputFrame = new InputFrame(expectedStateCount, s_singleFrameDuration);
            }

            // Gather all input states (without dependency to a view)
            foreach (var actInputHandler in _globalInputHandlers)
            {
                actInputHandler.GetInputStates(_cachedStates);
                for (var loop = 0; loop < _cachedStates.Count; loop++)
                {
                    var actInputState = _cachedStates[loop];
                    if (actInputState == null)
                    {
                        continue;
                    }

                    newInputFrame.AddCopyOfState(actInputState, null);
                }
                _cachedStates.Clear();
            }

            // Gather all input states (with view dependency)
            foreach (var actViewSpecificHandlers in _viewInputHandlers)
            {
                var renderLoop = actViewSpecificHandlers.Key.RenderLoop;

                foreach (var actInputHandler in actViewSpecificHandlers.Value)
                {
                    actInputHandler.GetInputStates(_cachedStates);
                    for (var loop = 0; loop < _cachedStates.Count; loop++)
                    {
                        var actInputState = _cachedStates[loop];
                        if (actInputState == null)
                        {
                            continue;
                        }

                        newInputFrame.AddCopyOfState(actInputState, renderLoop.ViewInformation);
                    }
                    _cachedStates.Clear();
                }
            }

            // Store the generated InputFrame
            _lastInputFrame = newInputFrame;
            _gatheredInputFrames.Enqueue(newInputFrame);

            // Ensure that we hold input frames for a maximum time range of a second
            //  (older input is obsolete)
            while (_gatheredInputFrames.Count > SeeingSharpConstants.INPUT_FRAMES_PER_SECOND)
            {
                _gatheredInputFrames.TryDequeue(out _);
            }
        }