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 <sstream> |
19 | #include <map> |
20 | |
21 | #include "Logger.hxx" |
22 | |
23 | #include "Base.hxx" |
24 | #include "Console.hxx" |
25 | #include "FrameBuffer.hxx" |
26 | #include "FSNode.hxx" |
27 | #include "OSystem.hxx" |
28 | #include "Joystick.hxx" |
29 | #include "Paddles.hxx" |
30 | #include "PointingDevice.hxx" |
31 | #include "PropsSet.hxx" |
32 | #include "Settings.hxx" |
33 | #include "Sound.hxx" |
34 | #include "StateManager.hxx" |
35 | #include "RewindManager.hxx" |
36 | #include "TimerManager.hxx" |
37 | #include "Switches.hxx" |
38 | #include "M6532.hxx" |
39 | #include "MouseControl.hxx" |
40 | #include "PNGLibrary.hxx" |
41 | #include "TIASurface.hxx" |
42 | |
43 | #include "EventHandler.hxx" |
44 | |
45 | #ifdef CHEATCODE_SUPPORT |
46 | #include "Cheat.hxx" |
47 | #include "CheatManager.hxx" |
48 | #endif |
49 | #ifdef DEBUGGER_SUPPORT |
50 | #include "Debugger.hxx" |
51 | #endif |
52 | #ifdef GUI_SUPPORT |
53 | #include "Menu.hxx" |
54 | #include "CommandMenu.hxx" |
55 | #include "DialogContainer.hxx" |
56 | #include "Launcher.hxx" |
57 | #include "TimeMachine.hxx" |
58 | #include "FileListWidget.hxx" |
59 | #include "ScrollBarWidget.hxx" |
60 | #endif |
61 | |
62 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
63 | EventHandler::EventHandler(OSystem& osystem) |
64 | : myOSystem(osystem), |
65 | myOverlay(nullptr), |
66 | myState(EventHandlerState::NONE), |
67 | myAllowAllDirectionsFlag(false), |
68 | myFryingFlag(false), |
69 | mySkipMouseMotion(true), |
70 | myIs7800(false) |
71 | { |
72 | // Create keyboard handler (to handle all physical keyboard functionality) |
73 | myPKeyHandler = make_unique<PhysicalKeyboardHandler>(osystem, *this); |
74 | |
75 | // Create joystick handler (to handle all physical joystick functionality) |
76 | myPJoyHandler = make_unique<PhysicalJoystickHandler>(osystem, *this); |
77 | |
78 | // Erase the 'combo' array |
79 | for(int i = 0; i < COMBO_SIZE; ++i) |
80 | for(int j = 0; j < EVENTS_PER_COMBO; ++j) |
81 | myComboTable[i][j] = Event::NoType; |
82 | } |
83 | |
84 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
85 | EventHandler::~EventHandler() |
86 | { |
87 | } |
88 | |
89 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
90 | void EventHandler::initialize() |
91 | { |
92 | // Make sure the event/action mappings are correctly set, |
93 | // and fill the ActionList structure with valid values |
94 | setComboMap(); |
95 | setActionMappings(EventMode::kEmulationMode); |
96 | setActionMappings(EventMode::kMenuMode); |
97 | |
98 | Joystick::setDeadZone(myOSystem.settings().getInt("joydeadzone" )); |
99 | Paddles::setDejitterBase(myOSystem.settings().getInt("dejitter.base" )); |
100 | Paddles::setDejitterDiff(myOSystem.settings().getInt("dejitter.diff" )); |
101 | Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense" )); |
102 | Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense" )); |
103 | PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense" )); |
104 | |
105 | #ifdef GUI_SUPPORT |
106 | // Set quick select delay when typing characters in listwidgets |
107 | FileListWidget::setQuickSelectDelay(myOSystem.settings().getInt("listdelay" )); |
108 | |
109 | // Set number of lines a mousewheel will scroll |
110 | ScrollBarWidget::setWheelLines(myOSystem.settings().getInt("mwheel" )); |
111 | |
112 | // Mouse double click |
113 | DialogContainer::setDoubleClickDelay(myOSystem.settings().getInt("mdouble" )); |
114 | |
115 | // Input delay |
116 | DialogContainer::setControllerDelay(myOSystem.settings().getInt("inpDelay" )); |
117 | |
118 | // Input rate |
119 | DialogContainer::setControllerRate(myOSystem.settings().getInt("inpRate" )); |
120 | #endif |
121 | |
122 | // Integer to string conversions (for HEX) use upper or lower-case |
123 | Common::Base::setHexUppercase(myOSystem.settings().getBool("dbg.uhex" )); |
124 | |
125 | // Default phosphor blend |
126 | Properties::setDefault(PropType::Display_PPBlend, |
127 | myOSystem.settings().getString("tv.phosblend" )); |
128 | } |
129 | |
130 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
131 | void EventHandler::reset(EventHandlerState state) |
132 | { |
133 | setState(state); |
134 | myOSystem.state().reset(); |
135 | #ifdef PNG_SUPPORT |
136 | myOSystem.png().setContinuousSnapInterval(0); |
137 | #endif |
138 | myFryingFlag = false; |
139 | |
140 | // Reset events almost immediately after starting emulation mode |
141 | // We wait a little while (0.5s), since 'hold' events may be present, |
142 | // and we want time for the ROM to process them |
143 | if(state == EventHandlerState::EMULATION) |
144 | myOSystem.timer().setTimeout([&ev = myEvent]() { ev.clear(); }, 500); |
145 | // Toggle 7800 mode |
146 | set7800Mode(); |
147 | } |
148 | |
149 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
150 | void EventHandler::addPhysicalJoystick(PhysicalJoystickPtr joy) |
151 | { |
152 | #ifdef JOYSTICK_SUPPORT |
153 | int ID = myPJoyHandler->add(joy); |
154 | if(ID < 0) |
155 | return; |
156 | |
157 | setActionMappings(EventMode::kEmulationMode); |
158 | setActionMappings(EventMode::kMenuMode); |
159 | |
160 | ostringstream buf; |
161 | buf << "Added joystick " << ID << ":" << endl |
162 | << " " << joy->about() << endl; |
163 | Logger::info(buf.str()); |
164 | #endif |
165 | } |
166 | |
167 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
168 | void EventHandler::removePhysicalJoystick(int id) |
169 | { |
170 | #ifdef JOYSTICK_SUPPORT |
171 | myPJoyHandler->remove(id); |
172 | #endif |
173 | } |
174 | |
175 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
176 | void EventHandler::mapStelladaptors(const string& saport) |
177 | { |
178 | #ifdef JOYSTICK_SUPPORT |
179 | myPJoyHandler->mapStelladaptors(saport); |
180 | #endif |
181 | } |
182 | |
183 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
184 | void EventHandler::toggleSAPortOrder() |
185 | { |
186 | #ifdef JOYSTICK_SUPPORT |
187 | const string& saport = myOSystem.settings().getString("saport" ); |
188 | if(saport == "lr" ) |
189 | { |
190 | mapStelladaptors("rl" ); |
191 | myOSystem.frameBuffer().showMessage("Stelladaptor ports right/left" ); |
192 | } |
193 | else |
194 | { |
195 | mapStelladaptors("lr" ); |
196 | myOSystem.frameBuffer().showMessage("Stelladaptor ports left/right" ); |
197 | } |
198 | #endif |
199 | } |
200 | |
201 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
202 | void EventHandler::set7800Mode() |
203 | { |
204 | if(myOSystem.hasConsole()) |
205 | myIs7800 = myOSystem.console().switches().check7800Mode(myOSystem.settings()); |
206 | else |
207 | myIs7800 = false; |
208 | } |
209 | |
210 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
211 | void EventHandler::handleMouseControl() |
212 | { |
213 | if(myMouseControl) |
214 | myOSystem.frameBuffer().showMessage(myMouseControl->next()); |
215 | } |
216 | |
217 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
218 | void EventHandler::poll(uInt64 time) |
219 | { |
220 | // Process events from the underlying hardware |
221 | pollEvent(); |
222 | |
223 | // Update controllers and console switches, and in general all other things |
224 | // related to emulation |
225 | if(myState == EventHandlerState::EMULATION) |
226 | { |
227 | myOSystem.console().riot().update(); |
228 | |
229 | // Now check if the StateManager should be saving or loading state |
230 | // (for rewind and/or movies |
231 | if(myOSystem.state().mode() != StateManager::Mode::Off) |
232 | myOSystem.state().update(); |
233 | |
234 | #ifdef CHEATCODE_SUPPORT |
235 | for(auto& cheat: myOSystem.cheat().perFrame()) |
236 | cheat->evaluate(); |
237 | #endif |
238 | |
239 | #ifdef PNG_SUPPORT |
240 | // Handle continuous snapshots |
241 | if(myOSystem.png().continuousSnapEnabled()) |
242 | myOSystem.png().updateTime(time); |
243 | #endif |
244 | } |
245 | else if(myOverlay) |
246 | { |
247 | #ifdef GUI_SUPPORT |
248 | // Update the current dialog container at regular intervals |
249 | // Used to implement continuous events |
250 | myOverlay->updateTime(time); |
251 | #endif |
252 | } |
253 | |
254 | // Turn off all mouse-related items; if they haven't been taken care of |
255 | // in the previous ::update() methods, they're now invalid |
256 | myEvent.set(Event::MouseAxisXValue, 0); |
257 | myEvent.set(Event::MouseAxisYValue, 0); |
258 | } |
259 | |
260 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
261 | void EventHandler::handleTextEvent(char text) |
262 | { |
263 | #ifdef GUI_SUPPORT |
264 | // Text events are only used in GUI mode |
265 | if(myOverlay) |
266 | myOverlay->handleTextEvent(text); |
267 | #endif |
268 | } |
269 | |
270 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
271 | void EventHandler::handleMouseMotionEvent(int x, int y, int xrel, int yrel) |
272 | { |
273 | // Determine which mode we're in, then send the event to the appropriate place |
274 | if(myState == EventHandlerState::EMULATION) |
275 | { |
276 | if(!mySkipMouseMotion) |
277 | { |
278 | myEvent.set(Event::MouseAxisXValue, xrel); |
279 | myEvent.set(Event::MouseAxisYValue, yrel); |
280 | } |
281 | mySkipMouseMotion = false; |
282 | } |
283 | #ifdef GUI_SUPPORT |
284 | else if(myOverlay) |
285 | myOverlay->handleMouseMotionEvent(x, y); |
286 | #endif |
287 | } |
288 | |
289 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
290 | void EventHandler::handleMouseButtonEvent(MouseButton b, bool pressed, |
291 | int x, int y) |
292 | { |
293 | // Determine which mode we're in, then send the event to the appropriate place |
294 | if(myState == EventHandlerState::EMULATION) |
295 | { |
296 | switch(b) |
297 | { |
298 | case MouseButton::LEFT: |
299 | myEvent.set(Event::MouseButtonLeftValue, int(pressed)); |
300 | break; |
301 | case MouseButton::RIGHT: |
302 | myEvent.set(Event::MouseButtonRightValue, int(pressed)); |
303 | break; |
304 | default: |
305 | return; |
306 | } |
307 | } |
308 | #ifdef GUI_SUPPORT |
309 | else if(myOverlay) |
310 | myOverlay->handleMouseButtonEvent(b, pressed, x, y); |
311 | #endif |
312 | } |
313 | |
314 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
315 | void EventHandler::handleSystemEvent(SystemEvent e, int, int) |
316 | { |
317 | switch(e) |
318 | { |
319 | case SystemEvent::WINDOW_EXPOSED: |
320 | case SystemEvent::WINDOW_RESIZED: |
321 | myOSystem.frameBuffer().update(true); // force full update |
322 | break; |
323 | #ifdef BSPF_UNIX |
324 | case SystemEvent::WINDOW_FOCUS_GAINED: |
325 | // Used to handle Alt-x key combos; sometimes the key associated with |
326 | // Alt gets 'stuck' and is passed to the core for processing |
327 | if(myPKeyHandler->altKeyCount() > 0) |
328 | myPKeyHandler->altKeyCount() = 2; |
329 | break; |
330 | #endif |
331 | #if 0 |
332 | case SystemEvent::WINDOW_MINIMIZED: |
333 | if(myState == EventHandlerState::EMULATION) enterMenuMode(EventHandlerState::OPTIONSMENU); |
334 | break; |
335 | #endif |
336 | default: // handle other events as testing requires |
337 | // cerr << "handleSystemEvent: " << e << endl; |
338 | break; |
339 | } |
340 | } |
341 | |
342 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
343 | void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) |
344 | { |
345 | // Take care of special events that aren't part of the emulation core |
346 | // or need to be preprocessed before passing them on |
347 | bool pressed = (value != 0); |
348 | |
349 | switch(event) |
350 | { |
351 | //////////////////////////////////////////////////////////////////////// |
352 | // If enabled, make sure 'impossible' joystick directions aren't allowed |
353 | case Event::JoystickZeroUp: |
354 | if(!myAllowAllDirectionsFlag && pressed) |
355 | myEvent.set(Event::JoystickZeroDown, 0); |
356 | break; |
357 | |
358 | case Event::JoystickZeroDown: |
359 | if(!myAllowAllDirectionsFlag && pressed) |
360 | myEvent.set(Event::JoystickZeroUp, 0); |
361 | break; |
362 | |
363 | case Event::JoystickZeroLeft: |
364 | if(!myAllowAllDirectionsFlag && pressed) |
365 | myEvent.set(Event::JoystickZeroRight, 0); |
366 | break; |
367 | |
368 | case Event::JoystickZeroRight: |
369 | if(!myAllowAllDirectionsFlag && pressed) |
370 | myEvent.set(Event::JoystickZeroLeft, 0); |
371 | break; |
372 | |
373 | case Event::JoystickOneUp: |
374 | if(!myAllowAllDirectionsFlag && pressed) |
375 | myEvent.set(Event::JoystickOneDown, 0); |
376 | break; |
377 | |
378 | case Event::JoystickOneDown: |
379 | if(!myAllowAllDirectionsFlag && pressed) |
380 | myEvent.set(Event::JoystickOneUp, 0); |
381 | break; |
382 | |
383 | case Event::JoystickOneLeft: |
384 | if(!myAllowAllDirectionsFlag && pressed) |
385 | myEvent.set(Event::JoystickOneRight, 0); |
386 | break; |
387 | |
388 | case Event::JoystickOneRight: |
389 | if(!myAllowAllDirectionsFlag && pressed) |
390 | myEvent.set(Event::JoystickOneLeft, 0); |
391 | break; |
392 | //////////////////////////////////////////////////////////////////////// |
393 | |
394 | case Event::Fry: |
395 | if (!repeated) myFryingFlag = pressed; |
396 | return; |
397 | |
398 | case Event::ReloadConsole: |
399 | if (pressed && !repeated) myOSystem.reloadConsole(); |
400 | return; |
401 | |
402 | case Event::VolumeDecrease: |
403 | if(pressed) myOSystem.sound().adjustVolume(-1); |
404 | return; |
405 | |
406 | case Event::VolumeIncrease: |
407 | if(pressed) myOSystem.sound().adjustVolume(+1); |
408 | return; |
409 | |
410 | case Event::SoundToggle: |
411 | if(pressed && !repeated) myOSystem.sound().toggleMute(); |
412 | return; |
413 | |
414 | case Event::VidmodeDecrease: |
415 | if(pressed) myOSystem.frameBuffer().changeVidMode(-1); |
416 | return; |
417 | |
418 | case Event::VidmodeIncrease: |
419 | if(pressed) myOSystem.frameBuffer().changeVidMode(+1); |
420 | return; |
421 | |
422 | case Event::ToggleFullScreen: |
423 | if (pressed && !repeated) myOSystem.frameBuffer().toggleFullscreen(); |
424 | return; |
425 | |
426 | case Event::DecreaseOverscan: |
427 | if (pressed) myOSystem.frameBuffer().changeOverscan(-1); |
428 | return; |
429 | |
430 | case Event::IncreaseOverScan: |
431 | if (pressed) myOSystem.frameBuffer().changeOverscan(1); |
432 | return; |
433 | |
434 | case Event::VidmodeStd: |
435 | if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::OFF); |
436 | return; |
437 | |
438 | case Event::VidmodeRGB: |
439 | if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::RGB); |
440 | return; |
441 | |
442 | case Event::VidmodeSVideo: |
443 | if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::SVIDEO); |
444 | return; |
445 | |
446 | case Event::VidModeComposite: |
447 | if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::COMPOSITE); |
448 | return; |
449 | |
450 | case Event::VidModeBad: |
451 | if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::BAD); |
452 | return; |
453 | |
454 | case Event::VidModeCustom: |
455 | if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); |
456 | return; |
457 | |
458 | case Event::ScanlinesDecrease: |
459 | if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-2); |
460 | return; |
461 | |
462 | case Event::ScanlinesIncrease: |
463 | if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+2); |
464 | return; |
465 | |
466 | case Event::PreviousAttribute: |
467 | if (pressed) |
468 | { |
469 | myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); |
470 | myOSystem.frameBuffer().showMessage( |
471 | myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable()); |
472 | } |
473 | return; |
474 | |
475 | case Event::NextAttribute: |
476 | if (pressed) |
477 | { |
478 | myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); |
479 | myOSystem.frameBuffer().showMessage( |
480 | myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable()); |
481 | } |
482 | return; |
483 | |
484 | case Event::DecreaseAttribute: |
485 | if (pressed) |
486 | { |
487 | myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); |
488 | myOSystem.frameBuffer().showMessage( |
489 | myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable()); |
490 | } |
491 | return; |
492 | |
493 | case Event::IncreaseAttribute: |
494 | if (pressed) |
495 | { |
496 | myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); |
497 | myOSystem.frameBuffer().showMessage( |
498 | myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable()); |
499 | } |
500 | return; |
501 | |
502 | case Event::DecreasePhosphor: |
503 | if (pressed) myOSystem.console().changePhosphor(-1); |
504 | return; |
505 | |
506 | case Event::IncreasePhosphor: |
507 | if (pressed) myOSystem.console().changePhosphor(1); |
508 | return; |
509 | |
510 | case Event::TogglePhosphor: |
511 | if (pressed && !repeated) myOSystem.console().togglePhosphor(); |
512 | return; |
513 | |
514 | case Event::ToggleColorLoss: |
515 | if (pressed && !repeated) myOSystem.console().toggleColorLoss(); |
516 | return; |
517 | |
518 | case Event::TogglePalette: |
519 | if (pressed && !repeated) myOSystem.console().togglePalette(); |
520 | return; |
521 | |
522 | case Event::ToggleJitter: |
523 | if (pressed && !repeated) myOSystem.console().toggleJitter(); |
524 | return; |
525 | |
526 | case Event::ToggleFrameStats: |
527 | if (pressed) myOSystem.frameBuffer().toggleFrameStats(); |
528 | return; |
529 | |
530 | case Event::ToggleTimeMachine: |
531 | if (pressed && !repeated) myOSystem.state().toggleTimeMachine(); |
532 | return; |
533 | |
534 | #ifdef PNG_SUPPORT |
535 | case Event::ToggleContSnapshots: |
536 | if (pressed && !repeated) myOSystem.png().toggleContinuousSnapshots(false); |
537 | return; |
538 | |
539 | case Event::ToggleContSnapshotsFrame: |
540 | if (pressed && !repeated) myOSystem.png().toggleContinuousSnapshots(true); |
541 | return; |
542 | #endif |
543 | |
544 | case Event::HandleMouseControl: |
545 | if (pressed && !repeated) handleMouseControl(); |
546 | return; |
547 | |
548 | case Event::ToggleSAPortOrder: |
549 | if (pressed && !repeated) toggleSAPortOrder(); |
550 | return; |
551 | |
552 | case Event::DecreaseFormat: |
553 | if (pressed) myOSystem.console().toggleFormat(-1); |
554 | return; |
555 | |
556 | case Event::IncreaseFormat: |
557 | if (pressed) myOSystem.console().toggleFormat(1); |
558 | return; |
559 | |
560 | case Event::ToggleGrabMouse: |
561 | if (pressed && !repeated && !myOSystem.frameBuffer().fullScreen()) |
562 | { |
563 | myOSystem.frameBuffer().toggleGrabMouse(); |
564 | myOSystem.frameBuffer().showMessage(myOSystem.frameBuffer().grabMouseEnabled() |
565 | ? "Grab mouse enabled" : "Grab mouse disabled" ); |
566 | } |
567 | return; |
568 | |
569 | case Event::ToggleP0Collision: |
570 | if (pressed && !repeated) myOSystem.console().toggleP0Collision(); |
571 | return; |
572 | |
573 | case Event::ToggleP0Bit: |
574 | if (pressed && !repeated) myOSystem.console().toggleP0Bit(); |
575 | return; |
576 | |
577 | case Event::ToggleP1Collision: |
578 | if (pressed && !repeated) myOSystem.console().toggleP1Collision(); |
579 | return; |
580 | |
581 | case Event::ToggleP1Bit: |
582 | if (pressed && !repeated) myOSystem.console().toggleP1Bit(); |
583 | return; |
584 | |
585 | case Event::ToggleM0Collision: |
586 | if (pressed && !repeated) myOSystem.console().toggleM0Collision(); |
587 | return; |
588 | |
589 | case Event::ToggleM0Bit: |
590 | if (pressed && !repeated) myOSystem.console().toggleM0Bit(); |
591 | return; |
592 | |
593 | case Event::ToggleM1Collision: |
594 | if (pressed && !repeated) myOSystem.console().toggleM1Collision(); |
595 | return; |
596 | |
597 | case Event::ToggleM1Bit: |
598 | if (pressed && !repeated) myOSystem.console().toggleM1Bit(); |
599 | return; |
600 | |
601 | case Event::ToggleBLCollision: |
602 | if (pressed && !repeated) myOSystem.console().toggleBLCollision(); |
603 | return; |
604 | |
605 | case Event::ToggleBLBit: |
606 | if (pressed) myOSystem.console().toggleBLBit(); |
607 | return; |
608 | |
609 | case Event::TogglePFCollision: |
610 | if (pressed && !repeated) myOSystem.console().togglePFCollision(); |
611 | return; |
612 | |
613 | case Event::TogglePFBit: |
614 | if (pressed && !repeated) myOSystem.console().togglePFBit(); |
615 | return; |
616 | |
617 | case Event::ToggleFixedColors: |
618 | if (pressed) myOSystem.console().toggleFixedColors(); |
619 | return; |
620 | |
621 | case Event::ToggleCollisions: |
622 | if (pressed && !repeated) myOSystem.console().toggleCollisions(); |
623 | return; |
624 | |
625 | case Event::ToggleBits: |
626 | if (pressed && !repeated) myOSystem.console().toggleBits(); |
627 | return; |
628 | |
629 | case Event::SaveState: |
630 | if(pressed && !repeated) myOSystem.state().saveState(); |
631 | return; |
632 | |
633 | case Event::SaveAllStates: |
634 | if (pressed && !repeated) |
635 | myOSystem.frameBuffer().showMessage(myOSystem.state().rewindManager().saveAllStates()); |
636 | return; |
637 | |
638 | case Event::ChangeState: |
639 | if(pressed) myOSystem.state().changeState(); |
640 | return; |
641 | |
642 | case Event::ToggleAutoSlot: |
643 | if (pressed) myOSystem.state().toggleAutoSlot(); |
644 | return; |
645 | |
646 | case Event::LoadState: |
647 | if(pressed && !repeated) myOSystem.state().loadState(); |
648 | return; |
649 | |
650 | case Event::LoadAllStates: |
651 | if (pressed && !repeated) |
652 | myOSystem.frameBuffer().showMessage(myOSystem.state().rewindManager().loadAllStates()); |
653 | return; |
654 | |
655 | case Event::RewindPause: |
656 | if (pressed) myOSystem.state().rewindStates(); |
657 | if (myState == EventHandlerState::EMULATION) |
658 | setState(EventHandlerState::PAUSE); |
659 | return; |
660 | |
661 | case Event::UnwindPause: |
662 | if (pressed) myOSystem.state().unwindStates(); |
663 | if (myState == EventHandlerState::EMULATION) |
664 | setState(EventHandlerState::PAUSE); |
665 | return; |
666 | |
667 | case Event::Rewind1Menu: |
668 | if (pressed) enterTimeMachineMenuMode(1, false); |
669 | return; |
670 | |
671 | case Event::Rewind10Menu: |
672 | if (pressed) enterTimeMachineMenuMode(10, false); |
673 | return; |
674 | |
675 | case Event::RewindAllMenu: |
676 | if (pressed) enterTimeMachineMenuMode(1000, false); |
677 | return; |
678 | |
679 | case Event::Unwind1Menu: |
680 | if (pressed) enterTimeMachineMenuMode(1, true); |
681 | return; |
682 | |
683 | case Event::Unwind10Menu: |
684 | if (pressed) enterTimeMachineMenuMode(10, true); |
685 | return; |
686 | |
687 | case Event::UnwindAllMenu: |
688 | if (pressed) enterTimeMachineMenuMode(1000, true); |
689 | return; |
690 | |
691 | case Event::TakeSnapshot: |
692 | if(pressed && !repeated) myOSystem.frameBuffer().tiaSurface().saveSnapShot(); |
693 | return; |
694 | |
695 | case Event::ExitMode: |
696 | // Special handling for Escape key |
697 | // Basically, exit whichever mode we're currently in |
698 | switch (myState) |
699 | { |
700 | case EventHandlerState::PAUSE: |
701 | if (pressed && !repeated) changeStateByEvent(Event::TogglePauseMode); |
702 | return; |
703 | |
704 | case EventHandlerState::CMDMENU: |
705 | if (pressed && !repeated) changeStateByEvent(Event::CmdMenuMode); |
706 | return; |
707 | |
708 | case EventHandlerState::TIMEMACHINE: |
709 | if (pressed && !repeated) changeStateByEvent(Event::TimeMachineMode); |
710 | return; |
711 | |
712 | // this event is called when exiting a ROM from the debugger, so it acts like pressing ESC in emulation |
713 | case EventHandlerState::DEBUGGER: |
714 | case EventHandlerState::EMULATION: |
715 | if (pressed && !repeated) |
716 | { |
717 | exitEmulation(); |
718 | // Go back to the launcher, or immediately quit |
719 | if (myOSystem.settings().getBool("exitlauncher" ) || |
720 | myOSystem.launcherUsed()) |
721 | myOSystem.createLauncher(); |
722 | else |
723 | handleEvent(Event::Quit); |
724 | } |
725 | return; |
726 | |
727 | default: |
728 | return; |
729 | } |
730 | |
731 | case Event::Quit: |
732 | if(pressed && !repeated) |
733 | { |
734 | saveKeyMapping(); |
735 | saveJoyMapping(); |
736 | if (myState != EventHandlerState::LAUNCHER) |
737 | exitEmulation(); |
738 | myOSystem.quit(); |
739 | } |
740 | return; |
741 | |
742 | case Event::StartPauseMode: |
743 | if (pressed && !repeated && myState == EventHandlerState::EMULATION) |
744 | setState(EventHandlerState::PAUSE); |
745 | return; |
746 | |
747 | //////////////////////////////////////////////////////////////////////// |
748 | // A combo event is simply multiple calls to handleEvent, once for |
749 | // each event it contains |
750 | case Event::Combo1: |
751 | case Event::Combo2: |
752 | case Event::Combo3: |
753 | case Event::Combo4: |
754 | case Event::Combo5: |
755 | case Event::Combo6: |
756 | case Event::Combo7: |
757 | case Event::Combo8: |
758 | case Event::Combo9: |
759 | case Event::Combo10: |
760 | case Event::Combo11: |
761 | case Event::Combo12: |
762 | case Event::Combo13: |
763 | case Event::Combo14: |
764 | case Event::Combo15: |
765 | case Event::Combo16: |
766 | for(int i = 0, combo = event - Event::Combo1; i < EVENTS_PER_COMBO; ++i) |
767 | if(myComboTable[combo][i] != Event::NoType) |
768 | handleEvent(myComboTable[combo][i], pressed, repeated); |
769 | return; |
770 | //////////////////////////////////////////////////////////////////////// |
771 | |
772 | //////////////////////////////////////////////////////////////////////// |
773 | // Events which relate to switches() |
774 | case Event::ConsoleColor: |
775 | if(pressed && !repeated) |
776 | { |
777 | myEvent.set(Event::ConsoleBlackWhite, 0); |
778 | myEvent.set(Event::ConsoleColor, 1); |
779 | myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause released" : "Color Mode" ); |
780 | myOSystem.console().switches().update(); |
781 | } |
782 | return; |
783 | case Event::ConsoleBlackWhite: |
784 | if(pressed && !repeated) |
785 | { |
786 | myEvent.set(Event::ConsoleBlackWhite, 1); |
787 | myEvent.set(Event::ConsoleColor, 0); |
788 | myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause pushed" : "B/W Mode" ); |
789 | myOSystem.console().switches().update(); |
790 | } |
791 | return; |
792 | case Event::ConsoleColorToggle: |
793 | if(pressed && !repeated) |
794 | { |
795 | if(myOSystem.console().switches().tvColor()) |
796 | { |
797 | myEvent.set(Event::ConsoleBlackWhite, 1); |
798 | myEvent.set(Event::ConsoleColor, 0); |
799 | myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause pushed" : "B/W Mode" ); |
800 | } |
801 | else |
802 | { |
803 | myEvent.set(Event::ConsoleBlackWhite, 0); |
804 | myEvent.set(Event::ConsoleColor, 1); |
805 | myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause released" : "Color Mode" ); |
806 | } |
807 | myOSystem.console().switches().update(); |
808 | } |
809 | return; |
810 | |
811 | case Event::Console7800Pause: |
812 | if(pressed && !repeated) |
813 | { |
814 | myEvent.set(Event::ConsoleBlackWhite, 0); |
815 | myEvent.set(Event::ConsoleColor, 0); |
816 | if (myIs7800) |
817 | myOSystem.frameBuffer().showMessage("Pause pressed" ); |
818 | myOSystem.console().switches().update(); |
819 | } |
820 | return; |
821 | |
822 | case Event::ConsoleLeftDiffA: |
823 | if(pressed && !repeated) |
824 | { |
825 | myEvent.set(Event::ConsoleLeftDiffA, 1); |
826 | myEvent.set(Event::ConsoleLeftDiffB, 0); |
827 | myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " A" ); |
828 | myOSystem.console().switches().update(); |
829 | } |
830 | return; |
831 | case Event::ConsoleLeftDiffB: |
832 | if(pressed && !repeated) |
833 | { |
834 | myEvent.set(Event::ConsoleLeftDiffA, 0); |
835 | myEvent.set(Event::ConsoleLeftDiffB, 1); |
836 | myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " B" ); |
837 | myOSystem.console().switches().update(); |
838 | } |
839 | return; |
840 | case Event::ConsoleLeftDiffToggle: |
841 | if(pressed && !repeated) |
842 | { |
843 | if(myOSystem.console().switches().leftDifficultyA()) |
844 | { |
845 | myEvent.set(Event::ConsoleLeftDiffA, 0); |
846 | myEvent.set(Event::ConsoleLeftDiffB, 1); |
847 | myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " B" ); |
848 | } |
849 | else |
850 | { |
851 | myEvent.set(Event::ConsoleLeftDiffA, 1); |
852 | myEvent.set(Event::ConsoleLeftDiffB, 0); |
853 | myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " A" ); |
854 | } |
855 | myOSystem.console().switches().update(); |
856 | } |
857 | return; |
858 | |
859 | case Event::ConsoleRightDiffA: |
860 | if(pressed && !repeated) |
861 | { |
862 | myEvent.set(Event::ConsoleRightDiffA, 1); |
863 | myEvent.set(Event::ConsoleRightDiffB, 0); |
864 | myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " A" ); |
865 | myOSystem.console().switches().update(); |
866 | } |
867 | return; |
868 | case Event::ConsoleRightDiffB: |
869 | if(pressed && !repeated) |
870 | { |
871 | myEvent.set(Event::ConsoleRightDiffA, 0); |
872 | myEvent.set(Event::ConsoleRightDiffB, 1); |
873 | myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " B" ); |
874 | myOSystem.console().switches().update(); |
875 | } |
876 | return; |
877 | case Event::ConsoleRightDiffToggle: |
878 | if(pressed && !repeated) |
879 | { |
880 | if(myOSystem.console().switches().rightDifficultyA()) |
881 | { |
882 | myEvent.set(Event::ConsoleRightDiffA, 0); |
883 | myEvent.set(Event::ConsoleRightDiffB, 1); |
884 | myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " B" ); |
885 | } |
886 | else |
887 | { |
888 | myEvent.set(Event::ConsoleRightDiffA, 1); |
889 | myEvent.set(Event::ConsoleRightDiffB, 0); |
890 | myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " A" ); |
891 | } |
892 | myOSystem.console().switches().update(); |
893 | } |
894 | return; |
895 | //////////////////////////////////////////////////////////////////////// |
896 | |
897 | case Event::NoType: // Ignore unmapped events |
898 | return; |
899 | |
900 | default: |
901 | break; |
902 | } |
903 | |
904 | // Otherwise, pass it to the emulation core |
905 | if (!repeated) |
906 | myEvent.set(event, value); |
907 | } |
908 | |
909 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
910 | void EventHandler::handleConsoleStartupEvents() |
911 | { |
912 | if(myOSystem.settings().getBool("holdreset" )) |
913 | handleEvent(Event::ConsoleReset); |
914 | |
915 | if(myOSystem.settings().getBool("holdselect" )) |
916 | handleEvent(Event::ConsoleSelect); |
917 | |
918 | const string& holdjoy0 = myOSystem.settings().getString("holdjoy0" ); |
919 | |
920 | if(BSPF::containsIgnoreCase(holdjoy0, "U" )) |
921 | handleEvent(Event::JoystickZeroUp); |
922 | if(BSPF::containsIgnoreCase(holdjoy0, "D" )) |
923 | handleEvent(Event::JoystickZeroDown); |
924 | if(BSPF::containsIgnoreCase(holdjoy0, "L" )) |
925 | handleEvent(Event::JoystickZeroLeft); |
926 | if(BSPF::containsIgnoreCase(holdjoy0, "R" )) |
927 | handleEvent(Event::JoystickZeroRight); |
928 | if(BSPF::containsIgnoreCase(holdjoy0, "F" )) |
929 | handleEvent(Event::JoystickZeroFire); |
930 | |
931 | const string& holdjoy1 = myOSystem.settings().getString("holdjoy1" ); |
932 | if(BSPF::containsIgnoreCase(holdjoy1, "U" )) |
933 | handleEvent(Event::JoystickOneUp); |
934 | if(BSPF::containsIgnoreCase(holdjoy1, "D" )) |
935 | handleEvent(Event::JoystickOneDown); |
936 | if(BSPF::containsIgnoreCase(holdjoy1, "L" )) |
937 | handleEvent(Event::JoystickOneLeft); |
938 | if(BSPF::containsIgnoreCase(holdjoy1, "R" )) |
939 | handleEvent(Event::JoystickOneRight); |
940 | if(BSPF::containsIgnoreCase(holdjoy1, "F" )) |
941 | handleEvent(Event::JoystickOneFire); |
942 | } |
943 | |
944 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
945 | bool EventHandler::changeStateByEvent(Event::Type type) |
946 | { |
947 | bool handled = true; |
948 | |
949 | switch(type) |
950 | { |
951 | case Event::TogglePauseMode: |
952 | if(myState == EventHandlerState::EMULATION) |
953 | setState(EventHandlerState::PAUSE); |
954 | else if(myState == EventHandlerState::PAUSE) |
955 | setState(EventHandlerState::EMULATION); |
956 | else |
957 | handled = false; |
958 | break; |
959 | |
960 | case Event::OptionsMenuMode: |
961 | if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) |
962 | enterMenuMode(EventHandlerState::OPTIONSMENU); |
963 | else |
964 | handled = false; |
965 | break; |
966 | |
967 | case Event::CmdMenuMode: |
968 | if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) |
969 | enterMenuMode(EventHandlerState::CMDMENU); |
970 | else if(myState == EventHandlerState::CMDMENU && !myOSystem.settings().getBool("minimal_ui" )) |
971 | // The extra check for "minimal_ui" allows mapping e.g. right joystick fire |
972 | // to open the command dialog and navigate there using that fire button |
973 | leaveMenuMode(); |
974 | else |
975 | handled = false; |
976 | break; |
977 | |
978 | case Event::TimeMachineMode: |
979 | if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) |
980 | enterTimeMachineMenuMode(0, false); |
981 | else if(myState == EventHandlerState::TIMEMACHINE) |
982 | leaveMenuMode(); |
983 | else |
984 | handled = false; |
985 | break; |
986 | |
987 | case Event::DebuggerMode: |
988 | #ifdef DEBUGGER_SUPPORT |
989 | if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE |
990 | || myState == EventHandlerState::TIMEMACHINE) |
991 | enterDebugMode(); |
992 | else if(myState == EventHandlerState::DEBUGGER && myOSystem.debugger().canExit()) |
993 | leaveDebugMode(); |
994 | else |
995 | handled = false; |
996 | #endif |
997 | break; |
998 | |
999 | default: |
1000 | handled = false; |
1001 | } |
1002 | |
1003 | return handled; |
1004 | } |
1005 | |
1006 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1007 | void EventHandler::setActionMappings(EventMode mode) |
1008 | { |
1009 | int listsize = 0; |
1010 | ActionList* list = nullptr; |
1011 | |
1012 | switch(mode) |
1013 | { |
1014 | case EventMode::kEmulationMode: |
1015 | listsize = EMUL_ACTIONLIST_SIZE; |
1016 | list = ourEmulActionList; |
1017 | break; |
1018 | case EventMode::kMenuMode: |
1019 | listsize = MENU_ACTIONLIST_SIZE; |
1020 | list = ourMenuActionList; |
1021 | break; |
1022 | default: |
1023 | return; |
1024 | } |
1025 | |
1026 | // Fill the ActionList with the current key and joystick mappings |
1027 | for(int i = 0; i < listsize; ++i) |
1028 | { |
1029 | Event::Type event = list[i].event; |
1030 | list[i].key = "None" ; |
1031 | string key = myPKeyHandler->getMappingDesc(event, mode); |
1032 | |
1033 | #ifdef JOYSTICK_SUPPORT |
1034 | string joydesc = myPJoyHandler->getMappingDesc(event, mode); |
1035 | if(joydesc != "" ) |
1036 | { |
1037 | if(key != "" ) |
1038 | key += ", " ; |
1039 | key += joydesc; |
1040 | } |
1041 | #endif |
1042 | |
1043 | if(key != "" ) |
1044 | list[i].key = key; |
1045 | } |
1046 | } |
1047 | |
1048 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1049 | void EventHandler::setComboMap() |
1050 | { |
1051 | // Since istringstream swallows whitespace, we have to make the |
1052 | // delimiters be spaces |
1053 | string list = myOSystem.settings().getString("combomap" ); |
1054 | replace(list.begin(), list.end(), ':', ' '); |
1055 | istringstream buf(list); |
1056 | Int32 version = myOSystem.settings().getInt("event_ver" ); |
1057 | |
1058 | // Erase the 'combo' array |
1059 | auto ERASE_ALL = [&]() { |
1060 | for(int i = 0; i < COMBO_SIZE; ++i) |
1061 | for(int j = 0; j < EVENTS_PER_COMBO; ++j) |
1062 | myComboTable[i][j] = Event::NoType; |
1063 | }; |
1064 | |
1065 | // Compare if event list version has changed so that combo maps became invalid |
1066 | if(version != Event::VERSION || !buf.good()) |
1067 | ERASE_ALL(); |
1068 | else |
1069 | { |
1070 | // Get combo count, which should be the first int in the list |
1071 | // If it isn't, then we treat the entire list as invalid |
1072 | string key; |
1073 | buf >> key; |
1074 | if(atoi(key.c_str()) == COMBO_SIZE) |
1075 | { |
1076 | // Fill the combomap table with events for as long as they exist |
1077 | int combocount = 0; |
1078 | while(buf >> key && combocount < COMBO_SIZE) |
1079 | { |
1080 | // Each event in a comboevent is separated by a comma |
1081 | replace(key.begin(), key.end(), ',', ' '); |
1082 | istringstream buf2(key); |
1083 | |
1084 | int eventcount = 0; |
1085 | while(buf2 >> key && eventcount < EVENTS_PER_COMBO) |
1086 | { |
1087 | myComboTable[combocount][eventcount] = Event::Type(atoi(key.c_str())); |
1088 | ++eventcount; |
1089 | } |
1090 | ++combocount; |
1091 | } |
1092 | } |
1093 | else |
1094 | ERASE_ALL(); |
1095 | } |
1096 | |
1097 | saveComboMapping(); |
1098 | } |
1099 | |
1100 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1101 | void EventHandler::removePhysicalJoystickFromDatabase(const string& name) |
1102 | { |
1103 | #ifdef JOYSTICK_SUPPORT |
1104 | myPJoyHandler->remove(name); |
1105 | #endif |
1106 | } |
1107 | |
1108 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1109 | bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key, StellaMod mod) |
1110 | { |
1111 | bool mapped = myPKeyHandler->addMapping(event, mode, key, mod); |
1112 | if(mapped) |
1113 | setActionMappings(mode); |
1114 | |
1115 | return mapped; |
1116 | } |
1117 | |
1118 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1119 | bool EventHandler::addJoyMapping(Event::Type event, EventMode mode, |
1120 | int stick, int button, JoyAxis axis, JoyDir adir, |
1121 | bool ) |
1122 | { |
1123 | #ifdef JOYSTICK_SUPPORT |
1124 | bool mapped = myPJoyHandler->addJoyMapping(event, mode, stick, button, axis, adir); |
1125 | if (mapped && updateMenus) |
1126 | setActionMappings(mode); |
1127 | |
1128 | return mapped; |
1129 | #else |
1130 | return false; |
1131 | #endif |
1132 | } |
1133 | |
1134 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1135 | bool EventHandler::addJoyHatMapping(Event::Type event, EventMode mode, |
1136 | int stick, int button, int hat, JoyHatDir dir, |
1137 | bool ) |
1138 | { |
1139 | #ifdef JOYSTICK_SUPPORT |
1140 | bool mapped = myPJoyHandler->addJoyHatMapping(event, mode, stick, button, hat, dir); |
1141 | if (mapped && updateMenus) |
1142 | setActionMappings(mode); |
1143 | |
1144 | return mapped; |
1145 | #else |
1146 | return false; |
1147 | #endif |
1148 | } |
1149 | |
1150 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1151 | void EventHandler::eraseMapping(Event::Type event, EventMode mode) |
1152 | { |
1153 | // Erase the KeyEvent array |
1154 | myPKeyHandler->eraseMapping(event, mode); |
1155 | |
1156 | #ifdef JOYSTICK_SUPPORT |
1157 | // Erase the joystick mapping arrays |
1158 | myPJoyHandler->eraseMapping(event, mode); |
1159 | #endif |
1160 | |
1161 | setActionMappings(mode); |
1162 | } |
1163 | |
1164 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1165 | void EventHandler::setDefaultMapping(Event::Type event, EventMode mode) |
1166 | { |
1167 | setDefaultKeymap(event, mode); |
1168 | setDefaultJoymap(event, mode); |
1169 | } |
1170 | |
1171 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1172 | void EventHandler::setDefaultKeymap(Event::Type event, EventMode mode) |
1173 | { |
1174 | myPKeyHandler->setDefaultMapping(event, mode); |
1175 | setActionMappings(mode); |
1176 | } |
1177 | |
1178 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1179 | void EventHandler::setDefaultJoymap(Event::Type event, EventMode mode) |
1180 | { |
1181 | #ifdef JOYSTICK_SUPPORT |
1182 | myPJoyHandler->setDefaultMapping(event, mode); |
1183 | setActionMappings(mode); |
1184 | #endif |
1185 | } |
1186 | |
1187 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1188 | void EventHandler::saveKeyMapping() |
1189 | { |
1190 | myPKeyHandler->saveMapping(); |
1191 | } |
1192 | |
1193 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1194 | void EventHandler::saveJoyMapping() |
1195 | { |
1196 | #ifdef JOYSTICK_SUPPORT |
1197 | myPJoyHandler->saveMapping(); |
1198 | #endif |
1199 | } |
1200 | |
1201 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1202 | void EventHandler::saveComboMapping() |
1203 | { |
1204 | // Iterate through the combomap table and create a colon-separated list |
1205 | // For each combo event, create a comma-separated list of its events |
1206 | // Prepend the event count, so we can check it on next load |
1207 | ostringstream buf; |
1208 | buf << COMBO_SIZE; |
1209 | for(int i = 0; i < COMBO_SIZE; ++i) |
1210 | { |
1211 | buf << ":" << myComboTable[i][0]; |
1212 | for(int j = 1; j < EVENTS_PER_COMBO; ++j) |
1213 | buf << "," << myComboTable[i][j]; |
1214 | } |
1215 | myOSystem.settings().setValue("combomap" , buf.str()); |
1216 | } |
1217 | |
1218 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1219 | StringList EventHandler::getActionList(EventMode mode) const |
1220 | { |
1221 | StringList l; |
1222 | switch(mode) |
1223 | { |
1224 | case EventMode::kEmulationMode: |
1225 | for(uInt32 i = 0; i < EMUL_ACTIONLIST_SIZE; ++i) |
1226 | l.push_back(EventHandler::ourEmulActionList[i].action); |
1227 | break; |
1228 | case EventMode::kMenuMode: |
1229 | for(uInt32 i = 0; i < MENU_ACTIONLIST_SIZE; ++i) |
1230 | l.push_back(EventHandler::ourMenuActionList[i].action); |
1231 | break; |
1232 | default: |
1233 | break; |
1234 | } |
1235 | return l; |
1236 | } |
1237 | |
1238 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1239 | StringList EventHandler::getActionList(Event::Group group) const |
1240 | { |
1241 | StringList l; |
1242 | |
1243 | switch(group) |
1244 | { |
1245 | case Event::Group::Menu: |
1246 | return getActionList(EventMode::kMenuMode); |
1247 | |
1248 | case Event::Group::Emulation: |
1249 | return getActionList(EventMode::kEmulationMode); |
1250 | |
1251 | case Event::Group::Misc: |
1252 | return getActionList(MiscEvents); |
1253 | |
1254 | case Event::Group::AudioVideo: |
1255 | return getActionList(AudioVideoEvents); |
1256 | |
1257 | case Event::Group::States: |
1258 | return getActionList(StateEvents); |
1259 | |
1260 | case Event::Group::Console: |
1261 | return getActionList(ConsoleEvents); |
1262 | |
1263 | case Event::Group::Joystick: |
1264 | return getActionList(JoystickEvents); |
1265 | |
1266 | case Event::Group::Paddles: |
1267 | return getActionList(PaddlesEvents); |
1268 | |
1269 | case Event::Group::Keyboard: |
1270 | return getActionList(KeyboardEvents); |
1271 | |
1272 | case Event::Group::Debug: |
1273 | return getActionList(DebugEvents); |
1274 | |
1275 | case Event::Group::Combo: |
1276 | return getActionList(ComboEvents); |
1277 | |
1278 | default: |
1279 | return l; // ToDo |
1280 | } |
1281 | } |
1282 | |
1283 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1284 | StringList EventHandler::getActionList(const Event::EventSet& events, EventMode mode) const |
1285 | { |
1286 | StringList l; |
1287 | |
1288 | switch(mode) |
1289 | { |
1290 | case EventMode::kMenuMode: |
1291 | for(uInt32 i = 0; i < MENU_ACTIONLIST_SIZE; ++i) |
1292 | for(const auto& event : events) |
1293 | if(EventHandler::ourMenuActionList[i].event == event) |
1294 | { |
1295 | l.push_back(EventHandler::ourMenuActionList[i].action); |
1296 | break; |
1297 | } |
1298 | break; |
1299 | |
1300 | default: |
1301 | for(uInt32 i = 0; i < EMUL_ACTIONLIST_SIZE; ++i) |
1302 | for(const auto& event : events) |
1303 | if(EventHandler::ourEmulActionList[i].event == event) |
1304 | { |
1305 | l.push_back(EventHandler::ourEmulActionList[i].action); |
1306 | break; |
1307 | } |
1308 | } |
1309 | return l; |
1310 | } |
1311 | |
1312 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1313 | VariantList EventHandler::getComboList(EventMode /**/) const |
1314 | { |
1315 | // For now, this only works in emulation mode |
1316 | VariantList l; |
1317 | ostringstream buf; |
1318 | |
1319 | VarList::push_back(l, "None" , "-1" ); |
1320 | for(uInt32 i = 0; i < EMUL_ACTIONLIST_SIZE; ++i) |
1321 | { |
1322 | Event::Type event = EventHandler::ourEmulActionList[i].event; |
1323 | // exclude combos events |
1324 | if(!(event >= Event::Combo1 && event <= Event::Combo16)) |
1325 | { |
1326 | buf << i; |
1327 | VarList::push_back(l, EventHandler::ourEmulActionList[i].action, buf.str()); |
1328 | buf.str("" ); |
1329 | } |
1330 | } |
1331 | return l; |
1332 | } |
1333 | |
1334 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1335 | StringList EventHandler::getComboListForEvent(Event::Type event) const |
1336 | { |
1337 | StringList l; |
1338 | ostringstream buf; |
1339 | if(event >= Event::Combo1 && event <= Event::Combo16) |
1340 | { |
1341 | int combo = event - Event::Combo1; |
1342 | for(uInt32 i = 0; i < EVENTS_PER_COMBO; ++i) |
1343 | { |
1344 | Event::Type e = myComboTable[combo][i]; |
1345 | for(uInt32 j = 0; j < EMUL_ACTIONLIST_SIZE; ++j) |
1346 | { |
1347 | if(EventHandler::ourEmulActionList[j].event == e) |
1348 | { |
1349 | buf << j; |
1350 | l.push_back(buf.str()); |
1351 | buf.str("" ); |
1352 | } |
1353 | } |
1354 | // Make sure entries are 1-to-1, using '-1' to indicate Event::NoType |
1355 | if(i == l.size()) |
1356 | l.push_back("-1" ); |
1357 | } |
1358 | } |
1359 | return l; |
1360 | } |
1361 | |
1362 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1363 | void EventHandler::setComboListForEvent(Event::Type event, const StringList& events) |
1364 | { |
1365 | if(event >= Event::Combo1 && event <= Event::Combo16) |
1366 | { |
1367 | assert(events.size() == 8); |
1368 | int combo = event - Event::Combo1; |
1369 | for(int i = 0; i < 8; ++i) |
1370 | { |
1371 | int idx = atoi(events[i].c_str()); |
1372 | if(idx >= 0 && idx < EMUL_ACTIONLIST_SIZE) |
1373 | myComboTable[combo][i] = EventHandler::ourEmulActionList[idx].event; |
1374 | else |
1375 | myComboTable[combo][i] = Event::NoType; |
1376 | } |
1377 | saveComboMapping(); |
1378 | } |
1379 | } |
1380 | |
1381 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1382 | int EventHandler::getEmulActionListIndex(int idx, const Event::EventSet& events) const |
1383 | { |
1384 | // idx = index into intersection set of 'events' and 'ourEmulActionList' |
1385 | // ordered by 'ourEmulActionList'! |
1386 | Event::Type event = Event::NoType; |
1387 | |
1388 | for(uInt32 i = 0; i < EMUL_ACTIONLIST_SIZE; ++i) |
1389 | { |
1390 | for(const auto& item : events) |
1391 | if(EventHandler::ourEmulActionList[i].event == item) |
1392 | { |
1393 | idx--; |
1394 | if(idx < 0) |
1395 | event = item; |
1396 | break; |
1397 | } |
1398 | if(idx < 0) |
1399 | break; |
1400 | } |
1401 | |
1402 | for(uInt32 i = 0; i < EMUL_ACTIONLIST_SIZE; ++i) |
1403 | if(EventHandler::ourEmulActionList[i].event == event) |
1404 | return i; |
1405 | |
1406 | return -1; |
1407 | } |
1408 | |
1409 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1410 | int EventHandler::getActionListIndex(int idx, Event::Group group) const |
1411 | { |
1412 | switch(group) |
1413 | { |
1414 | case Event::Group::Menu: |
1415 | return idx; |
1416 | |
1417 | case Event::Group::Emulation: |
1418 | return idx; |
1419 | |
1420 | case Event::Group::Misc: |
1421 | return getEmulActionListIndex(idx, MiscEvents); |
1422 | |
1423 | case Event::Group::AudioVideo: |
1424 | return getEmulActionListIndex(idx, AudioVideoEvents); |
1425 | |
1426 | case Event::Group::States: |
1427 | return getEmulActionListIndex(idx, StateEvents); |
1428 | |
1429 | case Event::Group::Console: |
1430 | return getEmulActionListIndex(idx, ConsoleEvents); |
1431 | |
1432 | case Event::Group::Joystick: |
1433 | return getEmulActionListIndex(idx, JoystickEvents); |
1434 | |
1435 | case Event::Group::Paddles: |
1436 | return getEmulActionListIndex(idx, PaddlesEvents); |
1437 | |
1438 | case Event::Group::Keyboard: |
1439 | return getEmulActionListIndex(idx, KeyboardEvents); |
1440 | |
1441 | case Event::Group::Debug: |
1442 | return getEmulActionListIndex(idx, DebugEvents); |
1443 | |
1444 | case Event::Group::Combo: |
1445 | return getEmulActionListIndex(idx, ComboEvents); |
1446 | |
1447 | default: |
1448 | return -1; |
1449 | } |
1450 | } |
1451 | |
1452 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1453 | Event::Type EventHandler::eventAtIndex(int idx, Event::Group group) const |
1454 | { |
1455 | int index = getActionListIndex(idx, group); |
1456 | |
1457 | switch(group) |
1458 | { |
1459 | case Event::Group::Menu: |
1460 | if(index < 0 || index >= MENU_ACTIONLIST_SIZE) |
1461 | return Event::NoType; |
1462 | else |
1463 | return ourMenuActionList[index].event; |
1464 | |
1465 | default: |
1466 | if(index < 0 || index >= EMUL_ACTIONLIST_SIZE) |
1467 | return Event::NoType; |
1468 | else |
1469 | return ourEmulActionList[index].event; |
1470 | } |
1471 | } |
1472 | |
1473 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1474 | string EventHandler::actionAtIndex(int idx, Event::Group group) const |
1475 | { |
1476 | int index = getActionListIndex(idx, group); |
1477 | |
1478 | switch(group) |
1479 | { |
1480 | case Event::Group::Menu: |
1481 | if(index < 0 || index >= MENU_ACTIONLIST_SIZE) |
1482 | return EmptyString; |
1483 | else |
1484 | return ourMenuActionList[index].action; |
1485 | |
1486 | default: |
1487 | if(index < 0 || index >= EMUL_ACTIONLIST_SIZE) |
1488 | return EmptyString; |
1489 | else |
1490 | return ourEmulActionList[index].action; |
1491 | } |
1492 | } |
1493 | |
1494 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1495 | string EventHandler::keyAtIndex(int idx, Event::Group group) const |
1496 | { |
1497 | int index = getActionListIndex(idx, group); |
1498 | |
1499 | switch(group) |
1500 | { |
1501 | case Event::Group::Menu: |
1502 | if(index < 0 || index >= MENU_ACTIONLIST_SIZE) |
1503 | return EmptyString; |
1504 | else |
1505 | return ourMenuActionList[index].key; |
1506 | |
1507 | default: |
1508 | if(index < 0 || index >= EMUL_ACTIONLIST_SIZE) |
1509 | return EmptyString; |
1510 | else |
1511 | return ourEmulActionList[index].key; |
1512 | } |
1513 | } |
1514 | |
1515 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1516 | void EventHandler::setMouseControllerMode(const string& enable) |
1517 | { |
1518 | if(myOSystem.hasConsole()) |
1519 | { |
1520 | bool usemouse = false; |
1521 | if(BSPF::equalsIgnoreCase(enable, "always" )) |
1522 | usemouse = true; |
1523 | else if(BSPF::equalsIgnoreCase(enable, "never" )) |
1524 | usemouse = false; |
1525 | else // 'analog' |
1526 | { |
1527 | usemouse = myOSystem.console().leftController().isAnalog() || |
1528 | myOSystem.console().rightController().isAnalog(); |
1529 | } |
1530 | |
1531 | const string& control = usemouse ? |
1532 | myOSystem.console().properties().get(PropType::Controller_MouseAxis) : "none" ; |
1533 | |
1534 | myMouseControl = make_unique<MouseControl>(myOSystem.console(), control); |
1535 | myMouseControl->next(); // set first available mode |
1536 | } |
1537 | } |
1538 | |
1539 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1540 | void EventHandler::enterMenuMode(EventHandlerState state) |
1541 | { |
1542 | #ifdef GUI_SUPPORT |
1543 | setState(state); |
1544 | myOverlay->reStack(); |
1545 | myOSystem.sound().mute(true); |
1546 | #endif |
1547 | } |
1548 | |
1549 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1550 | void EventHandler::leaveMenuMode() |
1551 | { |
1552 | #ifdef GUI_SUPPORT |
1553 | setState(EventHandlerState::EMULATION); |
1554 | myOSystem.sound().mute(false); |
1555 | #endif |
1556 | } |
1557 | |
1558 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1559 | bool EventHandler::enterDebugMode() |
1560 | { |
1561 | #ifdef DEBUGGER_SUPPORT |
1562 | if(myState == EventHandlerState::DEBUGGER || !myOSystem.hasConsole()) |
1563 | return false; |
1564 | |
1565 | // Make sure debugger starts in a consistent state |
1566 | // This absolutely *has* to come before we actually change to debugger |
1567 | // mode, since it takes care of locking the debugger state, which will |
1568 | // probably be modified below |
1569 | myOSystem.debugger().setStartState(); |
1570 | setState(EventHandlerState::DEBUGGER); |
1571 | |
1572 | FBInitStatus fbstatus = myOSystem.createFrameBuffer(); |
1573 | if(fbstatus != FBInitStatus::Success) |
1574 | { |
1575 | myOSystem.debugger().setQuitState(); |
1576 | setState(EventHandlerState::EMULATION); |
1577 | if(fbstatus == FBInitStatus::FailTooLarge) |
1578 | myOSystem.frameBuffer().showMessage("Debugger window too large for screen" , |
1579 | MessagePosition::BottomCenter, true); |
1580 | return false; |
1581 | } |
1582 | myOverlay->reStack(); |
1583 | myOSystem.sound().mute(true); |
1584 | #else |
1585 | myOSystem.frameBuffer().showMessage("Debugger support not included" , |
1586 | MessagePosition::BottomCenter, true); |
1587 | #endif |
1588 | |
1589 | return true; |
1590 | } |
1591 | |
1592 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1593 | void EventHandler::leaveDebugMode() |
1594 | { |
1595 | #ifdef DEBUGGER_SUPPORT |
1596 | // paranoia: this should never happen: |
1597 | if(myState != EventHandlerState::DEBUGGER) |
1598 | return; |
1599 | |
1600 | // Make sure debugger quits in a consistent state |
1601 | myOSystem.debugger().setQuitState(); |
1602 | |
1603 | setState(EventHandlerState::EMULATION); |
1604 | myOSystem.createFrameBuffer(); |
1605 | myOSystem.sound().mute(false); |
1606 | #endif |
1607 | } |
1608 | |
1609 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1610 | void EventHandler::enterTimeMachineMenuMode(uInt32 numWinds, bool unwind) |
1611 | { |
1612 | #ifdef GUI_SUPPORT |
1613 | // add one extra state if we are in Time Machine mode |
1614 | // TODO: maybe remove this state if we leave the menu at this new state |
1615 | myOSystem.state().addExtraState("enter Time Machine dialog" ); // force new state |
1616 | |
1617 | if(numWinds) |
1618 | // hande winds and display wind message (numWinds != 0) in time machine dialog |
1619 | myOSystem.timeMachine().setEnterWinds(unwind ? numWinds : -numWinds); |
1620 | |
1621 | enterMenuMode(EventHandlerState::TIMEMACHINE); |
1622 | #endif |
1623 | } |
1624 | |
1625 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1626 | void EventHandler::setState(EventHandlerState state) |
1627 | { |
1628 | myState = state; |
1629 | |
1630 | // Normally, the usage of modifier keys is determined by 'modcombo' |
1631 | // For certain ROMs it may be forced off, whatever the setting |
1632 | myPKeyHandler->useModKeys() = myOSystem.settings().getBool("modcombo" ); |
1633 | |
1634 | // Only enable text input in GUI modes, since in emulation mode the |
1635 | // keyboard acts as one large joystick with many (single) buttons |
1636 | myOverlay = nullptr; |
1637 | switch(myState) |
1638 | { |
1639 | case EventHandlerState::EMULATION: |
1640 | myOSystem.sound().mute(false); |
1641 | enableTextEvents(false); |
1642 | break; |
1643 | |
1644 | case EventHandlerState::PAUSE: |
1645 | myOSystem.sound().mute(true); |
1646 | enableTextEvents(false); |
1647 | break; |
1648 | |
1649 | #ifdef GUI_SUPPORT |
1650 | case EventHandlerState::OPTIONSMENU: |
1651 | myOverlay = &myOSystem.menu(); |
1652 | enableTextEvents(true); |
1653 | break; |
1654 | |
1655 | case EventHandlerState::CMDMENU: |
1656 | myOverlay = &myOSystem.commandMenu(); |
1657 | enableTextEvents(true); |
1658 | break; |
1659 | |
1660 | case EventHandlerState::TIMEMACHINE: |
1661 | myOSystem.timeMachine().requestResize(); |
1662 | myOverlay = &myOSystem.timeMachine(); |
1663 | enableTextEvents(true); |
1664 | break; |
1665 | |
1666 | case EventHandlerState::LAUNCHER: |
1667 | myOverlay = &myOSystem.launcher(); |
1668 | enableTextEvents(true); |
1669 | break; |
1670 | #endif |
1671 | |
1672 | #ifdef DEBUGGER_SUPPORT |
1673 | case EventHandlerState::DEBUGGER: |
1674 | myOverlay = &myOSystem.debugger(); |
1675 | enableTextEvents(true); |
1676 | break; |
1677 | #endif |
1678 | |
1679 | case EventHandlerState::NONE: |
1680 | default: |
1681 | break; |
1682 | } |
1683 | |
1684 | // Inform various subsystems about the new state |
1685 | myOSystem.stateChanged(myState); |
1686 | myOSystem.frameBuffer().stateChanged(myState); |
1687 | myOSystem.frameBuffer().setCursorState(); |
1688 | if(myOSystem.hasConsole()) |
1689 | myOSystem.console().stateChanged(myState); |
1690 | |
1691 | // Sometimes an extraneous mouse motion event is generated |
1692 | // after a state change, which should be supressed |
1693 | mySkipMouseMotion = true; |
1694 | |
1695 | // Erase any previously set events, since a state change implies |
1696 | // that old events are now invalid |
1697 | myEvent.clear(); |
1698 | } |
1699 | |
1700 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1701 | void EventHandler::exitEmulation() |
1702 | { |
1703 | // TODO: confirm message |
1704 | string saveOnExit = myOSystem.settings().getString("saveonexit" ); |
1705 | |
1706 | if (saveOnExit == "all" ) |
1707 | handleEvent(Event::SaveAllStates); |
1708 | else if (saveOnExit == "current" ) |
1709 | handleEvent(Event::SaveState); |
1710 | } |
1711 | |
1712 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1713 | EventHandler::ActionList EventHandler::ourEmulActionList[EMUL_ACTIONLIST_SIZE] = { |
1714 | { Event::Quit, "Quit" , "" }, |
1715 | { Event::ReloadConsole, "Reload current ROM/load next game" , "" }, |
1716 | { Event::ExitMode, "Exit current Stella menu/mode" , "" }, |
1717 | { Event::OptionsMenuMode, "Enter Options menu UI" , "" }, |
1718 | { Event::CmdMenuMode, "Toggle Commands menu UI" , "" }, |
1719 | { Event::TogglePauseMode, "Toggle Pause mode" , "" }, |
1720 | { Event::StartPauseMode, "Start Pause mode" , "" }, |
1721 | { Event::Fry, "Fry cartridge" , "" }, |
1722 | { Event::DebuggerMode, "Toggle Debugger mode" , "" }, |
1723 | |
1724 | { Event::ConsoleSelect, "Select" , "" }, |
1725 | { Event::ConsoleReset, "Reset" , "" }, |
1726 | { Event::ConsoleColor, "Color TV" , "" }, |
1727 | { Event::ConsoleBlackWhite, "Black & White TV" , "" }, |
1728 | { Event::ConsoleColorToggle, "Toggle Color / B&W TV" , "" }, |
1729 | { Event::Console7800Pause, "7800 Pause Key" , "" }, |
1730 | { Event::ConsoleLeftDiffA, "P0 Difficulty A" , "" }, |
1731 | { Event::ConsoleLeftDiffB, "P0 Difficulty B" , "" }, |
1732 | { Event::ConsoleLeftDiffToggle, "P0 Toggle Difficulty" , "" }, |
1733 | { Event::ConsoleRightDiffA, "P1 Difficulty A" , "" }, |
1734 | { Event::ConsoleRightDiffB, "P1 Difficulty B" , "" }, |
1735 | { Event::ConsoleRightDiffToggle, "P1 Toggle Difficulty" , "" }, |
1736 | { Event::SaveState, "Save state" , "" }, |
1737 | { Event::ChangeState, "Change state slot" , "" }, |
1738 | { Event::ToggleAutoSlot, "Toggle automatic state slot change" , "" }, |
1739 | { Event::LoadState, "Load state" , "" }, |
1740 | #ifdef PNG_SUPPORT |
1741 | { Event::TakeSnapshot, "Snapshot" , "" }, |
1742 | { Event::ToggleContSnapshots, "Save continuous snapsh. (as defined)" , "" }, |
1743 | { Event::ToggleContSnapshotsFrame,"Save continuous snapsh. (every frame)" , "" }, |
1744 | #endif |
1745 | |
1746 | { Event::JoystickZeroUp, "P0 Joystick Up" , "" }, |
1747 | { Event::JoystickZeroDown, "P0 Joystick Down" , "" }, |
1748 | { Event::JoystickZeroLeft, "P0 Joystick Left" , "" }, |
1749 | { Event::JoystickZeroRight, "P0 Joystick Right" , "" }, |
1750 | { Event::JoystickZeroFire, "P0 Joystick Fire" , "" }, |
1751 | { Event::JoystickZeroFire5, "P0 Booster Top Booster Button" , "" }, |
1752 | { Event::JoystickZeroFire9, "P0 Booster Handle Grip Trigger" , "" }, |
1753 | |
1754 | { Event::JoystickOneUp, "P1 Joystick Up" , "" }, |
1755 | { Event::JoystickOneDown, "P1 Joystick Down" , "" }, |
1756 | { Event::JoystickOneLeft, "P1 Joystick Left" , "" }, |
1757 | { Event::JoystickOneRight, "P1 Joystick Right" , "" }, |
1758 | { Event::JoystickOneFire, "P1 Joystick Fire" , "" }, |
1759 | { Event::JoystickOneFire5, "P1 Booster Top Booster Button" , "" }, |
1760 | { Event::JoystickOneFire9, "P1 Booster Handle Grip Trigger" , "" }, |
1761 | |
1762 | { Event::PaddleZeroAnalog, "Paddle 0 Analog" , "" }, |
1763 | { Event::PaddleZeroIncrease, "Paddle 0 Turn Left" , "" }, |
1764 | { Event::PaddleZeroDecrease, "Paddle 0 Turn Right" , "" }, |
1765 | { Event::PaddleZeroFire, "Paddle 0 Fire" , "" }, |
1766 | |
1767 | { Event::PaddleOneAnalog, "Paddle 1 Analog" , "" }, |
1768 | { Event::PaddleOneIncrease, "Paddle 1 Turn Left" , "" }, |
1769 | { Event::PaddleOneDecrease, "Paddle 1 Turn Right" , "" }, |
1770 | { Event::PaddleOneFire, "Paddle 1 Fire" , "" }, |
1771 | |
1772 | { Event::PaddleTwoAnalog, "Paddle 2 Analog" , "" }, |
1773 | { Event::PaddleTwoIncrease, "Paddle 2 Turn Left" , "" }, |
1774 | { Event::PaddleTwoDecrease, "Paddle 2 Turn Right" , "" }, |
1775 | { Event::PaddleTwoFire, "Paddle 2 Fire" , "" }, |
1776 | |
1777 | { Event::PaddleThreeAnalog, "Paddle 3 Analog" , "" }, |
1778 | { Event::PaddleThreeIncrease, "Paddle 3 Turn Left" , "" }, |
1779 | { Event::PaddleThreeDecrease, "Paddle 3 Turn Right" , "" }, |
1780 | { Event::PaddleThreeFire, "Paddle 3 Fire" , "" }, |
1781 | |
1782 | { Event::KeyboardZero1, "P0 Keyboard 1" , "" }, |
1783 | { Event::KeyboardZero2, "P0 Keyboard 2" , "" }, |
1784 | { Event::KeyboardZero3, "P0 Keyboard 3" , "" }, |
1785 | { Event::KeyboardZero4, "P0 Keyboard 4" , "" }, |
1786 | { Event::KeyboardZero5, "P0 Keyboard 5" , "" }, |
1787 | { Event::KeyboardZero6, "P0 Keyboard 6" , "" }, |
1788 | { Event::KeyboardZero7, "P0 Keyboard 7" , "" }, |
1789 | { Event::KeyboardZero8, "P0 Keyboard 8" , "" }, |
1790 | { Event::KeyboardZero9, "P0 Keyboard 9" , "" }, |
1791 | { Event::KeyboardZeroStar, "P0 Keyboard *" , "" }, |
1792 | { Event::KeyboardZero0, "P0 Keyboard 0" , "" }, |
1793 | { Event::KeyboardZeroPound, "P0 Keyboard #" , "" }, |
1794 | |
1795 | { Event::KeyboardOne1, "P1 Keyboard 1" , "" }, |
1796 | { Event::KeyboardOne2, "P1 Keyboard 2" , "" }, |
1797 | { Event::KeyboardOne3, "P1 Keyboard 3" , "" }, |
1798 | { Event::KeyboardOne4, "P1 Keyboard 4" , "" }, |
1799 | { Event::KeyboardOne5, "P1 Keyboard 5" , "" }, |
1800 | { Event::KeyboardOne6, "P1 Keyboard 6" , "" }, |
1801 | { Event::KeyboardOne7, "P1 Keyboard 7" , "" }, |
1802 | { Event::KeyboardOne8, "P1 Keyboard 8" , "" }, |
1803 | { Event::KeyboardOne9, "P1 Keyboard 9" , "" }, |
1804 | { Event::KeyboardOneStar, "P1 Keyboard *" , "" }, |
1805 | { Event::KeyboardOne0, "P1 Keyboard 0" , "" }, |
1806 | { Event::KeyboardOnePound, "P1 Keyboard #" , "" }, |
1807 | // Video |
1808 | { Event::VidmodeDecrease, "Previous zoom level" , "" }, |
1809 | { Event::VidmodeIncrease, "Next zoom level" , "" }, |
1810 | { Event::ToggleFullScreen, "Toggle fullscreen" , "" }, |
1811 | { Event::DecreaseOverscan, "Decrease overscan in fullscreen mode" , "" }, |
1812 | { Event::IncreaseOverScan, "Increase overscan in fullscreen mode" , "" }, |
1813 | { Event::DecreaseFormat, "Decrease display format" , "" }, |
1814 | { Event::IncreaseFormat, "Increase display format" , "" }, |
1815 | { Event::TogglePalette, "Switch palette (Standard/Z26/User)" , "" }, |
1816 | |
1817 | // TV effects: |
1818 | { Event::VidmodeStd, "Disable TV effects" , "" }, |
1819 | { Event::VidmodeRGB, "Select 'RGB' preset" , "" }, |
1820 | { Event::VidmodeSVideo, "Select 'S-Video' preset" , "" }, |
1821 | { Event::VidModeComposite, "Select 'Composite' preset" , "" }, |
1822 | { Event::VidModeBad, "Select 'Badly adjusted' preset" , "" }, |
1823 | { Event::VidModeCustom, "Select 'Custom' preset" , "" }, |
1824 | { Event::PreviousAttribute, "Select previous 'Custom' attribute" , "" }, |
1825 | { Event::NextAttribute, "Select next 'Custom' attribute" , "" }, |
1826 | { Event::DecreaseAttribute, "Decrease selected 'Custom' attribute" , "" }, |
1827 | { Event::IncreaseAttribute, "Increase selected 'Custom' attribute" , "" }, |
1828 | { Event::TogglePhosphor, "Toggle 'phosphor' effect" , "" }, |
1829 | { Event::DecreasePhosphor, "Decrease 'phosphor' blend" , "" }, |
1830 | { Event::IncreasePhosphor, "Increase 'phosphor' blend" , "" }, |
1831 | { Event::ScanlinesDecrease, "Decrease scanlines" , "" }, |
1832 | { Event::ScanlinesIncrease, "Increase scanlines" , "" }, |
1833 | // Developer keys: |
1834 | { Event::ToggleFrameStats, "Toggle frame stats" , "" }, |
1835 | { Event::ToggleP0Bit, "Toggle TIA Player0 object" , "" }, |
1836 | { Event::ToggleP0Collision, "Toggle TIA Player0 collisions" , "" }, |
1837 | { Event::ToggleP1Bit, "Toggle TIA Player1 object" , "" }, |
1838 | { Event::ToggleP1Collision, "Toggle TIA Player1 collisions" , "" }, |
1839 | { Event::ToggleM0Bit, "Toggle TIA Missile0 object" , "" }, |
1840 | { Event::ToggleM0Collision, "Toggle TIA Missile0 collisions" , "" }, |
1841 | { Event::ToggleM1Bit, "Toggle TIA Missile1 object" , "" }, |
1842 | { Event::ToggleM1Collision, "Toggle TIA Missile1 collisions" , "" }, |
1843 | { Event::ToggleBLBit, "Toggle TIA Ball object" , "" }, |
1844 | { Event::ToggleBLCollision, "Toggle TIA Ball collisions" , "" }, |
1845 | { Event::TogglePFBit, "Toggle TIA Playfield object" , "" }, |
1846 | { Event::TogglePFCollision, "Toggle TIA Playfield collisions" , "" }, |
1847 | { Event::ToggleBits, "Toggle all TIA objects" , "" }, |
1848 | { Event::ToggleCollisions, "Toggle all TIA collisions" , "" }, |
1849 | { Event::ToggleFixedColors, "Toggle TIA 'Fixed Debug Colors' mode" , "" }, |
1850 | { Event::ToggleColorLoss, "Toggle PAL color-loss effect" , "" }, |
1851 | { Event::ToggleJitter, "Toggle TV 'Jitter' effect" , "" }, |
1852 | // Other keys: |
1853 | { Event::SoundToggle, "Toggle sound" , "" }, |
1854 | { Event::VolumeDecrease, "Decrease volume" , "" }, |
1855 | { Event::VolumeIncrease, "Increase volume" , "" }, |
1856 | |
1857 | { Event::HandleMouseControl, "Switch mouse emulation modes" , "" }, |
1858 | { Event::ToggleGrabMouse, "Toggle grab mouse" , "" }, |
1859 | { Event::ToggleSAPortOrder, "Swap Stelladaptor port ordering" , "" }, |
1860 | |
1861 | { Event::SaveAllStates, "Save all TM states of current game" , "" }, |
1862 | { Event::LoadAllStates, "Load saved TM states for current game" , "" }, |
1863 | { Event::ToggleTimeMachine, "Toggle 'Time Machine' mode" , "" }, |
1864 | { Event::TimeMachineMode, "Toggle 'Time Machine' UI" , "" }, |
1865 | { Event::RewindPause, "Rewind one state & enter Pause mode" , "" }, |
1866 | { Event::Rewind1Menu, "Rewind one state & enter TM UI" , "" }, |
1867 | { Event::Rewind10Menu, "Rewind 10 states & enter TM UI" , "" }, |
1868 | { Event::RewindAllMenu, "Rewind all states & enter TM UI" , "" }, |
1869 | { Event::UnwindPause, "Unwind one state & enter Pause mode" , "" }, |
1870 | { Event::Unwind1Menu, "Unwind one state & enter TM UI" , "" }, |
1871 | { Event::Unwind10Menu, "Unwind 10 states & enter TM UI" , "" }, |
1872 | { Event::UnwindAllMenu, "Unwind all states & enter TM UI" , "" }, |
1873 | |
1874 | { Event::Combo1, "Combo 1" , "" }, |
1875 | { Event::Combo2, "Combo 2" , "" }, |
1876 | { Event::Combo3, "Combo 3" , "" }, |
1877 | { Event::Combo4, "Combo 4" , "" }, |
1878 | { Event::Combo5, "Combo 5" , "" }, |
1879 | { Event::Combo6, "Combo 6" , "" }, |
1880 | { Event::Combo7, "Combo 7" , "" }, |
1881 | { Event::Combo8, "Combo 8" , "" }, |
1882 | { Event::Combo9, "Combo 9" , "" }, |
1883 | { Event::Combo10, "Combo 10" , "" }, |
1884 | { Event::Combo11, "Combo 11" , "" }, |
1885 | { Event::Combo12, "Combo 12" , "" }, |
1886 | { Event::Combo13, "Combo 13" , "" }, |
1887 | { Event::Combo14, "Combo 14" , "" }, |
1888 | { Event::Combo15, "Combo 15" , "" }, |
1889 | { Event::Combo16, "Combo 16" , "" } |
1890 | }; |
1891 | |
1892 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1893 | EventHandler::ActionList EventHandler::ourMenuActionList[MENU_ACTIONLIST_SIZE] = { |
1894 | { Event::UIUp, "Move Up" , "" }, |
1895 | { Event::UIDown, "Move Down" , "" }, |
1896 | { Event::UILeft, "Move Left" , "" }, |
1897 | { Event::UIRight, "Move Right" , "" }, |
1898 | |
1899 | { Event::UIHome, "Home" , "" }, |
1900 | { Event::UIEnd, "End" , "" }, |
1901 | { Event::UIPgUp, "Page Up" , "" }, |
1902 | { Event::UIPgDown, "Page Down" , "" }, |
1903 | |
1904 | { Event::UIOK, "OK" , "" }, |
1905 | { Event::UICancel, "Cancel" , "" }, |
1906 | { Event::UISelect, "Select item" , "" }, |
1907 | |
1908 | { Event::UINavPrev, "Previous object" , "" }, |
1909 | { Event::UINavNext, "Next object" , "" }, |
1910 | { Event::UITabPrev, "Previous tab" , "" }, |
1911 | { Event::UITabNext, "Next tab" , "" }, |
1912 | |
1913 | { Event::UIPrevDir, "Parent directory" , "" }, |
1914 | { Event::ToggleFullScreen, "Toggle fullscreen" , "" }, |
1915 | { Event::Quit, "Quit" , "" } |
1916 | }; |
1917 | |
1918 | // Event groups |
1919 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1920 | const Event::EventSet EventHandler::MiscEvents = { |
1921 | Event::Quit, Event::ReloadConsole, Event::Fry, Event::StartPauseMode, |
1922 | Event::TogglePauseMode, Event::OptionsMenuMode, Event::CmdMenuMode, Event::ExitMode, |
1923 | Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame, |
1924 | // Event::MouseAxisXValue, Event::MouseAxisYValue, |
1925 | // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, |
1926 | Event::HandleMouseControl, Event::ToggleGrabMouse, |
1927 | Event::ToggleSAPortOrder, |
1928 | }; |
1929 | |
1930 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1931 | const Event::EventSet EventHandler::AudioVideoEvents = { |
1932 | Event::VolumeDecrease, Event::VolumeIncrease, Event::SoundToggle, |
1933 | Event::VidmodeDecrease, Event::VidmodeIncrease, |
1934 | Event::ToggleFullScreen, |
1935 | Event::VidmodeStd, Event::VidmodeRGB, Event::VidmodeSVideo, Event::VidModeComposite, Event::VidModeBad, Event::VidModeCustom, |
1936 | Event::PreviousAttribute, Event::NextAttribute, Event::DecreaseAttribute, Event::IncreaseAttribute, |
1937 | Event::ScanlinesDecrease, Event::ScanlinesIncrease, |
1938 | Event::DecreasePhosphor, Event::IncreasePhosphor, Event::TogglePhosphor, |
1939 | Event::DecreaseFormat, Event::IncreaseFormat, |
1940 | Event::DecreaseOverscan, Event::IncreaseOverScan, |
1941 | Event::TogglePalette, |
1942 | }; |
1943 | |
1944 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1945 | const Event::EventSet EventHandler::StateEvents = { |
1946 | Event::ChangeState, Event::LoadState, Event::SaveState, Event::TimeMachineMode, |
1947 | Event::RewindPause, Event::UnwindPause, Event::ToggleTimeMachine, |
1948 | Event::Rewind1Menu, Event::Rewind10Menu, Event::RewindAllMenu, |
1949 | Event::Unwind1Menu, Event::Unwind10Menu, Event::UnwindAllMenu, |
1950 | Event::SaveAllStates, Event::LoadAllStates, Event::ToggleAutoSlot, |
1951 | }; |
1952 | |
1953 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1954 | const Event::EventSet EventHandler::ConsoleEvents = { |
1955 | Event::ConsoleColor, Event::ConsoleBlackWhite, |
1956 | Event::ConsoleLeftDiffA, Event::ConsoleLeftDiffB, |
1957 | Event::ConsoleRightDiffA, Event::ConsoleRightDiffB, |
1958 | Event::ConsoleSelect, Event::ConsoleReset, |
1959 | Event::ConsoleLeftDiffToggle, Event::ConsoleRightDiffToggle, Event::ConsoleColorToggle, |
1960 | Event::Console7800Pause, |
1961 | }; |
1962 | |
1963 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1964 | const Event::EventSet EventHandler::JoystickEvents = { |
1965 | Event::JoystickZeroUp, Event::JoystickZeroDown, Event::JoystickZeroLeft, Event::JoystickZeroRight, |
1966 | Event::JoystickZeroFire, Event::JoystickZeroFire5, Event::JoystickZeroFire9, |
1967 | Event::JoystickOneUp, Event::JoystickOneDown, Event::JoystickOneLeft, Event::JoystickOneRight, |
1968 | Event::JoystickOneFire, Event::JoystickOneFire5, Event::JoystickOneFire9, |
1969 | }; |
1970 | |
1971 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1972 | const Event::EventSet EventHandler::PaddlesEvents = { |
1973 | Event::PaddleZeroDecrease, Event::PaddleZeroIncrease, Event::PaddleZeroAnalog, Event::PaddleZeroFire, |
1974 | Event::PaddleOneDecrease, Event::PaddleOneIncrease, Event::PaddleOneAnalog, Event::PaddleOneFire, |
1975 | Event::PaddleTwoDecrease, Event::PaddleTwoIncrease, Event::PaddleTwoAnalog, Event::PaddleTwoFire, |
1976 | Event::PaddleThreeDecrease, Event::PaddleThreeIncrease, Event::PaddleThreeAnalog, Event::PaddleThreeFire, |
1977 | }; |
1978 | |
1979 | const Event::EventSet EventHandler::KeyboardEvents = { |
1980 | Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3, |
1981 | Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6, |
1982 | Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9, |
1983 | Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound, |
1984 | |
1985 | Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3, |
1986 | Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6, |
1987 | Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9, |
1988 | Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound, |
1989 | }; |
1990 | |
1991 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1992 | const Event::EventSet EventHandler::ComboEvents = { |
1993 | Event::Combo1, Event::Combo2, Event::Combo3, Event::Combo4, Event::Combo5, Event::Combo6, Event::Combo7, Event::Combo8, |
1994 | Event::Combo9, Event::Combo10, Event::Combo11, Event::Combo12, Event::Combo13, Event::Combo14, Event::Combo15, Event::Combo16, |
1995 | }; |
1996 | |
1997 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1998 | const Event::EventSet EventHandler::DebugEvents = { |
1999 | Event::DebuggerMode, |
2000 | Event::ToggleFrameStats, |
2001 | Event::ToggleP0Collision, Event::ToggleP0Bit, Event::ToggleP1Collision, Event::ToggleP1Bit, |
2002 | Event::ToggleM0Collision, Event::ToggleM0Bit, Event::ToggleM1Collision, Event::ToggleM1Bit, |
2003 | Event::ToggleBLCollision, Event::ToggleBLBit, Event::TogglePFCollision, Event::TogglePFBit, |
2004 | Event::ToggleCollisions, Event::ToggleBits, Event::ToggleFixedColors, |
2005 | Event::ToggleColorLoss, |
2006 | Event::ToggleJitter, |
2007 | }; |
2008 | |