2 * fg_input_devices_wl.c
4 * Handles Wayland input devices : keyboard, pointer, touchscreen.
6 * Written by Manuel Bachmann <tarnyko@tarnyko.net> 2015
8 * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
9 * Creation date: Thur Mar 19 2015
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:
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
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.
30 #include <linux/input.h>
32 #define BTN_LEFT 0x110
33 #define BTN_RIGHT 0x111
34 #define BTN_MIDDLE 0x112
37 #include <GL/freeglut.h>
38 #include "../fg_internal.h"
41 * This function will effectively set the pointer (mouse) cursor
42 * depending on the GLUT_CURSOR_* choice.
44 void fghPointerSetCursor( SFG_Window* window,
45 struct wl_pointer* pointer,
48 struct wl_cursor_image* image;
49 struct wl_buffer* buffer;
51 image = window->Window.pContext.cursor->images[0];
52 buffer = wl_cursor_image_get_buffer( image );
54 wl_surface_attach( window->Window.pContext.cursor_surface, buffer,
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 );
60 wl_pointer_set_cursor( pointer, serial,
61 window->Window.pContext.cursor_surface,
62 image->hotspot_x, image->hotspot_y );
66 * This function will interpret a keyboard keysym, and call the
67 * possible callbacks accordingly.
69 void fghKeyboardInterpretKeysym( SFG_Window* window,
74 FGCBKeyboard keyboard_cb;
75 FGCBSpecial special_cb;
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... */
84 keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
85 special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special ));
89 keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
90 special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp ));
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;
127 if( special_cb && (special != -1) )
129 fgSetWindow( window );
130 special_cb( special, window->State.MouseX, window->State.MouseY );
132 else if( keyboard_cb && (special == -1) )
134 fgSetWindow( window );
135 xkb_keysym_to_utf8( sym, string, sizeof( string ) );
136 keyboard_cb( string[0], window->State.MouseX, window->State.MouseY );
142 * Touchscreen section
143 * For now, let us pretend it is a mouse with only one button
145 static void fghTouchDown( void* data, struct wl_touch* touch,
146 uint32_t serial, uint32_t time,
147 struct wl_surface* surface,
149 wl_fixed_t x_w, wl_fixed_t y_w )
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,
157 win->State.MouseY ) );
159 static void fghTouchUp( void* data, struct wl_touch* touch,
160 uint32_t serial, uint32_t time,
163 SFG_Window* win = fgStructure.CurrentWindow;
164 INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
167 win->State.MouseY ) );
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 )
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 ) );
179 static void fghTouchFrame( void* data, struct wl_touch* touch )
182 static void fghTouchCancel( void* data, struct wl_touch* touch )
185 static const struct wl_touch_listener fghTouchListener =
196 * Pointer (mouse) section
198 static void fghPointerEnter( void* data, struct wl_pointer* pointer,
200 struct wl_surface* surface,
201 wl_fixed_t x_w, wl_fixed_t y_w )
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 ) );
209 static void fghPointerLeave( void* data, struct wl_pointer* pointer,
211 struct wl_surface* surface )
213 SFG_Window* win = fgStructure.CurrentWindow;
214 INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
216 static void fghPointerMotion( void* data, struct wl_pointer* pointer,
218 wl_fixed_t x_w, wl_fixed_t y_w )
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 );
224 if ( win->Window.pContext.pointer_button_pressed )
225 INVOKE_WCB( *win, Motion, ( win->State.MouseX,
226 win->State.MouseY ) );
228 INVOKE_WCB( *win, Passive, ( win->State.MouseX,
229 win->State.MouseY ) );
231 static void fghPointerButton( void* data, struct wl_pointer* pointer,
232 uint32_t serial, uint32_t time,
233 uint32_t button, uint32_t state )
235 SFG_Window* win = fgStructure.CurrentWindow;
241 button_f = GLUT_LEFT_BUTTON;
244 button_f = GLUT_RIGHT_BUTTON;
247 button_f = GLUT_MIDDLE_BUTTON;
251 win->Window.pContext.pointer_button_pressed =
252 state ? GL_TRUE : GL_FALSE;
254 INVOKE_WCB( *win, Mouse, ( button_f,
255 state ? GLUT_DOWN : GLUT_UP ,
257 win->State.MouseY ) );
259 static void fghPointerAxis( void* data, struct wl_pointer* pointer,
260 uint32_t time, uint32_t axis,
263 SFG_Window* win = fgStructure.CurrentWindow;
264 int direction = wl_fixed_to_int( value );
266 INVOKE_WCB( *win, MouseWheel, ( 0,
269 win->State.MouseY ) );
271 static const struct wl_pointer_listener fghPointerListener =
284 static void fghKeyboardKeymap( void* data, struct wl_keyboard* keyboard,
285 uint32_t format, int fd, uint32_t size )
287 SFG_PlatformDisplay* pDisplay = data;
289 struct xkb_keymap* keymap;
291 keymap_str = mmap( NULL, size, PROT_READ, MAP_SHARED, fd, 0 );
292 keymap = xkb_keymap_new_from_string( pDisplay->xkb_context,
294 XKB_KEYMAP_FORMAT_TEXT_V1,
296 munmap( keymap_str, size );
298 if( pDisplay->xkb_state )
299 xkb_state_unref( pDisplay->xkb_state );
300 pDisplay->xkb_state = xkb_state_new( keymap );
302 static void fghKeyboardEnter( void* data, struct wl_keyboard* keyboard,
303 uint32_t serial, struct wl_surface* surface,
304 struct wl_array* keys )
306 SFG_Window* win = fgStructure.CurrentWindow;
307 INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
309 static void fghKeyboardLeave( void* data, struct wl_keyboard* keyboard,
310 uint32_t serial, struct wl_surface* surface )
312 SFG_Window* win = fgStructure.CurrentWindow;
313 INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
315 static void fghKeyboardKey( void* data, struct wl_keyboard* keyboard,
316 uint32_t serial, uint32_t time,
317 uint32_t key, uint32_t state )
319 SFG_PlatformDisplay* pDisplay = data;
320 SFG_Window* win = fgStructure.CurrentWindow;
321 const xkb_keysym_t* syms;
323 xkb_state_key_get_syms( pDisplay->xkb_state,
325 fghKeyboardInterpretKeysym( win, key, syms[0], state );
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,
333 static const struct wl_keyboard_listener fghKeyboardListener =
344 * Discover potential input device(s) (keyboard, pointer, touch)
346 static void fghSeatCapabilities( void* data,
347 struct wl_seat* seat,
348 enum wl_seat_capability capabilities )
350 SFG_PlatformDisplay* pDisplay = data;
352 if( capabilities & WL_SEAT_CAPABILITY_KEYBOARD )
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,
361 if( capabilities & WL_SEAT_CAPABILITY_POINTER )
363 pDisplay->pointer = wl_seat_get_pointer( seat );
364 wl_pointer_add_listener( pDisplay->pointer,
369 if( capabilities & WL_SEAT_CAPABILITY_TOUCH )
371 pDisplay->touch = wl_seat_get_touch( seat );
372 wl_touch_add_listener( pDisplay->touch,
377 static const struct wl_seat_listener fghSeatListener =
384 * Try initializing the input device(s)
386 void fgPlatformInitialiseInputDevices( void )
388 wl_seat_add_listener( fgDisplay.pDisplay.seat,
390 &fgDisplay.pDisplay );
392 wl_display_roundtrip( fgDisplay.pDisplay.display );
396 * Try closing the input device(s)
398 void fgPlatformCloseInputDevices( void )
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 );
414 * Wayland backend will not be implementing spaceball at all
416 void fgPlatformInitializeSpaceball( void )
419 void fgPlatformSpaceballClose( void )
422 void fgPlatformSpaceballSetWindow( SFG_Window *window )
425 int fgPlatformHasSpaceball( void )
429 int fgPlatformSpaceballNumButtons( void )