/// <summary>
        /// Press mouse's button.
        /// </summary>
        /// <param name="button"> Button to press.</param>
        /// <see cref="SerialSymbols.MouseButton"/>
        /// <seealso cref="MouseReleaseButton"/>
        /// <seealso cref="MouseReleaseAllButtons"/>
        /// <exception cref="SerialDeviceException">If command failed.</exception>
        public Task MousePressButton(SerialSymbols.MouseButton button)
        {
            CheckMouseButton(button);
            SerialCommandFrame frame = SerialCommandFrame.OfKeyType(SerialSymbols.FrameType.MousePress, (byte)button);

            return(_sender.SendFrame(frame));
        }
        /// <summary>
        /// Move the absolute mouse to desired coordinate.
        /// </summary>
        /// <param name="x">Coordinate X</param>
        /// <param name="y">Coordinate Y </param>
        /// <exception cref="ArgumentException">If supplied with non-positive values or out of resolution range.</exception>
        /// <exception cref="SerialDeviceException">If command failed.</exception>
        public Task MoveMouseToCoordinate(int x, int y)
        {
            if (x <= 0 || y <= 0 || x > MouseResolutionWidth || y > MouseResolutionHeight)
            {
                throw new ArgumentOutOfRangeException($"Mouse Coordinate {x},{y} is out of range {MouseResolutionWidth},{MouseResolutionHeight}!\n");
            }
            SerialCommandFrame frame
                = SerialCommandFrame.OfCoordinateType(SerialSymbols.FrameType.MouseMove,
                                                      new Tuple <ushort, ushort>((ushort)x, (ushort)y));

            return(_sender.SendFrame(frame));
        }
        /// <summary>
        /// Set the absolute mouse's resolution.
        /// Note that in firmware, it has a limitation of 8K resolution.
        /// </summary>
        /// <param name="width">Width of resolution.</param>
        /// <param name="height">Height of resolution. </param>
        /// <exception cref="ArgumentException">If supplied with non-positive values</exception>
        /// <exception cref="SerialDeviceException">If command failed.</exception>
        public Task SetMouseResolution(int width, int height)
        {
            if (width <= 0 || height <= 0)
            {
                throw new ArgumentException("Resolution values cannot be negative!");
            }
            MouseResolutionWidth  = width;
            MouseResolutionHeight = height;
            SerialCommandFrame frame
                = SerialCommandFrame.OfCoordinateType(SerialSymbols.FrameType.MouseResolution,
                                                      new Tuple <ushort, ushort>((ushort)width, (ushort)height));

            return(_sender.SendFrame(frame));
        }
        /// <summary>
        /// Scroll the wheel
        /// </summary>
        /// <param name="value">Wheel delta</param>
        /// <exception cref="SerialDeviceException">If command failed.</exception>
        public Task MouseScroll(sbyte value)
        {
            SerialCommandFrame frame = SerialCommandFrame.OfKeyType(SerialSymbols.FrameType.MouseScroll, (byte)value);

            return(_sender.SendFrame(frame));
        }
        /// <summary>
        /// Release all keys.
        /// </summary>
        /// <seealso cref="KeyboardPress"/>
        /// <seealso cref="KeyboardRelease"/>
        /// <seealso cref="HidHelper.GetHidUsageFromPs2Set1"/>
        /// <exception cref="SerialDeviceException">If command failed.</exception>
        public Task KeyboardReleaseAll()
        {
            SerialCommandFrame frame = SerialCommandFrame.OfKeyType(SerialSymbols.FrameType.KeyboardRelease, SerialSymbols.ReleaseAllKeys);

            return(_sender.SendFrame(frame).ContinueWith(task => Array.Fill(_keyboardKeyStates, false)));
        }
        /// <summary>
        /// Release the specific key.
        /// </summary>
        /// <param name="key">The HID usage id combined with modifiers.</param>
        /// <seealso cref="KeyboardPress"/>
        /// <seealso cref="KeyboardReleaseAll"/>
        /// <seealso cref="HidHelper.GetHidUsageFromPs2Set1"/>
        /// <exception cref="SerialDeviceException">If command failed.</exception>
        public Task KeyboardRelease(byte key)
        {
            SerialCommandFrame frame = SerialCommandFrame.OfKeyType(SerialSymbols.FrameType.KeyboardRelease, key);

            return(_sender.SendFrame(frame).ContinueWith(task => _keyboardKeyStates[key] = false));
        }
        /// <summary>
        /// Release all mouse's buttons.
        /// </summary>
        /// <see cref="SerialSymbols.MouseButton"/>
        /// <seealso cref="MousePressButton"/>
        /// <seealso cref="MouseReleaseButton"/>
        /// <exception cref="SerialDeviceException">If command failed.</exception>
        public Task MouseReleaseAllButtons()
        {
            SerialCommandFrame frame = SerialCommandFrame.OfKeyType(SerialSymbols.FrameType.MouseRelease, SerialSymbols.ReleaseAllKeys);

            return(_sender.SendFrame(frame));
        }