1 /**
2 * @file lv_sdl_keyboard.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_sdl_keyboard.h"
10 #if LV_USE_SDL
11
12 #include "../../core/lv_group.h"
13 #include "../../stdlib/lv_string.h"
14 #include "lv_sdl_private.h"
15
16 /*********************
17 * DEFINES
18 *********************/
19
20 /**********************
21 * TYPEDEFS
22 **********************/
23 typedef struct {
24 char buf[KEYBOARD_BUFFER_SIZE];
25 bool dummy_read;
26 } lv_sdl_keyboard_t;
27
28 /**********************
29 * STATIC PROTOTYPES
30 **********************/
31 static void sdl_keyboard_read(lv_indev_t * indev, lv_indev_data_t * data);
32 static uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key);
33 static void release_indev_cb(lv_event_t * e);
34
35 /**********************
36 * STATIC VARIABLES
37 **********************/
38
39 /**********************
40 * GLOBAL FUNCTIONS
41 **********************/
42
lv_sdl_keyboard_create(void)43 lv_indev_t * lv_sdl_keyboard_create(void)
44 {
45 lv_sdl_keyboard_t * dsc = lv_malloc_zeroed(sizeof(lv_sdl_keyboard_t));
46 LV_ASSERT_MALLOC(dsc);
47 if(dsc == NULL) return NULL;
48
49 lv_indev_t * indev = lv_indev_create();
50 LV_ASSERT_MALLOC(indev);
51 if(indev == NULL) {
52 lv_free(dsc);
53 return NULL;
54 }
55
56 lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
57 lv_indev_set_read_cb(indev, sdl_keyboard_read);
58 lv_indev_set_driver_data(indev, dsc);
59 lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT);
60 lv_indev_add_event_cb(indev, release_indev_cb, LV_EVENT_DELETE, indev);
61
62 return indev;
63 }
64
65 /**********************
66 * STATIC FUNCTIONS
67 **********************/
68
sdl_keyboard_read(lv_indev_t * indev,lv_indev_data_t * data)69 static void sdl_keyboard_read(lv_indev_t * indev, lv_indev_data_t * data)
70 {
71 lv_sdl_keyboard_t * dev = lv_indev_get_driver_data(indev);
72
73 const size_t len = lv_strlen(dev->buf);
74
75 /*Send a release manually*/
76 if(dev->dummy_read) {
77 dev->dummy_read = false;
78 data->state = LV_INDEV_STATE_RELEASED;
79 }
80 /*Send the pressed character*/
81 else if(len > 0) {
82 dev->dummy_read = true;
83 data->state = LV_INDEV_STATE_PRESSED;
84 data->key = dev->buf[0];
85 lv_memmove(dev->buf, dev->buf + 1, len);
86 }
87 }
88
release_indev_cb(lv_event_t * e)89 static void release_indev_cb(lv_event_t * e)
90 {
91 lv_indev_t * indev = (lv_indev_t *) lv_event_get_user_data(e);
92 lv_sdl_keyboard_t * dev = lv_indev_get_driver_data(indev);
93 if(dev) {
94 lv_indev_set_driver_data(indev, NULL);
95 lv_indev_set_read_cb(indev, NULL);
96 lv_free(dev);
97 LV_LOG_INFO("done");
98 }
99 }
100
lv_sdl_keyboard_handler(SDL_Event * event)101 void lv_sdl_keyboard_handler(SDL_Event * event)
102 {
103 uint32_t win_id = UINT32_MAX;
104 switch(event->type) {
105 case SDL_KEYDOWN:
106 win_id = event->key.windowID;
107 break;
108 case SDL_TEXTINPUT:
109 win_id = event->text.windowID;
110 break;
111 default:
112 return;
113 }
114
115 lv_display_t * disp = lv_sdl_get_disp_from_win_id(win_id);
116
117
118 /*Find a suitable indev*/
119 lv_indev_t * indev = lv_indev_get_next(NULL);
120 while(indev) {
121 if(lv_indev_get_read_cb(indev) == sdl_keyboard_read) {
122 /*If disp is NULL for any reason use the first indev with the correct type*/
123 if(disp == NULL || lv_indev_get_display(indev) == disp) break;
124 }
125 indev = lv_indev_get_next(indev);
126 }
127 if(indev == NULL) return;
128 lv_sdl_keyboard_t * dsc = lv_indev_get_driver_data(indev);
129
130 /* We only care about SDL_KEYDOWN and SDL_TEXTINPUT events */
131 switch(event->type) {
132 case SDL_KEYDOWN: { /*Button press*/
133 const uint32_t ctrl_key = keycode_to_ctrl_key(event->key.keysym.sym);
134 if(ctrl_key == '\0')
135 return;
136 const size_t len = lv_strlen(dsc->buf);
137 if(len < KEYBOARD_BUFFER_SIZE - 1) {
138 dsc->buf[len] = ctrl_key;
139 dsc->buf[len + 1] = '\0';
140 }
141 break;
142 }
143 case SDL_TEXTINPUT: { /*Text input*/
144 const size_t len = lv_strlen(dsc->buf) + lv_strlen(event->text.text);
145 if(len < KEYBOARD_BUFFER_SIZE - 1)
146 strcat(dsc->buf, event->text.text);
147 }
148 break;
149 default:
150 break;
151
152 }
153
154 size_t len = lv_strlen(dsc->buf);
155 while(len) {
156 lv_indev_read(indev);
157
158 /*Call again to handle dummy read in `sdl_keyboard_read`*/
159 lv_indev_read(indev);
160 len--;
161 }
162 }
163
164 /**
165 * Convert a SDL key code to it's LV_KEY_* counterpart or return '\0' if it's not a control character.
166 * @param sdl_key the key code
167 * @return LV_KEY_* control character or '\0'
168 */
keycode_to_ctrl_key(SDL_Keycode sdl_key)169 static uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key)
170 {
171 /*Remap some key to LV_KEY_... to manage groups*/
172 switch(sdl_key) {
173 case SDLK_RIGHT:
174 case SDLK_KP_PLUS:
175 return LV_KEY_RIGHT;
176
177 case SDLK_LEFT:
178 case SDLK_KP_MINUS:
179 return LV_KEY_LEFT;
180
181 case SDLK_UP:
182 return LV_KEY_UP;
183
184 case SDLK_DOWN:
185 return LV_KEY_DOWN;
186
187 case SDLK_ESCAPE:
188 return LV_KEY_ESC;
189
190 case SDLK_BACKSPACE:
191 return LV_KEY_BACKSPACE;
192
193 case SDLK_DELETE:
194 return LV_KEY_DEL;
195
196 case SDLK_KP_ENTER:
197 case '\r':
198 return LV_KEY_ENTER;
199
200 case SDLK_TAB:
201 case SDLK_PAGEDOWN:
202 return LV_KEY_NEXT;
203
204 case SDLK_PAGEUP:
205 return LV_KEY_PREV;
206
207 case SDLK_HOME:
208 return LV_KEY_HOME;
209
210 case SDLK_END:
211 return LV_KEY_END;
212
213 default:
214 return '\0';
215 }
216 }
217
218 #endif /*LV_USE_SDL*/
219