private void LoadFromFile(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Filter = "TAS Input Files|*.tas|All Files|*.*";
            DialogResult res = dialog.ShowDialog();

            if (res != DialogResult.OK)
            {
                return;
            }

            string file = dialog.FileName;

            if (!File.Exists(file))
            {
                return;
            }

            using FileStream stream   = File.OpenRead(file);
            using BinaryReader reader = new BinaryReader(stream);

            _frames.Clear();
            while (reader.BaseStream.Position < reader.BaseStream.Length)
            {
                InputFrame frame = DeserializeFrame(reader);
                _frames.Add(frame);
            }

            UpdateFrameBox();

            _lastIndex             = -1;
            frameBox.SelectedIndex = 0;
        }
        private void SetValues(int frameIndex)
        {
            if (frameIndex < 0 || frameIndex >= _frames.Count)
            {
                return;
            }

            InputFrame frame = _frames[frameIndex];

            frameLengthInput.Value = frame.Length;

            keysBox.Items.Clear();
            keysBox.Items.AddRange(frame.Keys.Select(key => key.ToString()).ToArray());

            mouseXInput.Value      = frame.MouseX;
            mouseYInput.Value      = frame.MouseY;
            mouseScrollInput.Value = frame.MouseScroll;
            mouseLeftBox.Checked   = frame.MouseLeft;
            mouseMiddleBox.Checked = frame.MouseMiddle;
            mouseRightBox.Checked  = frame.MouseRight;
            mouse4Box.Checked      = frame.Mouse4;
            mouse5Box.Checked      = frame.Mouse5;

            for (int i = 0; i < 4; i++)
            {
                _pads[i].Connected = frame.Pads[i].Connected;
                _pads[i].SetButtons(frame.Pads[i].Buttons);
                _pads[i].LeftTrigger  = frame.Pads[i].LeftTrigger;
                _pads[i].RightTrigger = frame.Pads[i].RightTrigger;
                _pads[i].LX           = frame.Pads[i].ThumbLX;
                _pads[i].LY           = frame.Pads[i].ThumbLY;
                _pads[i].RX           = frame.Pads[i].ThumbRX;
                _pads[i].RY           = frame.Pads[i].ThumbRY;
            }
        }
        private InputFrame DeserializeFrame(BinaryReader reader)
        {
            int frames = reader.ReadInt32();

            // Keyboard
            byte keyLength = reader.ReadByte();

            XnaKeys[] keys = new XnaKeys[keyLength];
            for (int i = 0; i < keyLength; i++)
            {
                keys[i] = (XnaKeys)reader.ReadByte();
            }

            // Mouse
            int  mouseX       = reader.ReadInt32();
            int  mouseY       = reader.ReadInt32();
            int  mouseScroll  = reader.ReadInt32();
            byte mouseButtons = reader.ReadByte();

            bool leftButton   = (mouseButtons & 0b00001) != 0;
            bool middleButton = (mouseButtons & 0b00010) != 0;
            bool rightButton  = (mouseButtons & 0b00100) != 0;
            bool xButton1     = (mouseButtons & 0b01000) != 0;
            bool xButton2     = (mouseButtons & 0b10000) != 0;

            // Create frame
            InputFrame frame = new InputFrame(frames);

            frame.Keys        = keys;
            frame.MouseX      = mouseX;
            frame.MouseY      = mouseY;
            frame.MouseScroll = mouseScroll;
            frame.MouseLeft   = leftButton;
            frame.MouseMiddle = middleButton;
            frame.MouseRight  = rightButton;
            frame.Mouse4      = xButton1;
            frame.Mouse5      = xButton2;

            // Gamepads
            for (int i = 0; i < 4; i++)
            {
                frame.Pads[i].Connected = reader.ReadBoolean();
                if (!frame.Pads[i].Connected)
                {
                    continue;
                }

                frame.Pads[i].Buttons      = reader.ReadUInt16();
                frame.Pads[i].LeftTrigger  = reader.ReadByte();
                frame.Pads[i].RightTrigger = reader.ReadByte();
                frame.Pads[i].ThumbLX      = reader.ReadInt16();
                frame.Pads[i].ThumbLY      = reader.ReadInt16();
                frame.Pads[i].ThumbRX      = reader.ReadInt16();
                frame.Pads[i].ThumbRY      = reader.ReadInt16();
            }

            return(frame);
        }
        private void SaveValues(int frameIndex)
        {
            if (frameIndex < 0 || frameIndex >= _frames.Count)
            {
                return;
            }

            InputFrame frame = new InputFrame((int)frameLengthInput.Value);

            List <XnaKeys> keys = new List <XnaKeys>();

            foreach (string key in keysBox.Items)
            {
                keys.Add((XnaKeys)Enum.Parse(typeof(XnaKeys), key));
            }

            frame.Keys        = keys.ToArray();
            frame.MouseX      = (int)mouseXInput.Value;
            frame.MouseY      = (int)mouseYInput.Value;
            frame.MouseScroll = (int)mouseScrollInput.Value;
            frame.MouseLeft   = mouseLeftBox.Checked;
            frame.MouseMiddle = mouseMiddleBox.Checked;
            frame.MouseRight  = mouseRightBox.Checked;
            frame.Mouse4      = mouse4Box.Checked;
            frame.Mouse5      = mouse5Box.Checked;

            for (int i = 0; i < 4; i++)
            {
                frame.Pads[i].Connected    = _pads[i].Connected;
                frame.Pads[i].Buttons      = _pads[i].GetButtons();
                frame.Pads[i].LeftTrigger  = _pads[i].LeftTrigger;
                frame.Pads[i].RightTrigger = _pads[i].RightTrigger;
                frame.Pads[i].ThumbLX      = _pads[i].LX;
                frame.Pads[i].ThumbLY      = _pads[i].LY;
                frame.Pads[i].ThumbRX      = _pads[i].RX;
                frame.Pads[i].ThumbRY      = _pads[i].RY;
            }

            int oldFrameCount = _frames[frameIndex].Length;

            _frames[frameIndex] = frame;

            if (oldFrameCount != frame.Length)
            {
                int oldSel = frameBox.SelectedIndex;
                UpdateFrameBox();
                frameBox.SelectedIndex = oldSel;
            }
        }