Fixed x11 and Wayland not using INVOKE_WCB
[freeglut] / src / wayland / fg_input_devices_wl.c
1 /*
2  * fg_input_devices_wl.c
3  *
4  * Handles Wayland input devices : keyboard, pointer, touchscreen.
5  *
6  * Written by Manuel Bachmann <tarnyko@tarnyko.net> 2015
7  *
8  * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
9  * Creation date: Thur Mar 19 2015
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28
29 #ifdef __linux__
30 #include <linux/input.h>
31 #else
32 #define BTN_LEFT    0x110
33 #define BTN_RIGHT   0x111
34 #define BTN_MIDDLE  0x112
35 #endif
36 #include <sys/mman.h>
37 #include <GL/freeglut.h>
38 #include "../fg_internal.h"
39
40 /*
41  * This function will effectively set the pointer (mouse) cursor
42  * depending on the GLUT_CURSOR_* choice.
43  */
44 void fghPointerSetCursor( SFG_Window* window,
45                           struct wl_pointer* pointer,
46                           uint32_t serial )
47 {
48     struct wl_cursor_image* image;
49     struct wl_buffer* buffer;
50
51     image = window->Window.pContext.cursor->images[0];
52     buffer = wl_cursor_image_get_buffer( image );
53
54     wl_surface_attach( window->Window.pContext.cursor_surface, buffer,
55                        0, 0 );
56     wl_surface_damage( window->Window.pContext.cursor_surface, 0, 0,
57                        image->width, image->height );
58     wl_surface_commit( window->Window.pContext.cursor_surface );
59
60     wl_pointer_set_cursor( pointer, serial,
61                            window->Window.pContext.cursor_surface,
62                            image->hotspot_x, image->hotspot_y );
63 }
64
65 /*
66  * This function will interpret a keyboard keysym, and call the
67  * possible callbacks accordingly.
68  */
69 void fghKeyboardInterpretKeysym(  SFG_Window* window,
70                                   uint32_t key,
71                                   xkb_keysym_t sym,
72                                   uint32_t state )
73 {
74     FGCBKeyboardUC keyboard_cb;
75     FGCBSpecialUC special_cb;
76     FGCBUserData keyboard_ud;
77     FGCBUserData special_ud;
78     char string[16];
79     int special = -1;
80
81     /* GLUT API tells us to have two separate callbacks, one for
82      * the ASCII translateable keypresses, and one for all the
83      * others, which need to be translated to GLUT_KEY_Xs... */
84     if( state )
85     {
86         keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, Keyboard ));
87         special_cb  = (FGCBSpecialUC) ( FETCH_WCB( *window, Special  ));
88         keyboard_ud = FETCH_USER_DATA_WCB( *window, Keyboard );
89         special_ud  = FETCH_USER_DATA_WCB( *window, Special  );
90     }
91     else
92     {
93         keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, KeyboardUp ));
94         special_cb  = (FGCBSpecialUC) ( FETCH_WCB( *window, SpecialUp  ));
95         keyboard_ud = FETCH_USER_DATA_WCB( *window, KeyboardUp );
96         special_ud  = FETCH_USER_DATA_WCB( *window, SpecialUp  );
97     }
98
99     switch( sym )
100     {
101     case XKB_KEY_F1:        special = GLUT_KEY_F1;        break;
102     case XKB_KEY_F2:        special = GLUT_KEY_F2;        break;
103     case XKB_KEY_F3:        special = GLUT_KEY_F3;        break;
104     case XKB_KEY_F4:        special = GLUT_KEY_F4;        break;
105     case XKB_KEY_F5:        special = GLUT_KEY_F5;        break;
106     case XKB_KEY_F6:        special = GLUT_KEY_F6;        break;
107     case XKB_KEY_F7:        special = GLUT_KEY_F7;        break;
108     case XKB_KEY_F8:        special = GLUT_KEY_F8;        break;
109     case XKB_KEY_F9:        special = GLUT_KEY_F9;        break;
110     case XKB_KEY_F10:       special = GLUT_KEY_F10;       break;
111     case XKB_KEY_F11:       special = GLUT_KEY_F11;       break;
112     case XKB_KEY_F12:       special = GLUT_KEY_F12;       break;
113     case XKB_KEY_Left:      special = GLUT_KEY_LEFT;      break;
114     case XKB_KEY_Right:     special = GLUT_KEY_RIGHT;     break;
115     case XKB_KEY_Up:        special = GLUT_KEY_UP;        break;
116     case XKB_KEY_Down:      special = GLUT_KEY_DOWN;      break;
117     case XKB_KEY_Page_Up:   special = GLUT_KEY_PAGE_UP;   break;
118     case XKB_KEY_Page_Down: special = GLUT_KEY_PAGE_DOWN; break;
119     case XKB_KEY_Home:      special = GLUT_KEY_HOME;      break;
120     case XKB_KEY_End:       special = GLUT_KEY_END;       break;
121     case XKB_KEY_Insert:    special = GLUT_KEY_INSERT;    break;
122     case XKB_KEY_Num_Lock:  special = GLUT_KEY_NUM_LOCK;  break;
123     case XKB_KEY_Begin:     special = GLUT_KEY_BEGIN;     break;
124     case XKB_KEY_Delete:    special = GLUT_KEY_DELETE;    break;
125     case XKB_KEY_Shift_L:   special = GLUT_KEY_SHIFT_L;   break;
126     case XKB_KEY_Shift_R:   special = GLUT_KEY_SHIFT_R;   break;
127     case XKB_KEY_Control_L: special = GLUT_KEY_CTRL_L;    break;
128     case XKB_KEY_Control_R: special = GLUT_KEY_CTRL_R;    break;
129     case XKB_KEY_Alt_L:     special = GLUT_KEY_ALT_L;     break;
130     case XKB_KEY_Alt_R:     special = GLUT_KEY_ALT_R;     break;
131     }
132
133     if( special_cb && (special != -1) )
134     {
135         fgSetWindow( window );
136         special_cb( special, window->State.MouseX, window->State.MouseY, special_ud );
137     }
138     else if( keyboard_cb && (special == -1) )
139     {
140         fgSetWindow( window );
141         xkb_keysym_to_utf8( sym, string, sizeof( string ) );
142         keyboard_cb( string[0], window->State.MouseX, window->State.MouseY, keyboard_ud );
143     }
144 }
145
146
147 /*
148  * Touchscreen section
149  * For now, let us pretend it is a mouse with only one button
150  */
151 static void fghTouchDown( void* data, struct wl_touch* touch,
152                           uint32_t serial, uint32_t time,
153                           struct wl_surface* surface,
154                           int32_t id,
155                           wl_fixed_t x_w, wl_fixed_t y_w )
156 {
157     SFG_Window* win = fgStructure.CurrentWindow;
158     win->State.MouseX = wl_fixed_to_int( x_w );
159     win->State.MouseY = wl_fixed_to_int( y_w );
160     INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
161                                GLUT_DOWN,
162                                win->State.MouseX,
163                                win->State.MouseY ) );
164 }
165 static void fghTouchUp( void* data, struct wl_touch* touch,
166                         uint32_t serial, uint32_t time,
167                         int32_t id )
168 {
169     SFG_Window* win = fgStructure.CurrentWindow;
170     INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
171                                GLUT_UP,
172                                win->State.MouseX,
173                                win->State.MouseY ) );
174 }
175 static void fghTouchMotion( void* data, struct wl_touch* touch,
176                             uint32_t time, int32_t id,
177                             wl_fixed_t x_w, wl_fixed_t y_w )
178 {
179     SFG_Window* win = fgStructure.CurrentWindow;
180     win->State.MouseX = wl_fixed_to_int( x_w );
181     win->State.MouseY = wl_fixed_to_int( y_w );
182     INVOKE_WCB( *win, Motion, ( win->State.MouseX,
183                                 win->State.MouseY ) );
184 }
185 static void fghTouchFrame( void* data, struct wl_touch* touch )
186 {
187 }
188 static void fghTouchCancel( void* data, struct wl_touch* touch )
189 {
190 }
191 static const struct wl_touch_listener fghTouchListener =
192 {
193         fghTouchDown,
194         fghTouchUp,
195         fghTouchMotion,
196         fghTouchFrame,
197         fghTouchCancel
198 };
199
200
201 /*
202  * Pointer (mouse) section
203  */
204 static void fghPointerEnter( void* data, struct wl_pointer* pointer,
205                              uint32_t serial,
206                              struct wl_surface* surface,
207                              wl_fixed_t x_w, wl_fixed_t y_w )
208 {
209     SFG_Window* win = fgStructure.CurrentWindow;
210     fghPointerSetCursor( win, pointer, serial );
211     win->State.MouseX = wl_fixed_to_int( x_w );
212     win->State.MouseY = wl_fixed_to_int( y_w );
213     INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
214 }
215 static void fghPointerLeave( void* data, struct wl_pointer* pointer,
216                              uint32_t serial,
217                              struct wl_surface* surface )
218 {
219     SFG_Window* win = fgStructure.CurrentWindow;
220     INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
221 }
222 static void fghPointerMotion( void* data, struct wl_pointer* pointer,
223                               uint32_t time,
224                               wl_fixed_t x_w, wl_fixed_t y_w )
225 {
226     SFG_Window* win = fgStructure.CurrentWindow;
227     win->State.MouseX = wl_fixed_to_int( x_w );
228     win->State.MouseY = wl_fixed_to_int( y_w );
229
230     if ( win->Window.pContext.pointer_button_pressed )
231       INVOKE_WCB( *win, Motion, ( win->State.MouseX,
232                                   win->State.MouseY ) );
233     else
234       INVOKE_WCB( *win, Passive, ( win->State.MouseX,
235                                    win->State.MouseY ) );
236 }
237 static void fghPointerButton( void* data, struct wl_pointer* pointer,
238                               uint32_t serial, uint32_t time,
239                               uint32_t button, uint32_t state )
240 {
241     SFG_Window* win = fgStructure.CurrentWindow;
242     int button_f;
243
244     switch( button )
245     {
246     case BTN_LEFT:
247         button_f = GLUT_LEFT_BUTTON;
248         break;
249     case BTN_RIGHT:
250         button_f = GLUT_RIGHT_BUTTON;
251         break;
252     case BTN_MIDDLE:
253         button_f = GLUT_MIDDLE_BUTTON;
254         break;
255     }
256
257     win->Window.pContext.pointer_button_pressed =
258       state ? GL_TRUE : GL_FALSE;
259
260     INVOKE_WCB( *win, Mouse, ( button_f,
261                                state ? GLUT_DOWN : GLUT_UP ,
262                                win->State.MouseX,
263                                win->State.MouseY ) );
264 }
265 static void fghPointerAxis( void* data, struct wl_pointer* pointer,
266                             uint32_t time, uint32_t axis,
267                             wl_fixed_t value )
268 {
269     SFG_Window* win = fgStructure.CurrentWindow;
270     int direction = wl_fixed_to_int( value );
271
272     INVOKE_WCB( *win, MouseWheel, ( 0,
273                                     direction ,
274                                     win->State.MouseX,
275                                     win->State.MouseY ) );
276 }
277 static const struct wl_pointer_listener fghPointerListener =
278 {
279         fghPointerEnter,
280         fghPointerLeave,
281         fghPointerMotion,
282         fghPointerButton,
283         fghPointerAxis
284 };
285
286
287 /*
288  * Keyboard section
289  */
290 static void fghKeyboardKeymap( void* data, struct wl_keyboard* keyboard,
291                                uint32_t format, int fd, uint32_t size )
292 {
293     SFG_PlatformDisplay* pDisplay = data;
294     char* keymap_str;
295     struct xkb_keymap* keymap;
296
297     keymap_str = mmap( NULL, size, PROT_READ, MAP_SHARED, fd, 0 );
298     keymap = xkb_keymap_new_from_string( pDisplay->xkb_context,
299                                          keymap_str,
300                                          XKB_KEYMAP_FORMAT_TEXT_V1,
301                                          0 );
302     munmap( keymap_str, size );
303
304     if( pDisplay->xkb_state )
305       xkb_state_unref( pDisplay->xkb_state );
306     pDisplay->xkb_state = xkb_state_new( keymap );
307 }
308 static void fghKeyboardEnter( void* data, struct wl_keyboard* keyboard,
309                               uint32_t serial, struct wl_surface* surface,
310                               struct wl_array* keys )
311 {
312     SFG_Window* win = fgStructure.CurrentWindow;
313     INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
314 }
315 static void fghKeyboardLeave( void* data, struct wl_keyboard* keyboard,
316                               uint32_t serial, struct wl_surface* surface )
317 {
318     SFG_Window* win = fgStructure.CurrentWindow;
319     INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
320 }
321 static void fghKeyboardKey( void* data, struct wl_keyboard* keyboard,
322                             uint32_t serial, uint32_t time,
323                             uint32_t key, uint32_t state )
324 {
325     SFG_PlatformDisplay* pDisplay = data;
326     SFG_Window* win = fgStructure.CurrentWindow;
327     const xkb_keysym_t* syms;
328
329     xkb_state_key_get_syms( pDisplay->xkb_state,
330                             key + 8, &syms );
331     fghKeyboardInterpretKeysym( win, key, syms[0], state );
332 }
333 static void fghKeyboardModifiers( void* data, struct wl_keyboard* keyboard,
334                                   uint32_t serial, uint32_t mods_depr,
335                                   uint32_t mods_latch, uint32_t mods_lock,
336                                   uint32_t group )
337 {
338 }
339 static const struct wl_keyboard_listener fghKeyboardListener =
340 {
341         fghKeyboardKeymap,
342         fghKeyboardEnter,
343         fghKeyboardLeave,
344         fghKeyboardKey,
345         fghKeyboardModifiers
346 };
347
348
349 /*
350  * Discover potential input device(s) (keyboard, pointer, touch)
351  */
352 static void fghSeatCapabilities( void* data,
353                                  struct wl_seat* seat,
354                                  enum wl_seat_capability capabilities )
355 {
356     SFG_PlatformDisplay* pDisplay = data;
357
358     if( capabilities & WL_SEAT_CAPABILITY_KEYBOARD )
359     {
360         pDisplay->xkb_context = xkb_context_new ( 0 );
361         pDisplay->keyboard = wl_seat_get_keyboard( seat );
362         wl_keyboard_add_listener( pDisplay->keyboard,
363                                   &fghKeyboardListener,
364                                   pDisplay );
365     }
366
367     if( capabilities & WL_SEAT_CAPABILITY_POINTER )
368     {
369         pDisplay->pointer = wl_seat_get_pointer( seat );
370         wl_pointer_add_listener( pDisplay->pointer,
371                                  &fghPointerListener,
372                                  pDisplay );
373     }
374
375     if( capabilities & WL_SEAT_CAPABILITY_TOUCH )
376     {
377         pDisplay->touch = wl_seat_get_touch( seat );
378         wl_touch_add_listener( pDisplay->touch,
379                                &fghTouchListener,
380                                pDisplay );
381     }
382 }
383 static const struct wl_seat_listener fghSeatListener =
384 {
385     fghSeatCapabilities
386 };
387
388
389 /*
390  * Try initializing the input device(s)
391  */
392 void fgPlatformInitialiseInputDevices( void )
393 {
394     wl_seat_add_listener( fgDisplay.pDisplay.seat,
395                           &fghSeatListener,
396                           &fgDisplay.pDisplay );
397
398     wl_display_roundtrip( fgDisplay.pDisplay.display );
399 }
400
401 /*
402  * Try closing the input device(s)
403  */
404 void fgPlatformCloseInputDevices( void )
405 {
406     if( fgDisplay.pDisplay.touch )
407       wl_touch_destroy( fgDisplay.pDisplay.touch );
408     if( fgDisplay.pDisplay.pointer )
409       wl_pointer_destroy( fgDisplay.pDisplay.pointer );
410     if( fgDisplay.pDisplay.keyboard )
411       wl_keyboard_destroy( fgDisplay.pDisplay.keyboard );
412     if( fgDisplay.pDisplay.xkb_state )
413       xkb_state_unref( fgDisplay.pDisplay.xkb_state );
414     if( fgDisplay.pDisplay.xkb_context )
415       xkb_context_unref( fgDisplay.pDisplay.xkb_context );
416 }
417
418
419 /*
420  * Wayland backend will not be implementing spaceball at all
421  */
422 void fgPlatformInitializeSpaceball( void )
423 {
424 }
425 void fgPlatformSpaceballClose( void )
426 {
427 }
428 void fgPlatformSpaceballSetWindow( SFG_Window *window )
429 {
430 }
431 int fgPlatformHasSpaceball( void )
432 {
433     return 0;
434 }
435 int fgPlatformSpaceballNumButtons( void )
436 {
437     return 0;
438 }
439