1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "Logger.hxx"
19#include "OSystem.hxx"
20#include "EventHandlerSDL2.hxx"
21
22#include "ThreadDebugging.hxx"
23
24// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
25EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
26 : EventHandler(osystem)
27{
28 ASSERT_MAIN_THREAD;
29
30#ifdef JOYSTICK_SUPPORT
31 if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
32 {
33 ostringstream buf;
34 buf << "ERROR: Couldn't initialize SDL joystick support: " << SDL_GetError() << endl;
35 Logger::error(buf.str());
36 }
37 Logger::debug("EventHandlerSDL2::EventHandlerSDL2 SDL_INIT_JOYSTICK");
38#endif
39}
40
41// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
42EventHandlerSDL2::~EventHandlerSDL2()
43{
44 ASSERT_MAIN_THREAD;
45
46 if(SDL_WasInit(SDL_INIT_JOYSTICK))
47 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
48}
49
50// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
51void EventHandlerSDL2::enableTextEvents(bool enable)
52{
53 ASSERT_MAIN_THREAD;
54
55 if(enable)
56 SDL_StartTextInput();
57 else
58 SDL_StopTextInput();
59}
60
61// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62void EventHandlerSDL2::pollEvent()
63{
64 ASSERT_MAIN_THREAD;
65
66 while(SDL_PollEvent(&myEvent))
67 {
68 switch(myEvent.type)
69 {
70 // keyboard events
71 case SDL_KEYUP:
72 case SDL_KEYDOWN:
73 {
74 handleKeyEvent(StellaKey(myEvent.key.keysym.scancode),
75 StellaMod(myEvent.key.keysym.mod),
76 myEvent.key.type == SDL_KEYDOWN,
77 myEvent.key.repeat);
78 break;
79 }
80
81 case SDL_TEXTINPUT:
82 {
83 handleTextEvent(*(myEvent.text.text));
84 break;
85 }
86
87 case SDL_MOUSEMOTION:
88 {
89 handleMouseMotionEvent(myEvent.motion.x, myEvent.motion.y,
90 myEvent.motion.xrel, myEvent.motion.yrel);
91 break;
92 }
93
94 case SDL_MOUSEBUTTONDOWN:
95 case SDL_MOUSEBUTTONUP:
96 {
97 // ToDo: check support of more buttons and double-click
98 switch(myEvent.button.button)
99 {
100 case SDL_BUTTON_LEFT:
101 handleMouseButtonEvent(MouseButton::LEFT, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
102 myEvent.button.x, myEvent.button.y);
103 break;
104 case SDL_BUTTON_RIGHT:
105 handleMouseButtonEvent(MouseButton::RIGHT, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
106 myEvent.button.x, myEvent.button.y);
107 break;
108 }
109 break;
110 }
111
112 case SDL_MOUSEWHEEL:
113 {
114 int x, y;
115 SDL_GetMouseState(&x, &y); // we need mouse position too
116 if(myEvent.wheel.y < 0)
117 handleMouseButtonEvent(MouseButton::WHEELDOWN, true, x, y);
118 else if(myEvent.wheel.y > 0)
119 handleMouseButtonEvent(MouseButton::WHEELUP, true, x, y);
120 break;
121 }
122
123 #ifdef JOYSTICK_SUPPORT
124 case SDL_JOYBUTTONUP:
125 case SDL_JOYBUTTONDOWN:
126 {
127 handleJoyBtnEvent(myEvent.jbutton.which, myEvent.jbutton.button,
128 myEvent.jbutton.state == SDL_PRESSED);
129 break;
130 }
131
132 case SDL_JOYAXISMOTION:
133 {
134 handleJoyAxisEvent(myEvent.jaxis.which, myEvent.jaxis.axis,
135 myEvent.jaxis.value);
136 break;
137 }
138
139 case SDL_JOYHATMOTION:
140 {
141 int v = myEvent.jhat.value, value = 0;
142 if(v == SDL_HAT_CENTERED)
143 value = EVENT_HATCENTER_M;
144 else
145 {
146 if(v & SDL_HAT_UP) value |= EVENT_HATUP_M;
147 if(v & SDL_HAT_DOWN) value |= EVENT_HATDOWN_M;
148 if(v & SDL_HAT_LEFT) value |= EVENT_HATLEFT_M;
149 if(v & SDL_HAT_RIGHT) value |= EVENT_HATRIGHT_M;
150 }
151
152 handleJoyHatEvent(myEvent.jhat.which, myEvent.jhat.hat, value);
153 break; // SDL_JOYHATMOTION
154 }
155
156 case SDL_JOYDEVICEADDED:
157 {
158 addPhysicalJoystick(make_shared<JoystickSDL2>(myEvent.jdevice.which));
159 break; // SDL_JOYDEVICEADDED
160 }
161 case SDL_JOYDEVICEREMOVED:
162 {
163 removePhysicalJoystick(myEvent.jdevice.which);
164 break; // SDL_JOYDEVICEREMOVED
165 }
166 #endif
167
168 case SDL_QUIT:
169 {
170 handleEvent(Event::Quit);
171 break; // SDL_QUIT
172 }
173
174 case SDL_WINDOWEVENT:
175 switch(myEvent.window.event)
176 {
177 case SDL_WINDOWEVENT_SHOWN:
178 handleSystemEvent(SystemEvent::WINDOW_SHOWN);
179 break;
180 case SDL_WINDOWEVENT_HIDDEN:
181 handleSystemEvent(SystemEvent::WINDOW_HIDDEN);
182 break;
183 case SDL_WINDOWEVENT_EXPOSED:
184 handleSystemEvent(SystemEvent::WINDOW_EXPOSED);
185 break;
186 case SDL_WINDOWEVENT_MOVED:
187 handleSystemEvent(SystemEvent::WINDOW_MOVED,
188 myEvent.window.data1, myEvent.window.data1);
189 break;
190 case SDL_WINDOWEVENT_RESIZED:
191 handleSystemEvent(SystemEvent::WINDOW_RESIZED,
192 myEvent.window.data1, myEvent.window.data1);
193 break;
194 case SDL_WINDOWEVENT_MINIMIZED:
195 handleSystemEvent(SystemEvent::WINDOW_MINIMIZED);
196 break;
197 case SDL_WINDOWEVENT_MAXIMIZED:
198 handleSystemEvent(SystemEvent::WINDOW_MAXIMIZED);
199 break;
200 case SDL_WINDOWEVENT_RESTORED:
201 handleSystemEvent(SystemEvent::WINDOW_RESTORED);
202 break;
203 case SDL_WINDOWEVENT_ENTER:
204 handleSystemEvent(SystemEvent::WINDOW_ENTER);
205 break;
206 case SDL_WINDOWEVENT_LEAVE:
207 handleSystemEvent(SystemEvent::WINDOW_LEAVE);
208 break;
209 case SDL_WINDOWEVENT_FOCUS_GAINED:
210 handleSystemEvent(SystemEvent::WINDOW_FOCUS_GAINED);
211 break;
212 case SDL_WINDOWEVENT_FOCUS_LOST:
213 handleSystemEvent(SystemEvent::WINDOW_FOCUS_LOST);
214 break;
215 }
216 break; // SDL_WINDOWEVENT
217 }
218 }
219}
220
221// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
222EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
223 : myStick(nullptr)
224{
225 ASSERT_MAIN_THREAD;
226
227 myStick = SDL_JoystickOpen(idx);
228 if(myStick)
229 {
230 // In Windows, all XBox controllers using the XInput API seem to name
231 // the controller as "XInput Controller". This would be fine, except
232 // it also appends " #x", where x seems to vary. Obviously this wreaks
233 // havoc with the idea that a joystick will always have the same name.
234 // So we truncate the number.
235 const char* sdlname = SDL_JoystickName(myStick);
236 const string& desc = BSPF::startsWithIgnoreCase(sdlname, "XInput Controller")
237 ? "XInput Controller" : sdlname;
238
239 initialize(SDL_JoystickInstanceID(myStick), desc,
240 SDL_JoystickNumAxes(myStick), SDL_JoystickNumButtons(myStick),
241 SDL_JoystickNumHats(myStick), SDL_JoystickNumBalls(myStick));
242 }
243}
244
245// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
246EventHandlerSDL2::JoystickSDL2::~JoystickSDL2()
247{
248 ASSERT_MAIN_THREAD;
249
250 if(SDL_WasInit(SDL_INIT_JOYSTICK) && myStick)
251 SDL_JoystickClose(myStick);
252}
253