5 #include "keyentry.hpp"
6 #include "coroutine.hpp"
7 #include "moviedata.hpp"
8 #include "memorywatch.hpp"
10 #include "command.hpp"
11 #include "controller.hpp"
12 #include "mainloop.hpp"
13 #include "keymapper.hpp"
17 #include "framerate.hpp"
19 #include "moviedata.hpp"
20 #include "authorseditor.hpp"
21 #include "settingseditor.hpp"
22 #include "axeseditor.hpp"
25 #include <wx/control.h>
26 #include <wx/combobox.h>
27 #include "status_window.hpp"
32 #define UINT64_C(val) val##ULL
34 #include <libswscale/swscale.h>
36 #define STACKSIZE (8 * 1024 * 1024)
37 #define REQ_POLL_JOYSTICK 1
38 #define REQ_KEY_PRESS 2
39 #define REQ_KEY_RELEASE 3
40 #define REQ_CONTINUE 4
43 extern std::string lsnes_version
;
47 wxID_PAUSE
= wxID_HIGHEST
+ 1,
53 wxID_SHOW_AUDIO_STATUS
,
55 wxID_AUDIODEV_LAST
= wxID_AUDIODEV_FIRST
+ 255,
70 wxID_AUTOHOLD_LAST
= wxID_AUTOHOLD_FIRST
+ 127,
73 wxID_EDIT_KEYBINDINGS
,
75 wxID_EDIT_MEMORYWATCH
,
76 wxID_SAVE_MEMORYWATCH
,
77 wxID_LOAD_MEMORYWATCH
,
86 #define MAXCONTROLLERS 8
87 #define CONTROLS_COUNT 16
89 class controller_autohold_menu
: public wxMenu
92 controller_autohold_menu(unsigned lid
, enum devicetype_t dtype
);
93 void change_type(enum devicetype_t dtype
);
95 void on_select(wxCommandEvent
& e
);
96 void update(unsigned pid
, unsigned ctrlnum
, bool newstate
);
100 wxMenuItem
* entries
[CONTROLS_COUNT
];
103 class autohold_menu
: public wxMenu
108 void on_select(wxCommandEvent
& e
);
109 void update(unsigned pid
, unsigned ctrlnum
, bool newstate
);
111 controller_autohold_menu
* menus
[MAXCONTROLLERS
];
112 wxMenuItem
* entries
[MAXCONTROLLERS
];
115 controller_autohold_menu::controller_autohold_menu(unsigned lid
, enum devicetype_t dtype
)
119 for(unsigned i
= 0; i
< CONTROLS_COUNT
; i
++) {
120 int id
= wxID_AUTOHOLD_FIRST
+ CONTROLS_COUNT
* lid
+ i
;
121 entries
[i
] = AppendCheckItem(id
, towxstring(get_button_name(i
)));
126 void controller_autohold_menu::change_type(enum devicetype_t dtype
)
128 int pid
= controller_index_by_logical(our_lid
);
129 for(unsigned i
= 0; i
< CONTROLS_COUNT
; i
++) {
130 int pidx
= get_physcial_id_for_control(dtype
, i
);
132 entries
[i
]->Check(pid
> 0 && get_autohold(pid
, pidx
));
133 entries
[i
]->Enable();
135 entries
[i
]->Check(false);
136 entries
[i
]->Enable(false);
142 bool controller_autohold_menu::is_dummy()
144 return (devtype
== DT_NONE
);
147 void controller_autohold_menu::on_select(wxCommandEvent
& e
)
150 if(x
< wxID_AUTOHOLD_FIRST
+ our_lid
* CONTROLS_COUNT
|| x
>= wxID_AUTOHOLD_FIRST
* (our_lid
+ 1) *
154 unsigned lidx
= (x
- wxID_AUTOHOLD_FIRST
) % CONTROLS_COUNT
;
155 int pidx
= get_physcial_id_for_control(devtype
, lidx
);
156 int pid
= controller_index_by_logical(our_lid
);
157 if(pid
< 0 || pidx
< 0 || !entries
[lidx
]) {
160 //Autohold change on pid=pid, ctrlindx=idx, state
161 bool newstate
= entries
[lidx
]->IsChecked();
162 change_autohold(pid
, pidx
, newstate
);
165 void controller_autohold_menu::update(unsigned pid
, unsigned ctrlnum
, bool newstate
)
167 int pid2
= controller_index_by_logical(our_lid
);
168 if(pid2
< 0 || static_cast<unsigned>(pid
) != pid2
)
170 for(unsigned i
= 0; i
< CONTROLS_COUNT
; i
++) {
171 int idx
= get_physcial_id_for_control(devtype
, i
);
172 if(idx
< 0 || static_cast<unsigned>(idx
) != ctrlnum
)
174 entries
[i
]->Check(newstate
);
178 autohold_menu::autohold_menu()
180 for(unsigned i
= 0; i
< MAXCONTROLLERS
; i
++) {
181 std::ostringstream str
;
182 str
<< "Controller #&" << (i
+ 1);
183 menus
[i
] = new controller_autohold_menu(i
, DT_NONE
);
184 entries
[i
] = AppendSubMenu(menus
[i
], towxstring(str
.str()));
185 entries
[i
]->Enable(!menus
[i
]->is_dummy());
190 void autohold_menu::reconfigure()
192 for(unsigned i
= 0; i
< MAXCONTROLLERS
; i
++) {
193 menus
[i
]->change_type(controller_type_by_logical(i
));
194 entries
[i
]->Enable(!menus
[i
]->is_dummy());
198 void autohold_menu::on_select(wxCommandEvent
& e
)
200 for(unsigned i
= 0; i
< MAXCONTROLLERS
; i
++)
201 menus
[i
]->on_select(e
);
204 void autohold_menu::update(unsigned pid
, unsigned ctrlnum
, bool newstate
)
206 for(unsigned i
= 0; i
< MAXCONTROLLERS
; i
++)
207 menus
[i
]->update(pid
, ctrlnum
, newstate
);
211 class emulator_main_window
;
213 class sound_listener
: public window_callback
216 sound_listener(emulator_main_window
* w
);
217 ~sound_listener() throw();
218 void on_sound_unmute(bool unmute
) throw();
219 void on_sound_change(const std::string
& dev
) throw();
220 void on_mode_change(bool readonly
) throw();
221 void on_autohold_update(unsigned pid
, unsigned ctrlnum
, bool newstate
);
222 void on_autohold_reconfigure();
224 emulator_main_window
* win
;
227 class emulator_main_panel
: public wxPanel
230 emulator_main_panel(wxWindow
* win
);
231 void on_paint(wxPaintEvent
& e
);
232 void on_erase(wxEraseEvent
& e
);
233 void on_keyboard_down(wxKeyEvent
& e
);
234 void on_keyboard_up(wxKeyEvent
& e
);
235 void on_mouse(wxMouseEvent
& e
);
238 class emulator_main_window
: public wxFrame
241 emulator_main_window(const std::string
& name
);
242 ~emulator_main_window();
243 void on_idle(wxIdleEvent
& e
);
244 void on_close(wxCloseEvent
& e
);
245 void menu_pause(wxCommandEvent
& e
);
246 void menu_frameadvance(wxCommandEvent
& e
);
247 void menu_exit(wxCommandEvent
& e
);
248 void menu_subframeadvance(wxCommandEvent
& e
);
249 void menu_nextpoll(wxCommandEvent
& e
);
250 void menu_reset(wxCommandEvent
& e
);
251 void menu_audio_enable(wxCommandEvent
& e
);
252 void menu_audio_status(wxCommandEvent
& e
);
253 void menu_choose_audio_device(wxCommandEvent
& e
);
254 void menu_loadsave(wxCommandEvent
& e
);
255 void menu_scripting(wxCommandEvent
& e
);
256 void menu_readonly(wxCommandEvent
& e
);
257 void menu_edit_authors(wxCommandEvent
& e
);
258 void menu_edit_axes(wxCommandEvent
& e
);
259 void menu_edit_settings(wxCommandEvent
& e
);
260 void menu_edit_keybindings(wxCommandEvent
& e
);
261 void menu_edit_aliases(wxCommandEvent
& e
);
262 void menu_edit_memorywatch(wxCommandEvent
& e
);
263 void menu_load_memorywatch(wxCommandEvent
& e
);
264 void menu_save_memorywatch(wxCommandEvent
& e
);
265 void menu_handle_dump(wxCommandEvent
& e
);
266 void request_paint();
267 wxMenuItem
* sound_enable
;
268 wxMenuItem
* readonly_enable
;
269 autohold_menu
* ahmenu
;
271 emulator_main_panel
* gpanel
;
272 sound_listener
* slistener
;
279 struct modifier_entry
286 { wxMOD_ALT
, "alt", NULL
, NULL
},
287 { wxMOD_CONTROL
, "ctrl", NULL
, NULL
},
288 { wxMOD_SHIFT
, "shift", NULL
, NULL
},
289 { wxMOD_META
, "meta", NULL
, NULL
},
291 { wxMOD_CMD
, "cmd", NULL
, NULL
},
302 { WXK_BACK
, "back", NULL
},
303 { WXK_TAB
, "tab", NULL
},
304 { WXK_RETURN
, "return", NULL
},
305 { WXK_ESCAPE
, "escape", NULL
},
306 { WXK_SPACE
, "space", NULL
},
307 { 33, "exclaim", NULL
},
308 { 34, "quotedbl", NULL
},
309 { 35, "hash", NULL
},
310 { 36, "dollar", NULL
},
311 { 37, "percent", NULL
},
312 { 38, "ampersand", NULL
},
313 { 39, "quote", NULL
},
314 { 40, "leftparen", NULL
},
315 { 41, "rightparen", NULL
},
316 { 42, "asterisk", NULL
},
317 { 43, "plus", NULL
},
318 { 44, "comma", NULL
},
319 { 45, "minus", NULL
},
320 { 46, "period", NULL
},
321 { 47, "slash", NULL
},
332 { 58, "colon", NULL
},
333 { 59, "semicolon", NULL
},
334 { 60, "less", NULL
},
335 { 61, "equals", NULL
},
336 { 62, "greater", NULL
},
337 { 63, "question", NULL
},
365 { 91, "leftbracket", NULL
},
366 { 92, "backslash", NULL
},
367 { 93, "rightbracket", NULL
},
368 { 94, "caret", NULL
},
369 { 95, "underscore", NULL
},
370 { 96, "backquote", NULL
},
397 { 123, "leftcurly", NULL
},
398 { 124, "pipe", NULL
},
399 { 125, "rightcurly", NULL
},
400 { 126, "tilde", NULL
},
401 { WXK_DELETE
, "delete", NULL
},
402 { WXK_START
, "start", NULL
},
403 { WXK_LBUTTON
, "lbutton", NULL
},
404 { WXK_RBUTTON
, "rbutton", NULL
},
405 { WXK_CANCEL
, "cancel", NULL
},
406 { WXK_MBUTTON
, "mbutton", NULL
},
407 { WXK_CLEAR
, "clear", NULL
},
408 { WXK_SHIFT
, "shift", NULL
},
409 { WXK_ALT
, "alt", NULL
},
410 { WXK_CONTROL
, "control", NULL
},
411 { WXK_MENU
, "menu", NULL
},
412 { WXK_PAUSE
, "pause", NULL
},
413 { WXK_CAPITAL
, "capital", NULL
},
414 { WXK_END
, "end", NULL
},
415 { WXK_HOME
, "home", NULL
},
416 { WXK_LEFT
, "lefT", NULL
},
417 { WXK_UP
, "up", NULL
},
418 { WXK_RIGHT
, "right", NULL
},
419 { WXK_DOWN
, "down", NULL
},
420 { WXK_SELECT
, "select", NULL
},
421 { WXK_PRINT
, "print", NULL
},
422 { WXK_EXECUTE
, "execute", NULL
},
423 { WXK_SNAPSHOT
, "snapshot", NULL
},
424 { WXK_INSERT
, "insert", NULL
},
425 { WXK_HELP
, "help", NULL
},
426 { WXK_NUMPAD0
, "numpad0", NULL
},
427 { WXK_NUMPAD1
, "numpad1", NULL
},
428 { WXK_NUMPAD2
, "numpad2", NULL
},
429 { WXK_NUMPAD3
, "numpad3", NULL
},
430 { WXK_NUMPAD4
, "numpad4", NULL
},
431 { WXK_NUMPAD5
, "numpad5", NULL
},
432 { WXK_NUMPAD6
, "numpad6", NULL
},
433 { WXK_NUMPAD7
, "numpad7", NULL
},
434 { WXK_NUMPAD8
, "numpad8", NULL
},
435 { WXK_NUMPAD9
, "numpad9", NULL
},
436 { WXK_MULTIPLY
, "multiply", NULL
},
437 { WXK_ADD
, "add", NULL
},
438 { WXK_SEPARATOR
, "separator", NULL
},
439 { WXK_SUBTRACT
, "subtract", NULL
},
440 { WXK_DECIMAL
, "decimal", NULL
},
441 { WXK_DIVIDE
, "divide", NULL
},
442 { WXK_F1
, "f1", NULL
},
443 { WXK_F2
, "f2", NULL
},
444 { WXK_F3
, "f3", NULL
},
445 { WXK_F4
, "f4", NULL
},
446 { WXK_F5
, "f5", NULL
},
447 { WXK_F6
, "f6", NULL
},
448 { WXK_F7
, "f7", NULL
},
449 { WXK_F8
, "f8", NULL
},
450 { WXK_F9
, "f9", NULL
},
451 { WXK_F10
, "f10", NULL
},
452 { WXK_F11
, "f11", NULL
},
453 { WXK_F12
, "f12", NULL
},
454 { WXK_F13
, "f13", NULL
},
455 { WXK_F14
, "f14", NULL
},
456 { WXK_F15
, "f15", NULL
},
457 { WXK_F16
, "f16", NULL
},
458 { WXK_F17
, "f17", NULL
},
459 { WXK_F18
, "f18", NULL
},
460 { WXK_F19
, "f19", NULL
},
461 { WXK_F20
, "f20", NULL
},
462 { WXK_F21
, "f21", NULL
},
463 { WXK_F22
, "f22", NULL
},
464 { WXK_F23
, "f23", NULL
},
465 { WXK_F24
, "f24", NULL
},
466 { WXK_NUMLOCK
, "numlock", NULL
},
467 { WXK_SCROLL
, "scroll", NULL
},
468 { WXK_PAGEUP
, "pageup", NULL
},
469 { WXK_PAGEDOWN
, "pagedown", NULL
},
470 { WXK_NUMPAD_SPACE
, "numpad_space", NULL
},
471 { WXK_NUMPAD_TAB
, "numpad_tab", NULL
},
472 { WXK_NUMPAD_ENTER
, "numpad_enter", NULL
},
473 { WXK_NUMPAD_F1
, "numpad_f1", NULL
},
474 { WXK_NUMPAD_F2
, "numpad_f2", NULL
},
475 { WXK_NUMPAD_F3
, "numpad_f3", NULL
},
476 { WXK_NUMPAD_F4
, "numpad_f4", NULL
},
477 { WXK_NUMPAD_HOME
, "numpad_home", NULL
},
478 { WXK_NUMPAD_LEFT
, "numpad_left", NULL
},
479 { WXK_NUMPAD_UP
, "numpad_up", NULL
},
480 { WXK_NUMPAD_RIGHT
, "numpad_right", NULL
},
481 { WXK_NUMPAD_DOWN
, "numpad_down", NULL
},
482 { WXK_NUMPAD_PAGEUP
, "numpad_pageup", NULL
},
483 { WXK_NUMPAD_PAGEDOWN
, "numpad_pagedown", NULL
},
484 { WXK_NUMPAD_END
, "numpad_end", NULL
},
485 { WXK_NUMPAD_BEGIN
, "numpad_begin", NULL
},
486 { WXK_NUMPAD_INSERT
, "numpad_insert", NULL
},
487 { WXK_NUMPAD_DELETE
, "numpad_delete", NULL
},
488 { WXK_NUMPAD_EQUAL
, "numpad_equal", NULL
},
489 { WXK_NUMPAD_MULTIPLY
, "numpad_multiply", NULL
},
490 { WXK_NUMPAD_ADD
, "numpad_add", NULL
},
491 { WXK_NUMPAD_SEPARATOR
, "numpad_separator", NULL
},
492 { WXK_NUMPAD_SUBTRACT
, "numpad_subtract", NULL
},
493 { WXK_NUMPAD_DECIMAL
, "numpad_decimal", NULL
},
494 { WXK_NUMPAD_DIVIDE
, "numpad_divide", NULL
},
495 { WXK_WINDOWS_LEFT
, "windows_left", NULL
},
496 { WXK_WINDOWS_RIGHT
, "windows_right", NULL
},
497 { WXK_WINDOWS_MENU
, "windows_menu", NULL
},
498 { WXK_COMMAND
, "command", NULL
},
499 { WXK_SPECIAL1
, "special1", NULL
},
500 { WXK_SPECIAL2
, "special2", NULL
},
501 { WXK_SPECIAL3
, "special3", NULL
},
502 { WXK_SPECIAL4
, "special4", NULL
},
503 { WXK_SPECIAL5
, "special5", NULL
},
504 { WXK_SPECIAL6
, "special6", NULL
},
505 { WXK_SPECIAL7
, "special7", NULL
},
506 { WXK_SPECIAL8
, "special8", NULL
},
507 { WXK_SPECIAL9
, "special9", NULL
},
508 { WXK_SPECIAL10
, "special10", NULL
},
509 { WXK_SPECIAL11
, "special11", NULL
},
510 { WXK_SPECIAL12
, "special12", NULL
},
511 { WXK_SPECIAL13
, "special13", NULL
},
512 { WXK_SPECIAL14
, "special14", NULL
},
513 { WXK_SPECIAL15
, "special15", NULL
},
514 { WXK_SPECIAL16
, "special16", NULL
},
515 { WXK_SPECIAL17
, "special17", NULL
},
516 { WXK_SPECIAL18
, "special18", NULL
},
517 { WXK_SPECIAL19
, "special19", NULL
},
518 { WXK_SPECIAL20
, "special20", NULL
},
522 std::map
<int, modifier
*> modifier_map
;
523 std::map
<int, keygroup
*> key_map
;
524 std::map
<std::string
, int> keys_allocated
;
525 std::set
<int> keys_held
;
527 void init_modifiers_and_keys()
529 static bool done
= false;
532 modifier_entry
* m
= modifiers
;
535 m
->allocated
= new modifier(m
->name
, m
->lname
);
537 m
->allocated
= new modifier(m
->name
);
538 modifier_map
[m
->mod
] = m
->allocated
;
543 if(!keys_allocated
.count(k
->name
)) {
544 k
->allocated
= new keygroup(k
->name
, keygroup::KT_KEY
);
545 key_map
[k
->keynum
] = k
->allocated
;
546 keys_allocated
[k
->name
] = k
->keynum
;
548 key_map
[k
->keynum
] = key_map
[keys_allocated
[k
->name
]];
554 //The coroutine emulator itself runs in.
556 emulator_main_window
* main_window
= NULL
;
558 struct emulator_boot_state
564 void emulator_bootup_fn(void* state
)
567 struct emulator_boot_state
* boot_state
= reinterpret_cast<struct emulator_boot_state
*>(state
);
568 main_loop(*boot_state
->rom
, *boot_state
->movie
);
569 } catch(std::bad_alloc
& e
) {
571 } catch(std::exception
& e
) {
572 messages
<< "FATAL: " << e
.what() << std::endl
;
580 auto& emustatus
= window::get_emustatus();
582 std::ostringstream y
;
583 y
<< get_framerate();
584 emustatus
["FPS"] = y
.str();
589 //Set to true if the emulator is in paused mode.
590 volatile bool e_paused
;
591 //Set to true if the emulator is in waiting mode. wait_until is set to get_utime() time when emulator is
593 volatile bool waiting
;
594 volatile uint64_t wait_until
;
595 //Set to true if the screen needs updating. screen_updated_full is set if update needs to be full.
596 volatile bool screen_updated
;
597 volatile bool screen_updated_full
;
598 //The backrequest type.
599 volatile int request
;
600 //The modifier_set and the key (for REQ_KEY_PRESS and REQ_KEY_RELEASE).
601 modifier_set keypress_modifiers
;
602 keygroup
* presed_key
;
603 //Command to send (for REQ_COMMAND).
604 std::string pending_command
;
607 unsigned char* screen_buffer
;
608 uint32_t old_width
= 0;
609 uint32_t old_height
= 0;
610 //Message queue (undisplayed messages), and last message.
611 bool messages_need_painting
;
612 std::string last_message
;
613 //In modal dialog flag.
614 bool in_modal_dialog
;
616 bool main_window_dirty
= false;
618 std::map
<int, std::string
> audio_devs
;
619 std::map
<int, wxMenuItem
*> audio_devitems
;
621 void handle_idle(wxIdleEvent
& e
)
623 if(!emu_cr
|| in_modal_dialog
) {
628 request
= REQ_POLL_JOYSTICK
;
630 if(e_paused
|| (waiting
&& wait_until
> get_utime())) {
637 request
= REQ_CONTINUE
;
638 uint64_t exec_start
= get_utime();
641 if(emu_cr
->is_dead()) {
650 main_window
->Destroy();
653 if(get_utime() < exec_start
+ 10000 && !e_paused
&& !waiting
)
659 //Request keypress event to happen.
660 void do_keypress(modifier_set mods
, keygroup
& key
, bool polarity
)
664 keypress_modifiers
= mods
;
666 request
= polarity
? REQ_KEY_PRESS
: REQ_KEY_RELEASE
;
670 void handle_wx_keyboard(wxKeyEvent
& e
, bool polarity
)
672 int mods
= e
.GetModifiers();
673 int keyc
= e
.GetKeyCode();
675 modifier_entry
* m
= modifiers
;
677 if((keyc
& m
->mod
) == m
->mod
) {
678 mset
.add(*m
->allocated
);
683 if(keys_held
.count(keyc
)) {
687 keys_held
.insert(keyc
);
689 keys_held
.erase(keyc
);
691 keygroup
* grp
= NULL
;
693 if(k
->keynum
== keyc
) {
700 do_keypress(mset
, *grp
, polarity
);
704 void handle_wx_mouse(wxMouseEvent
& e
)
706 static uint32_t mask
= 0;
719 window_callback::do_click(e
.GetX(), e
.GetY(), mask
);
723 void emulator_main_panel::on_keyboard_down(wxKeyEvent
& e
)
725 handle_wx_keyboard(e
, true);
728 void emulator_main_panel::on_keyboard_up(wxKeyEvent
& e
)
730 handle_wx_keyboard(e
, false);
733 void emulator_main_panel::on_mouse(wxMouseEvent
& e
)
739 emulator_main_panel::emulator_main_panel(wxWindow
* win
)
742 this->Connect(wxEVT_PAINT
, wxPaintEventHandler(emulator_main_panel::on_paint
), NULL
, this);
743 this->Connect(wxEVT_ERASE_BACKGROUND
, wxEraseEventHandler(emulator_main_panel::on_erase
), NULL
, this);
744 this->Connect(wxEVT_KEY_DOWN
, wxKeyEventHandler(emulator_main_panel::on_keyboard_down
), NULL
, this);
745 this->Connect(wxEVT_KEY_UP
, wxKeyEventHandler(emulator_main_panel::on_keyboard_up
), NULL
, this);
746 this->Connect(wxEVT_LEFT_DOWN
, wxMouseEventHandler(emulator_main_panel::on_mouse
), NULL
, this);
747 this->Connect(wxEVT_LEFT_UP
, wxMouseEventHandler(emulator_main_panel::on_mouse
), NULL
, this);
748 this->Connect(wxEVT_MIDDLE_DOWN
, wxMouseEventHandler(emulator_main_panel::on_mouse
), NULL
, this);
749 this->Connect(wxEVT_MIDDLE_UP
, wxMouseEventHandler(emulator_main_panel::on_mouse
), NULL
, this);
750 this->Connect(wxEVT_RIGHT_DOWN
, wxMouseEventHandler(emulator_main_panel::on_mouse
), NULL
, this);
751 this->Connect(wxEVT_RIGHT_UP
, wxMouseEventHandler(emulator_main_panel::on_mouse
), NULL
, this);
752 SetMinSize(wxSize(512, 448));
755 void emulator_main_panel::on_paint(wxPaintEvent
& e
)
757 static struct SwsContext
* ctx
;
765 if(main_screen
->width
!= old_width
|| main_screen
->height
!= old_height
) {
766 delete[] screen_buffer
;
767 screen_buffer
= new unsigned char[main_screen
->width
* main_screen
->height
* 3];
768 old_height
= main_screen
->height
;
769 old_width
= main_screen
->width
;
770 uint32_t w
= main_screen
->width
;
771 uint32_t h
= main_screen
->height
;
772 ctx
= sws_getCachedContext(ctx
, w
, h
, PIX_FMT_RGBA
, w
, h
, PIX_FMT_BGR24
, SWS_POINT
|
773 SWS_CPU_CAPS_MMX2
, NULL
, NULL
, NULL
);
778 SetMinSize(wxSize(w
, h
));
780 srcs
[0] = 4 * main_screen
->width
;
781 dsts
[0] = 3 * main_screen
->width
;
782 srcp
[0] = reinterpret_cast<unsigned char*>(main_screen
->memory
);
783 dstp
[0] = screen_buffer
;
784 memset(screen_buffer
, 0, main_screen
->width
* main_screen
->height
* 3);
785 uint64_t t1
= get_utime();
786 sws_scale(ctx
, srcp
, srcs
, 0, main_screen
->height
, dstp
, dsts
);
787 uint64_t t2
= get_utime();
788 wxBitmap
bmp(wxImage(main_screen
->width
, main_screen
->height
, screen_buffer
, true));
789 uint64_t t3
= get_utime();
790 dc
.DrawBitmap(bmp
, 0, 0, false);
791 main_window_dirty
= false;
794 void emulator_main_panel::on_erase(wxEraseEvent
& e
)
798 emulator_main_window::emulator_main_window(const std::string
& name
)
799 : wxFrame(NULL
, wxID_ANY
, towxstring(name
), wxDefaultPosition
, wxSize(-1, -1), primary_window_style
)
802 wxFlexGridSizer
* top_s
= new wxFlexGridSizer(1, 1, 0, 0);
803 top_s
->Add(gpanel
= new emulator_main_panel(this), 1, wxGROW
);
804 top_s
->SetSizeHints(this);
807 Connect(wxEVT_IDLE
, wxIdleEventHandler(emulator_main_window::on_idle
));
808 Connect(wxEVT_CLOSE_WINDOW
, wxCloseEventHandler(emulator_main_window::on_close
));
810 event
.SetEventObject(this);
811 AddPendingEvent(event
);
814 wxMenuBar
* menubar
= new wxMenuBar
;
815 wxMenu
* system
= new wxMenu
;
816 wxMenu
* sound
= new wxMenu
;
817 wxMenu
* file
= new wxMenu
;
818 wxMenu
* scripting
= new wxMenu
;
819 wxMenu
* settings
= new wxMenu
;
820 wxMenu
* dump
= new wxMenu
;
821 ahmenu
= new autohold_menu();
823 //Main menubar: ACFOS
824 menubar
->Append(system
, wxT("&System"));
825 menubar
->Append(file
, wxT("&File"));
826 menubar
->Append(ahmenu
, wxT("&Autohold"));
827 menubar
->Append(scripting
, wxT("S&cripting"));
828 menubar
->Append(settings
, wxT("Settings"));
829 if(window::sound_initialized())
830 menubar
->Append(sound
, wxT("S&ound"));
831 //System menu: EMNPQRU
832 system
->Append(wxID_FRAMEADVANCE
, wxT("Fra&me advance"));
833 system
->Append(wxID_SUBFRAMEADVANCE
, wxT("S&ubframe advance"));
834 system
->Append(wxID_NEXTPOLL
, wxT("&Next poll"));
835 system
->Append(wxID_PAUSE
, wxT("&Pause/Unpause"));
836 system
->AppendSeparator();
837 system
->Append(wxID_ERESET
, wxT("&Reset"));
838 system
->AppendSeparator();
839 system
->Append(wxID_EDIT_AUTHORS
, wxT("&Edit game name && authors"));
840 system
->AppendSeparator();
841 system
->Append(wxID_EXIT
, wxT("&Quit"));
842 //File menu: DELMNPRTV
843 readonly_enable
= file
->AppendCheckItem(wxID_READONLY_MODE
, wxT("Reado&nly mode"));
844 readonly_enable
->Check(movb
.get_movie().readonly_mode());
845 file
->AppendSeparator();
846 file
->Append(wxID_SAVE_STATE
, wxT("Save stat&e"));
847 file
->Append(wxID_SAVE_MOVIE
, wxT("Sa&ve movie"));
848 file
->AppendSeparator();
849 file
->Append(wxID_LOAD_STATE
, wxT("&Load state"));
850 file
->Append(wxID_LOAD_STATE_RO
, wxT("Loa&d state (readonly)"));
851 file
->Append(wxID_LOAD_STATE_RW
, wxT("Load s&tate (read-write)"));
852 file
->Append(wxID_LOAD_STATE_P
, wxT("Load state (&preserve)"));
853 file
->Append(wxID_LOAD_MOVIE
, wxT("Load &movie"));
854 file
->AppendSeparator();
855 file
->Append(wxID_SAVE_SCREENSHOT
, wxT("Save sc&reenshot"));
856 file
->AppendSeparator();
857 file
->AppendSubMenu(dump
, wxT("Video dump"));
858 dump
->Append(wxID_DUMP_AVICSCD
, wxT("Dump AVI(CSCD)"));
859 dump
->Append(wxID_END_AVICSCD
, wxT("End AVI(CSCD) dump"));
860 dump
->AppendSeparator();
861 dump
->Append(wxID_DUMP_JMD
, wxT("Dump JMD"));
862 dump
->Append(wxID_END_JMD
, wxT("End JMD dump"));
863 dump
->AppendSeparator();
864 dump
->Append(wxID_DUMP_SDMP
, wxT("Dump SDMP"));
865 dump
->Append(wxID_END_SDMP
, wxT("End SDMP dump"));
866 //Scripting menu: ERU
867 scripting
->Append(wxID_RUN_SCRIPT
, wxT("&Run script"));
869 scripting
->AppendSeparator();
870 scripting
->Append(wxID_EVAL_LUA
, wxT("&Evaluate Lua statement"));
871 scripting
->Append(wxID_RUN_LUA
, wxT("R&un Lua script"));
873 scripting
->AppendSeparator();
874 scripting
->Append(wxID_EDIT_MEMORYWATCH
, wxT("Edit memory watch"));
875 scripting
->AppendSeparator();
876 scripting
->Append(wxID_LOAD_MEMORYWATCH
, wxT("Load memory watch"));
877 scripting
->Append(wxID_SAVE_MEMORYWATCH
, wxT("Save memory watch"));
879 settings
->Append(wxID_EDIT_AXES
, wxT("Configure axes"));
880 settings
->Append(wxID_EDIT_SETTINGS
, wxT("Configure settings"));
881 settings
->Append(wxID_EDIT_KEYBINDINGS
, wxT("Configure keybindings"));
882 settings
->Append(wxID_EDIT_ALIAS
, wxT("Configure aliases"));
885 if(window::sound_initialized()) {
886 slistener
= new sound_listener(this);
887 sound_enable
= sound
->AppendCheckItem(wxID_AUDIO_ENABLED
, wxT("So&unds enabled"));
888 sound_enable
->Check(window::is_sound_enabled());
889 sound
->Append(wxID_SHOW_AUDIO_STATUS
, wxT("Show audio status"));
890 sound
->AppendSeparator();
891 int j
= wxID_AUDIODEV_FIRST
;
892 std::string curdev
= window::get_current_sound_device();
893 for(auto i
: window::get_sound_devices()) {
894 audio_devitems
[j
] = sound
->AppendRadioItem(j
, towxstring(i
.first
+ "(" + i
.second
+ ")"));
895 audio_devs
[j
] = i
.first
;
896 if(i
.first
== curdev
)
897 audio_devitems
[j
]->Check();
902 menu_action(this, wxID_PAUSE
, &emulator_main_window::menu_pause
);
903 menu_action(this, wxID_FRAMEADVANCE
, &emulator_main_window::menu_frameadvance
);
904 menu_action(this, wxID_SUBFRAMEADVANCE
, &emulator_main_window::menu_subframeadvance
);
905 menu_action(this, wxID_NEXTPOLL
, &emulator_main_window::menu_nextpoll
);
906 menu_action(this, wxID_ERESET
, &emulator_main_window::menu_reset
);
907 menu_action(this, wxID_EXIT
, &emulator_main_window::menu_exit
);
908 menu_action(this, wxID_READONLY_MODE
, &emulator_main_window::menu_readonly
);
909 menu_action(this, wxID_SAVE_STATE
, &emulator_main_window::menu_loadsave
);
910 menu_action(this, wxID_SAVE_MOVIE
, &emulator_main_window::menu_loadsave
);
911 menu_action(this, wxID_LOAD_STATE
, &emulator_main_window::menu_loadsave
);
912 menu_action(this, wxID_LOAD_STATE_RO
, &emulator_main_window::menu_loadsave
);
913 menu_action(this, wxID_LOAD_STATE_RW
, &emulator_main_window::menu_loadsave
);
914 menu_action(this, wxID_LOAD_STATE_P
, &emulator_main_window::menu_loadsave
);
915 menu_action(this, wxID_LOAD_MOVIE
, &emulator_main_window::menu_loadsave
);
916 menu_action(this, wxID_SAVE_SCREENSHOT
, &emulator_main_window::menu_loadsave
);
917 menu_action(this, wxID_DUMP_AVICSCD
, &emulator_main_window::menu_handle_dump
);
918 menu_action(this, wxID_DUMP_JMD
, &emulator_main_window::menu_handle_dump
);
919 menu_action(this, wxID_DUMP_SDMP
, &emulator_main_window::menu_handle_dump
);
920 menu_action(this, wxID_END_AVICSCD
, &emulator_main_window::menu_handle_dump
);
921 menu_action(this, wxID_END_JMD
, &emulator_main_window::menu_handle_dump
);
922 menu_action(this, wxID_END_SDMP
, &emulator_main_window::menu_handle_dump
);
923 menu_action(this, wxID_RUN_SCRIPT
, &emulator_main_window::menu_scripting
);
924 menu_action(this, wxID_EDIT_AUTHORS
, &emulator_main_window::menu_edit_authors
);
925 Connect(wxID_AUTOHOLD_FIRST
, wxID_AUTOHOLD_LAST
, wxEVT_COMMAND_MENU_SELECTED
,
926 wxCommandEventHandler(autohold_menu::on_select
), NULL
, ahmenu
);
928 menu_action(this, wxID_EVAL_LUA
, &emulator_main_window::menu_scripting
);
929 menu_action(this, wxID_RUN_LUA
, &emulator_main_window::menu_scripting
);
931 menu_action(this, wxID_EDIT_MEMORYWATCH
, &emulator_main_window::menu_edit_memorywatch
);
932 menu_action(this, wxID_LOAD_MEMORYWATCH
, &emulator_main_window::menu_load_memorywatch
);
933 menu_action(this, wxID_SAVE_MEMORYWATCH
, &emulator_main_window::menu_save_memorywatch
);
934 menu_action(this, wxID_EDIT_AXES
, &emulator_main_window::menu_edit_axes
);
935 menu_action(this, wxID_EDIT_SETTINGS
, &emulator_main_window::menu_edit_settings
);
936 menu_action(this, wxID_EDIT_KEYBINDINGS
, &emulator_main_window::menu_edit_keybindings
);
937 menu_action(this, wxID_EDIT_ALIAS
, &emulator_main_window::menu_edit_aliases
);
938 if(window::sound_initialized()) {
939 menu_action(this, wxID_AUDIO_ENABLED
, &emulator_main_window::menu_audio_enable
);
940 menu_action(this, wxID_SHOW_AUDIO_STATUS
, &emulator_main_window::menu_audio_status
);
941 for(auto i
: audio_devs
)
942 menu_action(this, i
.first
, &emulator_main_window::menu_choose_audio_device
);
946 emulator_main_window::~emulator_main_window()
951 void emulator_main_window::request_paint()
956 void emulator_main_window::on_idle(wxIdleEvent
& e
)
961 void emulator_main_window::on_close(wxCloseEvent
& e
)
963 //Veto it for now, latter things will delete it.
965 exec_command("quit-emulator");
968 void emulator_main_window::menu_pause(wxCommandEvent
& e
)
970 exec_command("pause-emulator");
973 void emulator_main_window::menu_frameadvance(wxCommandEvent
& e
)
975 exec_command("+advance-frame");
976 exec_command("-advance-frame");
979 void emulator_main_window::menu_subframeadvance(wxCommandEvent
& e
)
981 exec_command("+advance-poll");
982 exec_command("-advance-poll");
985 void emulator_main_window::menu_nextpoll(wxCommandEvent
& e
)
987 exec_command("advance-skiplag");
990 void emulator_main_window::menu_reset(wxCommandEvent
& e
)
992 exec_command("reset");
995 void emulator_main_window::menu_exit(wxCommandEvent
& e
)
997 exec_command("quit-emulator");
1000 void emulator_main_window::menu_audio_enable(wxCommandEvent
& e
)
1002 window::sound_enable(sound_enable
->IsChecked());
1005 void emulator_main_window::menu_readonly(wxCommandEvent
& e
)
1007 bool s
= readonly_enable
->IsChecked();
1008 movb
.get_movie().readonly_mode(s
);
1010 lua_callback_do_readwrite();
1011 update_movie_state();
1012 window::notify_screen_update();
1015 void emulator_main_window::menu_edit_authors(wxCommandEvent
& e
)
1017 wxDialog
* editor
= new wx_authors_editor(this);
1018 editor
->ShowModal();
1022 void emulator_main_window::menu_edit_axes(wxCommandEvent
& e
)
1024 wxDialog
* editor
= new wx_axes_editor(this);
1025 editor
->ShowModal();
1029 void emulator_main_window::menu_edit_settings(wxCommandEvent
& e
)
1031 wxDialog
* editor
= new wx_settings_editor(this);
1032 editor
->ShowModal();
1036 #define NEW_KEYBINDING "A new binding..."
1037 #define NEW_ALIAS "A new alias..."
1038 #define NEW_WATCH "A new watch..."
1040 void emulator_main_window::menu_edit_keybindings(wxCommandEvent
& e
)
1042 std::set
<std::string
> bind
= keymapper::get_bindings();
1043 std::vector
<wxString
> choices
;
1044 choices
.push_back(wxT(NEW_KEYBINDING
));
1046 choices
.push_back(towxstring(i
));
1047 wxSingleChoiceDialog
* d
= new wxSingleChoiceDialog(this, wxT("Select keybinding to edit"),
1048 wxT("Select binding"), choices
.size(), &choices
[0]);
1049 if(d
->ShowModal() == wxID_CANCEL
) {
1053 std::string key
= tostdstring(d
->GetStringSelection());
1055 if(key
== NEW_KEYBINDING
) {
1056 wx_key_entry
* d2
= new wx_key_entry(this);
1057 //wxTextEntryDialog* d2 = new wxTextEntryDialog(this, wxT("Enter key for binding:"),
1058 // wxT("Edit binding"), wxT(""));
1059 if(d2
->ShowModal() == wxID_CANCEL
) {
1064 //key = tostdstring(d2->GetValue());
1067 std::string old_command_value
= keymapper::get_command_for(key
);
1068 wxTextEntryDialog
* d4
= new wxTextEntryDialog(this, wxT("Enter new command for binding:"), wxT("Edit binding"),
1069 towxstring(old_command_value
));
1070 if(d4
->ShowModal() == wxID_CANCEL
) {
1075 keymapper::bind_for(key
, tostdstring(d4
->GetValue()));
1076 } catch(std::exception
& e
) {
1077 wxMessageDialog
* d3
= new wxMessageDialog(this, towxstring(std::string("Can't bind key: ") +
1078 e
.what()), wxT("Error"), wxOK
| wxICON_EXCLAMATION
);
1085 void emulator_main_window::menu_edit_aliases(wxCommandEvent
& e
)
1087 std::set
<std::string
> bind
= command::get_aliases();
1088 std::vector
<wxString
> choices
;
1089 choices
.push_back(wxT(NEW_ALIAS
));
1091 choices
.push_back(towxstring(i
));
1092 wxSingleChoiceDialog
* d
= new wxSingleChoiceDialog(this, wxT("Select alias to edit"),
1093 wxT("Select alias"), choices
.size(), &choices
[0]);
1094 if(d
->ShowModal() == wxID_CANCEL
) {
1098 std::string alias
= tostdstring(d
->GetStringSelection());
1100 if(alias
== NEW_ALIAS
) {
1101 wxTextEntryDialog
* d2
= new wxTextEntryDialog(this, wxT("Enter name for the new alias:"),
1102 wxT("Enter alias name"));
1103 if(d2
->ShowModal() == wxID_CANCEL
) {
1107 alias
= tostdstring(d2
->GetValue());
1109 if(!command::valid_alias_name(alias
)) {
1110 wxMessageDialog
* d3
= new wxMessageDialog(this, towxstring(std::string("Not a valid alias "
1111 "name: ") + alias
), wxT("Error"), wxOK
| wxICON_EXCLAMATION
);
1117 std::string old_alias_value
= command::get_alias_for(alias
);
1118 wxTextEntryDialog
* d4
= new wxTextEntryDialog(this, wxT("Enter new commands for alias:"), wxT("Edit alias"),
1119 towxstring(old_alias_value
), wxOK
| wxCANCEL
| wxCENTRE
| wxTE_MULTILINE
);
1120 if(d4
->ShowModal() == wxID_CANCEL
) {
1124 command::set_alias_for(alias
, tostdstring(d4
->GetValue()));
1128 void emulator_main_window::menu_load_memorywatch(wxCommandEvent
& e
)
1130 std::set
<std::string
> old_watches
= get_watches();
1131 std::map
<std::string
, std::string
> new_watches
;
1132 std::string filename
;
1134 wxFileDialog
* d
= new wxFileDialog(this, towxstring("Choose memory watch file"), wxT("."));
1135 if(d
->ShowModal() == wxID_CANCEL
) {
1139 filename
= tostdstring(d
->GetPath());
1141 //Did we pick a .zip file?
1143 zip_reader
zr(filename
);
1144 std::vector
<wxString
> files
;
1146 files
.push_back(towxstring(i
));
1147 wxSingleChoiceDialog
* d2
= new wxSingleChoiceDialog(this, wxT("Select file within .zip"),
1148 wxT("Select member"), files
.size(), &files
[0]);
1149 if(d2
->ShowModal() == wxID_CANCEL
) {
1153 filename
= filename
+ "/" + tostdstring(d2
->GetStringSelection());
1160 std::istream
& in
= open_file_relative(filename
, "");
1164 std::getline(in
, wname
);
1165 std::getline(in
, wexpr
);
1166 new_watches
[wname
] = wexpr
;
1169 } catch(std::exception
& e
) {
1170 wxMessageDialog
* d3
= new wxMessageDialog(this, towxstring(std::string("Can't load memory "
1171 "watch: ") + e
.what()), wxT("Error"), wxOK
| wxICON_EXCLAMATION
);
1176 for(auto i
: new_watches
)
1177 set_watchexpr_for(i
.first
, i
.second
);
1178 for(auto i
: old_watches
)
1179 if(!new_watches
.count(i
))
1180 set_watchexpr_for(i
, "");
1183 void emulator_main_window::menu_save_memorywatch(wxCommandEvent
& e
)
1185 std::set
<std::string
> old_watches
= get_watches();
1186 std::string filename
;
1188 wxFileDialog
* d
= new wxFileDialog(this, towxstring("Save watches to file"), wxT("."));
1189 if(d
->ShowModal() == wxID_CANCEL
) {
1193 filename
= tostdstring(d
->GetPath());
1196 std::ofstream
out(filename
.c_str());
1197 for(auto i
: old_watches
)
1198 out
<< i
<< std::endl
<< get_watchexpr_for(i
) << std::endl
;
1203 void emulator_main_window::menu_edit_memorywatch(wxCommandEvent
& e
)
1205 std::set
<std::string
> bind
= get_watches();
1206 std::vector
<wxString
> choices
;
1207 choices
.push_back(wxT(NEW_WATCH
));
1209 choices
.push_back(towxstring(i
));
1210 wxSingleChoiceDialog
* d
= new wxSingleChoiceDialog(this, wxT("Select watch to edit"),
1211 wxT("Select watch"), choices
.size(), &choices
[0]);
1212 if(d
->ShowModal() == wxID_CANCEL
) {
1216 std::string watch
= tostdstring(d
->GetStringSelection());
1218 if(watch
== NEW_WATCH
) {
1219 wxTextEntryDialog
* d2
= new wxTextEntryDialog(this, wxT("Enter name for the new watch:"),
1220 wxT("Enter watch name"));
1221 if(d2
->ShowModal() == wxID_CANCEL
) {
1225 watch
= tostdstring(d2
->GetValue());
1228 std::string old_watch_value
= get_watchexpr_for(watch
);
1229 wxTextEntryDialog
* d4
= new wxTextEntryDialog(this, wxT("Enter new expression for watch:"), wxT("Edit watch"),
1230 towxstring(old_watch_value
), wxOK
| wxCANCEL
| wxCENTRE
);
1231 if(d4
->ShowModal() == wxID_CANCEL
) {
1235 set_watchexpr_for(watch
, tostdstring(d4
->GetValue()));
1239 void emulator_main_window::menu_handle_dump(wxCommandEvent
& e
)
1241 wxString choices
[19];
1242 size_t choice_count
= 0;
1244 case wxID_END_AVICSCD
:
1245 exec_command("end-avi");
1248 exec_command("end-jmd");
1251 exec_command("end-sdmp");
1256 bool is_prefix
= false;
1257 bool has_level
= false;
1259 std::string caption
;
1262 case wxID_DUMP_AVICSCD
:
1263 choices
[choice_count
++] = wxT("Compression Level 0 intraframe-only");
1264 choices
[choice_count
++] = wxT("Compression Level 1 intraframe-only");
1265 choices
[choice_count
++] = wxT("Compression Level 2 intraframe-only");
1266 choices
[choice_count
++] = wxT("Compression Level 3 intraframe-only");
1267 choices
[choice_count
++] = wxT("Compression Level 4 intraframe-only");
1268 choices
[choice_count
++] = wxT("Compression Level 5 intraframe-only");
1269 choices
[choice_count
++] = wxT("Compression Level 6 intraframe-only");
1270 choices
[choice_count
++] = wxT("Compression Level 7 intraframe-only");
1271 choices
[choice_count
++] = wxT("Compression Level 8 intraframe-only");
1272 choices
[choice_count
++] = wxT("Compression Level 9 intraframe-only");
1273 choices
[choice_count
++] = wxT("Compression Level 1");
1274 choices
[choice_count
++] = wxT("Compression Level 2");
1275 choices
[choice_count
++] = wxT("Compression Level 3");
1276 choices
[choice_count
++] = wxT("Compression Level 4");
1277 choices
[choice_count
++] = wxT("Compression Level 5");
1278 choices
[choice_count
++] = wxT("Compression Level 6");
1279 choices
[choice_count
++] = wxT("Compression Level 7");
1280 choices
[choice_count
++] = wxT("Compression Level 8");
1281 choices
[choice_count
++] = wxT("Compression Level 9");
1282 msg
= "Choose CSCD compression level: ";
1283 caption
= "AVI(CSCD) dump";
1289 choices
[choice_count
++] = wxT("Compression Level 0");
1290 choices
[choice_count
++] = wxT("Compression Level 1");
1291 choices
[choice_count
++] = wxT("Compression Level 2");
1292 choices
[choice_count
++] = wxT("Compression Level 3");
1293 choices
[choice_count
++] = wxT("Compression Level 4");
1294 choices
[choice_count
++] = wxT("Compression Level 5");
1295 choices
[choice_count
++] = wxT("Compression Level 6");
1296 choices
[choice_count
++] = wxT("Compression Level 7");
1297 choices
[choice_count
++] = wxT("Compression Level 8");
1298 choices
[choice_count
++] = wxT("Compression Level 9");
1299 msg
= "Choose JMD compression level: ";
1300 caption
= "JMD dump";
1305 case wxID_DUMP_SDMP
:
1306 choices
[choice_count
++] = wxT("Segmented");
1307 choices
[choice_count
++] = wxT("Single segment");
1308 msg
= "Choose SDMP settings: ";
1309 caption
= "SDMP dump";
1311 cmd
= "dump-sdmpss";
1315 wxSingleChoiceDialog
* d
= new wxSingleChoiceDialog(this, towxstring(msg
), towxstring(caption
), choice_count
,
1317 if(d
->ShowModal() == wxID_CANCEL
) {
1321 int choice
= d
->GetSelection();
1322 if(e
.GetId() == wxID_DUMP_SDMP
&& choice
== 0) {
1329 wxFileDialog
* d2
= new wxFileDialog(this, is_prefix
? wxT("Dump prefix") : wxT("Dump file"), wxT("."));
1330 if(d2
->ShowModal() == wxID_OK
)
1331 prefix
= tostdstring(d2
->GetPath());
1334 std::ostringstream str
;
1337 str
<< " " << choice
;
1338 str
<< " " << prefix
;
1339 exec_command(str
.str());
1343 void emulator_main_window::menu_audio_status(wxCommandEvent
& e
)
1345 exec_command("show-sound-status");
1348 void emulator_main_window::menu_choose_audio_device(wxCommandEvent
& e
)
1350 if(!audio_devs
.count(e
.GetId()))
1351 return; //Not supposed to happen.
1352 window::set_sound_device(audio_devs
[e
.GetId()]);
1355 void emulator_main_window::menu_loadsave(wxCommandEvent
& e
)
1358 bool is_save
= (id
== wxID_SAVE_MOVIE
|| id
== wxID_SAVE_STATE
|| id
== wxID_SAVE_SCREENSHOT
);
1359 std::string filename
;
1361 wxFileDialog
* d
= new wxFileDialog(this, is_save
? wxT("Save") : wxT("Load"), wxT("."));
1362 if(d
->ShowModal() == wxID_OK
)
1363 filename
= tostdstring(d
->GetPath());
1369 case wxID_LOAD_MOVIE
:
1370 exec_command("load-movie " + filename
);
1372 case wxID_LOAD_STATE
:
1373 exec_command("load " + filename
);
1375 case wxID_LOAD_STATE_RO
:
1376 exec_command("load-readonly " + filename
);
1378 case wxID_LOAD_STATE_RW
:
1379 exec_command("load-state " + filename
);
1381 case wxID_SAVE_MOVIE
:
1382 exec_command("save-movie " + filename
);
1384 case wxID_SAVE_STATE
:
1385 exec_command("save-state " + filename
);
1387 case wxID_SAVE_SCREENSHOT
:
1388 exec_command("take-screenshot " + filename
);
1393 void emulator_main_window::menu_scripting(wxCommandEvent
& e
)
1396 bool file
= (id
== wxID_RUN_LUA
|| id
== wxID_RUN_SCRIPT
);
1400 wxFileDialog
* d
= new wxFileDialog(this, wxT("Select Script"), wxT("."));
1401 if(d
->ShowModal() == wxID_OK
)
1402 name
= tostdstring(d
->GetPath());
1405 wxTextEntryDialog
* d
= new wxTextEntryDialog(this, wxT("Enter Lua statement:"),
1406 wxT("Evaluate Lua"));
1407 if(d
->ShowModal() == wxID_OK
)
1408 name
= tostdstring(d
->GetValue());
1415 case wxID_RUN_SCRIPT
:
1416 exec_command("run-script " + name
);
1419 exec_command("evaluate-lua " + name
);
1422 exec_command("run-lua " + name
);
1427 sound_listener::sound_listener(emulator_main_window
* w
)
1432 sound_listener::~sound_listener() throw()
1436 void sound_listener::on_sound_unmute(bool unmute
) throw()
1438 if(win
&& win
->sound_enable
)
1439 win
->sound_enable
->Check(unmute
);
1442 void sound_listener::on_mode_change(bool readonly
) throw()
1444 if(win
&& win
->readonly_enable
)
1445 win
->readonly_enable
->Check(readonly
);
1448 void sound_listener::on_autohold_update(unsigned pid
, unsigned ctrlnum
, bool newstate
)
1450 if(win
&& win
->ahmenu
)
1451 win
->ahmenu
->update(pid
, ctrlnum
, newstate
);
1454 void sound_listener::on_autohold_reconfigure()
1456 if(win
&& win
->ahmenu
)
1457 win
->ahmenu
->reconfigure();
1460 void sound_listener::on_sound_change(const std::string
& dev
) throw()
1463 for(auto i
: audio_devs
) {
1464 if(dev
== i
.second
) {
1471 audio_devitems
[j
]->Check();
1474 void boot_emulator(loaded_rom
& rom
, moviefile
& movie
)
1476 wx_status_window
* status
= new wx_status_window();
1479 std::string windowname
= "lsnes-" + lsnes_version
+ "[" + bsnes_core_version
+ "]";
1480 main_window
= new emulator_main_window(windowname
);
1481 struct emulator_boot_state s
;
1484 emu_cr
= new coroutine(emulator_bootup_fn
, &s
, STACKSIZE
);
1485 messages
<< "Started emulator main coroutine" << std::endl
;
1486 //Delete the rom and movie. They aren't needed anymore.
1488 main_window
->Show();
1491 void exec_command(const std::string
& cmd
)
1495 pending_command
= cmd
;
1496 request
= REQ_COMMAND
;
1501 void window::poll_inputs() throw(std::bad_alloc
)
1505 if(request
== REQ_POLL_JOYSTICK
)
1506 window::poll_joysticks();
1507 if(request
== REQ_KEY_PRESS
)
1508 presed_key
->set_position(1, keypress_modifiers
);
1509 if(request
== REQ_KEY_RELEASE
)
1510 presed_key
->set_position(0, keypress_modifiers
);
1511 if(request
== REQ_CONTINUE
)
1513 if(request
== REQ_COMMAND
)
1514 command::invokeC(pending_command
);
1518 void window::notify_screen_update(bool full
) throw()
1520 screen_updated_full
= true;
1521 screen_updated
= true;
1522 if(main_window
&& !main_window_dirty
) {
1523 main_window_dirty
= true;
1524 main_window
->request_paint();
1526 if(wx_status_window::ptr
)
1527 wx_status_window::ptr
->notify_status_change();
1530 void window::set_main_surface(screen
& scr
) throw()
1533 screen_updated_full
= true;
1534 screen_updated
= true;
1537 void window::paused(bool enable
) throw()
1540 screen_updated
= true;
1543 void window::wait_usec(uint64_t usec
) throw(std::bad_alloc
)
1546 wait_until
= get_utime() + usec
;
1550 void window::cancel_wait() throw()
1555 void window::fatal_error2() throw()
1557 in_modal_dialog
= true;
1558 std::string err
= "Unknown fatal error occured";
1559 if(window::msgbuf
.get_msg_count() > 0)
1560 err
= window::msgbuf
.get_message(window::msgbuf
.get_msg_first() + window::msgbuf
.get_msg_count() - 1);
1561 wxMessageDialog
* d
= new wxMessageDialog(main_window
, towxstring(err
), wxT("Fatal Error"),
1562 wxOK
| wxICON_ERROR
);
1567 bool window::modal_message(const std::string
& msg
, bool confirm
) throw(std::bad_alloc
)
1569 in_modal_dialog
= true;
1572 d
= new wxMessageDialog(main_window
, towxstring(msg
), wxT("Question"),
1573 wxOK
| wxCANCEL
| wxICON_QUESTION
);
1575 d
= new wxMessageDialog(main_window
, towxstring(msg
), wxT("Information"),
1576 wxOK
| wxICON_INFORMATION
);
1577 auto r
= d
->ShowModal();
1579 in_modal_dialog
= false;
1585 void graphics_init()
1587 init_modifiers_and_keys();
1590 void graphics_quit()
1592 for(auto i
: modifier_map
)
1594 for(auto i
: keys_allocated
)
1595 delete key_map
[i
.second
];
1596 modifier_map
.clear();
1598 keys_allocated
.clear();
1603 const char* graphics_plugin_name
= "Wxwidgets graphics plugin";