1 module grape.joystick;
2 
3 import derelict.sdl2.sdl;
4 import std.exception : enforce;
5 import std.stdio;
6 
7 enum {
8   MAX_AXIS_STATE = 32767.0
9 }
10 
11 private final class JoystickUnit {
12   public:
13     this(in int deviceIndex) {
14       _joystick = SDL_JoystickOpen(deviceIndex);
15       enforce(_joystick != null, "SDL_JoystickOpen() failed");
16     }
17 
18     ~this() {
19       debug(tor) writeln("JoystickUnit dtor");
20       if (SDL_JoystickGetAttached(_joystick))
21         SDL_JoystickClose(_joystick);
22     }
23 
24     float getAxis(in int axis) {
25       return SDL_JoystickGetAxis(_joystick, axis) / MAX_AXIS_STATE;
26     }
27 
28     int getButton(in int button) {
29       return SDL_JoystickGetButton(_joystick, button);
30     }
31 
32     /*
33     int getBall(int ball) {
34       return SDL_JoystickGetBall(_joystick, ball);
35     }
36     */
37 
38     int getHat(in int hat) {
39       return SDL_JoystickGetHat(_joystick, hat);
40     }
41 
42     int numAxes() {
43       return SDL_JoystickNumAxes(_joystick);
44     }
45 
46     int numButtons() {
47       return SDL_JoystickNumButtons(_joystick);
48     }
49 
50     int numBalls() {
51       return SDL_JoystickNumHats(_joystick);
52     }
53 
54     int numHats() {
55       return SDL_JoystickNumBalls(_joystick);
56     }
57 
58   private:
59     SDL_Joystick* _joystick;
60 }
61 
62 /**
63  * ジョイパッドを管理するクラス
64  */
65 class Joystick {
66   public:
67     /**
68      * ジョイパッドの読み込み
69      *
70      * deviceIndex: 読み込むジョイパッドの番号
71      */
72     this(in int deviceIndex) {
73       if (!_initialized) {
74         _initialized = true;
75         DerelictSDL2.load();
76 
77         if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0)
78           throw new Exception("SDL_InitSubSystem(SDL_INIT_JOYSTICK) failed");
79       }
80 
81       _joystick = new JoystickUnit(deviceIndex);
82       set_num();
83       _instance ~= this;
84     }
85 
86     ~this() {
87       debug(tor) writeln("Joystick dtor");
88       destroy(_joystick);
89     }
90 
91     static ~this() {
92       debug(tor) writeln("Joystick static dtor");
93       if (_initialized) {
94         foreach (v; _instance) destroy(v);      
95         SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
96       }
97     }
98 
99     /**
100      *
101      */
102     float getAxis(in int axis) 
103       in {
104         assert(0 <= axis && axis <= _numAxes);
105       }
106         
107       body {
108         return _joystick.getAxis(axis);
109       }
110 
111     /**
112      *
113      */
114     int getButton(in int button) 
115       in {
116         assert(0 <= button && button <= _numButtons);
117       }
118 
119       body {
120         return _joystick.getButton(button);
121       }
122 
123       /*
124     int getBall(int ball)
125       in {
126         assert(0 <= ball && ball <= _numBalls);
127       }
128 
129       body {
130         return _joystick.getBall(ball);
131       }
132       */
133 
134     /**
135      *
136      */
137     int getHat(in int hat)
138       in {
139         assert(0 <= hat && hat <= _numHats);
140       }
141 
142       body {
143         return _joystick.getHat(hat);
144       }
145 
146     // rename show_info("num")etc...
147     /**
148      * 情報の表示
149      *
150      * 軸の数、ボタンの数、ボールの数、ハットの数を表示します。
151      */
152     void show_info() {
153       writef("axes:%d buttons:%d balls:%d hats:%d \n", _numAxes, _numButtons, _numBalls, _numHats);
154       // writefln
155     }
156 
157     @property {
158       /**
159        * Returns: 軸の総数
160        */
161       int numAxes() {
162         return _numAxes;
163       }
164 
165       /**
166        * Returns: ボタンの総数
167        */
168       int numButtons() {
169         return _numButtons;
170       }
171 
172       /**
173        * Returns: ボールの総数
174        */
175       int numBalls() {
176         return _numBalls;
177       }
178 
179       /**
180        * Returns: ハットの総数
181        */
182       int numHats() {
183         return _numHats;
184       }
185     }
186 
187   private:
188     void set_num() {
189       _numAxes = _joystick.numAxes();
190       _numButtons = _joystick.numButtons();
191       _numBalls = _joystick.numHats();
192       _numHats= _joystick.numBalls();
193     }
194 
195     JoystickUnit _joystick;
196     static Joystick[] _instance;
197     int _numAxes, _numButtons, _numBalls, _numHats;
198     static bool _initialized = false;
199 }
200