1 /*
2 * ============================================================================
3 * Title: Event Handling Driver for both SDL1 and SDL2
4 * Author: J. Zbiciak
5 * ============================================================================
6 * This is the platform-specific driver for SDL 1.2.x and SDL 2.x
7 * The SDL1 and SDL2 specific pieces are in event_sdl1.c and event_sdl2.c.
8 * ============================================================================
9 */
10
11 #include "config.h"
12 #include "sdl_jzintv.h"
13 #include "event/event_tbl.h"
14 #include "event/event_plat.h"
15 #include "event/event_sdl_pvt.h"
16 #include "joy/joy.h"
17 #include "joy/joy_sdl.h"
18 #include "mouse/mouse.h"
19
20 /* TODO: Migrate Enscripten support to SDL2. */
21 #if defined(__EMSCRIPTEN__)
22 # define SDL_EventState(x,y) ((void)(x), (void)(y))
23 #endif
24
25 /* ======================================================================== */
26 /* Some very minor platform-specific tweaks. */
27 /* ======================================================================== */
28 #ifdef WII
29 # define ENABLE_JOY_EVENTS SDL_IGNORE
30 #else
31 # define ENABLE_JOY_EVENTS SDL_ENABLE
32 #endif
33
34 #ifdef N900
35 # define ENABLE_SYSWM_EVENTS SDL_IGNORE
36 #else
37 # define ENABLE_SYSWM_EVENTS SDL_ENABLE
38 #endif
39
40 #ifdef USE_SDL2
41 # define WINDOW_EVENT_CATEGORY SDL_WINDOWEVENT
42 #else
43 # define WINDOW_EVENT_CATEGORY SDL_ACTIVEEVENT
44 #endif
45
46 typedef struct event_sdl_pvt
47 {
48 bool mouse_enabled;
49 } event_sdl_pvt_t;
50
51 /* ======================================================================== */
52 /* EVENT_PLAT_INIT -- Initializes the SDL1 Event subsystem. */
53 /* ======================================================================== */
event_plat_init(const bool enable_mouse,evt_pvt_t * const evt_pvt,void ** const ptr_plat_pvt)54 int event_plat_init(
55 const bool enable_mouse, /* Enable mouse events? */
56 evt_pvt_t *const evt_pvt, /* Event core private ptr, if needed. */
57 void **const ptr_plat_pvt /* Our allocated private struct. */
58 )
59 {
60 SDL_Event dummy;
61
62 UNUSED(evt_pvt);
63
64 /* -------------------------------------------------------------------- */
65 /* Set up our "private" structure. */
66 /* -------------------------------------------------------------------- */
67 event_sdl_pvt_t *plat_pvt = CALLOC(event_sdl_pvt_t, 1);
68
69 if (!plat_pvt)
70 {
71 fprintf(stderr, "event_sdl1: Unable to allocate private state.\n");
72 return -1;
73 }
74
75 *ptr_plat_pvt = plat_pvt;
76
77 /* -------------------------------------------------------------------- */
78 /* Set up SDL to filter out the events we're NOT interested in... */
79 /* -------------------------------------------------------------------- */
80 if (!enable_mouse)
81 {
82 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
83 SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
84 SDL_EventState(SDL_MOUSEBUTTONUP, SDL_IGNORE);
85 } else
86 {
87 plat_pvt->mouse_enabled = true;
88 SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
89 SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
90 SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
91 }
92 SDL_EventState(SDL_SYSWMEVENT, ENABLE_SYSWM_EVENTS);
93
94 /* -------------------------------------------------------------------- */
95 /* ...and leave us only with the events we ARE interested in. */
96 /* -------------------------------------------------------------------- */
97 SDL_EventState(WINDOW_EVENT_CATEGORY, SDL_ENABLE);
98 SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
99 SDL_EventState(SDL_KEYUP, SDL_ENABLE);
100 SDL_EventState(SDL_QUIT, SDL_ENABLE);
101 SDL_EventState(SDL_JOYAXISMOTION, ENABLE_JOY_EVENTS);
102 SDL_EventState(SDL_JOYHATMOTION, ENABLE_JOY_EVENTS);
103 SDL_EventState(SDL_JOYBUTTONDOWN, ENABLE_JOY_EVENTS);
104 SDL_EventState(SDL_JOYBUTTONUP, ENABLE_JOY_EVENTS);
105 SDL_EventState(SDL_JOYBALLMOTION, ENABLE_JOY_EVENTS);
106 SDL_JoystickEventState(ENABLE_JOY_EVENTS);
107
108 /* -------------------------------------------------------------------- */
109 /* Drain the event queue right now to clear any initial events. */
110 /* -------------------------------------------------------------------- */
111 while (SDL_PollEvent(&dummy))
112 ;
113
114 /* -------------------------------------------------------------------- */
115 /* Done! */
116 /* -------------------------------------------------------------------- */
117 return 0;
118 }
119
120 /* ======================================================================== */
121 /* EVENT_PLAT_DTOR -- Tear down the event engine. */
122 /* ======================================================================== */
event_plat_dtor(void * const plat_pvt)123 void event_plat_dtor(void *const plat_pvt)
124 {
125 if (plat_pvt) free(plat_pvt);
126 joy_dtor();
127 }
128
129 /* ======================================================================== */
130 /* EVENT_PLAT_PUMP -- Pump the event engine before the full tick starts. */
131 /* ======================================================================== */
event_plat_pump(evt_pvt_t * const evt_pvt,void * const void_plat_pvt)132 void event_plat_pump(evt_pvt_t *const evt_pvt, void *const void_plat_pvt)
133 {
134 UNUSED(evt_pvt);
135 UNUSED(void_plat_pvt);
136
137 SDL_PumpEvents();
138 }
139
140 /* ======================================================================== */
141 /* EVENT_PLAT_TICK -- Performs the bulk of the tick cycle. */
142 /* */
143 /* Returns true if we need to cork events, typically due to a combo. */
144 /* ======================================================================== */
event_plat_tick(evt_pvt_t * const evt_pvt,void * const void_plat_pvt)145 bool event_plat_tick(evt_pvt_t *const evt_pvt, void *const void_plat_pvt)
146 {
147 const event_sdl_pvt_t *const plat_pvt = (event_sdl_pvt_t*)void_plat_pvt;
148 SDL_Event event;
149
150 /* -------------------------------------------------------------------- */
151 /* Now, process all pending events. */
152 /* -------------------------------------------------------------------- */
153 #ifdef WII
154 getWiiJoyEvents();
155 #endif
156 while (event_queue_has_room(evt_pvt, 4) && SDL_PollEvent(&event))
157 {
158 switch (event.type)
159 {
160 /* ------------------------------------------------------------ */
161 /* Handle keypresses and releases by sending the decoded */
162 /* keysym value as event #. */
163 /* ------------------------------------------------------------ */
164 case SDL_KEYDOWN:
165 case SDL_KEYUP:
166 {
167 const event_updn_t event_updn =
168 event.type == SDL_KEYUP ? EV_UP : EV_DOWN;
169
170 const event_num_t event_num = event_sdl_translate_key(&event);
171
172 if (event_enqueue_check_combo(evt_pvt, event_updn, event_num))
173 return true;
174
175 break;
176 }
177
178 /* ------------------------------------------------------------ */
179 /* Outsource all the joystick event decoding... */
180 /* ------------------------------------------------------------ */
181 case SDL_JOYAXISMOTION:
182 case SDL_JOYHATMOTION:
183 case SDL_JOYBUTTONDOWN:
184 case SDL_JOYBUTTONUP:
185 {
186 event_updn_t event_updn[2] = { EV_DOWN, EV_DOWN };
187 event_num_t event_num[2] = { EVENT_IGNORE, EVENT_IGNORE };
188
189 const bool may_combo =
190 joy_decode_event(&event, event_updn, event_num);
191
192 assert(!may_combo || event_num[1] == EVENT_IGNORE);
193 if (may_combo)
194 {
195 if (event_enqueue_check_combo(
196 evt_pvt, event_updn[0], event_num[0]))
197 return true;
198 } else
199 {
200 event_enqueue(evt_pvt, event_updn[0], event_num[0]);
201 event_enqueue(evt_pvt, event_updn[1], event_num[1]);
202 }
203 break;
204 }
205
206 /* ------------------------------------------------------------ */
207 /* Outsource all mouse event decoding... */
208 /* ------------------------------------------------------------ */
209 case SDL_MOUSEMOTION:
210 case SDL_MOUSEBUTTONDOWN:
211 case SDL_MOUSEBUTTONUP:
212 {
213 if (plat_pvt->mouse_enabled)
214 {
215 event_updn_t event_updn[2] = { EV_DOWN, EV_DOWN };
216 event_num_t event_num[2] = { EVENT_IGNORE, EVENT_IGNORE };
217
218 mouse_decode_event(&event, event_updn, event_num);
219
220 event_enqueue(evt_pvt, event_updn[0], event_num[0]);
221 event_enqueue(evt_pvt, event_updn[1], event_num[1]);
222 }
223 break;
224 }
225
226 /* ------------------------------------------------------------ */
227 /* And finally, handle the QUIT event. */
228 /* ------------------------------------------------------------ */
229 case SDL_QUIT:
230 {
231 event_enqueue(evt_pvt, EV_DOWN, EVENT_QUIT);
232 break;
233 }
234
235 /* ------------------------------------------------------------ */
236 /* If it's unhandled, pass down to the SDL-version specific */
237 /* handlers to see if they understand it. */
238 /* ------------------------------------------------------------ */
239 default:
240 {
241 /* If this returns 'true', that means it queued a combo. */
242 if (event_sdl_unhandled_event(evt_pvt, &event))
243 return true;
244 break;
245 }
246 }
247 }
248
249 return false; /* did not need to cork. */
250 }
251
252 /* ======================================================================== */
253 /* EVENT_PLAT_TICK_LATE -- Performs deferred tick cycle tasks, after we */
254 /* have drained our internal event queue. */
255 /* */
256 /* Currently this is only used by SDL's experimental mouse processing. */
257 /* Not sure if this is really necessary. */
258 /* ======================================================================== */
event_plat_tick_late(evt_pvt_t * const evt_pvt,void * const void_plat_pvt)259 void event_plat_tick_late(evt_pvt_t *const evt_pvt, void *const void_plat_pvt)
260 {
261 const event_sdl_pvt_t *const plat_pvt = (event_sdl_pvt_t*)void_plat_pvt;
262
263 /* -------------------------------------------------------------------- */
264 /* If the mouse is enabled, see if we need to do any delayed events. */
265 /* -------------------------------------------------------------------- */
266 if (plat_pvt->mouse_enabled)
267 {
268 event_updn_t event_updn = EV_DOWN;
269 event_num_t event_num = EVENT_IGNORE;
270
271 mouse_pump(&event_updn, &event_num);
272 event_enqueue(evt_pvt, event_updn, event_num);
273 }
274 }
275
276 /* ======================================================================== */
277 /* This program is free software; you can redistribute it and/or modify */
278 /* it under the terms of the GNU General Public License as published by */
279 /* the Free Software Foundation; either version 2 of the License, or */
280 /* (at your option) any later version. */
281 /* */
282 /* This program is distributed in the hope that it will be useful, */
283 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
284 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
285 /* General Public License for more details. */
286 /* */
287 /* You should have received a copy of the GNU General Public License along */
288 /* with this program; if not, write to the Free Software Foundation, Inc., */
289 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
290 /* ======================================================================== */
291 /* Copyright (c) 1998-2020, Joseph Zbiciak */
292 /* ======================================================================== */
293