1 module Dgame.System.GameController;
2 
3 private:
4 
5 import derelict.sdl2.sdl;
6 
7 import Dgame.System.Joystick;
8 
9 import Dgame.Internal.Error;
10 
11 public:
12 
13 /**
14  * Represent a Game Controller
15  *
16  * Author: Randy Schuett (rswhite4@googlemail.com)
17  */
18 struct GameController {
19 private:
20     SDL_GameController* _controller;
21 
22 public:
23     /**
24      * Supported Game Controller Axis
25      */
26     enum Axis {
27         Invalid = SDL_CONTROLLER_AXIS_INVALID, ///
28         LeftX = SDL_CONTROLLER_AXIS_LEFTX, ///
29         LeftY = SDL_CONTROLLER_AXIS_LEFTY, ///
30         RightX = SDL_CONTROLLER_AXIS_RIGHTX, ///
31         RightY = SDL_CONTROLLER_AXIS_RIGHTY, ///
32         TriggerLeft = SDL_CONTROLLER_AXIS_TRIGGERLEFT, ///
33         TriggerRight = SDL_CONTROLLER_AXIS_TRIGGERRIGHT ///
34     }
35 
36     /**
37      * Supported Game Controller Buttons
38      */
39     enum Button {
40         Invalid = SDL_CONTROLLER_BUTTON_INVALID, ///
41         A = SDL_CONTROLLER_BUTTON_A, ///
42         B = SDL_CONTROLLER_BUTTON_B, ///
43         X = SDL_CONTROLLER_BUTTON_X, ///
44         Y = SDL_CONTROLLER_BUTTON_Y, ///
45         Back = SDL_CONTROLLER_BUTTON_BACK, ///
46         Guide = SDL_CONTROLLER_BUTTON_GUIDE, ///
47         Start = SDL_CONTROLLER_BUTTON_START, ///
48         LeftStick = SDL_CONTROLLER_BUTTON_LEFTSTICK, ///
49         RightStick = SDL_CONTROLLER_BUTTON_RIGHTSTICK, ///
50         LeftShoulder = SDL_CONTROLLER_BUTTON_LEFTSHOULDER, ///
51         RightShoulder = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, ///
52         DPadUp = SDL_CONTROLLER_BUTTON_DPAD_UP, ///
53         DPadDown = SDL_CONTROLLER_BUTTON_DPAD_DOWN, ///
54         DPadLeft = SDL_CONTROLLER_BUTTON_DPAD_LEFT, ///
55         DPadRight = SDL_CONTROLLER_BUTTON_DPAD_RIGHT ///
56     }
57 
58     /**
59      * CTor
60      */
61     @nogc
62     this(int device) nothrow {
63         _controller = SDL_GameControllerOpen(device);
64         if (!_controller)
65             print_fmt("Warning: Unable to open game controller %d! Error: %s\n", device, SDL_GetError());
66     }
67 
68     /**
69      * Postblit is disabled
70      */
71     @disable
72     this(this);
73 
74     /**
75      * DTor
76      */
77     @nogc
78     ~this() nothrow {
79         if (_controller)
80             SDL_GameControllerClose(_controller);
81     }
82 
83     /**
84      * Returns if the GameController has been opened and is currently connected.
85      */
86     @nogc
87     bool isAttached() nothrow {
88         return SDL_GameControllerGetAttached(_controller) == SDL_TRUE;
89     }
90 
91     /**
92      * Returns the value of the given Axis.
93      * The value is in range of short.min .. short.max
94      *
95      * See: Axis enum
96      */
97     @nogc
98     short getAxisValue(Axis axis) nothrow {
99         return SDL_GameControllerGetAxis(_controller, axis);
100     }
101 
102     /**
103      * Returns whether the given Button is pressed
104      */
105     @nogc
106     bool isPressed(Button btn) nothrow {
107         return SDL_GameControllerGetButton(_controller, btn) == 1;
108     }
109 
110     /**
111      * Returns the name of the GameController
112      */
113     @nogc
114     string getName() nothrow {
115         import core.stdc..string : strlen;
116 
117         const char* p = SDL_GameControllerName(_controller);
118         if (!p)
119             return null;
120 
121         return cast(immutable) p[0 .. strlen(p)];
122     }
123 
124     /**
125      * Returns the mapping of the GameController
126      */
127     @nogc
128     string getMapping() nothrow {
129         import core.stdc..string : strlen;
130 
131         const char* p =  SDL_GameControllerMapping(_controller);
132         if (!p)
133             return null;
134 
135         return cast(immutable) p[0 .. strlen(p)];
136     }
137 
138     /**
139      * Returns the Joystick interface of the GameController
140      */
141     @nogc
142     Joystick getJoystick() nothrow {
143         SDL_Joystick* joy = SDL_GameControllerGetJoystick(_controller);
144 
145         return Joystick(joy);
146     }
147 
148     /**
149      * Use this function to update the current state of the open GameController.
150      * This function is called automatically by the event loop
151      */
152     @nogc
153     static void update() nothrow {
154         SDL_GameControllerUpdate();
155     }
156 
157     /**
158      * Returns the name of the GameController of the given device
159      */
160     @nogc
161     static string getNameForIndex(int device) nothrow {
162         import core.stdc..string : strlen;
163 
164         const char* p = SDL_GameControllerNameForIndex(device);
165         if (!p)
166             return null;
167 
168         return cast(immutable) p[0 .. strlen(p)];
169     }
170 
171     /**
172      * Returns if the given device (e.g. a Joystick) is supported by the GameController interface.
173      *
174      * Note: Only if this method returns true, the device can be handled with the GameController struct
175      */
176     @nogc
177     static bool isGameController(int device) nothrow {
178         return SDL_IsGameController(device) == SDL_TRUE;
179     }
180 }