SDL_waylandevents.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
  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. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #if SDL_VIDEO_DRIVER_WAYLAND
  20. #include "SDL_stdinc.h"
  21. #include "SDL_assert.h"
  22. #include "../../events/SDL_sysevents.h"
  23. #include "../../events/SDL_events_c.h"
  24. #include "../../events/scancodes_xfree86.h"
  25. #include "SDL_waylandvideo.h"
  26. #include "SDL_waylandevents_c.h"
  27. #include "SDL_waylandwindow.h"
  28. #include "SDL_waylanddyn.h"
  29. #include <linux/input.h>
  30. #include <sys/select.h>
  31. #include <sys/mman.h>
  32. #include <poll.h>
  33. #include <errno.h>
  34. #include <unistd.h>
  35. #include <xkbcommon/xkbcommon.h>
  36. struct SDL_WaylandInput {
  37. SDL_VideoData *display;
  38. struct wl_seat *seat;
  39. struct wl_pointer *pointer;
  40. struct wl_keyboard *keyboard;
  41. SDL_WindowData *pointer_focus;
  42. SDL_WindowData *keyboard_focus;
  43. struct {
  44. struct xkb_keymap *keymap;
  45. struct xkb_state *state;
  46. } xkb;
  47. };
  48. void
  49. Wayland_PumpEvents(_THIS)
  50. {
  51. SDL_VideoData *d = _this->driverdata;
  52. struct pollfd pfd[1];
  53. pfd[0].fd = WAYLAND_wl_display_get_fd(d->display);
  54. pfd[0].events = POLLIN;
  55. poll(pfd, 1, 0);
  56. if (pfd[0].revents & POLLIN)
  57. WAYLAND_wl_display_dispatch(d->display);
  58. else
  59. WAYLAND_wl_display_dispatch_pending(d->display);
  60. }
  61. static void
  62. pointer_handle_enter(void *data, struct wl_pointer *pointer,
  63. uint32_t serial, struct wl_surface *surface,
  64. wl_fixed_t sx_w, wl_fixed_t sy_w)
  65. {
  66. struct SDL_WaylandInput *input = data;
  67. SDL_WindowData *window;
  68. if (!surface) {
  69. /* enter event for a window we've just destroyed */
  70. return;
  71. }
  72. /* This handler will be called twice in Wayland 1.4
  73. * Once for the window surface which has valid user data
  74. * and again for the mouse cursor surface which does not have valid user data
  75. * We ignore the later
  76. */
  77. window = (SDL_WindowData *)wl_surface_get_user_data(surface);
  78. if (window) {
  79. input->pointer_focus = window;
  80. SDL_SetMouseFocus(window->sdlwindow);
  81. }
  82. }
  83. static void
  84. pointer_handle_leave(void *data, struct wl_pointer *pointer,
  85. uint32_t serial, struct wl_surface *surface)
  86. {
  87. struct SDL_WaylandInput *input = data;
  88. if (input->pointer_focus) {
  89. SDL_SetMouseFocus(NULL);
  90. input->pointer_focus = NULL;
  91. }
  92. }
  93. static void
  94. pointer_handle_motion(void *data, struct wl_pointer *pointer,
  95. uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
  96. {
  97. struct SDL_WaylandInput *input = data;
  98. SDL_WindowData *window = input->pointer_focus;
  99. int sx = wl_fixed_to_int(sx_w);
  100. int sy = wl_fixed_to_int(sy_w);
  101. if (input->pointer_focus) {
  102. SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
  103. }
  104. }
  105. static void
  106. pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
  107. uint32_t time, uint32_t button, uint32_t state_w)
  108. {
  109. struct SDL_WaylandInput *input = data;
  110. SDL_WindowData *window = input->pointer_focus;
  111. enum wl_pointer_button_state state = state_w;
  112. uint32_t sdl_button;
  113. if (input->pointer_focus) {
  114. switch (button) {
  115. case BTN_LEFT:
  116. sdl_button = SDL_BUTTON_LEFT;
  117. break;
  118. case BTN_MIDDLE:
  119. sdl_button = SDL_BUTTON_MIDDLE;
  120. break;
  121. case BTN_RIGHT:
  122. sdl_button = SDL_BUTTON_RIGHT;
  123. break;
  124. case BTN_SIDE:
  125. sdl_button = SDL_BUTTON_X1;
  126. break;
  127. case BTN_EXTRA:
  128. sdl_button = SDL_BUTTON_X2;
  129. break;
  130. default:
  131. return;
  132. }
  133. SDL_SendMouseButton(window->sdlwindow, 0,
  134. state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
  135. }
  136. }
  137. static void
  138. pointer_handle_axis(void *data, struct wl_pointer *pointer,
  139. uint32_t time, uint32_t axis, wl_fixed_t value)
  140. {
  141. struct SDL_WaylandInput *input = data;
  142. SDL_WindowData *window = input->pointer_focus;
  143. enum wl_pointer_axis a = axis;
  144. int x, y;
  145. if (input->pointer_focus) {
  146. switch (a) {
  147. case WL_POINTER_AXIS_VERTICAL_SCROLL:
  148. x = 0;
  149. y = wl_fixed_to_int(value);
  150. break;
  151. case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
  152. x = wl_fixed_to_int(value);
  153. y = 0;
  154. break;
  155. default:
  156. return;
  157. }
  158. SDL_SendMouseWheel(window->sdlwindow, 0, x, y);
  159. }
  160. }
  161. static const struct wl_pointer_listener pointer_listener = {
  162. pointer_handle_enter,
  163. pointer_handle_leave,
  164. pointer_handle_motion,
  165. pointer_handle_button,
  166. pointer_handle_axis,
  167. };
  168. static void
  169. keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
  170. uint32_t format, int fd, uint32_t size)
  171. {
  172. struct SDL_WaylandInput *input = data;
  173. char *map_str;
  174. if (!data) {
  175. close(fd);
  176. return;
  177. }
  178. if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
  179. close(fd);
  180. return;
  181. }
  182. map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
  183. if (map_str == MAP_FAILED) {
  184. close(fd);
  185. return;
  186. }
  187. input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
  188. map_str,
  189. XKB_KEYMAP_FORMAT_TEXT_V1,
  190. 0);
  191. munmap(map_str, size);
  192. close(fd);
  193. if (!input->xkb.keymap) {
  194. fprintf(stderr, "failed to compile keymap\n");
  195. return;
  196. }
  197. input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
  198. if (!input->xkb.state) {
  199. fprintf(stderr, "failed to create XKB state\n");
  200. WAYLAND_xkb_keymap_unref(input->xkb.keymap);
  201. input->xkb.keymap = NULL;
  202. return;
  203. }
  204. }
  205. static void
  206. keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
  207. uint32_t serial, struct wl_surface *surface,
  208. struct wl_array *keys)
  209. {
  210. struct SDL_WaylandInput *input = data;
  211. SDL_WindowData *window = wl_surface_get_user_data(surface);
  212. input->keyboard_focus = window;
  213. window->keyboard_device = input;
  214. if (window) {
  215. SDL_SetKeyboardFocus(window->sdlwindow);
  216. }
  217. }
  218. static void
  219. keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
  220. uint32_t serial, struct wl_surface *surface)
  221. {
  222. SDL_SetKeyboardFocus(NULL);
  223. }
  224. static void
  225. keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
  226. uint32_t serial, uint32_t time, uint32_t key,
  227. uint32_t state_w)
  228. {
  229. struct SDL_WaylandInput *input = data;
  230. SDL_WindowData *window = input->keyboard_focus;
  231. enum wl_keyboard_key_state state = state_w;
  232. const xkb_keysym_t *syms;
  233. uint32_t scancode;
  234. char text[8];
  235. int size;
  236. if (key < SDL_arraysize(xfree86_scancode_table2)) {
  237. scancode = xfree86_scancode_table2[key];
  238. // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
  239. if (scancode != SDL_SCANCODE_UNKNOWN)
  240. SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
  241. SDL_PRESSED : SDL_RELEASED, scancode);
  242. }
  243. if (!window || window->keyboard_device != input || !input->xkb.state)
  244. return;
  245. // TODO can this happen?
  246. if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
  247. return;
  248. if (state) {
  249. size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
  250. if (size > 0) {
  251. text[size] = 0;
  252. SDL_SendKeyboardText(text);
  253. }
  254. }
  255. }
  256. static void
  257. keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
  258. uint32_t serial, uint32_t mods_depressed,
  259. uint32_t mods_latched, uint32_t mods_locked,
  260. uint32_t group)
  261. {
  262. struct SDL_WaylandInput *input = data;
  263. WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
  264. mods_locked, 0, 0, group);
  265. }
  266. static const struct wl_keyboard_listener keyboard_listener = {
  267. keyboard_handle_keymap,
  268. keyboard_handle_enter,
  269. keyboard_handle_leave,
  270. keyboard_handle_key,
  271. keyboard_handle_modifiers,
  272. };
  273. static void
  274. seat_handle_capabilities(void *data, struct wl_seat *seat,
  275. enum wl_seat_capability caps)
  276. {
  277. struct SDL_WaylandInput *input = data;
  278. if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
  279. input->pointer = wl_seat_get_pointer(seat);
  280. input->display->pointer = input->pointer;
  281. wl_pointer_set_user_data(input->pointer, input);
  282. wl_pointer_add_listener(input->pointer, &pointer_listener,
  283. input);
  284. } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
  285. wl_pointer_destroy(input->pointer);
  286. input->pointer = NULL;
  287. }
  288. if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
  289. input->keyboard = wl_seat_get_keyboard(seat);
  290. wl_keyboard_set_user_data(input->keyboard, input);
  291. wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
  292. input);
  293. } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
  294. wl_keyboard_destroy(input->keyboard);
  295. input->keyboard = NULL;
  296. }
  297. }
  298. static const struct wl_seat_listener seat_listener = {
  299. seat_handle_capabilities,
  300. };
  301. void
  302. Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
  303. {
  304. struct SDL_WaylandInput *input;
  305. input = SDL_calloc(1, sizeof *input);
  306. if (input == NULL)
  307. return;
  308. input->display = d;
  309. input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
  310. d->input = input;
  311. wl_seat_add_listener(input->seat, &seat_listener, input);
  312. wl_seat_set_user_data(input->seat, input);
  313. WAYLAND_wl_display_flush(d->display);
  314. }
  315. void Wayland_display_destroy_input(SDL_VideoData *d)
  316. {
  317. struct SDL_WaylandInput *input = d->input;
  318. if (!input)
  319. return;
  320. if (input->keyboard)
  321. wl_keyboard_destroy(input->keyboard);
  322. if (input->pointer)
  323. wl_pointer_destroy(input->pointer);
  324. if (input->seat)
  325. wl_seat_destroy(input->seat);
  326. if (input->xkb.state)
  327. WAYLAND_xkb_state_unref(input->xkb.state);
  328. if (input->xkb.keymap)
  329. WAYLAND_xkb_keymap_unref(input->xkb.keymap);
  330. SDL_free(input);
  331. d->input = NULL;
  332. }
  333. #endif /* SDL_VIDEO_DRIVER_WAYLAND */
  334. /* vi: set ts=4 sw=4 expandtab: */