1 /**
2  * @file lv_xkb.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "lv_xkb_private.h"
11 
12 #if defined(LV_LIBINPUT_XKB) && LV_LIBINPUT_XKB
13 
14 #include "../../core/lv_group.h"
15 #include "../../misc/lv_log.h"
16 
17 #include <errno.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 /*********************
24  *      DEFINES
25  *********************/
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 /**********************
32  *  STATIC PROTOTYPES
33  **********************/
34 
35 static bool _set_keymap(lv_xkb_t * dsc, struct xkb_rule_names names);
36 
37 /**********************
38  *  STATIC VARIABLES
39  **********************/
40 
41 static struct xkb_context * context = NULL;
42 
43 /**********************
44  *      MACROS
45  **********************/
46 
47 /**********************
48  *   GLOBAL FUNCTIONS
49  **********************/
50 
lv_xkb_init(lv_xkb_t * dsc,struct xkb_rule_names names)51 bool lv_xkb_init(lv_xkb_t * dsc, struct xkb_rule_names names)
52 {
53     if(!context) {
54         context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
55         if(!context) {
56             LV_LOG_ERROR("xkb_context_new failed: %s", strerror(errno));
57             return false;
58         }
59     }
60 
61     return _set_keymap(dsc, names);
62 }
63 
lv_xkb_deinit(lv_xkb_t * dsc)64 void lv_xkb_deinit(lv_xkb_t * dsc)
65 {
66     if(dsc->state) {
67         xkb_state_unref(dsc->state);
68         dsc->state = NULL;
69     }
70 
71     if(dsc->keymap) {
72         xkb_keymap_unref(dsc->keymap);
73         dsc->keymap = NULL;
74     }
75 }
76 
lv_xkb_process_key(lv_xkb_t * dsc,uint32_t scancode,bool down)77 uint32_t lv_xkb_process_key(lv_xkb_t * dsc, uint32_t scancode, bool down)
78 {
79     /* Offset the evdev scancode by 8, see https://xkbcommon.org/doc/current/xkbcommon_8h.html#ac29aee92124c08d1953910ab28ee1997 */
80     xkb_keycode_t keycode = scancode + 8;
81 
82     uint32_t result = 0;
83 
84     switch(xkb_state_key_get_one_sym(dsc->state, keycode)) {
85         case XKB_KEY_BackSpace:
86             result = LV_KEY_BACKSPACE;
87             break;
88         case XKB_KEY_Return:
89         case XKB_KEY_KP_Enter:
90             result = LV_KEY_ENTER;
91             break;
92         case XKB_KEY_Prior:
93         case XKB_KEY_KP_Prior:
94             result = LV_KEY_PREV;
95             break;
96         case XKB_KEY_Next:
97         case XKB_KEY_KP_Next:
98             result = LV_KEY_NEXT;
99             break;
100         case XKB_KEY_Up:
101         case XKB_KEY_KP_Up:
102             result = LV_KEY_UP;
103             break;
104         case XKB_KEY_Left:
105         case XKB_KEY_KP_Left:
106             result = LV_KEY_LEFT;
107             break;
108         case XKB_KEY_Right:
109         case XKB_KEY_KP_Right:
110             result = LV_KEY_RIGHT;
111             break;
112         case XKB_KEY_Down:
113         case XKB_KEY_KP_Down:
114             result = LV_KEY_DOWN;
115             break;
116         case XKB_KEY_Tab:
117         case XKB_KEY_KP_Tab:
118             result = LV_KEY_NEXT;
119             break;
120         case XKB_KEY_ISO_Left_Tab: /* Sent on SHIFT + TAB */
121             result = LV_KEY_PREV;
122             break;
123         case XKB_KEY_Home:
124         case XKB_KEY_KP_Home:
125             result = LV_KEY_HOME;
126             break;
127         case XKB_KEY_End:
128         case XKB_KEY_KP_End:
129             result = LV_KEY_END;
130             break;
131         default:
132             break;
133     }
134 
135     if(result == 0) {
136         char buffer[4] = { 0, 0, 0, 0 };
137         int size = xkb_state_key_get_utf8(dsc->state, keycode, NULL, 0) + 1;
138         if(size > 1) {
139             xkb_state_key_get_utf8(dsc->state, keycode, buffer, size);
140             memcpy(&result, buffer, 4);
141         }
142     }
143 
144     xkb_state_update_key(dsc->state, keycode, down ? XKB_KEY_DOWN : XKB_KEY_UP);
145 
146     return result;
147 }
148 
149 /**********************
150  *   STATIC FUNCTIONS
151  **********************/
152 
_set_keymap(lv_xkb_t * dsc,struct xkb_rule_names names)153 static bool _set_keymap(lv_xkb_t * dsc, struct xkb_rule_names names)
154 {
155     if(dsc->keymap) {
156         xkb_keymap_unref(dsc->keymap);
157         dsc->keymap = NULL;
158     }
159 
160     dsc->keymap = xkb_keymap_new_from_names(context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
161     if(!dsc->keymap) {
162         LV_LOG_ERROR("xkb_keymap_new_from_names failed: %s", strerror(errno));
163         return false;
164     }
165 
166     if(dsc->state) {
167         xkb_state_unref(dsc->state);
168         dsc->state = NULL;
169     }
170 
171     dsc->state = xkb_state_new(dsc->keymap);
172     if(!dsc->state) {
173         LV_LOG_ERROR("xkb_state_new failed: %s", strerror(errno));
174         return false;
175     }
176 
177     return true;
178 }
179 
180 #endif /* defined(LV_LIBINPUT_XKB) && LV_LIBINPUT_XKB */
181