1 /**
2  * @file lv_sdl_mouse.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_sdl_mouse.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 #ifndef KEYBOARD_BUFFER_SIZE
21     #define KEYBOARD_BUFFER_SIZE 32
22 #endif
23 
24 /**********************
25  *  STATIC PROTOTYPES
26  **********************/
27 static void sdl_mouse_read(lv_indev_t * indev, lv_indev_data_t * data);
28 static void release_indev_cb(lv_event_t * e);
29 
30 /**********************
31  *  STATIC VARIABLES
32  **********************/
33 
34 typedef struct {
35     int16_t last_x;
36     int16_t last_y;
37     bool left_button_down;
38 #if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
39     int32_t diff;
40 #endif
41 } lv_sdl_mouse_t;
42 
43 /**********************
44  *   GLOBAL FUNCTIONS
45  **********************/
46 
lv_sdl_mouse_create(void)47 lv_indev_t * lv_sdl_mouse_create(void)
48 {
49     lv_sdl_mouse_t * dsc = lv_malloc_zeroed(sizeof(lv_sdl_mouse_t));
50     LV_ASSERT_MALLOC(dsc);
51     if(dsc == NULL) return NULL;
52 
53     lv_indev_t * indev = lv_indev_create();
54     LV_ASSERT_MALLOC(indev);
55     if(indev == NULL) {
56         lv_free(dsc);
57         return NULL;
58     }
59 
60     lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
61     lv_indev_set_read_cb(indev, sdl_mouse_read);
62     lv_indev_set_driver_data(indev, dsc);
63 
64     lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT);
65     lv_indev_add_event_cb(indev, release_indev_cb, LV_EVENT_DELETE, indev);
66 
67     return indev;
68 }
69 
70 /**********************
71  *   STATIC FUNCTIONS
72  **********************/
73 
sdl_mouse_read(lv_indev_t * indev,lv_indev_data_t * data)74 static void sdl_mouse_read(lv_indev_t * indev, lv_indev_data_t * data)
75 {
76     lv_sdl_mouse_t * dsc = lv_indev_get_driver_data(indev);
77 
78     /*Store the collected data*/
79     data->point.x = dsc->last_x;
80     data->point.y = dsc->last_y;
81     data->state = dsc->left_button_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
82 #if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
83     data->enc_diff = dsc->diff;
84     dsc->diff = 0;
85 #endif
86 }
87 
release_indev_cb(lv_event_t * e)88 static void release_indev_cb(lv_event_t * e)
89 {
90     lv_indev_t * indev = (lv_indev_t *) lv_event_get_user_data(e);
91     lv_sdl_mouse_t * dsc = lv_indev_get_driver_data(indev);
92     if(dsc) {
93         lv_indev_set_driver_data(indev, NULL);
94         lv_indev_set_read_cb(indev, NULL);
95         lv_free(dsc);
96         LV_LOG_INFO("done");
97     }
98 }
99 
lv_sdl_mouse_handler(SDL_Event * event)100 void lv_sdl_mouse_handler(SDL_Event * event)
101 {
102     uint32_t win_id = UINT32_MAX;
103     switch(event->type) {
104         case SDL_MOUSEBUTTONUP:
105         case SDL_MOUSEBUTTONDOWN:
106             win_id = event->button.windowID;
107             break;
108         case SDL_MOUSEMOTION:
109             win_id = event->motion.windowID;
110             break;
111 #if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
112         case SDL_MOUSEWHEEL:
113             win_id = event->wheel.windowID;
114             break;
115 #endif
116         case SDL_FINGERUP:
117         case SDL_FINGERDOWN:
118         case SDL_FINGERMOTION:
119 #if SDL_VERSION_ATLEAST(2,0,12)
120             win_id = event->tfinger.windowID;
121 #endif
122             break;
123         case SDL_WINDOWEVENT:
124             win_id = event->window.windowID;
125             break;
126         default:
127             return;
128     }
129 
130     lv_display_t * disp = lv_sdl_get_disp_from_win_id(win_id);
131 
132     /*Find a suitable indev*/
133     lv_indev_t * indev = lv_indev_get_next(NULL);
134     while(indev) {
135         if(lv_indev_get_read_cb(indev) == sdl_mouse_read) {
136             /*If disp is NULL for any reason use the first indev with the correct type*/
137             if(disp == NULL || lv_indev_get_display(indev) == disp) break;
138         }
139         indev = lv_indev_get_next(indev);
140     }
141 
142     if(indev == NULL) return;
143     lv_sdl_mouse_t * indev_dev = lv_indev_get_driver_data(indev);
144     if(indev_dev == NULL) return;
145 
146     int32_t hor_res = lv_display_get_horizontal_resolution(disp);
147     int32_t ver_res = lv_display_get_vertical_resolution(disp);
148     float zoom = lv_sdl_window_get_zoom(disp);
149 
150     switch(event->type) {
151         case SDL_WINDOWEVENT:
152             if(event->window.event == SDL_WINDOWEVENT_LEAVE) {
153                 indev_dev->left_button_down = false;
154             }
155             break;
156         case SDL_MOUSEBUTTONUP:
157             if(event->button.button == SDL_BUTTON_LEFT)
158                 indev_dev->left_button_down = false;
159             break;
160         case SDL_WINDOWEVENT_LEAVE:
161             indev_dev->left_button_down = false;
162             break;
163         case SDL_MOUSEBUTTONDOWN:
164             if(event->button.button == SDL_BUTTON_LEFT) {
165                 indev_dev->left_button_down = true;
166                 indev_dev->last_x = (int16_t)((float)(event->motion.x) / zoom);
167                 indev_dev->last_y = (int16_t)((float)(event->motion.y) / zoom);
168             }
169             break;
170         case SDL_MOUSEMOTION:
171             indev_dev->last_x = (int16_t)((float)(event->motion.x) / zoom);
172             indev_dev->last_y = (int16_t)((float)(event->motion.y) / zoom);
173             break;
174 
175         case SDL_FINGERUP:
176             indev_dev->left_button_down = false;
177             indev_dev->last_x = (int16_t)((float)hor_res * event->tfinger.x / zoom);
178             indev_dev->last_y = (int16_t)((float)ver_res * event->tfinger.y / zoom);
179             break;
180         case SDL_FINGERDOWN:
181             indev_dev->left_button_down = true;
182             indev_dev->last_x = (int16_t)((float)hor_res * event->tfinger.x / zoom);
183             indev_dev->last_y = (int16_t)((float)ver_res * event->tfinger.y / zoom);
184             break;
185         case SDL_FINGERMOTION:
186             indev_dev->last_x = (int16_t)((float)hor_res * event->tfinger.x / zoom);
187             indev_dev->last_y = (int16_t)((float)ver_res * event->tfinger.y / zoom);
188             break;
189         case SDL_MOUSEWHEEL:
190 #if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
191 #ifdef __EMSCRIPTEN__
192             /*Emscripten scales it wrong*/
193             if(event->wheel.y < 0) dsc->diff++;
194             if(event->wheel.y > 0) dsc->diff--;
195 #else
196             indev_dev->diff = -event->wheel.y;
197 #endif  /*__EMSCRIPTEN__*/
198 #endif /*LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN*/
199             break;
200     }
201     lv_indev_read(indev);
202 }
203 
204 #endif /*LV_USE_SDL*/
205