wrap_JoystickModule.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /**
  2. * Copyright (c) 2006-2014 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. #include "wrap_JoystickModule.h"
  21. #include "wrap_Joystick.h"
  22. #include "filesystem/wrap_Filesystem.h"
  23. #include "sdl/JoystickModule.h"
  24. namespace love
  25. {
  26. namespace joystick
  27. {
  28. static JoystickModule *instance = nullptr;
  29. int w_getJoysticks(lua_State *L)
  30. {
  31. int stickcount = instance->getJoystickCount();
  32. lua_createtable(L, stickcount, 0);
  33. for (int i = 0; i < stickcount; i++)
  34. {
  35. Joystick *stick = instance->getJoystick(i);
  36. stick->retain();
  37. luax_pushtype(L, "Joystick", JOYSTICK_JOYSTICK_T, stick);
  38. lua_rawseti(L, -2, i + 1);
  39. }
  40. return 1;
  41. }
  42. int w_getIndex(lua_State *L)
  43. {
  44. Joystick *j = luax_checkjoystick(L, 1);
  45. int index = instance->getIndex(j);
  46. if (index >= 0)
  47. lua_pushinteger(L, index + 1);
  48. else
  49. lua_pushnil(L);
  50. return 1;
  51. }
  52. int w_getJoystickCount(lua_State *L)
  53. {
  54. lua_pushinteger(L, instance->getJoystickCount());
  55. return 1;
  56. }
  57. int w_setGamepadMapping(lua_State *L)
  58. {
  59. // Only accept a GUID string. We don't accept a Joystick object because
  60. // the gamepad mapping applies to all joysticks with the same GUID (e.g. all
  61. // Xbox 360 controllers on the system), rather than individual objects.
  62. const char *guid = luaL_checkstring(L, 1);
  63. const char *gpbindstr = luaL_checkstring(L, 2);
  64. Joystick::GamepadInput gpinput;
  65. if (Joystick::getConstant(gpbindstr, gpinput.axis))
  66. gpinput.type = Joystick::INPUT_TYPE_AXIS;
  67. else if (Joystick::getConstant(gpbindstr, gpinput.button))
  68. gpinput.type = Joystick::INPUT_TYPE_BUTTON;
  69. else
  70. return luaL_error(L, "Invalid gamepad axis/button: %s", gpbindstr);
  71. const char *jinputtypestr = luaL_checkstring(L, 3);
  72. Joystick::JoystickInput jinput;
  73. if (!Joystick::getConstant(jinputtypestr, jinput.type))
  74. return luaL_error(L, "Invalid joystick input type: %s", jinputtypestr);
  75. const char *hatstr;
  76. switch (jinput.type)
  77. {
  78. case Joystick::INPUT_TYPE_AXIS:
  79. jinput.axis = luaL_checkint(L, 4) - 1;
  80. break;
  81. case Joystick::INPUT_TYPE_BUTTON:
  82. jinput.button = luaL_checkint(L, 4) - 1;
  83. break;
  84. case Joystick::INPUT_TYPE_HAT:
  85. // Hats need both a hat index and a hat value.
  86. jinput.hat.index = luaL_checkint(L, 4) - 1;
  87. hatstr = luaL_checkstring(L, 5);
  88. if (!Joystick::getConstant(hatstr, jinput.hat.value))
  89. return luaL_error(L, "Invalid joystick hat: %s", hatstr);
  90. break;
  91. default:
  92. return luaL_error(L, "Invalid joystick input type: %s", jinputtypestr);
  93. }
  94. bool success = false;
  95. luax_catchexcept(L, [&](){ success = instance->setGamepadMapping(guid, gpinput, jinput); });
  96. luax_pushboolean(L, success);
  97. return 1;
  98. }
  99. int w_getGamepadMapping(lua_State *L)
  100. {
  101. std::string guid;
  102. // Accept either a GUID string or a Joystick object. This way we can re-use
  103. // the function for Joystick:getGamepadMapping.
  104. if (lua_type(L, 1) == LUA_TSTRING)
  105. guid = luax_checkstring(L, 1);
  106. else
  107. {
  108. Joystick *stick = luax_checkjoystick(L, 1);
  109. guid = stick->getGUID();
  110. }
  111. const char *gpbindstr = luaL_checkstring(L, 2);
  112. Joystick::GamepadInput gpinput;
  113. if (Joystick::getConstant(gpbindstr, gpinput.axis))
  114. gpinput.type = Joystick::INPUT_TYPE_AXIS;
  115. else if (Joystick::getConstant(gpbindstr, gpinput.button))
  116. gpinput.type = Joystick::INPUT_TYPE_BUTTON;
  117. else
  118. return luaL_error(L, "Invalid gamepad axis/button: %s", gpbindstr);
  119. Joystick::JoystickInput jinput;
  120. jinput.type = Joystick::INPUT_TYPE_MAX_ENUM;
  121. luax_catchexcept(L, [&](){ jinput = instance->getGamepadMapping(guid, gpinput); });
  122. if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM)
  123. return 0;
  124. const char *inputtypestr;
  125. if (!Joystick::getConstant(jinput.type, inputtypestr))
  126. return luaL_error(L, "Unknown joystick input type.");
  127. lua_pushstring(L, inputtypestr);
  128. const char *hatstr;
  129. switch (jinput.type)
  130. {
  131. case Joystick::INPUT_TYPE_AXIS:
  132. lua_pushinteger(L, jinput.axis + 1);
  133. return 2;
  134. case Joystick::INPUT_TYPE_BUTTON:
  135. lua_pushinteger(L, jinput.button + 1);
  136. return 2;
  137. case Joystick::INPUT_TYPE_HAT:
  138. lua_pushinteger(L, jinput.hat.index + 1);
  139. if (Joystick::getConstant(jinput.hat.value, hatstr))
  140. {
  141. lua_pushstring(L, hatstr);
  142. return 3;
  143. }
  144. else
  145. return luaL_error(L, "Unknown joystick hat.");
  146. default:
  147. break; // ?
  148. }
  149. return 1;
  150. }
  151. int w_loadGamepadMappings(lua_State *L)
  152. {
  153. lua_pushvalue(L, 1);
  154. luax_convobj(L, -1, "filesystem", "isFile");
  155. bool isfile = luax_toboolean(L, -1);
  156. lua_pop(L, 1);
  157. std::string mappings;
  158. if (isfile)
  159. {
  160. love::filesystem::FileData *fd = love::filesystem::luax_getfiledata(L, 1);
  161. mappings = std::string((const char *) fd->getData(), fd->getSize());
  162. fd->release();
  163. }
  164. else
  165. mappings = luax_checkstring(L, 1);
  166. luax_catchexcept(L, [&](){ instance->loadGamepadMappings(mappings); });
  167. return 0;
  168. }
  169. int w_saveGamepadMappings(lua_State *L)
  170. {
  171. lua_settop(L, 1);
  172. std::string mappings = instance->saveGamepadMappings();
  173. // Optionally write the mappings string to a file.
  174. if (!lua_isnoneornil(L, 1))
  175. {
  176. luax_pushstring(L, mappings);
  177. int idxs[] = {1, 2};
  178. luax_convobj(L, idxs, 2, "filesystem", "write");
  179. lua_pop(L, 1); // Pop the return value.
  180. }
  181. // Return the actual string even if we also wrote it to a file.
  182. luax_pushstring(L, mappings);
  183. return 1;
  184. }
  185. // List of functions to wrap.
  186. static const luaL_Reg functions[] =
  187. {
  188. { "getJoysticks", w_getJoysticks },
  189. { "getJoystickCount", w_getJoystickCount },
  190. { "setGamepadMapping", w_setGamepadMapping },
  191. { "getGamepadMapping", w_getGamepadMapping },
  192. { "loadGamepadMappings", w_loadGamepadMappings },
  193. { "saveGamepadMappings", w_saveGamepadMappings },
  194. { 0, 0 }
  195. };
  196. static const lua_CFunction types[] =
  197. {
  198. luaopen_joystick,
  199. 0,
  200. };
  201. extern "C" int luaopen_love_joystick(lua_State *L)
  202. {
  203. if (instance == nullptr)
  204. {
  205. luax_catchexcept(L, [&](){ instance = new sdl::JoystickModule(); });
  206. }
  207. else
  208. instance->retain();
  209. WrappedModule w;
  210. w.module = instance;
  211. w.name = "joystick";
  212. w.flags = MODULE_T;
  213. w.functions = functions;
  214. w.types = types;
  215. return luax_register_module(L, w);
  216. }
  217. } // joystick
  218. } // love