1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | // LOVE |
22 | #include "wrap_Joystick.h" |
23 | #include "wrap_JoystickModule.h" |
24 | |
25 | #include <vector> |
26 | |
27 | namespace love |
28 | { |
29 | namespace joystick |
30 | { |
31 | |
32 | Joystick *luax_checkjoystick(lua_State *L, int idx) |
33 | { |
34 | return luax_checktype<Joystick>(L, idx); |
35 | } |
36 | |
37 | int w_Joystick_isConnected(lua_State *L) |
38 | { |
39 | Joystick *j = luax_checkjoystick(L, 1); |
40 | luax_pushboolean(L, j->isConnected()); |
41 | return 1; |
42 | } |
43 | |
44 | int w_Joystick_getName(lua_State *L) |
45 | { |
46 | Joystick *j = luax_checkjoystick(L, 1); |
47 | lua_pushstring(L, j->getName()); |
48 | return 1; |
49 | } |
50 | |
51 | int w_Joystick_getID(lua_State *L) |
52 | { |
53 | Joystick *j = luax_checkjoystick(L, 1); |
54 | |
55 | // IDs are 1-based in Lua. |
56 | lua_pushinteger(L, j->getID() + 1); |
57 | |
58 | int instanceid = j->getInstanceID(); |
59 | if (instanceid >= 0) |
60 | lua_pushinteger(L, instanceid + 1); |
61 | else |
62 | lua_pushnil(L); |
63 | |
64 | return 2; |
65 | } |
66 | |
67 | int w_Joystick_getGUID(lua_State *L) |
68 | { |
69 | Joystick *j = luax_checkjoystick(L, 1); |
70 | luax_pushstring(L, j->getGUID()); |
71 | return 1; |
72 | } |
73 | |
74 | int w_Joystick_getDeviceInfo(lua_State *L) |
75 | { |
76 | Joystick *j = luax_checkjoystick(L, 1); |
77 | |
78 | int vendorID = 0, productID = 0, productVersion = 0; |
79 | j->getDeviceInfo(vendorID, productID, productVersion); |
80 | |
81 | lua_pushnumber(L, vendorID); |
82 | lua_pushnumber(L, productID); |
83 | lua_pushnumber(L, productVersion); |
84 | |
85 | return 3; |
86 | } |
87 | |
88 | int w_Joystick_getAxisCount(lua_State *L) |
89 | { |
90 | Joystick *j = luax_checkjoystick(L, 1); |
91 | lua_pushinteger(L, j->getAxisCount()); |
92 | return 1; |
93 | } |
94 | |
95 | int w_Joystick_getButtonCount(lua_State *L) |
96 | { |
97 | Joystick *j = luax_checkjoystick(L, 1); |
98 | lua_pushinteger(L, j->getButtonCount()); |
99 | return 1; |
100 | } |
101 | |
102 | int w_Joystick_getHatCount(lua_State *L) |
103 | { |
104 | Joystick *j = luax_checkjoystick(L, 1); |
105 | lua_pushinteger(L, j->getHatCount()); |
106 | return 1; |
107 | } |
108 | |
109 | int w_Joystick_getAxis(lua_State *L) |
110 | { |
111 | Joystick *j = luax_checkjoystick(L, 1); |
112 | int axisindex = (int) luaL_checkinteger(L, 2) - 1; |
113 | lua_pushnumber(L, j->getAxis(axisindex)); |
114 | return 1; |
115 | } |
116 | |
117 | int w_Joystick_getAxes(lua_State *L) |
118 | { |
119 | Joystick *j = luax_checkjoystick(L, 1); |
120 | std::vector<float> axes = j->getAxes(); |
121 | |
122 | for (float value : axes) |
123 | lua_pushnumber(L, value); |
124 | |
125 | return (int) axes.size(); |
126 | } |
127 | |
128 | int w_Joystick_getHat(lua_State *L) |
129 | { |
130 | Joystick *j = luax_checkjoystick(L, 1); |
131 | int hatindex = (int) luaL_checkinteger(L, 2) - 1; |
132 | |
133 | Joystick::Hat h = j->getHat(hatindex); |
134 | |
135 | const char *direction = "" ; |
136 | Joystick::getConstant(h, direction); |
137 | |
138 | lua_pushstring(L, direction); |
139 | return 1; |
140 | } |
141 | |
142 | int w_Joystick_isDown(lua_State *L) |
143 | { |
144 | Joystick *j = luax_checkjoystick(L, 1); |
145 | |
146 | bool istable = lua_istable(L, 2); |
147 | int num = istable ? (int) luax_objlen(L, 2) : (lua_gettop(L) - 1); |
148 | |
149 | if (num == 0) |
150 | luaL_checkinteger(L, 2); |
151 | |
152 | std::vector<int> buttons; |
153 | buttons.reserve(num); |
154 | |
155 | if (istable) |
156 | { |
157 | for (int i = 0; i < num; i++) |
158 | { |
159 | lua_rawgeti(L, 2, i + 1); |
160 | buttons.push_back((int) luaL_checkinteger(L, -1) - 1); |
161 | lua_pop(L, 1); |
162 | } |
163 | } |
164 | else |
165 | { |
166 | for (int i = 0; i < num; i++) |
167 | buttons.push_back((int) luaL_checkinteger(L, i + 2) - 1); |
168 | } |
169 | |
170 | luax_pushboolean(L, j->isDown(buttons)); |
171 | return 1; |
172 | } |
173 | |
174 | int w_Joystick_isGamepad(lua_State *L) |
175 | { |
176 | Joystick *j = luax_checkjoystick(L, 1); |
177 | luax_pushboolean(L, j->isGamepad()); |
178 | return 1; |
179 | } |
180 | |
181 | int w_Joystick_getGamepadAxis(lua_State *L) |
182 | { |
183 | Joystick *j = luax_checkjoystick(L, 1); |
184 | |
185 | const char *str = luaL_checkstring(L, 2); |
186 | Joystick::GamepadAxis axis; |
187 | |
188 | if (!joystick::Joystick::getConstant(str, axis)) |
189 | return luax_enumerror(L, "gamepad axis" , str); |
190 | |
191 | lua_pushnumber(L, j->getGamepadAxis(axis)); |
192 | return 1; |
193 | } |
194 | |
195 | int w_Joystick_isGamepadDown(lua_State *L) |
196 | { |
197 | Joystick *j = luax_checkjoystick(L, 1); |
198 | |
199 | bool istable = lua_istable(L, 2); |
200 | int num = istable ? (int) luax_objlen(L, 2) : (lua_gettop(L) - 1); |
201 | |
202 | if (num == 0) |
203 | luaL_checkstring(L, 2); |
204 | |
205 | std::vector<Joystick::GamepadButton> buttons; |
206 | buttons.reserve(num); |
207 | |
208 | Joystick::GamepadButton button; |
209 | |
210 | if (istable) |
211 | { |
212 | for (int i = 0; i < num; i++) |
213 | { |
214 | lua_rawgeti(L, 2, i + 1); |
215 | const char *str = luaL_checkstring(L, -1); |
216 | |
217 | if (!joystick::Joystick::getConstant(str, button)) |
218 | return luax_enumerror(L, "gamepad button" , str); |
219 | |
220 | buttons.push_back(button); |
221 | |
222 | lua_pop(L, 1); |
223 | } |
224 | } |
225 | else |
226 | { |
227 | for (int i = 0; i < num; i++) |
228 | { |
229 | const char *str = luaL_checkstring(L, i + 2); |
230 | |
231 | if (!joystick::Joystick::getConstant(str, button)) |
232 | return luax_enumerror(L, "gamepad button" , str); |
233 | |
234 | buttons.push_back(button); |
235 | } |
236 | } |
237 | |
238 | luax_pushboolean(L, j->isGamepadDown(buttons)); |
239 | return 1; |
240 | } |
241 | |
242 | int w_Joystick_getGamepadMapping(lua_State *L) |
243 | { |
244 | Joystick *j = luax_checkjoystick(L, 1); |
245 | |
246 | const char *gpbindstr = luaL_checkstring(L, 2); |
247 | Joystick::GamepadInput gpinput; |
248 | |
249 | if (Joystick::getConstant(gpbindstr, gpinput.axis)) |
250 | gpinput.type = Joystick::INPUT_TYPE_AXIS; |
251 | else if (Joystick::getConstant(gpbindstr, gpinput.button)) |
252 | gpinput.type = Joystick::INPUT_TYPE_BUTTON; |
253 | else |
254 | return luax_enumerror(L, "gamepad axis/button" , gpbindstr); |
255 | |
256 | Joystick::JoystickInput jinput; |
257 | jinput.type = Joystick::INPUT_TYPE_MAX_ENUM; |
258 | |
259 | luax_catchexcept(L, [&](){ jinput = j->getGamepadMapping(gpinput); }); |
260 | |
261 | if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM) |
262 | return 0; |
263 | |
264 | const char *inputtypestr; |
265 | if (!Joystick::getConstant(jinput.type, inputtypestr)) |
266 | return luaL_error(L, "Unknown joystick input type." ); |
267 | |
268 | lua_pushstring(L, inputtypestr); |
269 | |
270 | const char *hatstr; |
271 | switch (jinput.type) |
272 | { |
273 | case Joystick::INPUT_TYPE_AXIS: |
274 | lua_pushinteger(L, jinput.axis + 1); |
275 | return 2; |
276 | case Joystick::INPUT_TYPE_BUTTON: |
277 | lua_pushinteger(L, jinput.button + 1); |
278 | return 2; |
279 | case Joystick::INPUT_TYPE_HAT: |
280 | lua_pushinteger(L, jinput.hat.index + 1); |
281 | if (Joystick::getConstant(jinput.hat.value, hatstr)) |
282 | { |
283 | lua_pushstring(L, hatstr); |
284 | return 3; |
285 | } |
286 | else |
287 | return luaL_error(L, "Unknown joystick hat." ); |
288 | default: |
289 | return luaL_error(L, "Unknown joystick input type." ); |
290 | } |
291 | |
292 | return 1; |
293 | } |
294 | |
295 | int w_Joystick_getGamepadMappingString(lua_State *L) |
296 | { |
297 | Joystick *j = luax_checkjoystick(L, 1); |
298 | std::string mapping = j->getGamepadMappingString(); |
299 | if (mapping.empty()) |
300 | lua_pushnil(L); |
301 | else |
302 | luax_pushstring(L, mapping); |
303 | return 1; |
304 | } |
305 | |
306 | int w_Joystick_isVibrationSupported(lua_State *L) |
307 | { |
308 | Joystick *j = luax_checkjoystick(L, 1); |
309 | luax_pushboolean(L, j->isVibrationSupported()); |
310 | return 1; |
311 | } |
312 | |
313 | int w_Joystick_setVibration(lua_State *L) |
314 | { |
315 | Joystick *j = luax_checkjoystick(L, 1); |
316 | bool success = false; |
317 | |
318 | if (lua_isnoneornil(L, 2)) |
319 | { |
320 | // Disable joystick vibration if no argument is given. |
321 | success = j->setVibration(); |
322 | } |
323 | else |
324 | { |
325 | float left = (float) luaL_checknumber(L, 2); |
326 | float right = (float) luaL_optnumber(L, 3, left); |
327 | float duration = (float) luaL_optnumber(L, 4, -1.0); // -1 is infinite. |
328 | success = j->setVibration(left, right, duration); |
329 | } |
330 | |
331 | luax_pushboolean(L, success); |
332 | return 1; |
333 | } |
334 | |
335 | int w_Joystick_getVibration(lua_State *L) |
336 | { |
337 | Joystick *j = luax_checkjoystick(L, 1); |
338 | float left, right; |
339 | j->getVibration(left, right); |
340 | lua_pushnumber(L, left); |
341 | lua_pushnumber(L, right); |
342 | return 2; |
343 | } |
344 | |
345 | // List of functions to wrap. |
346 | static const luaL_Reg w_Joystick_functions[] = |
347 | { |
348 | { "isConnected" , w_Joystick_isConnected }, |
349 | { "getName" , w_Joystick_getName }, |
350 | { "getID" , w_Joystick_getID }, |
351 | { "getGUID" , w_Joystick_getGUID }, |
352 | { "getDeviceInfo" , w_Joystick_getDeviceInfo }, |
353 | { "getAxisCount" , w_Joystick_getAxisCount }, |
354 | { "getButtonCount" , w_Joystick_getButtonCount }, |
355 | { "getHatCount" , w_Joystick_getHatCount }, |
356 | { "getAxis" , w_Joystick_getAxis }, |
357 | { "getAxes" , w_Joystick_getAxes }, |
358 | { "getHat" , w_Joystick_getHat }, |
359 | { "isDown" , w_Joystick_isDown }, |
360 | |
361 | { "isGamepad" , w_Joystick_isGamepad }, |
362 | { "getGamepadAxis" , w_Joystick_getGamepadAxis }, |
363 | { "isGamepadDown" , w_Joystick_isGamepadDown }, |
364 | { "getGamepadMapping" , w_Joystick_getGamepadMapping }, |
365 | { "getGamepadMappingString" , w_Joystick_getGamepadMappingString }, |
366 | |
367 | { "isVibrationSupported" , w_Joystick_isVibrationSupported }, |
368 | { "setVibration" , w_Joystick_setVibration }, |
369 | { "getVibration" , w_Joystick_getVibration }, |
370 | |
371 | // From wrap_JoystickModule. |
372 | { "getConnectedIndex" , w_getIndex }, |
373 | |
374 | { 0, 0 }, |
375 | }; |
376 | |
377 | extern "C" int luaopen_joystick(lua_State *L) |
378 | { |
379 | return luax_register_type(L, &Joystick::type, w_Joystick_functions, nullptr); |
380 | } |
381 | |
382 | } // joystick |
383 | } // love |
384 | |