[OpenTK] Introduce OpenTK (#336)
[platform/core/csapi/tizenfx.git] / external / src / OpenTK / OpenTK / Platform / MappedGamePadDriver.cs
1 //
2 // MappedGamePadDriver.cs
3 //
4 // Author:
5 //       Stefanos A. <stapostol@gmail.com>
6 //
7 // Copyright (c) 2006-2013 Stefanos Apostolopoulos
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 //
27
28 using System;
29 using System.Collections.Generic;
30 using OpenTK.Input;
31
32 namespace OpenTK.Platform
33 {
34     /// \internal
35     /// <summary>
36     /// Implements IGamePadDriver using OpenTK.Input.Joystick
37     /// and a gamepad-specific axis/button mapping.
38     /// </summary>
39     /// <remarks>
40     /// <para>
41     /// This class supports OpenTK and is not meant to be accessed by user code.
42     /// </para>
43     /// <para>
44     /// To support gamepads on platforms that do not offer a gamepad-optimized API,
45     /// we need to use the generic OpenTK.Input.Joystick and implement a custom
46     /// mapping scheme to provide a stable mapping to OpenTK.Input.GamePad. This
47     /// class implements this mapping scheme.
48     /// </para>
49     /// </remarks>
50     internal class MappedGamePadDriver : IGamePadDriver
51     {
52         private readonly GamePadConfigurationDatabase database =
53             new GamePadConfigurationDatabase();
54
55         private readonly Dictionary<Guid, GamePadConfiguration> configurations =
56             new Dictionary<Guid, GamePadConfiguration>();
57
58         public GamePadState GetState(int index)
59         {
60             JoystickState joy = Joystick.GetState(index);
61             GamePadState pad = new GamePadState();
62
63             if (joy.IsConnected)
64             {
65                 pad.SetConnected(true);
66                 pad.SetPacketNumber(joy.PacketNumber);
67
68                 GamePadConfiguration configuration = GetConfiguration(Joystick.GetGuid(index));
69
70                 foreach (GamePadConfigurationItem map in configuration)
71                 {
72                     switch (map.Source.Type)
73                     {
74                         case ConfigurationType.Axis:
75                             {
76                                 // JoystickAxis -> Buttons/GamePadAxes mapping
77                                 int source_axis = map.Source.Axis;
78                                 short value = joy.GetAxisRaw(source_axis);
79
80                                 switch (map.Target.Type)
81                                 {
82                                     case ConfigurationType.Axis:
83                                         pad.SetAxis(map.Target.Axis, value);
84                                         break;
85
86                                     case ConfigurationType.Button:
87                                         // Todo: if SDL2 GameController config is ever updated to
88                                         // distinguish between negative/positive axes, then remove
89                                         // Math.Abs below.
90                                         // Button is considered press when the axis is >= 0.5 from center
91                                         pad.SetButton(map.Target.Button, Math.Abs(value) >= short.MaxValue >> 1);
92                                         break;
93                                 }
94                             }
95                             break;
96
97                         case ConfigurationType.Button:
98                             {
99                                 // JoystickButton -> Buttons/GamePadAxes mapping
100                                 int source_button = map.Source.Button;
101                                 bool pressed = joy.GetButton(source_button) == ButtonState.Pressed;
102
103                                 switch (map.Target.Type)
104                                 {
105                                     case ConfigurationType.Axis:
106                                         // Todo: if SDL2 GameController config is ever updated to
107                                         // distinguish between negative/positive axes, then update
108                                         // the following line to support both.
109                                         short value = pressed ?
110                                             short.MaxValue :
111                                             (map.Target.Axis & (GamePadAxes.LeftTrigger | GamePadAxes.RightTrigger)) != 0 ?
112                                                 short.MinValue :
113                                                 (short)0;
114                                         pad.SetAxis(map.Target.Axis, value);
115                                         break;
116
117                                     case ConfigurationType.Button:
118                                         pad.SetButton(map.Target.Button, pressed);
119                                         break;
120                                 }
121                             }
122                             break;
123
124                         case ConfigurationType.Hat:
125                             {
126                                 // JoystickHat -> Buttons/GamePadAxes mapping
127                                 JoystickHat source_hat = map.Source.Hat;
128                                 JoystickHatState state = joy.GetHat(source_hat);
129
130                                 bool pressed = false;
131                                 switch (map.Source.HatPosition)
132                                 {
133                                     case HatPosition.Down:
134                                         pressed = state.IsDown;
135                                         break;
136
137                                     case HatPosition.Up:
138                                         pressed = state.IsUp;
139                                         break;
140
141                                     case HatPosition.Left:
142                                         pressed = state.IsLeft;
143                                         break;
144
145                                     case HatPosition.Right:
146                                         pressed = state.IsRight;
147                                         break;
148                                 }
149
150                                 switch (map.Target.Type)
151                                 {
152                                     case ConfigurationType.Axis:
153                                         // Todo: if SDL2 GameController config is ever updated to
154                                         // distinguish between negative/positive axes, then update
155                                         // the following line to support both.
156                                         short value = pressed ?
157                                             short.MaxValue :
158                                             (map.Target.Axis & (GamePadAxes.LeftTrigger | GamePadAxes.RightTrigger)) != 0 ?
159                                                 short.MinValue :
160                                                 (short)0;
161                                         pad.SetAxis(map.Target.Axis, value);
162                                         break;
163
164                                     case ConfigurationType.Button:
165                                         pad.SetButton(map.Target.Button, pressed);
166                                         break;
167                                 }
168                             }
169                             break;
170                     }
171                 }
172             }
173
174             return pad;
175         }
176
177         public GamePadCapabilities GetCapabilities(int index)
178         {
179             JoystickCapabilities joy = Joystick.GetCapabilities(index);
180             GamePadCapabilities pad;
181             if (joy.IsConnected)
182             {
183                 GamePadConfiguration configuration = GetConfiguration(Joystick.GetGuid(index));
184                 GamePadAxes mapped_axes = 0;
185                 Buttons mapped_buttons = 0;
186
187                 foreach (GamePadConfigurationItem map in configuration)
188                 {
189                     switch (map.Target.Type)
190                     {
191                         case ConfigurationType.Axis:
192                             mapped_axes |= map.Target.Axis;
193                             break;
194
195                         case ConfigurationType.Button:
196                             mapped_buttons |= map.Target.Button;
197                             break;
198                     }
199                 }
200
201                 pad = new GamePadCapabilities(
202                     GamePadType.GamePad, // Todo: detect different types
203                     mapped_axes,
204                     mapped_buttons,
205                     joy.IsConnected,
206                     configuration.Name != GamePadConfigurationDatabase.UnmappedName);
207             }
208             else
209             {
210                 pad = new GamePadCapabilities();
211             }
212             return pad;
213         }
214
215         public string GetName(int index)
216         {
217             JoystickCapabilities joy = Joystick.GetCapabilities(index);
218             string name = String.Empty;
219             if (joy.IsConnected)
220             {
221                 GamePadConfiguration map = GetConfiguration(Joystick.GetGuid(index));
222                 name = map.Name;
223             }
224             return name;
225         }
226
227         public bool SetVibration(int index, float left, float right)
228         {
229             return false;
230         }
231
232         private GamePadConfiguration GetConfiguration(Guid guid)
233         {
234             if (!configurations.ContainsKey(guid))
235             {
236                 string config = database[guid];
237                 GamePadConfiguration map = new GamePadConfiguration(config);
238                 configurations.Add(guid, map);
239             }
240             return configurations[guid];
241         }
242
243         private bool IsMapped(GamePadConfigurationSource item)
244         {
245             return item.Type != ConfigurationType.Unmapped;
246         }
247     }
248 }