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