aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/Input/Controller/BaseController.cs
blob: dfd54a8324bc0ecafd88f0cc382dcf7e323fd179 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using static Ryujinx.HLE.Input.Hid;

namespace Ryujinx.HLE.Input
{
    public abstract class BaseController : IHidDevice
    {
        protected ControllerStatus HidControllerType;
        protected ControllerId     ControllerId;

        private long _currentLayoutOffset;
        private long _mainLayoutOffset;

        protected long DeviceStateOffset => Offset + 0x4188;

        protected Switch Device { get; }

        public long Offset    { get; private set; }
        public bool Connected { get; protected set; }

        public ControllerHeader            Header             { get; private set; }
        public ControllerStateHeader       CurrentStateHeader { get; private set; }
        public ControllerDeviceState       DeviceState        { get; private set; }
        public ControllerLayouts           CurrentLayout      { get; private set; }
        public ControllerState             LastInputState     { get; set; }
        public ControllerConnectionState   ConnectionState    { get; protected set; }

        public BaseController(Switch device, ControllerStatus controllerType)
        {
            Device            = device;
            HidControllerType = controllerType;
        }

        protected void Initialize(
            bool isHalf,
            (NpadColor left, NpadColor right) bodyColors,
            (NpadColor left, NpadColor right) buttonColors,
            ControllerColorDescription        singleColorDesc   = 0,
            ControllerColorDescription        splitColorDesc    = 0,
            NpadColor                         singleBodyColor   = 0,
            NpadColor                         singleButtonColor = 0
            )
        {
            Header = new ControllerHeader()
            {
                IsJoyConHalf           = isHalf ? 1 : 0,
                LeftBodyColor          = bodyColors.left,
                LeftButtonColor        = buttonColors.left,
                RightBodyColor         = bodyColors.right,
                RightButtonColor       = buttonColors.right,
                Status                 = HidControllerType,
                SingleBodyColor        = singleBodyColor,
                SingleButtonColor      = singleButtonColor,
                SplitColorDescription  = splitColorDesc,
                SingleColorDescription = singleColorDesc,
            };

            CurrentStateHeader = new ControllerStateHeader
            {
                EntryCount        = HidEntryCount,
                MaxEntryCount     = HidEntryCount - 1,
                CurrentEntryIndex = -1
            };

            DeviceState = new ControllerDeviceState()
            {
                PowerInfo0BatteryState = BatteryState.Percent100,
                PowerInfo1BatteryState = BatteryState.Percent100,
                PowerInfo2BatteryState = BatteryState.Percent100,
                DeviceType             = ControllerDeviceType.NPadLeftController | ControllerDeviceType.NPadRightController,
                DeviceFlags            = DeviceFlags.PowerInfo0Connected
                                            | DeviceFlags.PowerInfo1Connected
                                            | DeviceFlags.PowerInfo2Connected
            };

            LastInputState = new ControllerState()
            {
                SamplesTimestamp  = -1,
                SamplesTimestamp2 = -1
            };
        }

        public virtual void Connect(ControllerId controllerId)
        {
            ControllerId = controllerId;

            Offset = Device.Hid.HidPosition + HidControllersOffset + (int)controllerId * HidControllerSize;

            _mainLayoutOffset = Offset + HidControllerHeaderSize
                + ((int)ControllerLayouts.Main * HidControllerLayoutsSize);

            Device.Memory.FillWithZeros(Offset, 0x5000);
            Device.Memory.WriteStruct(Offset, Header);
            Device.Memory.WriteStruct(DeviceStateOffset, DeviceState);

            Connected = true;
        }

        public void SetLayout(ControllerLayouts controllerLayout)
        {
            CurrentLayout = controllerLayout;

            _currentLayoutOffset = Offset + HidControllerHeaderSize
                + ((int)controllerLayout * HidControllerLayoutsSize);
        }

        public void SendInput(
            ControllerButtons buttons,
            JoystickPosition  leftStick,
            JoystickPosition  rightStick)
        {
            ControllerState currentInput = new ControllerState()
            {
                SamplesTimestamp  = (long)LastInputState.SamplesTimestamp + 1,
                SamplesTimestamp2 = (long)LastInputState.SamplesTimestamp + 1,
                ButtonState       = buttons,
                ConnectionState   = ConnectionState,
                LeftStick         = leftStick,
                RightStick        = rightStick
            };

            ControllerStateHeader newInputStateHeader = new ControllerStateHeader
            {
                EntryCount        = HidEntryCount,
                MaxEntryCount     = HidEntryCount - 1,
                CurrentEntryIndex = (CurrentStateHeader.CurrentEntryIndex + 1) % HidEntryCount,
                Timestamp         = GetTimestamp(),
            };

            Device.Memory.WriteStruct(_currentLayoutOffset, newInputStateHeader);
            Device.Memory.WriteStruct(_mainLayoutOffset,    newInputStateHeader);

            long currentInputStateOffset = HidControllersLayoutHeaderSize
                + newInputStateHeader.CurrentEntryIndex * HidControllersInputEntrySize;

            Device.Memory.WriteStruct(_currentLayoutOffset + currentInputStateOffset, currentInput);
            Device.Memory.WriteStruct(_mainLayoutOffset + currentInputStateOffset,    currentInput);

            LastInputState     = currentInput;
            CurrentStateHeader = newInputStateHeader;
        }
    }
}