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#ifndef EVENTHANDLER_HXX
19#define EVENTHANDLER_HXX
20
21#include <map>
22
23class Console;
24class OSystem;
25class MouseControl;
26class DialogContainer;
27class PhysicalJoystick;
28
29#include "Event.hxx"
30#include "EventHandlerConstants.hxx"
31#include "Control.hxx"
32#include "StellaKeys.hxx"
33#include "PKeyboardHandler.hxx"
34#include "PJoystickHandler.hxx"
35#include "Variant.hxx"
36#include "bspf.hxx"
37
38/**
39 This class takes care of event remapping and dispatching for the
40 Stella core, as well as keeping track of the current 'mode'.
41
42 The frontend will send translated events here, and the handler will
43 check to see what the current 'mode' is.
44
45 If in emulation mode, events received from the frontend are remapped and
46 sent to the emulation core. If in menu mode, the events are sent
47 unchanged to the menu class, where (among other things) changing key
48 mapping can take place.
49
50 @author Stephen Anthony, Thomas Jentzsch
51*/
52class EventHandler
53{
54 public:
55 /**
56 Create a new event handler object
57 */
58 EventHandler(OSystem& osystem);
59 virtual ~EventHandler();
60
61 /**
62 Returns the event object associated with this handler class.
63
64 @return The event object
65 */
66 const Event& event() const { return myEvent; }
67
68 /**
69 Initialize state of this eventhandler.
70 */
71 void initialize();
72
73 /**
74 Maps the given Stelladaptor/2600-daptor(s) to specified ports on a real 2600.
75
76 @param saport How to map the ports ('lr' or 'rl')
77 */
78 void mapStelladaptors(const string& saport);
79
80 /**
81 Swaps the ordering of Stelladaptor/2600-daptor(s) devices.
82 */
83 void toggleSAPortOrder();
84
85 /**
86 Toggle whether the console is in 2600 or 7800 mode.
87 Note that for now, this only affects whether the 7800 pause button is
88 supported; there is no further emulation of the 7800 itself.
89 */
90 void set7800Mode();
91
92 /**
93 Collects and dispatches any pending events. This method should be
94 called regularly (at X times per second, where X is the game framerate).
95
96 @param time The current time in microseconds.
97 */
98 void poll(uInt64 time);
99
100 /**
101 Get/set the current state of the EventHandler
102
103 @return The EventHandlerState type
104 */
105 EventHandlerState state() const { return myState; }
106 void setState(EventHandlerState state);
107
108 /**
109 Resets the state machine of the EventHandler to the defaults
110
111 @param state The current state to set
112 */
113 void reset(EventHandlerState state);
114
115 /**
116 This method indicates that the system should terminate.
117 */
118 void quit() { handleEvent(Event::Quit); }
119
120 /**
121 Sets the mouse axes and buttons to act as the controller specified in
122 the ROM properties, otherwise disable mouse control completely
123
124 @param enable Whether to use the mouse to emulate controllers
125 Currently, this will be one of the following values:
126 'always', 'analog', 'never'
127 */
128 void setMouseControllerMode(const string& enable);
129
130 void enterMenuMode(EventHandlerState state);
131 void leaveMenuMode();
132 bool enterDebugMode();
133 void leaveDebugMode();
134 void enterTimeMachineMenuMode(uInt32 numWinds, bool unwind);
135
136 /**
137 Send an event directly to the event handler.
138 These events cannot be remapped.
139
140 @param type The event
141 @param value The value to use for the event
142 @param repeated Repeated key (true) or first press/release (false)
143 */
144 void handleEvent(Event::Type type, Int32 value = 1, bool repeated = false);
145
146 /**
147 Handle events that must be processed each time a new console is
148 created. Typically, these are events set by commandline arguments.
149 */
150 void handleConsoleStartupEvents();
151
152 bool frying() const { return myFryingFlag; }
153
154 StringList getActionList(Event::Group group) const;
155 VariantList getComboList(EventMode mode) const;
156
157 /** Used to access the list of events assigned to a specific combo event. */
158 StringList getComboListForEvent(Event::Type event) const;
159 void setComboListForEvent(Event::Type event, const StringList& events);
160
161 /** Convert keys and physical joystick events into Stella events. */
162 Event::Type eventForKey(EventMode mode, StellaKey key, StellaMod mod) const {
163 return myPKeyHandler->eventForKey(mode, key, mod);
164 }
165 Event::Type eventForJoyAxis(EventMode mode, int stick, JoyAxis axis, JoyDir adir, int button) const {
166 return myPJoyHandler->eventForAxis(mode, stick, axis, adir, button);
167 }
168 Event::Type eventForJoyButton(EventMode mode, int stick, int button) const {
169 return myPJoyHandler->eventForButton(mode, stick, button);
170 }
171 Event::Type eventForJoyHat(EventMode mode, int stick, int hat, JoyHatDir hdir, int button) const {
172 return myPJoyHandler->eventForHat(mode, stick, hat, hdir, button);
173 }
174
175 /** Get description of given event and mode. */
176 string getMappingDesc(Event::Type event, EventMode mode) const {
177 return myPKeyHandler->getMappingDesc(event, mode);
178 }
179
180 Event::Type eventAtIndex(int idx, Event::Group group) const;
181 string actionAtIndex(int idx, Event::Group group) const;
182 string keyAtIndex(int idx, Event::Group group) const;
183
184 /**
185 Bind a key to an event/action and regenerate the mapping array(s).
186
187 @param event The event we are remapping
188 @param mode The mode where this event is active
189 @param key The key to bind to this event
190 @param mod The modifier to bind to this event
191 */
192 bool addKeyMapping(Event::Type event, EventMode mode, StellaKey key, StellaMod mod);
193
194 /**
195 Enable controller specific keyboard event mappings.
196 */
197 void defineKeyControllerMappings(const Controller::Type type, Controller::Jack port) {
198 myPKeyHandler->defineControllerMappings(type, port);
199 }
200
201 /**
202 Enable emulation keyboard event mappings.
203 */
204 void enableEmulationKeyMappings() {
205 myPKeyHandler->enableEmulationMappings();
206 }
207
208 /**
209 Bind a physical joystick axis direction to an event/action and regenerate
210 the mapping array(s). The axis can be combined with a button. The button
211 can also be mapped without an axis.
212
213 @param event The event we are remapping
214 @param mode The mode where this event is active
215 @param stick The joystick number
216 @param button The joystick button
217 @param axis The joystick axis
218 @param adir The given axis
219 @param updateMenus Whether to update the action mappings (normally
220 we want to do this, unless there are a batch of
221 'adds', in which case it's delayed until the end
222 */
223 bool addJoyMapping(Event::Type event, EventMode mode, int stick,
224 int button, JoyAxis axis = JoyAxis::NONE, JoyDir adir = JoyDir::NONE,
225 bool updateMenus = true);
226
227 /**
228 Bind a physical joystick hat direction to an event/action and regenerate
229 the mapping array(s). The hat can be combined with a button.
230
231 @param event The event we are remapping
232 @param mode The mode where this event is active
233 @param stick The joystick number
234 @param button The joystick button
235 @param hat The joystick hat
236 @param dir The value on the given hat
237 @param updateMenus Whether to update the action mappings (normally
238 we want to do this, unless there are a batch of
239 'adds', in which case it's delayed until the end
240 */
241 bool addJoyHatMapping(Event::Type event, EventMode mode, int stick,
242 int button, int hat, JoyHatDir dir,
243 bool updateMenus = true);
244
245 /**
246 Enable controller specific keyboard event mappings.
247 */
248 void defineJoyControllerMappings(const Controller::Type type, Controller::Jack port) {
249 myPJoyHandler->defineControllerMappings(type, port);
250 }
251
252 /**
253 Enable emulation keyboard event mappings.
254 */
255 void enableEmulationJoyMappings() {
256 myPJoyHandler->enableEmulationMappings();
257 }
258
259 /**
260 Erase the specified mapping.
261
262 @param event The event for which we erase all mappings
263 @param mode The mode where this event is active
264 */
265 void eraseMapping(Event::Type event, EventMode mode);
266
267 /**
268 Resets the event mappings to default values.
269
270 @param event The event which to (re)set (Event::NoType resets all)
271 @param mode The mode for which the defaults are set
272 */
273 void setDefaultMapping(Event::Type event, EventMode mode);
274
275 /**
276 Sets the combo event mappings to those in the 'combomap' setting
277 */
278 void setComboMap();
279
280 /**
281 Joystick emulates 'impossible' directions (ie, left & right
282 at the same time).
283
284 @param allow Whether or not to allow impossible directions
285 */
286 void allowAllDirections(bool allow) { myAllowAllDirectionsFlag = allow; }
287
288 /**
289 Changes to a new state based on the current state and the given event.
290
291 @param type The event
292 @return True if the state changed, else false
293 */
294 bool changeStateByEvent(Event::Type type);
295
296 /**
297 Get the current overlay in use. The overlay won't always exist,
298 so we should test if it's available.
299
300 @return The overlay object
301 */
302 DialogContainer& overlay() const { return *myOverlay; }
303 bool hasOverlay() const { return myOverlay != nullptr; }
304
305 /**
306 Return a list of all physical joysticks currently in the internal database
307 (first part of variant) and its internal ID (second part of variant).
308 */
309 VariantList physicalJoystickDatabase() const {
310 return myPJoyHandler->database();
311 }
312
313 /**
314 Remove the physical joystick identified by 'name' from the joystick
315 database, only if it is not currently active.
316 */
317 void removePhysicalJoystickFromDatabase(const string& name);
318
319 /**
320 Enable/disable text events (distinct from single-key events).
321 */
322 virtual void enableTextEvents(bool enable) = 0;
323
324 /**
325 Handle changing mouse modes.
326 */
327 void handleMouseControl();
328
329 void saveKeyMapping();
330 void saveJoyMapping();
331
332 void exitEmulation();
333
334 protected:
335 // Global OSystem object
336 OSystem& myOSystem;
337
338 /**
339 Methods which are called by derived classes to handle specific types
340 of input.
341 */
342 void handleTextEvent(char text);
343 void handleMouseMotionEvent(int x, int y, int xrel, int yrel);
344 void handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y);
345 void handleKeyEvent(StellaKey key, StellaMod mod, bool pressed, bool repeated) {
346 myPKeyHandler->handleEvent(key, mod, pressed, repeated);
347 }
348 void handleJoyBtnEvent(int stick, int button, bool pressed) {
349 myPJoyHandler->handleBtnEvent(stick, button, pressed);
350 }
351 void handleJoyAxisEvent(int stick, int axis, int value) {
352 myPJoyHandler->handleAxisEvent(stick, axis, value);
353 }
354 void handleJoyHatEvent(int stick, int hat, int value) {
355 myPJoyHandler->handleHatEvent(stick, hat, value);
356 }
357
358 /**
359 Collects and dispatches any pending events.
360 */
361 virtual void pollEvent() = 0;
362
363 // Other events that can be received from the underlying event handler
364 enum class SystemEvent {
365 WINDOW_SHOWN,
366 WINDOW_HIDDEN,
367 WINDOW_EXPOSED,
368 WINDOW_MOVED,
369 WINDOW_RESIZED,
370 WINDOW_MINIMIZED,
371 WINDOW_MAXIMIZED,
372 WINDOW_RESTORED,
373 WINDOW_ENTER,
374 WINDOW_LEAVE,
375 WINDOW_FOCUS_GAINED,
376 WINDOW_FOCUS_LOST
377 };
378 void handleSystemEvent(SystemEvent e, int data1 = 0, int data2 = 0);
379
380 /**
381 Add the given joystick to the list of physical joysticks available to the handler.
382 */
383 void addPhysicalJoystick(PhysicalJoystickPtr stick);
384
385 /**
386 Remove physical joystick at the current index.
387 */
388 void removePhysicalJoystick(int index);
389
390 private:
391 static constexpr Int32
392 COMBO_SIZE = 16,
393 EVENTS_PER_COMBO = 8,
394 #ifdef PNG_SUPPORT
395 PNG_SIZE = 2,
396 #else
397 PNG_SIZE = 0,
398 #endif
399 EMUL_ACTIONLIST_SIZE = 139 + PNG_SIZE + COMBO_SIZE,
400 MENU_ACTIONLIST_SIZE = 18
401 ;
402
403 // Define event groups
404 static const Event::EventSet MiscEvents;
405 static const Event::EventSet AudioVideoEvents;
406 static const Event::EventSet StateEvents;
407 static const Event::EventSet ConsoleEvents;
408 static const Event::EventSet JoystickEvents;
409 static const Event::EventSet PaddlesEvents;
410 static const Event::EventSet KeyboardEvents;
411 static const Event::EventSet ComboEvents;
412 static const Event::EventSet DebugEvents;
413
414 /**
415 The following methods take care of assigning action mappings.
416 */
417 void setActionMappings(EventMode mode);
418 void setDefaultKeymap(Event::Type, EventMode mode);
419 void setDefaultJoymap(Event::Type, EventMode mode);
420 void saveComboMapping();
421
422 StringList getActionList(EventMode mode) const;
423 StringList getActionList(const Event::EventSet& events, EventMode mode = EventMode::kEmulationMode) const;
424 // returns the action array index of the index in the provided group
425 int getEmulActionListIndex(int idx, const Event::EventSet& events) const;
426 int getActionListIndex(int idx, Event::Group group) const;
427
428 private:
429 // Structure used for action menu items
430 struct ActionList {
431 Event::Type event;
432 string action;
433 string key;
434 };
435
436 // Global Event object
437 Event myEvent;
438
439 // Indicates current overlay object
440 DialogContainer* myOverlay;
441
442 // Handler for all keyboard-related events
443 unique_ptr<PhysicalKeyboardHandler> myPKeyHandler;
444
445 // Handler for all joystick addition/removal/mapping
446 unique_ptr<PhysicalJoystickHandler> myPJoyHandler;
447
448 // MouseControl object, which takes care of switching the mouse between
449 // all possible controller modes
450 unique_ptr<MouseControl> myMouseControl;
451
452 // The event(s) assigned to each combination event
453 Event::Type myComboTable[COMBO_SIZE][EVENTS_PER_COMBO];
454
455 // Indicates the current state of the system (ie, which mode is current)
456 EventHandlerState myState;
457
458 // Indicates whether the virtual joystick emulates 'impossible' directions
459 bool myAllowAllDirectionsFlag;
460
461 // Indicates whether or not we're in frying mode
462 bool myFryingFlag;
463
464 // Sometimes an extraneous mouse motion event occurs after a video
465 // state change; we detect when this happens and discard the event
466 bool mySkipMouseMotion;
467
468 // Whether the currently enabled console is emulating certain aspects
469 // of the 7800 (for now, only the switches are notified)
470 bool myIs7800;
471
472 // Holds static strings for the remap menu (emulation and menu events)
473 static ActionList ourEmulActionList[EMUL_ACTIONLIST_SIZE];
474 static ActionList ourMenuActionList[MENU_ACTIONLIST_SIZE];
475
476 // Following constructors and assignment operators not supported
477 EventHandler() = delete;
478 EventHandler(const EventHandler&) = delete;
479 EventHandler(EventHandler&&) = delete;
480 EventHandler& operator=(const EventHandler&) = delete;
481 EventHandler& operator=(EventHandler&&) = delete;
482};
483
484#endif
485