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 FGCBKeyboardUC keyboard_cb;
75 FGCBSpecialUC special_cb;
76 FGCBUserData keyboard_ud;
77 FGCBUserData special_ud;
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... */
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 );
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 );
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;
133 if( special_cb && (special != -1) )
135 fgSetWindow( window );
136 special_cb( special, window->State.MouseX, window->State.MouseY, special_ud );
138 else if( keyboard_cb && (special == -1) )
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 );
148 * Touchscreen section
149 * For now, let us pretend it is a mouse with only one button
151 static void fghTouchDown( void* data, struct wl_touch* touch,
152 uint32_t serial, uint32_t time,
153 struct wl_surface* surface,
155 wl_fixed_t x_w, wl_fixed_t y_w )
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,
163 win->State.MouseY ) );
165 static void fghTouchUp( void* data, struct wl_touch* touch,
166 uint32_t serial, uint32_t time,
169 SFG_Window* win = fgStructure.CurrentWindow;
170 INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
173 win->State.MouseY ) );
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 )
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 ) );
185 static void fghTouchFrame( void* data, struct wl_touch* touch )
188 static void fghTouchCancel( void* data, struct wl_touch* touch )
191 static const struct wl_touch_listener fghTouchListener =
202 * Pointer (mouse) section
204 static void fghPointerEnter( void* data, struct wl_pointer* pointer,
206 struct wl_surface* surface,
207 wl_fixed_t x_w, wl_fixed_t y_w )
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 ) );
215 static void fghPointerLeave( void* data, struct wl_pointer* pointer,
217 struct wl_surface* surface )
219 SFG_Window* win = fgStructure.CurrentWindow;
220 INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
222 static void fghPointerMotion( void* data, struct wl_pointer* pointer,
224 wl_fixed_t x_w, wl_fixed_t y_w )
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 );
230 if ( win->Window.pContext.pointer_button_pressed )
231 INVOKE_WCB( *win, Motion, ( win->State.MouseX,
232 win->State.MouseY ) );
234 INVOKE_WCB( *win, Passive, ( win->State.MouseX,
235 win->State.MouseY ) );
237 static void fghPointerButton( void* data, struct wl_pointer* pointer,
238 uint32_t serial, uint32_t time,
239 uint32_t button, uint32_t state )
241 SFG_Window* win = fgStructure.CurrentWindow;
247 button_f = GLUT_LEFT_BUTTON;
250 button_f = GLUT_RIGHT_BUTTON;
253 button_f = GLUT_MIDDLE_BUTTON;
257 win->Window.pContext.pointer_button_pressed =
258 state ? GL_TRUE : GL_FALSE;
260 INVOKE_WCB( *win, Mouse, ( button_f,
261 state ? GLUT_DOWN : GLUT_UP ,
263 win->State.MouseY ) );
265 static void fghPointerAxis( void* data, struct wl_pointer* pointer,
266 uint32_t time, uint32_t axis,
269 SFG_Window* win = fgStructure.CurrentWindow;
270 int direction = wl_fixed_to_int( value );
272 INVOKE_WCB( *win, MouseWheel, ( 0,
275 win->State.MouseY ) );
277 static const struct wl_pointer_listener fghPointerListener =
290 static void fghKeyboardKeymap( void* data, struct wl_keyboard* keyboard,
291 uint32_t format, int fd, uint32_t size )
293 SFG_PlatformDisplay* pDisplay = data;
295 struct xkb_keymap* keymap;
297 keymap_str = mmap( NULL, size, PROT_READ, MAP_SHARED, fd, 0 );
298 keymap = xkb_keymap_new_from_string( pDisplay->xkb_context,
300 XKB_KEYMAP_FORMAT_TEXT_V1,
302 munmap( keymap_str, size );
304 if( pDisplay->xkb_state )
305 xkb_state_unref( pDisplay->xkb_state );
306 pDisplay->xkb_state = xkb_state_new( keymap );
308 static void fghKeyboardEnter( void* data, struct wl_keyboard* keyboard,
309 uint32_t serial, struct wl_surface* surface,
310 struct wl_array* keys )
312 SFG_Window* win = fgStructure.CurrentWindow;
313 INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
315 static void fghKeyboardLeave( void* data, struct wl_keyboard* keyboard,
316 uint32_t serial, struct wl_surface* surface )
318 SFG_Window* win = fgStructure.CurrentWindow;
319 INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
321 static void fghKeyboardKey( void* data, struct wl_keyboard* keyboard,
322 uint32_t serial, uint32_t time,
323 uint32_t key, uint32_t state )
325 SFG_PlatformDisplay* pDisplay = data;
326 SFG_Window* win = fgStructure.CurrentWindow;
327 const xkb_keysym_t* syms;
329 xkb_state_key_get_syms( pDisplay->xkb_state,
331 fghKeyboardInterpretKeysym( win, key, syms[0], state );
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,
339 static const struct wl_keyboard_listener fghKeyboardListener =
350 * Discover potential input device(s) (keyboard, pointer, touch)
352 static void fghSeatCapabilities( void* data,
353 struct wl_seat* seat,
354 enum wl_seat_capability capabilities )
356 SFG_PlatformDisplay* pDisplay = data;
358 if( capabilities & WL_SEAT_CAPABILITY_KEYBOARD )
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,
367 if( capabilities & WL_SEAT_CAPABILITY_POINTER )
369 pDisplay->pointer = wl_seat_get_pointer( seat );
370 wl_pointer_add_listener( pDisplay->pointer,
375 if( capabilities & WL_SEAT_CAPABILITY_TOUCH )
377 pDisplay->touch = wl_seat_get_touch( seat );
378 wl_touch_add_listener( pDisplay->touch,
383 static const struct wl_seat_listener fghSeatListener =
390 * Try initializing the input device(s)
392 void fgPlatformInitialiseInputDevices( void )
394 wl_seat_add_listener( fgDisplay.pDisplay.seat,
396 &fgDisplay.pDisplay );
398 wl_display_roundtrip( fgDisplay.pDisplay.display );
402 * Try closing the input device(s)
404 void fgPlatformCloseInputDevices( void )
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 );
420 * Wayland backend will not be implementing spaceball at all
422 void fgPlatformInitializeSpaceball( void )
425 void fgPlatformSpaceballClose( void )
428 void fgPlatformSpaceballSetWindow( SFG_Window *window )
431 int fgPlatformHasSpaceball( void )
435 int fgPlatformSpaceballNumButtons( void )