NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
11KB

  1. #include <SDL.h>
  2. #include "input.h"
  3. #include "state.h"
  4. #define DBG_LOG(...) printf(__VA_ARGS__)
  5. #define ERR_LOG(...) DBG_LOG(__VA_ARGS__)
  6. #ifdef DEBUG_INPUT
  7. #define INPUT_DBG DBG_LOG
  8. #define INPUT_INFO DBG_LOG
  9. #else
  10. #define INPUT_DBG(...)
  11. #define INPUT_INFO(...)
  12. #endif
  13. #define INPUT_ERR ERR_LOG
  14. #define axis_threshold (8192L)
  15. typedef struct {
  16. int16_t last_x_axis;
  17. int16_t last_y_axis;
  18. SDL_GameController* gamepad;
  19. } sdl_input_data;
  20. static sdl_input_data the_input_data = {0};
  21. static SDL_GameController* sdl_find_gamepad() {
  22. int i = SDL_NumJoysticks() - 1;
  23. INPUT_INFO("Found %d joysticks\n", i + 1);
  24. for ( ; i >= 0 && !SDL_IsGameController(i); --i);
  25. if (i >= 0) INPUT_INFO("Joystick %d is a gamepad\n", i);
  26. return (i < 0 ? NULL : SDL_GameControllerOpen(i));
  27. }
  28. static void sdl_lose_gamepad(SDL_GameController* gamepad) {
  29. if (NULL != gamepad) {
  30. SDL_GameControllerClose(gamepad);
  31. }
  32. }
  33. static int sdl_match_gamepad(SDL_JoystickID id,
  34. SDL_GameController* gamepad) {
  35. return ( id == SDL_JoystickInstanceID(
  36. SDL_GameControllerGetJoystick(gamepad)));
  37. }
  38. /*
  39. static int sdl_event_filter(void*, SDL_Event* event) {
  40. return ( SDL_QUIT == event->type ||
  41. SDL_KEYDOWN == event->type ||
  42. SDL_KEYUP == event->type ||
  43. SDL_CONTROLLERBUTTONDOWN == event->type ||
  44. SDL_CONTROLLERBUTTONUP == event->type ||
  45. SDL_CONTROLLERDEVICEADDED == event->type ||
  46. SDL_CONTROLLERDEVICEREMOVED == event->type
  47. );
  48. }
  49. */
  50. static int sdl_input_init(nes_Input_Reader* reader) {
  51. reader->data = &the_input_data;
  52. sdl_input_data* data = (sdl_input_data*)reader->data;
  53. int status = SDL_Init(SDL_INIT_EVENTS |
  54. SDL_INIT_GAMECONTROLLER);
  55. if (status == 0) {
  56. data->gamepad = sdl_find_gamepad();
  57. // SDL_SetEventFilter(sdl_event_filter, NULL);
  58. if (NULL != data->gamepad) {
  59. INPUT_INFO("Gamepad found\n");
  60. }
  61. }
  62. return status;
  63. }
  64. static void sdl_input_done(nes_Input_Reader* reader) {
  65. sdl_input_data* data = (sdl_input_data*)reader->data;
  66. sdl_lose_gamepad(data->gamepad);
  67. }
  68. static const int sdl_menu_key = SDLK_ESCAPE;
  69. static const int sdl_save_key = SDLK_F1;
  70. static const int sdl_load_key = SDLK_F2;
  71. static const int sdl_alt_start_key = SDLK_RETURN;
  72. static const int sdl_keycodes[nes_controller_num_buttons] = {
  73. SDLK_a,
  74. SDLK_s,
  75. SDLK_q,
  76. SDLK_w,
  77. SDLK_UP,
  78. SDLK_DOWN,
  79. SDLK_LEFT,
  80. SDLK_RIGHT,
  81. };
  82. static const int sdl_menu_button = SDL_CONTROLLER_BUTTON_X;
  83. static const int sdl_save_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
  84. static const int sdl_load_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
  85. static const int sdl_buttons[nes_controller_num_buttons] = {
  86. SDL_CONTROLLER_BUTTON_A,
  87. SDL_CONTROLLER_BUTTON_B,
  88. SDL_CONTROLLER_BUTTON_BACK,
  89. SDL_CONTROLLER_BUTTON_START,
  90. SDL_CONTROLLER_BUTTON_DPAD_UP,
  91. SDL_CONTROLLER_BUTTON_DPAD_DOWN,
  92. SDL_CONTROLLER_BUTTON_DPAD_LEFT,
  93. SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
  94. };
  95. static int button_index(int keycode, const int* codes) {
  96. int index = nes_controller_num_buttons - 1;
  97. for ( ; index >= 0 && keycode != codes[index]; --index);
  98. return index;
  99. }
  100. #define input_debug(o, ...) INPUT_DBG(__VA_ARGS__)
  101. /*
  102. static void input_debug(Overlay* overlay,
  103. const char* fmt, ...) {
  104. char msg[100] = {0};
  105. va_list args;
  106. va_start(args, fmt);
  107. vsnprintf(msg, sizeof(msg) - 1, fmt, args);
  108. va_end(args);
  109. overlay_add_message(overlay, msg, 60);
  110. }
  111. */
  112. static int sdl_input_update(nes_Input_Reader* reader,
  113. nese_Components* comp) {
  114. int status = input_Result_OK;
  115. sdl_input_data* data = (sdl_input_data*)reader->data;
  116. if (reader->menu_timer > 0 && --reader->menu_timer == 0) {
  117. status = input_Result_Menu;
  118. }
  119. SDL_Event event = {0};
  120. while (0 == status && 0 != SDL_PollEvent(&event)) {
  121. if (SDL_QUIT == event.type) {
  122. status = input_Result_Quit;
  123. } else if (SDL_WINDOWEVENT == event.type) {
  124. if ( SDL_WINDOWEVENT_EXPOSED ==
  125. event.window.event) {
  126. nes_render_refresh(comp->rend);
  127. status = input_Result_Refresh;
  128. }
  129. } else if ( ( SDL_KEYDOWN == event.type ||
  130. SDL_KEYUP == event.type) &&
  131. 0 == event.key.repeat
  132. ) {
  133. input_debug(&comp->rend->overlay,
  134. "Input: K %d S %d\n",
  135. SDL_KEYDOWN == event.type ? 1 : 0,
  136. event.key.keysym.sym);
  137. int index = ( sdl_alt_start_key ==
  138. event.key.keysym.sym) ?
  139. Button_Start : button_index(
  140. event.key.keysym.sym,
  141. sdl_keycodes);
  142. if (index >= 0) {
  143. uint8_t mask = (1 << index);
  144. if (SDL_KEYDOWN == event.type) {
  145. comp->sys->input.controllers[0].buttons |= mask;
  146. } else {
  147. comp->sys->input.controllers[0].buttons &= ~mask;
  148. }
  149. /*
  150. input_debug(
  151. &comp->rend->overlay,
  152. "Input: Key: %s %02x\n",
  153. (SDL_KEYDOWN == event.type) ?
  154. "Set" : "Clear",
  155. mask
  156. );
  157. */
  158. } else if ( sdl_menu_key == event.key.keysym.sym &&
  159. SDL_KEYDOWN == event.type) {
  160. status = input_Result_Menu;
  161. } else if (sdl_save_key == event.key.keysym.sym) {
  162. if (SDL_KEYDOWN == event.type) {
  163. status = input_Result_Save;
  164. } else {
  165. status = input_Result_Cancel;
  166. }
  167. } else if (sdl_load_key == event.key.keysym.sym) {
  168. if (SDL_KEYDOWN == event.type) {
  169. status = input_Result_Load;
  170. } else {
  171. status = input_Result_Cancel;
  172. }
  173. }
  174. } else if ( SDL_CONTROLLERBUTTONDOWN == event.type ||
  175. SDL_CONTROLLERBUTTONUP == event.type) {
  176. input_debug(&comp->rend->overlay,
  177. "Input: B %d B %d\n",
  178. SDL_CONTROLLERBUTTONDOWN == event.type ?
  179. 1 : 0,
  180. event.cbutton.button);
  181. int index = button_index(event.cbutton.button,
  182. sdl_buttons);
  183. if (index >= 0) {
  184. uint8_t mask = (1 << index);
  185. if (SDL_CONTROLLERBUTTONDOWN == event.type) {
  186. comp->sys->input.controllers[0].buttons |= mask;
  187. } else {
  188. comp->sys->input.controllers[0].buttons &= ~mask;
  189. }
  190. /*
  191. input_debug(
  192. &comp->rend->overlay,
  193. "Input: Button: %s %02x\n",
  194. (SDL_CONTROLLERBUTTONDOWN == event.type) ?
  195. "Set" : "Clear",
  196. mask
  197. );
  198. */
  199. if (Button_Start == index) {
  200. if (SDL_CONTROLLERBUTTONDOWN == event.type) {
  201. reader->menu_timer = 60;
  202. } else {
  203. reader->menu_timer = 0;
  204. }
  205. }
  206. } else if (sdl_menu_button == event.cbutton.button) {
  207. if (SDL_CONTROLLERBUTTONDOWN == event.type) {
  208. status = input_Result_Menu;
  209. }
  210. } else if (sdl_save_button == event.cbutton.button) {
  211. if (SDL_CONTROLLERBUTTONDOWN == event.type) {
  212. status = input_Result_Save;
  213. } else {
  214. status = input_Result_Cancel;
  215. }
  216. } else if (sdl_load_button == event.cbutton.button) {
  217. if (SDL_CONTROLLERBUTTONDOWN == event.type) {
  218. status = input_Result_Load;
  219. } else {
  220. status = input_Result_Cancel;
  221. }
  222. }
  223. } else if (SDL_CONTROLLERAXISMOTION == event.type) {
  224. const uint8_t axis = event.caxis.axis;
  225. const int16_t value = event.caxis.value;
  226. uint8_t mask_set = 0;
  227. uint8_t mask_clear = 0;
  228. int dir = 0;
  229. if (value <= -axis_threshold) dir = -1;
  230. else if (value >= axis_threshold) dir = 1;
  231. if (SDL_CONTROLLER_AXIS_LEFTX == axis) {
  232. if (dir != data->last_x_axis) {
  233. mask_clear = (1 << Button_Left) |
  234. (1 << Button_Right);
  235. if (dir < 0) {
  236. mask_set = (1 << Button_Left);
  237. } else if (dir > 0) {
  238. mask_set = (1 << Button_Right);
  239. }
  240. }
  241. data->last_x_axis = dir;
  242. } else if (SDL_CONTROLLER_AXIS_LEFTY == axis) {
  243. if (dir != data->last_y_axis) {
  244. mask_clear = (1 << Button_Down) |
  245. (1 << Button_Up);
  246. if (dir < 0) {
  247. mask_set = (1 << Button_Up);
  248. } else if (dir > 0) {
  249. mask_set = (1 << Button_Down);
  250. }
  251. }
  252. data->last_y_axis = dir;
  253. }
  254. uint32_t old_buttons = comp->sys->input.controllers[0].buttons;
  255. uint32_t new_buttons = ((old_buttons & ~mask_clear) | mask_set);
  256. comp->sys->input.controllers[0].buttons = new_buttons;
  257. /*
  258. if (old_buttons != new_buttons) {
  259. input_debug(&comp->rend->overlay,
  260. "Input: Axis: S %02x C %02x V %d\n",
  261. mask_set, mask_clear, value);
  262. }
  263. */
  264. } else if (SDL_CONTROLLERDEVICEADDED == event.type) {
  265. if (NULL == data->gamepad) {
  266. INPUT_INFO("New gamepad connected\n");
  267. data->gamepad = sdl_find_gamepad();
  268. if (data->gamepad) INPUT_INFO("Using new gamepad\n");
  269. } else {
  270. INPUT_INFO("Redundant gamepad connected\n");
  271. }
  272. } else if (SDL_CONTROLLERDEVICEREMOVED == event.type) {
  273. if (sdl_match_gamepad(event.cdevice.which,
  274. data->gamepad)) {
  275. INPUT_INFO("Gamepad disconnected\n");
  276. sdl_lose_gamepad(reader->data);
  277. data->gamepad = sdl_find_gamepad();
  278. if (data->gamepad) INPUT_INFO("Using another gamepad\n");
  279. } else {
  280. INPUT_INFO("Redundant gamepad disconnected\n");
  281. }
  282. }
  283. }
  284. if (0 != status) {
  285. input_debug(&comp->rend->overlay,
  286. "Input: Returning %d\n", status);
  287. }
  288. return status;
  289. }
  290. nes_Input_Reader sdl_input = {
  291. .init = sdl_input_init,
  292. .done = sdl_input_done,
  293. .update = sdl_input_update,
  294. };