Implement initial Wayland support
[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     FGCBKeyboard keyboard_cb;
75     FGCBSpecial special_cb;
76     char string[16];
77     int special = -1;
78
79     /* GLUT API tells us to have two separate callbacks, one for
80      * the ASCII translateable keypresses, and one for all the
81      * others, which need to be translated to GLUT_KEY_Xs... */
82     if( state )
83     {
84         keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
85         special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, Special  ));
86     }
87     else
88     {
89         keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
90         special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp  ));
91     }
92
93     switch( sym )
94     {
95     case XKB_KEY_F1:        special = GLUT_KEY_F1;        break;
96     case XKB_KEY_F2:        special = GLUT_KEY_F2;        break;
97     case XKB_KEY_F3:        special = GLUT_KEY_F3;        break;
98     case XKB_KEY_F4:        special = GLUT_KEY_F4;        break;
99     case XKB_KEY_F5:        special = GLUT_KEY_F5;        break;
100     case XKB_KEY_F6:        special = GLUT_KEY_F6;        break;
101     case XKB_KEY_F7:        special = GLUT_KEY_F7;        break;
102     case XKB_KEY_F8:        special = GLUT_KEY_F8;        break;
103     case XKB_KEY_F9:        special = GLUT_KEY_F9;        break;
104     case XKB_KEY_F10:       special = GLUT_KEY_F10;       break;
105     case XKB_KEY_F11:       special = GLUT_KEY_F11;       break;
106     case XKB_KEY_F12:       special = GLUT_KEY_F12;       break;
107     case XKB_KEY_Left:      special = GLUT_KEY_LEFT;      break;
108     case XKB_KEY_Right:     special = GLUT_KEY_RIGHT;     break;
109     case XKB_KEY_Up:        special = GLUT_KEY_UP;        break;
110     case XKB_KEY_Down:      special = GLUT_KEY_DOWN;      break;
111     case XKB_KEY_Page_Up:   special = GLUT_KEY_PAGE_UP;   break;
112     case XKB_KEY_Page_Down: special = GLUT_KEY_PAGE_DOWN; break;
113     case XKB_KEY_Home:      special = GLUT_KEY_HOME;      break;
114     case XKB_KEY_End:       special = GLUT_KEY_END;       break;
115     case XKB_KEY_Insert:    special = GLUT_KEY_INSERT;    break;
116     case XKB_KEY_Num_Lock:  special = GLUT_KEY_NUM_LOCK;  break;
117     case XKB_KEY_Begin:     special = GLUT_KEY_BEGIN;     break;
118     case XKB_KEY_Delete:    special = GLUT_KEY_DELETE;    break;
119     case XKB_KEY_Shift_L:   special = GLUT_KEY_SHIFT_L;   break;
120     case XKB_KEY_Shift_R:   special = GLUT_KEY_SHIFT_R;   break;
121     case XKB_KEY_Control_L: special = GLUT_KEY_CTRL_L;    break;
122     case XKB_KEY_Control_R: special = GLUT_KEY_CTRL_R;    break;
123     case XKB_KEY_Alt_L:     special = GLUT_KEY_ALT_L;     break;
124     case XKB_KEY_Alt_R:     special = GLUT_KEY_ALT_R;     break;
125     }
126
127     if( special_cb && (special != -1) )
128     {
129         fgSetWindow( window );
130         special_cb( special, window->State.MouseX, window->State.MouseY );
131     }
132     else if( keyboard_cb && (special == -1) )
133     {
134         fgSetWindow( window );
135         xkb_keysym_to_utf8( sym, string, sizeof( string ) );
136         keyboard_cb( string[0], window->State.MouseX, window->State.MouseY );
137     }
138 }
139
140
141 /*
142  * Touchscreen section
143  * For now, let us pretend it is a mouse with only one button
144  */
145 static void fghTouchDown( void* data, struct wl_touch* touch,
146                           uint32_t serial, uint32_t time,
147                           struct wl_surface* surface,
148                           int32_t id,
149                           wl_fixed_t x_w, wl_fixed_t y_w )
150 {
151     SFG_Window* win = fgStructure.CurrentWindow;
152     win->State.MouseX = wl_fixed_to_int( x_w );
153     win->State.MouseY = wl_fixed_to_int( y_w );
154     INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
155                                GLUT_DOWN,
156                                win->State.MouseX,
157                                win->State.MouseY ) );
158 }
159 static void fghTouchUp( void* data, struct wl_touch* touch,
160                         uint32_t serial, uint32_t time,
161                         int32_t id )
162 {
163     SFG_Window* win = fgStructure.CurrentWindow;
164     INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
165                                GLUT_UP,
166                                win->State.MouseX,
167                                win->State.MouseY ) );
168 }
169 static void fghTouchMotion( void* data, struct wl_touch* touch,
170                             uint32_t time, int32_t id,
171                             wl_fixed_t x_w, wl_fixed_t y_w )
172 {
173     SFG_Window* win = fgStructure.CurrentWindow;
174     win->State.MouseX = wl_fixed_to_int( x_w );
175     win->State.MouseY = wl_fixed_to_int( y_w );
176     INVOKE_WCB( *win, Motion, ( win->State.MouseX,
177                                 win->State.MouseY ) );
178 }
179 static void fghTouchFrame( void* data, struct wl_touch* touch )
180 {
181 }
182 static void fghTouchCancel( void* data, struct wl_touch* touch )
183 {
184 }
185 static const struct wl_touch_listener fghTouchListener =
186 {
187         fghTouchDown,
188         fghTouchUp,
189         fghTouchMotion,
190         fghTouchFrame,
191         fghTouchCancel
192 };
193
194
195 /*
196  * Pointer (mouse) section
197  */
198 static void fghPointerEnter( void* data, struct wl_pointer* pointer,
199                              uint32_t serial,
200                              struct wl_surface* surface,
201                              wl_fixed_t x_w, wl_fixed_t y_w )
202 {
203     SFG_Window* win = fgStructure.CurrentWindow;
204     fghPointerSetCursor( win, pointer, serial );
205     win->State.MouseX = wl_fixed_to_int( x_w );
206     win->State.MouseY = wl_fixed_to_int( y_w );
207     INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
208 }
209 static void fghPointerLeave( void* data, struct wl_pointer* pointer,
210                              uint32_t serial,
211                              struct wl_surface* surface )
212 {
213     SFG_Window* win = fgStructure.CurrentWindow;
214     INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
215 }
216 static void fghPointerMotion( void* data, struct wl_pointer* pointer,
217                               uint32_t time,
218                               wl_fixed_t x_w, wl_fixed_t y_w )
219 {
220     SFG_Window* win = fgStructure.CurrentWindow;
221     win->State.MouseX = wl_fixed_to_int( x_w );
222     win->State.MouseY = wl_fixed_to_int( y_w );
223
224     if ( win->Window.pContext.pointer_button_pressed )
225       INVOKE_WCB( *win, Motion, ( win->State.MouseX,
226                                   win->State.MouseY ) );
227     else
228       INVOKE_WCB( *win, Passive, ( win->State.MouseX,
229                                    win->State.MouseY ) );
230 }
231 static void fghPointerButton( void* data, struct wl_pointer* pointer,
232                               uint32_t serial, uint32_t time,
233                               uint32_t button, uint32_t state )
234 {
235     SFG_Window* win = fgStructure.CurrentWindow;
236     int button_f;
237
238     switch( button )
239     {
240     case BTN_LEFT:
241         button_f = GLUT_LEFT_BUTTON;
242         break;
243     case BTN_RIGHT:
244         button_f = GLUT_RIGHT_BUTTON;
245         break;
246     case BTN_MIDDLE:
247         button_f = GLUT_MIDDLE_BUTTON;
248         break;
249     }
250
251     win->Window.pContext.pointer_button_pressed =
252       state ? GL_TRUE : GL_FALSE;
253
254     INVOKE_WCB( *win, Mouse, ( button_f,
255                                state ? GLUT_DOWN : GLUT_UP ,
256                                win->State.MouseX,
257                                win->State.MouseY ) );
258 }
259 static void fghPointerAxis( void* data, struct wl_pointer* pointer,
260                             uint32_t time, uint32_t axis,
261                             wl_fixed_t value )
262 {
263     SFG_Window* win = fgStructure.CurrentWindow;
264     int direction = wl_fixed_to_int( value );
265
266     INVOKE_WCB( *win, MouseWheel, ( 0,
267                                     direction ,
268                                     win->State.MouseX,
269                                     win->State.MouseY ) );
270 }
271 static const struct wl_pointer_listener fghPointerListener =
272 {
273         fghPointerEnter,
274         fghPointerLeave,
275         fghPointerMotion,
276         fghPointerButton,
277         fghPointerAxis
278 };
279
280
281 /*
282  * Keyboard section
283  */
284 static void fghKeyboardKeymap( void* data, struct wl_keyboard* keyboard,
285                                uint32_t format, int fd, uint32_t size )
286 {
287     SFG_PlatformDisplay* pDisplay = data;
288     char* keymap_str;
289     struct xkb_keymap* keymap;
290
291     keymap_str = mmap( NULL, size, PROT_READ, MAP_SHARED, fd, 0 );
292     keymap = xkb_keymap_new_from_string( pDisplay->xkb_context,
293                                          keymap_str,
294                                          XKB_KEYMAP_FORMAT_TEXT_V1,
295                                          0 );
296     munmap( keymap_str, size );
297
298     if( pDisplay->xkb_state )
299       xkb_state_unref( pDisplay->xkb_state );
300     pDisplay->xkb_state = xkb_state_new( keymap );
301 }
302 static void fghKeyboardEnter( void* data, struct wl_keyboard* keyboard,
303                               uint32_t serial, struct wl_surface* surface,
304                               struct wl_array* keys )
305 {
306     SFG_Window* win = fgStructure.CurrentWindow;
307     INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
308 }
309 static void fghKeyboardLeave( void* data, struct wl_keyboard* keyboard,
310                               uint32_t serial, struct wl_surface* surface )
311 {
312     SFG_Window* win = fgStructure.CurrentWindow;
313     INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
314 }
315 static void fghKeyboardKey( void* data, struct wl_keyboard* keyboard,
316                             uint32_t serial, uint32_t time,
317                             uint32_t key, uint32_t state )
318 {
319     SFG_PlatformDisplay* pDisplay = data;
320     SFG_Window* win = fgStructure.CurrentWindow;
321     const xkb_keysym_t* syms;
322
323     xkb_state_key_get_syms( pDisplay->xkb_state,
324                             key + 8, &syms );
325     fghKeyboardInterpretKeysym( win, key, syms[0], state );
326 }
327 static void fghKeyboardModifiers( void* data, struct wl_keyboard* keyboard,
328                                   uint32_t serial, uint32_t mods_depr,
329                                   uint32_t mods_latch, uint32_t mods_lock,
330                                   uint32_t group )
331 {
332 }
333 static const struct wl_keyboard_listener fghKeyboardListener =
334 {
335         fghKeyboardKeymap,
336         fghKeyboardEnter,
337         fghKeyboardLeave,
338         fghKeyboardKey,
339         fghKeyboardModifiers
340 };
341
342
343 /*
344  * Discover potential input device(s) (keyboard, pointer, touch)
345  */
346 static void fghSeatCapabilities( void* data,
347                                  struct wl_seat* seat,
348                                  enum wl_seat_capability capabilities )
349 {
350     SFG_PlatformDisplay* pDisplay = data;
351
352     if( capabilities & WL_SEAT_CAPABILITY_KEYBOARD )
353     {
354         pDisplay->xkb_context = xkb_context_new ( 0 );
355         pDisplay->keyboard = wl_seat_get_keyboard( seat );
356         wl_keyboard_add_listener( pDisplay->keyboard,
357                                   &fghKeyboardListener,
358                                   pDisplay );
359     }
360
361     if( capabilities & WL_SEAT_CAPABILITY_POINTER )
362     {
363         pDisplay->pointer = wl_seat_get_pointer( seat );
364         wl_pointer_add_listener( pDisplay->pointer,
365                                  &fghPointerListener,
366                                  pDisplay );
367     }
368
369     if( capabilities & WL_SEAT_CAPABILITY_TOUCH )
370     {
371         pDisplay->touch = wl_seat_get_touch( seat );
372         wl_touch_add_listener( pDisplay->touch,
373                                &fghTouchListener,
374                                pDisplay );
375     }
376 }
377 static const struct wl_seat_listener fghSeatListener =
378 {
379     fghSeatCapabilities
380 };
381
382
383 /*
384  * Try initializing the input device(s)
385  */
386 void fgPlatformInitialiseInputDevices( void )
387 {
388     wl_seat_add_listener( fgDisplay.pDisplay.seat,
389                           &fghSeatListener,
390                           &fgDisplay.pDisplay );
391
392     wl_display_roundtrip( fgDisplay.pDisplay.display );
393 }
394
395 /*
396  * Try closing the input device(s)
397  */
398 void fgPlatformCloseInputDevices( void )
399 {
400     if( fgDisplay.pDisplay.touch )
401       wl_touch_destroy( fgDisplay.pDisplay.touch );
402     if( fgDisplay.pDisplay.pointer )
403       wl_pointer_destroy( fgDisplay.pDisplay.pointer );
404     if( fgDisplay.pDisplay.keyboard )
405       wl_keyboard_destroy( fgDisplay.pDisplay.keyboard );
406     if( fgDisplay.pDisplay.xkb_state )
407       xkb_state_unref( fgDisplay.pDisplay.xkb_state );
408     if( fgDisplay.pDisplay.xkb_context )
409       xkb_context_unref( fgDisplay.pDisplay.xkb_context );
410 }
411
412
413 /*
414  * Wayland backend will not be implementing spaceball at all
415  */
416 void fgPlatformInitializeSpaceball( void )
417 {
418 }
419 void fgPlatformSpaceballClose( void )
420 {
421 }
422 void fgPlatformSpaceballSetWindow( SFG_Window *window )
423 {
424 }
425 int fgPlatformHasSpaceball( void )
426 {
427     return 0;
428 }
429 int fgPlatformSpaceballNumButtons( void )
430 {
431     return 0;
432 }
433