2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
7 [ win32 emulation i/f ]
15 #if defined(USE_DEBUGGER)
16 #include "vm/debugger.h"
22 // ----------------------------------------------------------------------------
24 // ----------------------------------------------------------------------------
25 static const int sound_frequency_table[8] = {
26 2000, 4000, 8000, 11025, 22050, 44100,
27 #ifdef OVERRIDE_SOUND_FREQ_48000HZ
28 OVERRIDE_SOUND_FREQ_48000HZ,
34 static const double sound_latency_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};
37 // Please permit at least them m(.. )m
38 //extern void get_long_full_path_name(_TCHAR* src, _TCHAR* dst);
44 EMU::EMU(class Ui_MainWindow *hwnd, GLDrawClass *hinst, std::shared_ptr<CSP_Logger> p_logger, std::shared_ptr<USING_FLAGS> p) : EMU_TEMPLATE(hwnd, hinst, p_logger, p)
45 #elif defined(OSD_WIN32)
46 EMU::EMU(HWND hwnd, HINSTANCE hinst) : EMU_TEMPLATE(hwnd, hinst)
52 // store main window handle
53 #ifdef USE_FLOPPY_DISK
54 // initialize d88 file info
55 memset(d88_file, 0, sizeof(d88_file));
58 // initialize d88 file info
59 memset(b77_file, 0, sizeof(b77_file));
63 if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
64 config.sound_frequency = 6; // default: 48KHz
66 if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
67 config.sound_latency = 1; // default: 100msec
69 sound_frequency = config.sound_frequency;
70 sound_latency = config.sound_latency;
71 sound_rate = sound_frequency_table[config.sound_frequency];
72 sound_samples = (int)(sound_rate * sound_latency_table[config.sound_latency] + 0.5);
75 cpu_type = config.cpu_type;
78 dipswitch = config.dipswitch;
81 sound_type = config.sound_type;
83 #ifdef USE_PRINTER_TYPE
84 printer_type = config.printer_type;
87 // initialize b77 file info
88 memset(b77_file, 0, sizeof(b77_file));
93 osd = new OSD(p, csp_logger);
94 osd->main_window_handle = hwnd;
97 #elif defined(OSD_WIN32)
99 osd->main_window_handle = hwnd;
100 osd->instance_handle = hinst;
102 int presented_rate, presented_samples;
103 osd->initialize(sound_rate, sound_samples, &presented_rate, &presented_samples);
104 sound_rate = presented_rate;
105 sound_samples = presented_samples;
109 # if defined(_USE_QT)
110 osd->reset_vm_node();
111 osd->update_keyname_table();
114 initialize_auto_key();
117 initialize_debugger();
119 now_waiting_in_debugger = false;
121 vm->initialize_sound(sound_rate, sound_samples);
122 #ifdef USE_SOUND_VOLUME
123 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
124 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
128 for(int drv = 0; drv < USE_HARD_DISK; drv++) {
129 if(config.last_hard_disk_path[drv][0] != _T('\0') && FILEIO::IsFileExisting(config.last_hard_disk_path[drv])) {
130 vm->open_hard_disk(drv, config.last_hard_disk_path[drv]);
131 my_tcscpy_s(hard_disk_status[drv].path, _MAX_PATH, config.last_hard_disk_path[drv]);
136 now_suspended = false;
162 EmuThreadClass *EMU::get_parent_handler()
164 return osd->get_parent_handler();
167 void EMU::set_parent_handler(EmuThreadClass *p, DrawThreadClass *q)
169 osd->set_parent_thread(p);
170 osd->set_draw_thread(q);
173 void EMU::set_host_cpus(int v)
175 osd->host_cpus = (v <= 0) ? 1 : v;
178 int EMU::get_host_cpus()
180 return osd->host_cpus;
184 // ----------------------------------------------------------------------------
186 // ----------------------------------------------------------------------------
188 double EMU::get_frame_rate()
190 return vm->get_frame_rate();
193 int EMU::get_frame_interval()
195 static int prev_interval = 0;
196 static double prev_fps = -1;
197 double fps = vm->get_frame_rate();
198 if(prev_fps != fps) {
199 prev_interval = (int)(1024. * 1000. / fps + 0.5);
202 return prev_interval;
205 bool EMU::is_frame_skippable()
207 return vm->is_frame_skippable();
210 const bool EMU::is_use_state()
220 #if defined(USE_DEBUGGER) && defined(USE_STATE)
221 if(request_save_state >= 0 || request_load_state >= 0) {
222 if(request_save_state >= 0) {
223 save_state(state_file_path(request_save_state));
225 load_state(state_file_path(request_load_state));
227 // NOTE: vm instance may be reinitialized in load_state
228 // ToDo: Support multiple debuggers. 20230110 K.O
229 if(!is_debugger_enabled(debugger_cpu_index)) {
230 for(int i = 0; i < 8; i++) {
231 if(is_debugger_enabled(i)) {
232 debugger_cpu_index = i;
233 debugger_target_id = vm->get_cpu(debugger_cpu_index)->this_device_id;
238 if(is_debugger_enabled(debugger_cpu_index)) {
239 if(!(vm->get_device(debugger_target_id) != NULL && vm->get_device(debugger_target_id)->get_debugger() != NULL)) {
240 debugger_target_id = vm->get_cpu(debugger_cpu_index)->this_device_id;
242 DEBUGGER *cpu_debugger = (DEBUGGER *)vm->get_cpu(debugger_cpu_index)->get_debugger();
243 cpu_debugger->now_going = false;
244 cpu_debugger->now_debugging = true;
245 debugger_thread_param.vm = vm;
247 close_debugger(debugger_cpu_index);
249 request_save_state = request_load_state = -1;
254 now_suspended = false;
260 //#ifdef USE_JOYSTICK
261 // update_joystick();
265 #if !defined(_USE_QT) // Temporally
266 osd->update_socket();
271 // virtual machine may be driven to fill sound buffer
272 int extra_frames = 0;
273 osd->update_sound(&extra_frames);
275 // drive virtual machine
276 if(extra_frames == 0) {
282 osd->add_extra_frames(extra_frames);
290 config.romaji_to_kana = false;
293 // check if virtual machine should be reinitialized
294 bool reinitialize = false;
296 reinitialize |= (cpu_type != config.cpu_type);
297 cpu_type = config.cpu_type;
300 reinitialize |= (dipswitch != config.dipswitch);
301 dipswitch = config.dipswitch;
303 #ifdef USE_SOUND_TYPE
304 reinitialize |= (sound_type != config.sound_type);
305 sound_type = config.sound_type;
307 #ifdef USE_PRINTER_TYPE
308 reinitialize |= (printer_type != config.printer_type);
309 printer_type = config.printer_type;
314 // reinitialize virtual machine
322 osd->reset_vm_node();
323 osd->update_keyname_table();
324 osd->reset_screen_buffer();
327 int presented_samples;
328 sound_rate = sound_frequency_table[config.sound_frequency];
329 sound_samples = (int)(sound_rate * sound_latency_table[config.sound_latency] + 0.5);
330 osd->initialize_sound(sound_rate, sound_samples, &presented_rate, &presented_samples);
331 if((sound_rate != presented_rate) ||
332 (sound_samples != presented_samples)) {
333 sound_rate = presented_rate;
334 sound_samples = presented_samples;
336 vm->initialize_sound(sound_rate, sound_samples);
337 #ifdef USE_SOUND_VOLUME
338 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
339 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
342 // restore inserted medias
347 // reset virtual machine
353 #if !defined(_USE_QT) // Temporally
355 osd->restart_record_sound();
356 osd->restart_record_video();
360 #ifdef USE_SPECIAL_RESET
361 void EMU::special_reset(int num)
364 if(num >= USE_SPECIAL_RESET) return;
367 config.romaji_to_kana = false;
370 // reset virtual machine
372 vm->special_reset(num);
375 #if !defined(_USE_QT) // Temporally
376 restart_record_sound();
377 restart_record_video();
382 #ifdef USE_NOTIFY_POWER_OFF
383 void EMU::notify_power_off()
385 vm->notify_power_off();
389 void EMU::power_off()
398 now_suspended = true;
407 void EMU::unlock_vm()
412 void EMU::force_unlock_vm()
414 osd->force_unlock_vm();
417 bool EMU::is_vm_locked()
419 return osd->is_vm_locked();
422 // ----------------------------------------------------------------------------
424 // ----------------------------------------------------------------------------
427 void EMU::key_down(int code, bool extended, bool repeat)
431 shift_pressed = true;
433 if(config.romaji_to_kana) {
435 // Page Up, Page Down, End, Home, Left, Up, Right, Down, Ins, Del, Help, and F1-F12
436 if((code >= 0x21 && code <= 0x2f) || (code >= 0x70 && code <= 0x7b)) {
438 auto_key_buffer->write(code | 0x100);
440 auto_key_buffer->write(code);
442 if(!is_auto_key_running()) {
447 } else if(!is_auto_key_running())
449 osd->key_down(code, extended, repeat);
450 // printf("KEY DOWN: %04X EXT=%d REPEAT=%d\n", code, extended, repeat);
453 void EMU::key_up(int code, bool extended)
457 shift_pressed = false;
459 if(config.romaji_to_kana) {
461 } else if(!is_auto_key_running())
463 osd->key_up(code, extended);
464 // printf("KEY UP: %04X EXT=%d\n", code, extended);
467 void EMU::key_char(char code)
470 if(config.romaji_to_kana) {
471 set_auto_key_char(code);
476 #ifdef USE_KEY_LOCKED
477 bool EMU::get_caps_locked()
479 return vm->get_caps_locked();
482 bool EMU::get_kana_locked()
484 return vm->get_kana_locked();
488 void EMU::key_lost_focus()
490 osd->key_lost_focus();
493 #ifdef ONE_BOARD_MICRO_COMPUTER
494 void EMU::press_button(int num)
496 int code = vm_buttons[num].code;
499 osd->key_down_native(code, false);
500 osd->get_key_buffer()[code] = KEY_KEEP_FRAMES;
502 // code=0: reset virtual machine
509 void EMU::enable_mouse()
514 void EMU::disable_mouse()
516 osd->disable_mouse();
519 void EMU::toggle_mouse()
524 bool EMU::is_mouse_enabled()
526 return osd->is_mouse_enabled();
531 static const int auto_key_table_base[][2] = {
538 {0x08, 0x000 | 0x08}, // BS
539 {0x09, 0x000 | 0x09}, // Tab
540 {0x0d, 0x000 | 0x0d}, // Enter
541 {0x1b, 0x000 | 0x1b}, // Escape
542 {0x20, 0x000 | 0x20}, // ' '
544 {0x21, 0x100 | 0x31}, // '!'
545 {0x22, 0x100 | 0xba}, // '"'
546 {0x23, 0x100 | 0x33}, // '#'
547 {0x24, 0x100 | 0x34}, // '$'
548 {0x25, 0x100 | 0x35}, // '%'
549 {0x26, 0x100 | 0x37}, // '&'
550 {0x27, 0x000 | 0xba}, // '''
551 {0x28, 0x100 | 0x39}, // '('
552 {0x29, 0x100 | 0x30}, // ')'
553 {0x2a, 0x100 | 0x38}, // '*'
554 {0x2b, 0x100 | 0xde}, // '+'
555 {0x2c, 0x000 | 0xbc}, // ','
556 {0x2d, 0x000 | 0xbd}, // '-'
557 {0x2e, 0x000 | 0xbe}, // '.'
558 {0x2f, 0x000 | 0xbf}, // '/'
560 {0x21, 0x100 | 0x31}, // '!'
561 {0x22, 0x100 | 0x32}, // '"'
562 {0x23, 0x100 | 0x33}, // '#'
563 {0x24, 0x100 | 0x34}, // '$'
564 {0x25, 0x100 | 0x35}, // '%'
565 {0x26, 0x100 | 0x36}, // '&'
566 {0x27, 0x100 | 0x37}, // '''
567 {0x28, 0x100 | 0x38}, // '('
568 {0x29, 0x100 | 0x39}, // ')'
569 {0x2a, 0x100 | 0xba}, // '*'
570 {0x2b, 0x100 | 0xbb}, // '+'
571 {0x2c, 0x000 | 0xbc}, // ','
572 {0x2d, 0x000 | 0xbd}, // '-'
573 {0x2e, 0x000 | 0xbe}, // '.'
574 {0x2f, 0x000 | 0xbf}, // '/'
576 {0x30, 0x000 | 0x30}, // '0'
577 {0x31, 0x000 | 0x31}, // '1'
578 {0x32, 0x000 | 0x32}, // '2'
579 {0x33, 0x000 | 0x33}, // '3'
580 {0x34, 0x000 | 0x34}, // '4'
581 {0x35, 0x000 | 0x35}, // '5'
582 {0x36, 0x000 | 0x36}, // '6'
583 {0x37, 0x000 | 0x37}, // '7'
584 {0x38, 0x000 | 0x38}, // '8'
585 {0x39, 0x000 | 0x39}, // '9'
587 {0x3a, 0x100 | 0xbb}, // ':'
588 {0x3b, 0x000 | 0xbb}, // ';'
589 {0x3c, 0x100 | 0xbc}, // '<'
590 {0x3d, 0x000 | 0xde}, // '='
591 {0x3e, 0x100 | 0xbe}, // '>'
592 {0x3f, 0x100 | 0xbf}, // '?'
593 {0x40, 0x100 | 0x32}, // '@'
595 {0x3a, 0x000 | 0xba}, // ':'
596 {0x3b, 0x000 | 0xbb}, // ';'
597 {0x3c, 0x100 | 0xbc}, // '<'
598 {0x3d, 0x100 | 0xbd}, // '='
599 {0x3e, 0x100 | 0xbe}, // '>'
600 {0x3f, 0x100 | 0xbf}, // '?'
601 {0x40, 0x000 | 0xc0}, // '@'
603 {0x41, 0x400 | 0x41}, // 'A'
604 {0x42, 0x400 | 0x42}, // 'B'
605 {0x43, 0x400 | 0x43}, // 'C'
606 {0x44, 0x400 | 0x44}, // 'D'
607 {0x45, 0x400 | 0x45}, // 'E'
608 {0x46, 0x400 | 0x46}, // 'F'
609 {0x47, 0x400 | 0x47}, // 'G'
610 {0x48, 0x400 | 0x48}, // 'H'
611 {0x49, 0x400 | 0x49}, // 'I'
612 {0x4a, 0x400 | 0x4a}, // 'J'
613 {0x4b, 0x400 | 0x4b}, // 'K'
614 {0x4c, 0x400 | 0x4c}, // 'L'
615 {0x4d, 0x400 | 0x4d}, // 'M'
616 {0x4e, 0x400 | 0x4e}, // 'N'
617 {0x4f, 0x400 | 0x4f}, // 'O'
618 {0x50, 0x400 | 0x50}, // 'P'
619 {0x51, 0x400 | 0x51}, // 'Q'
620 {0x52, 0x400 | 0x52}, // 'R'
621 {0x53, 0x400 | 0x53}, // 'S'
622 {0x54, 0x400 | 0x54}, // 'T'
623 {0x55, 0x400 | 0x55}, // 'U'
624 {0x56, 0x400 | 0x56}, // 'V'
625 {0x57, 0x400 | 0x57}, // 'W'
626 {0x58, 0x400 | 0x58}, // 'X'
627 {0x59, 0x400 | 0x59}, // 'Y'
628 {0x5a, 0x400 | 0x5a}, // 'Z'
630 {0x5b, 0x000 | 0xc0}, // '['
631 {0x5c, 0x000 | 0xe2}, // '\'
632 {0x5d, 0x000 | 0xdb}, // ']'
633 {0x5e, 0x100 | 0x36}, // '^'
634 {0x5f, 0x100 | 0xbd}, // '_'
635 {0x60, 0x000 | 0xdd}, // '`'
637 {0x5b, 0x000 | 0xdb}, // '['
638 {0x5c, 0x000 | 0xdc}, // '\'
639 {0x5d, 0x000 | 0xdd}, // ']'
640 {0x5e, 0x000 | 0xde}, // '^'
641 {0x5f, 0x100 | 0xe2}, // '_'
642 {0x60, 0x100 | 0xc0}, // '`'
644 {0x61, 0x800 | 0x41}, // 'a'
645 {0x62, 0x800 | 0x42}, // 'b'
646 {0x63, 0x800 | 0x43}, // 'c'
647 {0x64, 0x800 | 0x44}, // 'd'
648 {0x65, 0x800 | 0x45}, // 'e'
649 {0x66, 0x800 | 0x46}, // 'f'
650 {0x67, 0x800 | 0x47}, // 'g'
651 {0x68, 0x800 | 0x48}, // 'h'
652 {0x69, 0x800 | 0x49}, // 'i'
653 {0x6a, 0x800 | 0x4a}, // 'j'
654 {0x6b, 0x800 | 0x4b}, // 'k'
655 {0x6c, 0x800 | 0x4c}, // 'l'
656 {0x6d, 0x800 | 0x4d}, // 'm'
657 {0x6e, 0x800 | 0x4e}, // 'n'
658 {0x6f, 0x800 | 0x4f}, // 'o'
659 {0x70, 0x800 | 0x50}, // 'p'
660 {0x71, 0x800 | 0x51}, // 'q'
661 {0x72, 0x800 | 0x52}, // 'r'
662 {0x73, 0x800 | 0x53}, // 's'
663 {0x74, 0x800 | 0x54}, // 't'
664 {0x75, 0x800 | 0x55}, // 'u'
665 {0x76, 0x800 | 0x56}, // 'v'
666 {0x77, 0x800 | 0x57}, // 'w'
667 {0x78, 0x800 | 0x58}, // 'x'
668 {0x79, 0x800 | 0x59}, // 'y'
669 {0x7a, 0x800 | 0x5a}, // 'z'
671 {0x7b, 0x100 | 0xc0}, // '{'
672 {0x7c, 0x100 | 0xe2}, // '|'
673 {0x7d, 0x100 | 0xdb}, // '}'
674 {0x7e, 0x100 | 0xdd}, // '~'
676 {0x7b, 0x100 | 0xdb}, // '{'
677 {0x7c, 0x100 | 0xdc}, // '|'
678 {0x7d, 0x100 | 0xdd}, // '}'
679 {0x7e, 0x100 | 0xde}, // '~'
684 static const int auto_key_table_kana_base[][2] = {
685 {0xa1, 0x300 | 0xbe}, // '。'
686 {0xa2, 0x300 | 0xdb}, // '「'
687 {0xa3, 0x300 | 0xdd}, // '」'
688 {0xa4, 0x300 | 0xbc}, // '、'
689 {0xa5, 0x300 | 0xbf}, // '・'
690 {0xa6, 0x300 | 0x30}, // 'ヲ'
691 {0xa7, 0x300 | 0x33}, // 'ァ'
692 {0xa8, 0x300 | 0x45}, // 'ィ'
693 {0xa9, 0x300 | 0x34}, // 'ゥ'
694 {0xaa, 0x300 | 0x35}, // 'ェ'
695 {0xab, 0x300 | 0x36}, // 'ォ'
696 {0xac, 0x300 | 0x37}, // 'ャ'
697 {0xad, 0x300 | 0x38}, // 'ュ'
698 {0xae, 0x300 | 0x39}, // 'ョ'
699 {0xaf, 0x300 | 0x5a}, // 'ッ'
700 {0xb0, 0x200 | 0xdc}, // 'ー'
701 {0xb1, 0x200 | 0x33}, // 'ア'
702 {0xb2, 0x200 | 0x45}, // 'イ'
703 {0xb3, 0x200 | 0x34}, // 'ウ'
704 {0xb4, 0x200 | 0x35}, // 'エ'
705 {0xb5, 0x200 | 0x36}, // 'オ'
706 {0xb6, 0x200 | 0x54}, // 'カ'
707 {0xb7, 0x200 | 0x47}, // 'キ'
708 {0xb8, 0x200 | 0x48}, // 'ク'
709 {0xb9, 0x200 | 0xba}, // 'ケ'
710 {0xba, 0x200 | 0x42}, // 'コ'
711 {0xbb, 0x200 | 0x58}, // 'サ'
712 {0xbc, 0x200 | 0x44}, // 'シ'
713 {0xbd, 0x200 | 0x52}, // 'ス'
714 {0xbe, 0x200 | 0x50}, // 'セ'
715 {0xbf, 0x200 | 0x43}, // 'ソ'
716 {0xc0, 0x200 | 0x51}, // 'タ'
717 {0xc1, 0x200 | 0x41}, // 'チ'
718 {0xc2, 0x200 | 0x5a}, // 'ツ'
719 {0xc3, 0x200 | 0x57}, // 'テ'
720 {0xc4, 0x200 | 0x53}, // 'ト'
721 {0xc5, 0x200 | 0x55}, // 'ナ'
722 {0xc6, 0x200 | 0x49}, // 'ニ'
723 {0xc7, 0x200 | 0x31}, // 'ヌ'
724 {0xc8, 0x200 | 0xbc}, // 'ネ'
725 {0xc9, 0x200 | 0x4b}, // 'ノ'
726 {0xca, 0x200 | 0x46}, // 'ハ'
727 {0xcb, 0x200 | 0x56}, // 'ヒ'
728 {0xcc, 0x200 | 0x32}, // 'フ'
729 {0xcd, 0x200 | 0xde}, // 'ヘ'
730 {0xce, 0x200 | 0xbd}, // 'ホ'
731 {0xcf, 0x200 | 0x4a}, // 'マ'
732 {0xd0, 0x200 | 0x4e}, // 'ミ'
733 {0xd1, 0x200 | 0xdd}, // 'ム'
734 {0xd2, 0x200 | 0xbf}, // 'メ'
735 {0xd3, 0x200 | 0x4d}, // 'モ'
736 {0xd4, 0x200 | 0x37}, // 'ヤ'
737 {0xd5, 0x200 | 0x38}, // 'ユ'
738 {0xd6, 0x200 | 0x39}, // 'ヨ'
739 {0xd7, 0x200 | 0x4f}, // 'ラ'
740 {0xd8, 0x200 | 0x4c}, // 'リ'
741 {0xd9, 0x200 | 0xbe}, // 'ル'
742 {0xda, 0x200 | 0xbb}, // 'レ'
743 {0xdb, 0x200 | 0xe2}, // 'ロ'
744 {0xdc, 0x200 | 0x30}, // 'ワ'
745 {0xdd, 0x200 | 0x59}, // 'ン'
746 {0xde, 0x200 | 0xc0}, // '゙'
747 {0xdf, 0x200 | 0xdb}, // '゚'
751 static const int auto_key_table_50on_base[][2] = {
752 {0xa1, 0x300 | 0xbf}, // '。'
753 {0xa2, 0x300 | 0xdb}, // '「'
754 {0xa3, 0x300 | 0xdd}, // '」'
755 {0xa4, 0x300 | 0xbe}, // '、'
756 {0xa5, 0x300 | 0xe2}, // '・'
757 {0xa6, 0x200 | 0xbf}, // 'ヲ'
758 {0xa7, 0x300 | 0x31}, // 'ァ'
759 {0xa8, 0x300 | 0x32}, // 'ィ'
760 {0xa9, 0x300 | 0x33}, // 'ゥ'
761 {0xaa, 0x300 | 0x34}, // 'ェ'
762 {0xab, 0x300 | 0x35}, // 'ォ'
763 {0xac, 0x300 | 0x4e}, // 'ャ'
764 {0xad, 0x300 | 0x4d}, // 'ュ'
765 {0xae, 0x300 | 0xbc}, // 'ョ'
766 {0xaf, 0x300 | 0x43}, // 'ッ'
767 {0xb0, 0x300 | 0xba}, // 'ー'
768 {0xb1, 0x200 | 0x31}, // 'ア'
769 {0xb2, 0x200 | 0x32}, // 'イ'
770 {0xb3, 0x200 | 0x33}, // 'ウ'
771 {0xb4, 0x200 | 0x34}, // 'エ'
772 {0xb5, 0x200 | 0x35}, // 'オ'
773 {0xb6, 0x200 | 0x51}, // 'カ'
774 {0xb7, 0x200 | 0x57}, // 'キ'
775 {0xb8, 0x200 | 0x45}, // 'ク'
776 {0xb9, 0x200 | 0x52}, // 'ケ'
777 {0xba, 0x200 | 0x54}, // 'コ'
778 {0xbb, 0x200 | 0x41}, // 'サ'
779 {0xbc, 0x200 | 0x53}, // 'シ'
780 {0xbd, 0x200 | 0x44}, // 'ス'
781 {0xbe, 0x200 | 0x46}, // 'セ'
782 {0xbf, 0x200 | 0x47}, // 'ソ'
783 {0xc0, 0x200 | 0x5a}, // 'タ'
784 {0xc1, 0x200 | 0x58}, // 'チ'
785 {0xc2, 0x200 | 0x43}, // 'ツ'
786 {0xc3, 0x200 | 0x56}, // 'テ'
787 {0xc4, 0x200 | 0x42}, // 'ト'
788 {0xc5, 0x200 | 0x36}, // 'ナ'
789 {0xc6, 0x200 | 0x37}, // 'ニ'
790 {0xc7, 0x200 | 0x38}, // 'ヌ'
791 {0xc8, 0x200 | 0x39}, // 'ネ'
792 {0xc9, 0x200 | 0x30}, // 'ノ'
793 {0xca, 0x200 | 0x59}, // 'ハ'
794 {0xcb, 0x200 | 0x55}, // 'ヒ'
795 {0xcc, 0x200 | 0x49}, // 'フ'
796 {0xcd, 0x200 | 0x4f}, // 'ヘ'
797 {0xce, 0x200 | 0x50}, // 'ホ'
798 {0xcf, 0x200 | 0x48}, // 'マ'
799 {0xd0, 0x200 | 0x4a}, // 'ミ'
800 {0xd1, 0x200 | 0x4b}, // 'ム'
801 {0xd2, 0x200 | 0x4c}, // 'メ'
802 {0xd3, 0x200 | 0xbb}, // 'モ'
803 {0xd4, 0x200 | 0x4e}, // 'ヤ'
804 {0xd5, 0x200 | 0x4d}, // 'ユ'
805 {0xd6, 0x200 | 0xbc}, // 'ヨ'
806 {0xd7, 0x200 | 0xbd}, // 'ラ'
807 {0xd8, 0x200 | 0xde}, // 'リ'
808 {0xd9, 0x200 | 0xdc}, // 'ル'
809 {0xda, 0x200 | 0xc0}, // 'レ'
810 {0xdb, 0x200 | 0xdb}, // 'ロ'
811 {0xdc, 0x200 | 0xbe}, // 'ワ'
812 {0xdd, 0x200 | 0xe2}, // 'ン'
813 {0xde, 0x200 | 0xba}, // '゙'
814 {0xdf, 0x200 | 0xdd}, // '゚'
818 static const struct {
820 const uint8_t kana[4];
822 {"ltsu", {0xaf, 0x00}},
823 {"xtsu", {0xaf, 0x00}},
824 {"ltu", {0xaf, 0x00}},
825 {"xtu", {0xaf, 0x00}},
826 {"bya", {0xcb, 0xde, 0xac, 0x00}},
827 {"byi", {0xcb, 0xde, 0xa8, 0x00}},
828 {"byu", {0xcb, 0xde, 0xad, 0x00}},
829 {"bye", {0xcb, 0xde, 0xaa, 0x00}},
830 {"byo", {0xcb, 0xde, 0xae, 0x00}},
831 {"cha", {0xc1, 0xac, 0x00}},
832 {"chi", {0xc1, 0x00}},
833 {"chu", {0xc1, 0xad, 0x00}},
834 {"che", {0xc1, 0xaa, 0x00}},
835 {"cho", {0xc1, 0xae, 0x00}},
836 {"cya", {0xc1, 0xac, 0x00}},
837 {"cyi", {0xc1, 0xa8, 0x00}},
838 {"cyu", {0xc1, 0xad, 0x00}},
839 {"cye", {0xc1, 0xaa, 0x00}},
840 {"cyo", {0xc1, 0xae, 0x00}},
841 {"dha", {0xc3, 0xde, 0xac, 0x00}},
842 {"dhi", {0xc3, 0xde, 0xa8, 0x00}},
843 {"dhu", {0xc3, 0xde, 0xad, 0x00}},
844 {"dhe", {0xc3, 0xde, 0xaa, 0x00}},
845 {"dho", {0xc3, 0xde, 0xae, 0x00}},
846 {"dwa", {0xc4, 0xde, 0xa7, 0x00}},
847 {"dwi", {0xc4, 0xde, 0xa8, 0x00}},
848 {"dwu", {0xc4, 0xde, 0xa9, 0x00}},
849 {"dwe", {0xc4, 0xde, 0xaa, 0x00}},
850 {"dwo", {0xc4, 0xde, 0xab, 0x00}},
851 {"dya", {0xc1, 0xde, 0xac, 0x00}},
852 {"dyi", {0xc1, 0xde, 0xa8, 0x00}},
853 {"dyu", {0xc1, 0xde, 0xad, 0x00}},
854 {"dye", {0xc1, 0xde, 0xaa, 0x00}},
855 {"dyo", {0xc1, 0xde, 0xae, 0x00}},
856 {"fwa", {0xcc, 0xa7, 0x00}},
857 {"fwi", {0xcc, 0xa8, 0x00}},
858 {"fwu", {0xcc, 0xa9, 0x00}},
859 {"fwe", {0xcc, 0xaa, 0x00}},
860 {"fwo", {0xcc, 0xab, 0x00}},
861 {"fya", {0xcc, 0xac, 0x00}},
862 {"fyi", {0xcc, 0xa8, 0x00}},
863 {"fyu", {0xcc, 0xad, 0x00}},
864 {"fye", {0xcc, 0xaa, 0x00}},
865 {"fyo", {0xcc, 0xae, 0x00}},
866 {"gwa", {0xb8, 0xde, 0xa7, 0x00}},
867 {"gwi", {0xb8, 0xde, 0xa8, 0x00}},
868 {"gwu", {0xb8, 0xde, 0xa9, 0x00}},
869 {"gwe", {0xb8, 0xde, 0xaa, 0x00}},
870 {"gwo", {0xb8, 0xde, 0xab, 0x00}},
871 {"gya", {0xb7, 0xde, 0xac, 0x00}},
872 {"gyi", {0xb7, 0xde, 0xa8, 0x00}},
873 {"gyu", {0xb7, 0xde, 0xad, 0x00}},
874 {"gye", {0xb7, 0xde, 0xaa, 0x00}},
875 {"gyo", {0xb7, 0xde, 0xae, 0x00}},
876 {"hya", {0xcb, 0xac, 0x00}},
877 {"hyi", {0xcb, 0xa8, 0x00}},
878 {"hyu", {0xcb, 0xad, 0x00}},
879 {"hye", {0xcb, 0xaa, 0x00}},
880 {"hyo", {0xcb, 0xae, 0x00}},
881 {"jya", {0xbc, 0xde, 0xac, 0x00}},
882 {"jyi", {0xbc, 0xde, 0xa8, 0x00}},
883 {"jyu", {0xbc, 0xde, 0xad, 0x00}},
884 {"jye", {0xbc, 0xde, 0xaa, 0x00}},
885 {"jyo", {0xbc, 0xde, 0xae, 0x00}},
886 {"kya", {0xb7, 0xac, 0x00}},
887 {"kyi", {0xb7, 0xa8, 0x00}},
888 {"kyu", {0xb7, 0xad, 0x00}},
889 {"kye", {0xb7, 0xaa, 0x00}},
890 {"kyo", {0xb7, 0xae, 0x00}},
891 {"lya", {0xac, 0x00}},
892 {"lyi", {0xa8, 0x00}},
893 {"lyu", {0xad, 0x00}},
894 {"lye", {0xaa, 0x00}},
895 {"lyo", {0xae, 0x00}},
896 {"mya", {0xd0, 0xac, 0x00}},
897 {"myi", {0xd0, 0xa8, 0x00}},
898 {"myu", {0xd0, 0xad, 0x00}},
899 {"mye", {0xd0, 0xaa, 0x00}},
900 {"myo", {0xd0, 0xae, 0x00}},
901 {"nya", {0xc6, 0xac, 0x00}},
902 {"nyi", {0xc6, 0xa8, 0x00}},
903 {"nyu", {0xc6, 0xad, 0x00}},
904 {"nye", {0xc6, 0xaa, 0x00}},
905 {"nyo", {0xc6, 0xae, 0x00}},
906 {"pya", {0xcb, 0xdf, 0xac, 0x00}},
907 {"pyi", {0xcb, 0xdf, 0xa8, 0x00}},
908 {"pyu", {0xcb, 0xdf, 0xad, 0x00}},
909 {"pye", {0xcb, 0xdf, 0xaa, 0x00}},
910 {"pyo", {0xcb, 0xdf, 0xae, 0x00}},
911 {"qwa", {0xb8, 0xa7, 0x00}},
912 {"qwi", {0xb8, 0xa8, 0x00}},
913 {"qwu", {0xb8, 0xa9, 0x00}},
914 {"qwe", {0xb8, 0xaa, 0x00}},
915 {"qwo", {0xb8, 0xab, 0x00}},
916 {"qya", {0xb8, 0xac, 0x00}},
917 {"qyi", {0xb8, 0xa8, 0x00}},
918 {"qyu", {0xb8, 0xad, 0x00}},
919 {"qye", {0xb8, 0xaa, 0x00}},
920 {"qyo", {0xb8, 0xae, 0x00}},
921 {"rya", {0xd8, 0xac, 0x00}},
922 {"ryi", {0xd8, 0xa8, 0x00}},
923 {"ryu", {0xd8, 0xad, 0x00}},
924 {"rye", {0xd8, 0xaa, 0x00}},
925 {"ryo", {0xd8, 0xae, 0x00}},
926 {"sha", {0xbc, 0xac, 0x00}},
927 {"shi", {0xbc, 0x00}},
928 {"shu", {0xbc, 0xad, 0x00}},
929 {"she", {0xbc, 0xaa, 0x00}},
930 {"sho", {0xbc, 0xae, 0x00}},
931 {"swa", {0xbd, 0xa7, 0x00}},
932 {"swi", {0xbd, 0xa8, 0x00}},
933 {"swu", {0xbd, 0xa9, 0x00}},
934 {"swe", {0xbd, 0xaa, 0x00}},
935 {"swo", {0xbd, 0xab, 0x00}},
936 {"sya", {0xbc, 0xac, 0x00}},
937 {"syi", {0xbc, 0xa8, 0x00}},
938 {"syu", {0xbc, 0xad, 0x00}},
939 {"sye", {0xbc, 0xaa, 0x00}},
940 {"syo", {0xbc, 0xae, 0x00}},
941 {"tha", {0xc3, 0xac, 0x00}},
942 {"thi", {0xc3, 0xa8, 0x00}},
943 {"thu", {0xc3, 0xad, 0x00}},
944 {"the", {0xc3, 0xaa, 0x00}},
945 {"tho", {0xc3, 0xae, 0x00}},
946 {"tsa", {0xc2, 0xa7, 0x00}},
947 {"tsi", {0xc2, 0xa8, 0x00}},
948 {"tsu", {0xc2, 0x00}},
949 {"tse", {0xc2, 0xaa, 0x00}},
950 {"tso", {0xc2, 0xab, 0x00}},
951 {"twa", {0xc4, 0xa7, 0x00}},
952 {"twi", {0xc4, 0xa8, 0x00}},
953 {"twu", {0xc4, 0xa9, 0x00}},
954 {"twe", {0xc4, 0xaa, 0x00}},
955 {"two", {0xc4, 0xab, 0x00}},
956 {"tya", {0xc1, 0xac, 0x00}},
957 {"tyi", {0xc1, 0xa8, 0x00}},
958 {"tyu", {0xc1, 0xad, 0x00}},
959 {"tye", {0xc1, 0xaa, 0x00}},
960 {"tyo", {0xc1, 0xae, 0x00}},
961 {"vya", {0xb3, 0xde, 0xac, 0x00}},
962 {"vyi", {0xb3, 0xde, 0xa8, 0x00}},
963 {"vyu", {0xb3, 0xde, 0xad, 0x00}},
964 {"vye", {0xb3, 0xde, 0xaa, 0x00}},
965 {"vyo", {0xb3, 0xde, 0xae, 0x00}},
966 {"wha", {0xb3, 0xa7, 0x00}},
967 {"whi", {0xb3, 0xa8, 0x00}},
968 {"whu", {0xb3, 0x00}},
969 {"whe", {0xb3, 0xaa, 0x00}},
970 {"who", {0xb3, 0xab, 0x00}},
971 {"xya", {0xac, 0x00}},
972 {"xyi", {0xa8, 0x00}},
973 {"xyu", {0xad, 0x00}},
974 {"xye", {0xaa, 0x00}},
975 {"xyo", {0xae, 0x00}},
976 {"zya", {0xbc, 0xde, 0xac, 0x00}},
977 {"zyi", {0xbc, 0xde, 0xa8, 0x00}},
978 {"zyu", {0xbc, 0xde, 0xad, 0x00}},
979 {"zye", {0xbc, 0xde, 0xaa, 0x00}},
980 {"zyo", {0xbc, 0xde, 0xae, 0x00}},
981 {"ba", {0xca, 0xde, 0x00}},
982 {"bi", {0xcb, 0xde, 0x00}},
983 {"bu", {0xcc, 0xde, 0x00}},
984 {"be", {0xcd, 0xde, 0x00}},
985 {"bo", {0xce, 0xde, 0x00}},
986 {"ca", {0xb6, 0x00}},
987 {"ci", {0xbc, 0x00}},
988 {"cu", {0xb8, 0x00}},
989 {"ce", {0xbe, 0x00}},
990 {"co", {0xba, 0x00}},
991 {"da", {0xc0, 0xde, 0x00}},
992 {"di", {0xc1, 0xde, 0x00}},
993 {"du", {0xc2, 0xde, 0x00}},
994 {"de", {0xc3, 0xde, 0x00}},
995 {"do", {0xc4, 0xde, 0x00}},
996 {"fa", {0xcc, 0xa7, 0x00}},
997 {"fi", {0xcc, 0xa8, 0x00}},
998 {"fu", {0xcc, 0x00}},
999 {"fe", {0xcc, 0xaa, 0x00}},
1000 {"fo", {0xcc, 0xab, 0x00}},
1001 {"ga", {0xb6, 0xde, 0x00}},
1002 {"gi", {0xb7, 0xde, 0x00}},
1003 {"gu", {0xb8, 0xde, 0x00}},
1004 {"ge", {0xb9, 0xde, 0x00}},
1005 {"go", {0xba, 0xde, 0x00}},
1006 {"ha", {0xca, 0x00}},
1007 {"hi", {0xcb, 0x00}},
1008 {"hu", {0xcc, 0x00}},
1009 {"he", {0xcd, 0x00}},
1010 {"ho", {0xce, 0x00}},
1011 {"ja", {0xbc, 0xde, 0xac, 0x00}},
1012 {"ji", {0xbc, 0xde, 0x00}},
1013 {"ju", {0xbc, 0xde, 0xad, 0x00}},
1014 {"je", {0xbc, 0xde, 0xaa, 0x00}},
1015 {"jo", {0xbc, 0xde, 0xae, 0x00}},
1016 {"ka", {0xb6, 0x00}},
1017 {"ki", {0xb7, 0x00}},
1018 {"ku", {0xb8, 0x00}},
1019 {"ke", {0xb9, 0x00}},
1020 {"ko", {0xba, 0x00}},
1021 {"la", {0xa7, 0x00}},
1022 {"li", {0xa8, 0x00}},
1023 {"lu", {0xa9, 0x00}},
1024 {"le", {0xaa, 0x00}},
1025 {"lo", {0xab, 0x00}},
1026 {"ma", {0xcf, 0x00}},
1027 {"mi", {0xd0, 0x00}},
1028 {"mu", {0xd1, 0x00}},
1029 {"me", {0xd2, 0x00}},
1030 {"mo", {0xd3, 0x00}},
1031 {"na", {0xc5, 0x00}},
1032 {"ni", {0xc6, 0x00}},
1033 {"nu", {0xc7, 0x00}},
1034 {"ne", {0xc8, 0x00}},
1035 {"no", {0xc9, 0x00}},
1036 // {"nn", {0xdd, 0x00}},
1037 {"pa", {0xca, 0xdf, 0x00}},
1038 {"pi", {0xcb, 0xdf, 0x00}},
1039 {"pu", {0xcc, 0xdf, 0x00}},
1040 {"pe", {0xcd, 0xdf, 0x00}},
1041 {"po", {0xce, 0xdf, 0x00}},
1042 {"qa", {0xb8, 0xa7, 0x00}},
1043 {"qi", {0xb8, 0xa8, 0x00}},
1044 {"qu", {0xb8, 0x00}},
1045 {"qe", {0xb8, 0xaa, 0x00}},
1046 {"qo", {0xb8, 0xab, 0x00}},
1047 {"ra", {0xd7, 0x00}},
1048 {"ri", {0xd8, 0x00}},
1049 {"ru", {0xd9, 0x00}},
1050 {"re", {0xda, 0x00}},
1051 {"ro", {0xdb, 0x00}},
1052 {"sa", {0xbb, 0x00}},
1053 {"si", {0xbc, 0x00}},
1054 {"su", {0xbd, 0x00}},
1055 {"se", {0xbe, 0x00}},
1056 {"so", {0xbf, 0x00}},
1057 {"ta", {0xc0, 0x00}},
1058 {"ti", {0xc1, 0x00}},
1059 {"tu", {0xc2, 0x00}},
1060 {"te", {0xc3, 0x00}},
1061 {"to", {0xc4, 0x00}},
1062 {"va", {0xb3, 0xde, 0xa7, 0x00}},
1063 {"vi", {0xb3, 0xde, 0xa8, 0x00}},
1064 {"vu", {0xb3, 0xde, 0x00}},
1065 {"ve", {0xb3, 0xde, 0xaa, 0x00}},
1066 {"vo", {0xb3, 0xde, 0xab, 0x00}},
1067 {"wa", {0xdc, 0x00}},
1068 {"wi", {0xb3, 0xa8, 0x00}},
1069 {"wu", {0xb3, 0x00}},
1070 {"we", {0xb3, 0xaa, 0x00}},
1071 {"wo", {0xa6, 0x00}},
1072 {"xa", {0xa7, 0x00}},
1073 {"xi", {0xa8, 0x00}},
1074 {"xu", {0xa9, 0x00}},
1075 {"xe", {0xaa, 0x00}},
1076 {"xo", {0xab, 0x00}},
1077 {"ya", {0xd4, 0x00}},
1078 {"yi", {0xb2, 0x00}},
1079 {"yu", {0xd5, 0x00}},
1080 {"ye", {0xb2, 0xaa, 0x00}},
1081 {"yo", {0xd6, 0x00}},
1082 {"za", {0xbb, 0xde, 0x00}},
1083 {"zi", {0xbc, 0xde, 0x00}},
1084 {"zu", {0xbd, 0xde, 0x00}},
1085 {"ze", {0xbe, 0xde, 0x00}},
1086 {"zo", {0xbf, 0xde, 0x00}},
1087 {"a", {0xb1, 0x00}},
1088 {"i", {0xb2, 0x00}},
1089 {"u", {0xb3, 0x00}},
1090 {"e", {0xb4, 0x00}},
1091 {"o", {0xb5, 0x00}},
1092 {"[", {0xa2, 0x00}},
1093 {"]", {0xa3, 0x00}},
1094 {"-", {0xb0, 0x00}},
1095 {",", {0xa4, 0x00}},
1096 {".", {0xa1, 0x00}},
1097 {"/", {0xa5, 0x00}},
1098 // Pass through kana key codes.
1099 {"\x0bc", {0xa4, 0x00}},
1100 {"\x0bd", {0xb0, 0x00}},
1101 {"\x0be", {0xa1, 0x00}},
1102 {"\x0bf", {0xa5, 0x00}},
1103 {"\x0db", {0xa2, 0x00}},
1104 {"\x0dd", {0xa3, 0x00}},
1108 void EMU::initialize_auto_key()
1110 auto_key_buffer = new FIFO(65536);
1111 auto_key_buffer->clear();
1112 auto_key_phase = auto_key_shift = 0;
1113 shift_pressed = false;
1114 osd->now_auto_key = false;
1117 void EMU::release_auto_key()
1119 if(auto_key_buffer) {
1120 auto_key_buffer->release();
1121 delete auto_key_buffer;
1125 int EMU::get_auto_key_code(int code)
1127 static int auto_key_table[256];
1128 static bool initialized = false;
1129 #ifdef USE_KEYBOARD_TYPE
1130 static int keyboard_type = -1;
1132 if(keyboard_type != config.keyboard_type) {
1133 initialized = false;
1134 keyboard_type = config.keyboard_type;
1138 memset(auto_key_table, 0, sizeof(auto_key_table));
1139 for(int i = 0;; i++) {
1140 if(auto_key_table_base[i][0] == -1) {
1143 auto_key_table[auto_key_table_base[i][0]] = auto_key_table_base[i][1];
1145 #if defined(_X1TURBO) || defined(_X1TURBOZ)
1147 if(config.keyboard_type) {
1148 for(int i = 0;; i++) {
1149 if(auto_key_table_50on_base[i][0] == -1) {
1152 auto_key_table[auto_key_table_50on_base[i][0]] = auto_key_table_50on_base[i][1];
1156 for(int i = 0;; i++) {
1157 if(auto_key_table_kana_base[i][0] == -1) {
1160 auto_key_table[auto_key_table_kana_base[i][0]] = auto_key_table_kana_base[i][1];
1162 #ifdef USE_VM_AUTO_KEY_TABLE
1163 for(int i = 0;; i++) {
1164 if(vm_auto_key_table_base[i][0] == -1) {
1167 auto_key_table[vm_auto_key_table_base[i][0]] = vm_auto_key_table_base[i][1];
1172 return auto_key_table[code];
1175 void EMU::set_auto_key_code(int code)
1177 if(code == 0xf2 || (code = get_auto_key_code(code)) != 0) {
1178 if(code == 0x08 || code == 0x09 || code == 0x0d || code == 0x1b || code == 0x20 || code == 0xf2) {
1179 // VK_BACK, VK_TAB, VK_RETURN, VK_ESCAPE, VK_SPACE, VK_OEM_COPY(Katakana/Hiragana)
1180 auto_key_buffer->write(code);
1181 #ifdef USE_AUTO_KEY_NUMPAD
1182 } else if(code >= 0x30 && code <= 0x39) {
1184 auto_key_buffer->write(code - 0x30 + 0x60);
1186 } else if(code & 0x200) {
1188 auto_key_buffer->write(code & 0x1ff);
1190 // ank other than alphabet and kana
1191 auto_key_buffer->write(0xf2); // kana unlock
1192 auto_key_buffer->write(code & 0x1ff);
1193 auto_key_buffer->write(0xf2); // kana lock
1195 if(!is_auto_key_running()) {
1201 void EMU::set_auto_key_list(char *buf, int size)
1203 #if defined(USE_KEY_LOCKED)
1204 bool prev_caps = get_caps_locked();
1205 bool prev_kana = get_kana_locked();
1207 bool prev_caps = false;
1208 bool prev_kana = false;
1210 auto_key_buffer->clear();
1212 for(int i = 0; i < size; i++) {
1213 int code = buf[i] & 0xff;
1214 if((0x81 <= code && code <= 0x9f) || 0xe0 <= code) {
1217 } else if(code == 0x0a) {
1220 if((code = get_auto_key_code(code)) != 0) {
1222 bool kana = ((code & 0x200) != 0);
1223 if(prev_kana != kana) {
1224 auto_key_buffer->write(0xf2);
1228 if(i < (size - 1)) {
1229 bool dakuon_lock = false;
1230 bool handakuon_lock = false;
1231 #if defined(USE_TWO_STROKE_AUTOKEY_HANDAKUON)
1232 if((buf[i + 1] & 0xff) == 0xdf) { // Is Handakuon
1233 for(int jj = 0; ; jj++) {
1234 if(kana_handakuon_keyboard_table[jj][0] == -1) break;
1235 if(kana_handakuon_keyboard_table[jj][0] == (buf[i] & 0xff)) { // Found
1236 handakuon_lock = true;
1237 for(int l = 1; l < 6; l++) {
1238 int n_code = kana_handakuon_keyboard_table[jj][l];
1239 if(n_code == 0x00) break;
1240 if(n_code & (0x100 | 0x400 | 0x800)) {
1241 auto_key_buffer->write((n_code & 0x30ff)| 0x100);
1243 auto_key_buffer->write(n_code & 0x30ff);
1249 if(handakuon_lock) {
1255 #if defined(USE_TWO_STROKE_AUTOKEY_DAKUON)
1256 if((buf[i + 1] & 0xff) == 0xde) { // Is Dakuon
1257 for(int jj = 0; ; jj++) {
1258 if(kana_dakuon_keyboard_table[jj][0] == -1) break;
1259 if(kana_dakuon_keyboard_table[jj][0] == (buf[i] & 0xff)) { // Found
1261 for(int l = 1; l < 6; l++) {
1262 int n_code = kana_dakuon_keyboard_table[jj][l];
1263 if(n_code == 0x00) break;
1264 if(n_code & (0x100 | 0x400 | 0x800)) {
1265 auto_key_buffer->write((n_code & 0x30ff)| 0x100);
1267 auto_key_buffer->write(n_code & 0x30ff);
1280 #if defined(USE_AUTO_KEY_CAPS_LOCK)
1281 // use caps lock key to switch uppercase/lowercase of alphabet
1282 // USE_AUTO_KEY_CAPS_LOCK shows the caps lock key code
1283 bool caps = ((code & 0x400) != 0);
1284 if(prev_caps != caps) {
1285 auto_key_buffer->write(USE_AUTO_KEY_CAPS_LOCK);
1289 #if defined(USE_AUTO_KEY_CAPS_LOCK) || defined(USE_AUTO_KEY_NO_CAPS)
1290 code &= ~(0x400 | 0x800); // don't press shift key for both alphabet and ALPHABET
1291 #elif defined(USE_KEY_LOCKED)
1292 if(get_caps_locked()) {
1293 code &= ~0x400; // don't press shift key for ALPHABET
1295 code &= ~0x800; // don't press shift key for alphabet
1297 #elif defined(USE_AUTO_KEY_CAPS)
1298 code &= ~0x400; // don't press shift key for ALPHABET
1300 code &= ~0x800; // don't press shift key for alphabet
1302 if(code & (0x100 | 0x400 | 0x800)) {
1303 auto_key_buffer->write((code & 0xff) | 0x100);
1305 auto_key_buffer->write(code & 0xff);
1309 // release kana lock
1311 auto_key_buffer->write(0xf2);
1313 #if defined(USE_AUTO_KEY_CAPS_LOCK)
1314 // release caps lock
1316 auto_key_buffer->write(USE_AUTO_KEY_CAPS_LOCK);
1321 bool is_alphabet(char code)
1323 return (code >= 'a' && code <= 'z');
1326 bool is_vowel(char code)
1328 return (code == 'a' || code == 'i' || code == 'u' || code == 'e' || code == 'o');
1331 bool is_consonant(char code)
1333 return (is_alphabet(code) && !is_vowel(code));
1336 void EMU::set_auto_key_char(char code)
1338 static char codes[5] = {0};
1341 #ifdef USE_KEY_LOCKED
1342 if(!get_kana_locked())
1344 set_auto_key_code(0xf2);
1345 memset(codes, 0, sizeof(codes));
1346 } else if(code == 0) {
1348 if(codes[3] == 'n') {
1349 set_auto_key_code(0xdd); // 'ン'
1351 set_auto_key_code(0xf2);
1352 memset(codes, 0, sizeof(codes));
1353 } else if(code == 0x08 || code == 0x09 || code == 0x0d || code == 0x1b || code == 0x20) {
1354 if(codes[3] == 'n') {
1355 set_auto_key_code(0xdd); // 'ン'
1357 set_auto_key_code(code);
1358 memset(codes, 0, sizeof(codes));
1359 #ifdef USE_AUTO_KEY_NUMPAD
1360 } else if(code >= 0x30 && code <= 0x39) {
1361 if(codes[3] == 'n') {
1362 set_auto_key_code(0xdd); // 'ン'
1364 set_auto_key_code(code);
1365 memset(codes, 0, sizeof(codes));
1368 codes[0] = codes[1];
1369 codes[1] = codes[2];
1370 codes[2] = codes[3];
1371 codes[3] = (code >= 'A' && code <= 'Z') ? ('a' + (code - 'A')) : code & 0xff;
1374 if(codes[2] == 'n' && !is_vowel(codes[3])) {
1375 set_auto_key_code(0xdd); // 'ン'
1376 if(codes[3] == 'n') {
1377 memset(codes, 0, sizeof(codes));
1380 } else if(codes[2] == codes[3] && is_consonant(codes[3])) {
1381 set_auto_key_code(0xaf); // 'ッ'
1384 for(int i = 0;; i++) {
1385 size_t len = strlen(romaji_table[i].romaji);
1389 if(!(is_alphabet(codes[3])) /*&& !((codes[3] >= 0x2c) && (codes[3] <= 0x2e)) && !((codes[3] == 0x5b) || (codes[3] == 0x5d))*/) {
1390 set_auto_key_code(codes[3]);
1391 memset(codes, 0, sizeof(codes));
1394 } else if(len == 1) {
1395 comp = strcmp(romaji_table[i].romaji, &codes[3]);
1396 } else if(len == 2) {
1397 comp = strcmp(romaji_table[i].romaji, &codes[2]);
1398 } else if(len == 3) {
1399 comp = strcmp(romaji_table[i].romaji, &codes[1]);
1400 } else if(len == 4) {
1401 comp = strcmp(romaji_table[i].romaji, &codes[0]);
1404 for(int j = 0; j < 4; j++) {
1405 if(!romaji_table[i].kana[j]) {
1409 bool handakuon_found = false;
1410 bool dakuon_found = false;
1411 #if defined(USE_TWO_STROKE_AUTOKEY_HANDAKUON)
1412 if(romaji_table[i].kana[1] == 0xdf) {
1414 for(int jj = 0;;jj++) {
1415 if(kana_handakuon_keyboard_table[jj][0] == -1) break;
1416 if(kana_handakuon_keyboard_table[jj][0] == romaji_table[i].kana[0]) {
1417 for(int l = 1; l < 6; l++) {
1418 if(kana_handakuon_keyboard_table[jj][l] == 0x00) break;
1419 auto_key_buffer->write(kana_handakuon_keyboard_table[jj][l] & 0x31ff);
1420 if(!is_auto_key_running()) {
1424 handakuon_found = true;
1431 #if defined(USE_TWO_STROKE_AUTOKEY_DAKUON)
1432 if(romaji_table[i].kana[1] == 0xde) {
1434 for(int jj = 0;;jj++) {
1435 if(kana_dakuon_keyboard_table[jj][0] == -1) break;
1436 if(kana_dakuon_keyboard_table[jj][0] == romaji_table[i].kana[0]) {
1437 for(int l = 1; l < 6; l++) {
1438 if(kana_dakuon_keyboard_table[jj][l] == 0x00) break;
1439 auto_key_buffer->write(kana_dakuon_keyboard_table[jj][l] & 0x31ff);
1441 if(!is_auto_key_running()) {
1445 dakuon_found = true;
1451 if((handakuon_found) || (dakuon_found)) {
1455 set_auto_key_code(romaji_table[i].kana[j]);
1457 memset(codes, 0, sizeof(codes));
1464 void EMU::start_auto_key()
1468 osd->now_auto_key = true;
1471 void EMU::stop_auto_key()
1473 if(auto_key_shift) {
1474 osd->key_up_native(VK_LSHIFT);
1476 auto_key_phase = auto_key_shift = 0;
1477 osd->now_auto_key = false;
1480 #ifndef USE_AUTO_KEY_SHIFT
1481 #define USE_AUTO_KEY_SHIFT 0
1484 #define VK_LSHIFT 0xA0
1487 void EMU::update_auto_key()
1489 switch(auto_key_phase) {
1491 if(auto_key_buffer && !auto_key_buffer->empty()) {
1492 // update shift key status
1493 int shift = auto_key_buffer->read_not_remove(0) & 0x100;
1494 if(shift && !auto_key_shift) {
1495 osd->key_down_native(VK_LSHIFT, false);
1496 } else if(!shift && auto_key_shift) {
1497 osd->key_up_native(VK_LSHIFT);
1499 auto_key_shift = shift;
1503 case 3 + USE_AUTO_KEY_SHIFT:
1504 if(auto_key_buffer && !auto_key_buffer->empty()) {
1505 if(!(auto_key_buffer->read_not_remove(0) & 0x2000)) {
1506 osd->key_down_native(auto_key_buffer->read_not_remove(0) & 0xff, false);
1507 // printf("Press key: %04X\n", auto_key_buffer->read_not_remove(0));
1512 case USE_AUTO_KEY + USE_AUTO_KEY_SHIFT:
1513 if(auto_key_buffer && !auto_key_buffer->empty()) {
1514 if(!(auto_key_buffer->read_not_remove(0) & 0x1000)) {
1515 osd->key_up_native(auto_key_buffer->read_not_remove(0) & 0xff);
1516 // printf("Release key: %04X\n", auto_key_buffer->read_not_remove(0));
1521 case USE_AUTO_KEY_RELEASE + USE_AUTO_KEY_SHIFT:
1522 if(auto_key_buffer && !auto_key_buffer->empty()) {
1523 // wait enough while vm analyzes one line
1524 if(auto_key_buffer->read() == 0xd) {
1530 if(auto_key_buffer && !auto_key_buffer->empty()) {
1537 if(auto_key_phase) {
1545 void EMU::update_joystick()
1547 uint8_t *key_buffer = osd->get_key_buffer();
1549 uint32_t *joyp = osd->get_joy_buffer();
1550 uint32_t joy_buffer[4];
1551 memset(joy_status, 0, sizeof(joy_status));
1552 for(int i = 0; i < 4; i++) {
1553 joy_buffer[i] = joyp[i];
1555 osd->release_joy_buffer(joyp);
1557 for(int i = 0; i < 4; i++) {
1558 for(int j = 0; j < 16; j++) {
1559 if(config.joy_buttons[i][j] < 0) {
1560 int code = -config.joy_buttons[i][j];
1561 if(code < 256 && key_buffer[code]) {
1562 joy_status[i] |= (1 << j);
1563 //printf("%d %d %02x %02x\n", i, j, config.joy_buttons[i][j], joy_status[i]);
1566 int stick = config.joy_buttons[i][j] >> 5;
1567 int button = config.joy_buttons[i][j] & 0x1f;
1568 if(stick < 4 && (joy_buffer[stick & 3] & (1 << button))) {
1569 joy_status[i] |= (1 << j);
1570 //printf("%d %d %02x %02x\n", i, j, config.joy_buttons[i][j], joy_status[i]);
1578 const uint8_t* EMU::get_key_buffer()
1580 return (const uint8_t*)osd->get_key_buffer();
1584 const uint32_t* EMU::get_joy_buffer()
1586 // Update joystick data per query joystick buffer.
1588 return (const uint32_t*)joy_status;
1590 void EMU::release_joy_buffer(const uint32_t* ptr)
1592 // ToDo: Unlock buffer.
1597 const int32_t* EMU::get_mouse_buffer()
1599 return (const int32_t*)osd->get_mouse_buffer();
1601 void EMU::release_mouse_buffer(const int32_t* ptr)
1603 // ToDo: Unlock buffer.
1604 osd->release_mouse_buffer((int32_t*)ptr);
1606 const int32_t EMU::get_mouse_button()
1608 return (const int32_t)osd->get_mouse_button();
1613 // ----------------------------------------------------------------------------
1615 // ----------------------------------------------------------------------------
1617 double EMU::get_window_mode_power(int mode)
1619 return osd->get_window_mode_power(mode);
1622 int EMU::get_window_mode_width(int mode)
1624 return osd->get_window_mode_width(mode);
1627 int EMU::get_window_mode_height(int mode)
1629 return osd->get_window_mode_height(mode);
1632 void EMU::set_host_window_size(int window_width, int window_height, bool window_mode)
1634 osd->set_host_window_size(window_width, window_height, window_mode);
1637 void EMU::set_vm_screen_size(int screen_width, int screen_height, int window_width, int window_height, int window_width_aspect, int window_height_aspect)
1639 osd->set_vm_screen_size(screen_width, screen_height, window_width, window_height, window_width_aspect, window_height_aspect);
1642 void EMU::set_vm_screen_lines(int lines)
1644 osd->set_vm_screen_lines(lines);
1648 int EMU::get_vm_window_width()
1650 return osd->get_vm_window_width();
1653 int EMU::get_vm_window_height()
1655 return osd->get_vm_window_height();
1658 int EMU::get_vm_window_width_aspect()
1660 return osd->get_vm_window_width_aspect();
1663 int EMU::get_vm_window_height_aspect()
1665 return osd->get_vm_window_height_aspect();
1668 #if defined(USE_MINIMUM_RENDERING)
1669 bool EMU::is_screen_changed()
1671 return vm->is_screen_changed();
1675 int EMU::draw_screen()
1677 #ifdef ONE_BOARD_MICRO_COMPUTER
1678 if(now_waiting_in_debugger) {
1679 osd->reload_bitmap();
1682 return osd->draw_screen();
1685 scrntype_t* EMU::get_screen_buffer(int y)
1687 return osd->get_vm_screen_buffer(y);
1690 #ifdef USE_SCREEN_FILTER
1691 void EMU::screen_skip_line(bool skip_line)
1693 osd->screen_skip_line = skip_line;
1697 #ifdef ONE_BOARD_MICRO_COMPUTER
1698 void EMU::get_invalidated_rect(int *left, int *top, int *right, int *bottom)
1700 #ifdef MAX_DRAW_RANGES
1701 for(int i = 0; i < MAX_DRAW_RANGES; i++) {
1703 for(int i = 0; i < vm->max_draw_ranges(); i++) { // for TK-80BS
1705 int x1 = vm_ranges[i].x;
1706 int y1 = vm_ranges[i].y;
1707 int x2 = x1 + vm_ranges[i].width;
1708 int y2 = y1 + vm_ranges[i].height;
1710 *left = (i == 0) ? x1 : min(x1, *left );
1711 *top = (i == 0) ? y1 : min(y1, *top );
1712 *right = (i == 0) ? x2 : max(x2, *right );
1713 *bottom = (i == 0) ? y2 : max(y2, *bottom);
1717 void EMU::reload_bitmap()
1719 osd->reload_bitmap();
1724 void EMU::invalidate_screen()
1726 osd->invalidate_screen();
1729 void EMU::update_screen(HDC hdc)
1731 osd->update_screen(hdc);
1735 void EMU::capture_screen()
1737 osd->capture_screen();
1740 bool EMU::start_record_video(int fps)
1742 return osd->start_record_video(fps);
1745 void EMU::stop_record_video()
1747 osd->stop_record_video();
1750 bool EMU::is_video_recording()
1752 return osd->now_record_video;
1755 // ----------------------------------------------------------------------------
1757 // ----------------------------------------------------------------------------
1759 void EMU::mute_sound()
1764 void EMU::start_record_sound()
1766 osd->start_record_sound();
1769 void EMU::stop_record_sound()
1771 osd->stop_record_sound();
1774 bool EMU::is_sound_recording()
1776 return osd->now_record_sound;
1779 // ----------------------------------------------------------------------------
1781 // ----------------------------------------------------------------------------
1783 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
1784 void EMU::get_video_buffer()
1786 osd->get_video_buffer();
1789 void EMU::mute_video_dev(bool l, bool r)
1791 osd->mute_video_dev(l, r);
1795 #ifdef USE_MOVIE_PLAYER
1796 bool EMU::open_movie_file(const _TCHAR* file_path)
1798 return osd->open_movie_file(file_path);
1801 void EMU::close_movie_file()
1803 osd->close_movie_file();
1806 void EMU::play_movie()
1811 void EMU::stop_movie()
1816 void EMU::pause_movie()
1821 double EMU::get_movie_frame_rate()
1823 return osd->get_movie_frame_rate();
1826 int EMU::get_movie_sound_rate()
1828 return osd->get_movie_sound_rate();
1831 void EMU::set_cur_movie_frame(int frame, bool relative)
1833 osd->set_cur_movie_frame(frame, relative);
1836 uint32_t EMU::get_cur_movie_frame()
1838 return osd->get_cur_movie_frame();
1842 #ifdef USE_VIDEO_CAPTURE
1843 int EMU::get_cur_capture_dev_index()
1845 return osd->get_cur_capture_dev_index();
1848 int EMU::get_num_capture_devs()
1850 return osd->get_num_capture_devs();
1853 _TCHAR* EMU::get_capture_dev_name(int index)
1855 return osd->get_capture_dev_name(index);
1858 void EMU::open_capture_dev(int index, bool pin)
1860 osd->open_capture_dev(index, pin);
1863 void EMU::close_capture_dev()
1865 osd->close_capture_dev();
1868 void EMU::show_capture_dev_filter()
1870 osd->show_capture_dev_filter();
1873 void EMU::show_capture_dev_pin()
1875 osd->show_capture_dev_pin();
1878 void EMU::show_capture_dev_source()
1880 osd->show_capture_dev_source();
1883 void EMU::set_capture_dev_channel(int ch)
1885 osd->set_capture_dev_channel(ch);
1889 // ----------------------------------------------------------------------------
1891 // ----------------------------------------------------------------------------
1894 void EMU::create_bitmap(bitmap_t *bitmap, int width, int height)
1896 osd->create_bitmap(bitmap, width, height);
1899 void EMU::release_bitmap(bitmap_t *bitmap)
1901 osd->release_bitmap(bitmap);
1904 void EMU::create_font(font_t *font, const _TCHAR *family, int width, int height, int rotate, bool bold, bool italic)
1906 osd->create_font(font, family, width, height, rotate, bold, italic);
1909 void EMU::release_font(font_t *font)
1911 osd->release_font(font);
1914 void EMU::create_pen(pen_t *pen, int width, uint8_t r, uint8_t g, uint8_t b)
1916 osd->create_pen(pen, width, r, g, b);
1919 void EMU::release_pen(pen_t *pen)
1921 osd->release_pen(pen);
1924 void EMU::clear_bitmap(bitmap_t *bitmap, uint8_t r, uint8_t g, uint8_t b)
1926 osd->clear_bitmap(bitmap, r, g, b);
1929 int EMU::get_text_width(bitmap_t *bitmap, font_t *font, const char *text)
1931 return osd->get_text_width(bitmap, font, text);
1934 void EMU::draw_text_to_bitmap(bitmap_t *bitmap, font_t *font, int x, int y, const char *text, uint8_t r, uint8_t g, uint8_t b)
1936 osd->draw_text_to_bitmap(bitmap, font, x, y, text, r, g, b);
1939 void EMU::draw_line_to_bitmap(bitmap_t *bitmap, pen_t *pen, int sx, int sy, int ex, int ey)
1941 osd->draw_line_to_bitmap(bitmap, pen, sx, sy, ex, ey);
1944 void EMU::draw_rectangle_to_bitmap(bitmap_t *bitmap, int x, int y, int width, int height, uint8_t r, uint8_t g, uint8_t b)
1946 osd->draw_rectangle_to_bitmap(bitmap, x, y, width, height, r, g, b);
1949 void EMU::draw_point_to_bitmap(bitmap_t *bitmap, int x, int y, uint8_t r, uint8_t g, uint8_t b)
1951 osd->draw_point_to_bitmap(bitmap, x, y, r, g, b);
1954 void EMU::stretch_bitmap(bitmap_t *dest, int dest_x, int dest_y, int dest_width, int dest_height, bitmap_t *source, int source_x, int source_y, int source_width, int source_height)
1956 osd->stretch_bitmap(dest, dest_x, dest_y, dest_width, dest_height, source, source_x, source_y, source_width, source_height);
1959 void EMU::write_bitmap_to_file(bitmap_t *bitmap, const _TCHAR *file_path)
1961 osd->write_bitmap_to_file(bitmap, file_path);
1965 // ----------------------------------------------------------------------------
1967 // ----------------------------------------------------------------------------
1970 SOCKET EMU::get_socket(int ch)
1972 return osd->get_socket(ch);
1975 void EMU::notify_socket_connected(int ch)
1977 osd->notify_socket_connected(ch);
1980 void EMU::notify_socket_disconnected(int ch)
1982 osd->notify_socket_disconnected(ch);
1985 bool EMU::initialize_socket_tcp(int ch)
1987 return osd->initialize_socket_tcp(ch);
1990 bool EMU::initialize_socket_udp(int ch)
1992 return osd->initialize_socket_udp(ch);
1995 bool EMU::connect_socket(int ch, uint32_t ipaddr, int port)
1997 return osd->connect_socket(ch, ipaddr, port);
2000 void EMU::disconnect_socket(int ch)
2002 osd->disconnect_socket(ch);
2005 bool EMU::listen_socket(int ch)
2007 return osd->listen_socket(ch);
2010 void EMU::send_socket_data_tcp(int ch)
2012 osd->send_socket_data_tcp(ch);
2015 void EMU::send_socket_data_udp(int ch, uint32_t ipaddr, int port)
2017 osd->send_socket_data_udp(ch, ipaddr, port);
2020 void EMU::send_socket_data(int ch)
2022 osd->send_socket_data(ch);
2025 void EMU::recv_socket_data(int ch)
2027 osd->recv_socket_data(ch);
2031 // ----------------------------------------------------------------------------
2033 // ----------------------------------------------------------------------------
2036 void EMU::send_to_midi(uint8_t data, int ch, double timestamp_usec)
2038 osd->send_to_midi(data, ch, timestamp_usec);
2041 bool EMU::recv_from_midi(uint8_t *data, int ch, double timestamp_usec)
2043 return osd->recv_from_midi(data, ch, timestamp_usec);
2045 // ToDo: Will implement timeout function.
2046 bool EMU::send_to_midi_timeout(uint8_t data, int ch, uint64_t timeout_ms, double timestamp_usec)
2048 // ToDo: will implement handshake.
2049 // Q: Need to check VM's timeout status?
2050 return osd->send_to_midi_timeout(data, ch, timeout_ms, timestamp_usec);
2053 bool EMU::recv_from_midi_timeout(uint8_t* data, int ch, uint64_t timeout_ms, double timestamp_usec)
2055 // ToDo: will implement handshake.
2056 // Q: Need to check VM's timeout status?
2057 return osd->recv_from_midi_timeout(data, ch, timeout_ms, timestamp_usec);
2060 //void EMU::notify_timeout_sending_to_midi(int ch)
2062 // vm->notify_timeout_sending_to_midi(ch);
2064 //void EMU::notify_timeout_receiving_from_midi(int ch)
2066 // vm->notify_timeout_receiving_from_midi(ch);
2069 void EMU::reset_to_midi(int ch, double timestamp_usec)
2071 osd->reset_to_midi(ch, timestamp_usec);
2074 void EMU::initialize_midi_device(bool handshake_from_midi, bool handshake_to_midi, int ch)
2076 osd->initialize_midi_device(handshake_from_midi, handshake_to_midi, ch);
2079 //void EMU::ready_receive_from_midi(int ch, double timestamp_usec)
2081 // vm->ready_receive_from_midi(ch, timestamp_usec);
2084 void EMU::ready_send_to_midi(int ch, double timestamp_usec)
2086 osd->ready_send_to_midi(ch,timestamp_usec);
2089 void EMU::request_stop_to_receive_from_midi(int ch, double timestamp_usec)
2091 osd->request_stop_to_receive_from_midi(ch, timestamp_usec);
2094 //void EMU::request_stop_to_send_to_midi(int ch, double timestamp_usec)
2096 // vm->request_stop_to_send_to_midi(ch, timestamp_usec);
2101 // ---------------------------------------------------------------------------
2102 // debugger (some functions needed by libCSPcommon_vm 20190221 K.O)
2103 // ---------------------------------------------------------------------------
2105 void EMU::start_waiting_in_debugger()
2108 now_waiting_in_debugger = true;
2112 osd->start_waiting_in_debugger();
2116 void EMU::finish_waiting_in_debugger()
2119 osd->finish_waiting_in_debugger();
2120 now_waiting_in_debugger = false;
2121 osd->unmute_sound();
2125 void EMU::process_waiting_in_debugger()
2128 osd->process_waiting_in_debugger();
2134 // ----------------------------------------------------------------------------
2136 // ----------------------------------------------------------------------------
2139 void EMU::initialize_debug_log()
2141 _TCHAR path[_MAX_PATH];
2142 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
2145 void EMU::release_debug_log()
2155 static _TCHAR prev_buffer[2048] = {0};
2158 void EMU::out_debug_log(const _TCHAR* format, ...)
2160 common_initialize();
2164 _TCHAR buffer[2048];
2166 va_start(ap, format);
2167 my_vstprintf_s(buffer, 2048, format, ap);
2170 if(_tcscmp(prev_buffer, buffer) == 0) {
2173 my_tcscpy_s(prev_buffer, 2048, buffer);
2175 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
2176 std::shared_ptr<CSP_Logger> lp = csp_logger;
2177 lp->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_EMU, "%s", buffer);
2180 _ftprintf(debug_log, _T("(%f uS) %s"), vm->get_current_usec(), buffer);
2181 static int size = 0;
2182 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
2184 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
2192 void EMU::force_out_debug_log(const _TCHAR* format, ...)
2196 _TCHAR buffer[1024];
2198 va_start(ap, format);
2199 my_vstprintf_s(buffer, 1024, format, ap);
2201 my_tcscpy_s(prev_buffer, 1024, buffer);
2203 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
2204 std::shared_ptr<CSP_Logger> lp = csp_logger;
2205 lp->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_EMU, "%s", buffer);
2208 _ftprintf(debug_log, _T("%s"), buffer);
2209 static int size = 0;
2210 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
2212 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
2220 void EMU::out_message(const _TCHAR* format, ...)
2222 //#if defined(_USE_QT)
2223 // _TCHAR mes_buf[1024];
2226 va_start(ap, format);
2227 my_vstprintf_s(message, 1024, format, ap); // Security for MSVC:C6386.
2228 //#if defined(_USE_QT)
2229 // memset(mes_buf, 0x00, sizeof(mes_buf));
2230 // my_vstprintf_s(mes_buf, 1024, format, ap); // Security for MSVC:C6386.
2231 // csp_logger->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_EMU, "%s", mes_buf);
2234 message_count = 4; // 4sec
2237 // ----------------------------------------------------------------------------
2239 // ----------------------------------------------------------------------------
2242 void EMU::sleep(uint32_t ms)
2248 // ----------------------------------------------------------------------------
2250 // ----------------------------------------------------------------------------
2252 static uint8_t hex2uint8(char *value)
2255 memset(tmp, 0, sizeof(tmp));
2256 memcpy(tmp, value, 2);
2257 return (uint8_t)strtoul(tmp, NULL, 16);
2260 static uint16_t hex2uint16(char *value)
2263 memset(tmp, 0, sizeof(tmp));
2264 memcpy(tmp, value, 4);
2265 return (uint16_t)strtoul(tmp, NULL, 16);
2268 static bool hex2bin(const _TCHAR* file_path, const _TCHAR* dest_path)
2270 bool result = false;
2271 FILEIO *fio_s = new FILEIO();
2272 if(fio_s->Fopen(file_path, FILEIO_READ_BINARY)) {
2275 uint8_t buffer[0x10000];
2276 memset(buffer, 0xff, sizeof(buffer));
2277 while(fio_s->Fgets(line, sizeof(line)) != NULL) {
2278 if(line[0] != ':') continue;
2279 int bytes = hex2uint8(line + 1);
2280 int offset = hex2uint16(line + 3);
2281 uint8_t record_type = hex2uint8(line + 7);
2282 if(record_type == 0x01) break;
2283 if(record_type != 0x00) continue;
2284 for(int i = 0; i < bytes; i++) {
2285 if((offset + i) < (int)sizeof(buffer)) {
2286 if(length < (offset + i)) {
2287 length = offset + i;
2289 buffer[offset + i] = hex2uint8(line + 9 + 2 * i);
2294 FILEIO *fio_d = new FILEIO();
2295 if(fio_d->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
2296 fio_d->Fwrite(buffer, length, 1);
2308 void EMU::initialize_media()
2311 memset(&cart_status, 0, sizeof(cart_status));
2313 #ifdef USE_FLOPPY_DISK
2314 memset(floppy_disk_status, 0, sizeof(floppy_disk_status));
2316 #ifdef USE_QUICK_DISK
2317 memset(&quick_disk_status, 0, sizeof(quick_disk_status));
2319 #ifdef USE_HARD_DISK
2320 memset(&hard_disk_status, 0, sizeof(hard_disk_status));
2323 memset(&tape_status, 0, sizeof(tape_status));
2325 #ifdef USE_COMPACT_DISC
2326 memset(&compact_disc_status, 0, sizeof(compact_disc_status));
2328 #ifdef USE_LASER_DISC
2329 memset(&laser_disc_status, 0, sizeof(laser_disc_status));
2332 memset(&bubble_casette_status, 0, sizeof(bubble_casette_status));
2336 #if defined(_USE_QT)
2337 extern void DLL_PREFIX_I Convert_CP932_to_UTF8(char *dst, char *src, int n_limit, int i_limit);
2340 void EMU::update_media()
2342 #ifdef USE_FLOPPY_DISK
2343 for(int drv = 0; drv < USE_FLOPPY_DISK; drv++) {
2344 if(floppy_disk_status[drv].wait_count != 0 && --floppy_disk_status[drv].wait_count == 0) {
2345 vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank);
2346 #if USE_FLOPPY_DISK > 1
2347 out_message(_T("FD%d: %s"), drv + BASE_FLOPPY_DISK_NUM, floppy_disk_status[drv].path);
2349 out_message(_T("FD: %s"), floppy_disk_status[drv].path);
2354 #ifdef USE_QUICK_DISK
2355 for(int drv = 0; drv < USE_QUICK_DISK; drv++) {
2356 if(quick_disk_status[drv].wait_count != 0 && --quick_disk_status[drv].wait_count == 0) {
2357 vm->open_quick_disk(drv, quick_disk_status[drv].path);
2358 #if USE_QUICK_DISK > 1
2359 out_message(_T("QD%d: %s"), drv + BASE_QUICK_DISK_NUM, quick_disk_status[drv].path);
2361 out_message(_T("QD: %s"), quick_disk_status[drv].path);
2366 #ifdef USE_HARD_DISK
2367 for(int drv = 0; drv < USE_HARD_DISK; drv++) {
2368 if(hard_disk_status[drv].wait_count != 0 && --hard_disk_status[drv].wait_count == 0) {
2369 vm->open_hard_disk(drv, hard_disk_status[drv].path);
2370 #if USE_HARD_DISK > 1
2371 out_message(_T("HD%d: %s"), drv + BASE_HARD_DISK_NUM, hard_disk_status[drv].path);
2373 out_message(_T("HD: %s"), hard_disk_status[drv].path);
2379 for(int drv = 0; drv < USE_TAPE; drv++) {
2380 if(tape_status[drv].wait_count != 0 && --tape_status[drv].wait_count == 0) {
2381 if(tape_status[drv].play) {
2382 vm->play_tape(drv, tape_status[drv].path);
2384 vm->rec_tape(drv, tape_status[drv].path);
2387 out_message(_T("CMT%d: %s"), drv + BASE_TAPE_NUM, tape_status[drv].path);
2389 out_message(_T("CMT: %s"), tape_status[drv].path);
2394 #ifdef USE_COMPACT_DISC
2395 for(int drv = 0; drv < USE_COMPACT_DISC; drv++) {
2396 if(compact_disc_status[drv].wait_count != 0 && --compact_disc_status[drv].wait_count == 0) {
2397 vm->open_compact_disc(drv, compact_disc_status[drv].path);
2398 #if USE_COMPACT_DISC > 1
2399 out_message(_T("CD%d: %s"), drv + BASE_COMPACT_DISC_NUM, compact_disc_status[drv].path);
2401 out_message(_T("CD: %s"), compact_disc_status[drv].path);
2406 #ifdef USE_LASER_DISC
2407 for(int drv = 0; drv < USE_LASER_DISC; drv++) {
2408 if(laser_disc_status[drv].wait_count != 0 && --laser_disc_status[drv].wait_count == 0) {
2409 vm->open_laser_disc(drv, laser_disc_status[drv].path);
2410 #if USE_LASER_DISC > 1
2411 out_message(_T("LD%d: %s"), drv + BASE_LASER_DISC_NUM, laser_disc_status[drv].path);
2413 out_message(_T("LD: %s"), laser_disc_status[drv].path);
2419 for(int drv = 0; drv < USE_BUBBLE; drv++) {
2420 if(bubble_casette_status[drv].wait_count != 0 && --bubble_casette_status[drv].wait_count == 0) {
2421 vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
2423 out_message(_T("Bubble%d: %s"), drv + BASE_BUBBLE_NUM, bubble_casette_status[drv].path);
2425 out_message(_T("Bubble: %s"), bubble_casette_status[drv].path);
2432 void EMU::restore_media()
2435 for(int drv = 0; drv < USE_CART; drv++) {
2436 if(cart_status[drv].path[0] != _T('\0')) {
2437 if(check_file_extension(cart_status[drv].path, _T(".hex")) && hex2bin(cart_status[drv].path, create_local_path(_T("hex2bin.$$$")))) {
2438 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
2439 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
2441 vm->open_cart(drv, cart_status[drv].path);
2446 #ifdef USE_FLOPPY_DISK
2447 for(int drv = 0; drv < USE_FLOPPY_DISK; drv++) {
2448 if(floppy_disk_status[drv].path[0] != _T('\0')) {
2449 vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank);
2453 #ifdef USE_QUICK_DISK
2454 for(int drv = 0; drv < USE_QUICK_DISK; drv++) {
2455 if(quick_disk_status[drv].path[0] != _T('\0')) {
2456 vm->open_quick_disk(drv, quick_disk_status[drv].path);
2460 #ifdef USE_HARD_DISK
2461 for(int drv = 0; drv < USE_HARD_DISK; drv++) {
2462 if(hard_disk_status[drv].path[0] != _T('\0')) {
2463 vm->open_hard_disk(drv, hard_disk_status[drv].path);
2468 for(int drv = 0; drv < USE_TAPE; drv++) {
2469 if(tape_status[drv].path[0] != _T('\0')) {
2470 if(tape_status[drv].play) {
2471 vm->play_tape(drv, tape_status[drv].path);
2473 tape_status[drv].path[0] = _T('\0');
2478 #ifdef USE_COMPACT_DISC
2479 for(int drv = 0; drv < USE_COMPACT_DISC; drv++) {
2480 if(compact_disc_status[drv].path[0] != _T('\0')) {
2481 vm->open_compact_disc(drv, compact_disc_status[drv].path);
2485 #ifdef USE_LASER_DISC
2486 for(int drv = 0; drv < USE_LASER_DISC; drv++) {
2487 if(laser_disc_status[drv].path[0] != _T('\0')) {
2488 vm->open_laser_disc(drv, laser_disc_status[drv].path);
2493 for(int drv = 0; drv < USE_BUBBLE; drv++) {
2494 if(bubble_casette_status[drv].path[0] != _T('\0')) {
2495 vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
2502 void EMU::open_cart(int drv, const _TCHAR* file_path)
2504 if(drv < USE_CART) {
2505 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
2506 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
2507 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
2509 vm->open_cart(drv, file_path);
2511 my_tcscpy_s(cart_status[drv].path, _MAX_PATH, file_path);
2512 out_message(_T("Cart%d: %s"), drv + 1, file_path);
2513 #if !defined(_USE_QT)
2514 // restart recording
2515 bool s = osd->now_record_sound;
2516 bool v = osd->now_record_video;
2517 stop_record_sound();
2518 stop_record_video();
2520 if(s) osd->start_record_sound();
2521 if(v) osd->start_record_video(-1);
2526 void EMU::close_cart(int drv)
2528 if(drv < USE_CART) {
2529 vm->close_cart(drv);
2530 clear_media_status(&cart_status[drv]);
2532 out_message(_T("Cart%d: Ejected"), drv + BASE_CART_NUM);
2534 out_message(_T("Cart: Ejected"));
2536 #if !defined(_USE_QT)
2538 stop_record_video();
2539 stop_record_sound();
2544 bool EMU::is_cart_inserted(int drv)
2546 if(drv < USE_CART) {
2547 return vm->is_cart_inserted(drv);
2554 #ifdef USE_FLOPPY_DISK
2555 bool EMU::create_blank_floppy_disk(const _TCHAR* file_path, uint8_t type)
2558 type: 0x00 = 2D, 0x10 = 2DD, 0x20 = 2HD
2566 uint32_t trkptr[164];
2569 memset(&d88_hdr, 0, sizeof(d88_hdr));
2570 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "BLANK");
2571 d88_hdr.type = type;
2572 d88_hdr.size = sizeof(d88_hdr);
2574 FILEIO *fio = new FILEIO();
2575 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
2576 fio->Fwrite(&d88_hdr, sizeof(d88_hdr), 1);
2583 void EMU::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
2585 if(drv < USE_FLOPPY_DISK) {
2586 d88_file[drv].bank_num = 0;
2587 d88_file[drv].cur_bank = -1;
2588 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
2589 FILEIO *fio = new FILEIO();
2590 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
2592 fio->Fseek(0, FILEIO_SEEK_END);
2593 uint32_t file_size = fio->Ftell(), file_offset = 0;
2594 while(file_offset + 0x2b0 <= file_size && d88_file[drv].bank_num < MAX_D88_BANKS) {
2595 fio->Fseek(file_offset, FILEIO_SEEK_SET);
2598 fio->Fread(tmp, 17, 1);
2600 #if defined(_USE_QT)
2601 memset(d88_file[drv].disk_name[d88_file[drv].bank_num], 0x00, 128);
2602 if(strlen(tmp) > 0) {
2603 Convert_CP932_to_UTF8(d88_file[drv].disk_name[d88_file[drv].bank_num], tmp, 127, 17);
2605 #else /* not _USE_QT */
2606 MultiByteToWideChar(CP_ACP, 0, tmp, -1, d88_file[drv].disk_name[d88_file[drv].bank_num], 18);
2609 fio->Fread(d88_file[drv].disk_name[d88_file[drv].bank_num], 17, 1);
2610 d88_file[drv].disk_name[d88_file[drv].bank_num][17] = 0;
2612 fio->Fseek(file_offset + 0x1c, FILEIO_SEEK_SET);
2613 file_offset += fio->FgetUint32_LE();
2614 d88_file[drv].bank_num++;
2616 my_tcscpy_s(d88_file[drv].path, _MAX_PATH, file_path);
2617 d88_file[drv].cur_bank = bank;
2619 d88_file[drv].bank_num = 0;
2626 if(vm->is_floppy_disk_inserted(drv)) {
2627 vm->close_floppy_disk(drv);
2629 floppy_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
2630 #if USE_FLOPPY_DISK > 1
2631 out_message(_T("FD%d: Ejected"), drv + BASE_FLOPPY_DISK_NUM);
2633 out_message(_T("FD: Ejected"));
2635 } else if(floppy_disk_status[drv].wait_count == 0) {
2636 vm->open_floppy_disk(drv, file_path, bank);
2637 #if USE_FLOPPY_DISK > 1
2638 out_message(_T("FD%d: %s"), drv + BASE_FLOPPY_DISK_NUM, file_path);
2640 out_message(_T("FD: %s"), file_path);
2643 my_tcscpy_s(floppy_disk_status[drv].path, _MAX_PATH, file_path);
2644 floppy_disk_status[drv].bank = bank;
2649 void EMU::close_floppy_disk(int drv)
2651 if(drv < USE_FLOPPY_DISK) {
2652 d88_file[drv].bank_num = 0;
2653 d88_file[drv].cur_bank = -1;
2655 vm->close_floppy_disk(drv);
2656 clear_media_status(&floppy_disk_status[drv]);
2657 #if USE_FLOPPY_DISK > 1
2658 out_message(_T("FD%d: Ejected"), drv + BASE_FLOPPY_DISK_NUM);
2660 out_message(_T("FD: Ejected"));
2665 bool EMU::is_floppy_disk_connected(int drv)
2667 if(drv < USE_FLOPPY_DISK) {
2668 return vm->is_floppy_disk_connected(drv);
2674 bool EMU::is_floppy_disk_inserted(int drv)
2676 if(drv < USE_FLOPPY_DISK) {
2677 return vm->is_floppy_disk_inserted(drv);
2683 void EMU::is_floppy_disk_protected(int drv, bool value)
2685 if(drv < USE_FLOPPY_DISK) {
2686 vm->is_floppy_disk_protected(drv, value);
2690 bool EMU::is_floppy_disk_protected(int drv)
2692 if(drv < USE_FLOPPY_DISK) {
2693 return vm->is_floppy_disk_protected(drv);
2699 uint32_t EMU::is_floppy_disk_accessed()
2701 return vm->is_floppy_disk_accessed();
2704 uint32_t EMU::floppy_disk_indicator_color()
2706 return vm->floppy_disk_indicator_color();
2710 #ifdef USE_QUICK_DISK
2711 void EMU::open_quick_disk(int drv, const _TCHAR* file_path)
2713 if(drv < USE_QUICK_DISK) {
2714 if(vm->is_quick_disk_inserted(drv)) {
2715 vm->close_quick_disk(drv);
2717 quick_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
2718 #if USE_QUICK_DISK > 1
2719 out_message(_T("QD%d: Ejected"), drv + BASE_QUICK_DISK_NUM);
2721 out_message(_T("QD: Ejected"));
2723 } else if(quick_disk_status[drv].wait_count == 0) {
2724 vm->open_quick_disk(drv, file_path);
2725 #if USE_QUICK_DISK > 1
2726 out_message(_T("QD%d: %s"), drv + BASE_QUICK_DISK_NUM, file_path);
2728 out_message(_T("QD: %s"), file_path);
2731 my_tcscpy_s(quick_disk_status[drv].path, _MAX_PATH, file_path);
2735 void EMU::close_quick_disk(int drv)
2737 if(drv < USE_QUICK_DISK) {
2738 vm->close_quick_disk(drv);
2739 clear_media_status(&quick_disk_status[drv]);
2740 #if USE_QUICK_DISK > 1
2741 out_message(_T("QD%d: Ejected"), drv + BASE_QUICK_DISK_NUM);
2743 out_message(_T("QD: Ejected"));
2748 bool EMU::is_quick_disk_inserted(int drv)
2750 if(drv < USE_QUICK_DISK) {
2751 return vm->is_quick_disk_inserted(drv);
2757 bool EMU::is_quick_disk_connected(int drv)
2759 if(drv < USE_QUICK_DISK) {
2760 return vm->is_quick_disk_connected(drv);
2766 uint32_t EMU::is_quick_disk_accessed()
2768 return vm->is_quick_disk_accessed();
2772 #ifdef USE_HARD_DISK
2773 bool EMU::create_blank_hard_disk(const _TCHAR* file_path, int sector_size, int sectors, int surfaces, int cylinders)
2775 if(check_file_extension(file_path, _T(".nhd"))) {
2777 const char sig_nhd[] = "T98HDDIMAGE.R0";
2778 typedef struct nhd_header_s {
2781 int32_t header_size; // +272
2782 int32_t cylinders; // +276
2783 int16_t surfaces; // +280
2784 int16_t sectors; // +282
2785 int16_t sector_size; // +284
2786 uint8_t reserved[0xe2];
2788 nhd_header_t header;
2790 memset(&header, 0, sizeof(header));
2791 strcpy(header.sig, "T98HDDIMAGE.R0");
2792 header.header_size = sizeof(header);
2793 header.cylinders = cylinders;
2794 header.surfaces = surfaces;
2795 header.sectors = sectors;
2796 header.sector_size = sector_size;
2798 FILEIO *fio = new FILEIO();
2799 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
2800 fio->Fwrite(&header, sizeof(header), 1);
2801 void *empty = calloc(sector_size, 1);
2803 fio->Fwrite(empty, sector_size, sectors * surfaces * cylinders);
2805 for(int i = 0; i < sectors * surfaces * cylinders; i++) {
2806 fio->Fwrite(empty, sector_size, 1);
2814 } else if(check_file_extension(file_path, _T(".hdi"))) {
2816 typedef struct hdi_header_s {
2817 int32_t dummy; // + 0
2818 int32_t hdd_type; // + 4
2819 int32_t header_size; // + 8
2820 int32_t hdd_size; // +12
2821 int32_t sector_size; // +16
2822 int32_t sectors; // +20
2823 int32_t surfaces; // +24
2824 int32_t cylinders; // +28
2825 uint8_t padding[0x1000 - sizeof(int32_t) * 8];
2827 hdi_header_t header;
2829 memset(&header, 0, sizeof(header));
2830 header.hdd_type = 0; // ???
2831 header.header_size = sizeof(header);
2832 header.hdd_size = sector_size * sectors * surfaces * cylinders;
2833 header.sector_size = sector_size;
2834 header.sectors = sectors;
2835 header.surfaces = surfaces;
2836 header.cylinders = cylinders;
2838 FILEIO *fio = new FILEIO();
2839 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
2840 fio->Fwrite(&header, sizeof(header), 1);
2841 void *empty = calloc(sector_size, 1);
2843 fio->Fwrite(empty, sector_size, sectors * surfaces * cylinders);
2845 for(int i = 0; i < sectors * surfaces * cylinders; i++) {
2846 fio->Fwrite(empty, sector_size, 1);
2855 // unknown extension
2859 void EMU::open_hard_disk(int drv, const _TCHAR* file_path)
2861 if(drv < USE_HARD_DISK) {
2862 if(vm->is_hard_disk_inserted(drv)) {
2863 vm->close_hard_disk(drv);
2865 hard_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
2866 #if USE_HARD_DISK > 1
2867 out_message(_T("HD%d: Unmounted"), drv + BASE_HARD_DISK_NUM);
2869 out_message(_T("HD: Unmounted"));
2871 } else if(hard_disk_status[drv].wait_count == 0) {
2872 vm->open_hard_disk(drv, file_path);
2873 #if USE_HARD_DISK > 1
2874 out_message(_T("HD%d: %s"), drv + BASE_HARD_DISK_NUM, file_path);
2876 out_message(_T("HD: %s"), file_path);
2879 my_tcscpy_s(hard_disk_status[drv].path, _MAX_PATH, file_path);
2880 my_tcscpy_s(config.last_hard_disk_path[drv], _MAX_PATH, file_path);
2884 void EMU::close_hard_disk(int drv)
2886 if(drv < USE_HARD_DISK) {
2887 vm->close_hard_disk(drv);
2888 clear_media_status(&hard_disk_status[drv]);
2889 #if USE_HARD_DISK > 1
2890 out_message(_T("HD%d: Unmounted"), drv + BASE_HARD_DISK_NUM);
2892 out_message(_T("HD: Unmounted"));
2894 config.last_hard_disk_path[drv][0] = '\0';
2898 bool EMU::is_hard_disk_inserted(int drv)
2900 if(drv < USE_HARD_DISK) {
2901 return vm->is_hard_disk_inserted(drv);
2907 uint32_t EMU::is_hard_disk_accessed()
2909 return vm->is_hard_disk_accessed();
2914 void EMU::play_tape(int drv, const _TCHAR* file_path)
2916 if(drv < USE_TAPE) {
2917 if(vm->is_tape_inserted(drv)) {
2918 vm->close_tape(drv);
2920 tape_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
2922 out_message(_T("CMT%d: Ejected"), drv + BASE_TAPE_NUM);
2924 out_message(_T("CMT: Ejected"));
2926 } else if(tape_status[drv].wait_count == 0) {
2927 vm->play_tape(drv, file_path);
2929 out_message(_T("CMT%d: %s"), drv + BASE_TAPE_NUM, file_path);
2931 out_message(_T("CMT: %s"), file_path);
2934 my_tcscpy_s(tape_status[drv].path, _MAX_PATH, file_path);
2935 tape_status[drv].play = true;
2939 void EMU::rec_tape(int drv, const _TCHAR* file_path)
2941 if(drv < USE_TAPE) {
2942 if(vm->is_tape_inserted(drv)) {
2943 vm->close_tape(drv);
2945 tape_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
2947 out_message(_T("CMT%d: Ejected"), drv + BASE_TAPE_NUM);
2949 out_message(_T("CMT: Ejected"));
2951 } else if(tape_status[drv].wait_count == 0) {
2952 vm->rec_tape(drv, file_path);
2954 out_message(_T("CMT%d: %s"), drv + BASE_TAPE_NUM, file_path);
2956 out_message(_T("CMT: %s"), file_path);
2959 my_tcscpy_s(tape_status[drv].path, _MAX_PATH, file_path);
2960 tape_status[drv].play = false;
2964 void EMU::close_tape(int drv)
2966 if(drv < USE_TAPE) {
2967 vm->close_tape(drv);
2968 clear_media_status(&tape_status[drv]);
2970 out_message(_T("CMT%d: Ejected"), drv + BASE_TAPE_NUM);
2972 out_message(_T("CMT: Ejected"));
2977 bool EMU::is_tape_inserted(int drv)
2979 if(drv < USE_TAPE) {
2980 return vm->is_tape_inserted(drv);
2986 bool EMU::is_tape_playing(int drv)
2988 if(drv < USE_TAPE) {
2989 return vm->is_tape_playing(drv);
2995 bool EMU::is_tape_recording(int drv)
2997 if(drv < USE_TAPE) {
2998 return vm->is_tape_recording(drv);
3004 int EMU::get_tape_position(int drv)
3006 if(drv < USE_TAPE) {
3007 return vm->get_tape_position(drv);
3013 const _TCHAR* EMU::get_tape_message(int drv)
3015 if(drv < USE_TAPE) {
3016 return vm->get_tape_message(drv);
3022 void EMU::push_play(int drv)
3024 if(drv < USE_TAPE) {
3029 void EMU::push_stop(int drv)
3031 if(drv < USE_TAPE) {
3036 void EMU::push_fast_forward(int drv)
3038 if(drv < USE_TAPE) {
3039 vm->push_fast_forward(drv);
3043 void EMU::push_fast_rewind(int drv)
3045 if(drv < USE_TAPE) {
3046 vm->push_fast_rewind(drv);
3050 void EMU::push_apss_forward(int drv)
3052 if(drv < USE_TAPE) {
3053 vm->push_apss_forward(drv);
3057 void EMU::push_apss_rewind(int drv)
3059 if(drv < USE_TAPE) {
3060 vm->push_apss_rewind(drv);
3065 #ifdef USE_COMPACT_DISC
3066 void EMU::open_compact_disc(int drv, const _TCHAR* file_path)
3068 if(drv < USE_COMPACT_DISC) {
3069 if(vm->is_compact_disc_inserted(drv)) {
3070 vm->close_compact_disc(drv);
3072 compact_disc_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3073 #if USE_COMPACT_DISC > 1
3074 out_message(_T("CD%d: Ejected"), drv + BASE_COMPACT_DISC_NUM);
3076 out_message(_T("CD: Ejected"));
3078 } else if(compact_disc_status[drv].wait_count == 0) {
3079 vm->open_compact_disc(drv, file_path);
3080 #if USE_COMPACT_DISC > 1
3081 out_message(_T("CD%d: %s"), drv + BASE_COMPACT_DISC_NUM, file_path);
3083 out_message(_T("CD: %s"), file_path);
3086 my_tcscpy_s(compact_disc_status[drv].path, _MAX_PATH, file_path);
3090 void EMU::close_compact_disc(int drv)
3092 if(drv < USE_COMPACT_DISC) {
3093 vm->close_compact_disc(drv);
3094 clear_media_status(&compact_disc_status[drv]);
3095 #if USE_COMPACT_DISC > 1
3096 out_message(_T("CD%d: Ejected"), drv + BASE_COMPACT_DISC_NUM);
3098 out_message(_T("CD: Ejected"));
3103 bool EMU::is_compact_disc_inserted(int drv)
3105 if(drv < USE_COMPACT_DISC) {
3106 return vm->is_compact_disc_inserted(drv);
3112 uint32_t EMU::is_compact_disc_accessed()
3114 return vm->is_compact_disc_accessed();
3118 #ifdef USE_LASER_DISC
3119 void EMU::open_laser_disc(int drv, const _TCHAR* file_path)
3121 if(drv < USE_LASER_DISC) {
3122 if(vm->is_laser_disc_inserted(drv)) {
3123 vm->close_laser_disc(drv);
3125 laser_disc_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3126 #if USE_LASER_DISC > 1
3127 out_message(_T("LD%d: Ejected"), drv + BASE_LASER_DISC_NUM);
3129 out_message(_T("LD: Ejected"));
3131 } else if(laser_disc_status[drv].wait_count == 0) {
3132 vm->open_laser_disc(drv, file_path);
3133 #if USE_LASER_DISC > 1
3134 out_message(_T("LD%d: %s"), drv + BASE_LASER_DISC_NUM, file_path);
3136 out_message(_T("LD: %s"), file_path);
3139 my_tcscpy_s(laser_disc_status[drv].path, _MAX_PATH, file_path);
3143 void EMU::close_laser_disc(int drv)
3145 if(drv < USE_LASER_DISC) {
3146 vm->close_laser_disc(drv);
3147 clear_media_status(&laser_disc_status[drv]);
3148 #if USE_LASER_DISC > 1
3149 out_message(_T("LD%d: Ejected"), drv + BASE_LASER_DISC_NUM);
3151 out_message(_T("LD: Ejected"));
3156 bool EMU::is_laser_disc_inserted(int drv)
3158 if(drv < USE_LASER_DISC) {
3159 return vm->is_laser_disc_inserted(drv);
3165 uint32_t EMU::is_laser_disc_accessed()
3167 return vm->is_laser_disc_accessed();
3171 #ifdef USE_BINARY_FILE
3172 void EMU::load_binary(int drv, const _TCHAR* file_path)
3174 if(drv < USE_BINARY_FILE) {
3175 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
3176 vm->load_binary(drv, create_local_path(_T("hex2bin.$$$")));
3177 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
3179 vm->load_binary(drv, file_path);
3181 #if USE_BINARY_FILE > 1
3182 out_message(_T("Load Binary%d: %s"), drv + BASE_BINARY_FILE_NUM, file_path);
3184 out_message(_T("Load Binary: %s"), file_path);
3189 void EMU::save_binary(int drv, const _TCHAR* file_path)
3191 if(drv < USE_BINARY_FILE) {
3192 vm->save_binary(drv, file_path);
3193 #if USE_BINARY_FILE > 1
3194 out_message(_T("Save Binary%d: %s"), drv + BASE_BINARY_FILE_NUM, file_path);
3196 out_message(_T("Save Binary: %s"), file_path);
3203 void EMU::open_bubble_casette(int drv, const _TCHAR* file_path, int bank)
3205 if(drv < USE_BUBBLE) {
3206 if(vm->is_bubble_casette_inserted(drv)) {
3207 vm->close_bubble_casette(drv);
3209 bubble_casette_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3211 out_message(_T("Bubble%d: Ejected"), drv + BASE_BUBBLE_NUM);
3213 out_message(_T("Bubble: Ejected"));
3215 } else if(bubble_casette_status[drv].wait_count == 0) {
3216 vm->open_bubble_casette(drv, file_path, bank);
3218 out_message(_T("Bubble%d: %s"), drv + BASE_BUBBLE_NUM, file_path);
3220 out_message(_T("Bubble: %s"), file_path);
3223 my_tcscpy_s(bubble_casette_status[drv].path, _MAX_PATH, file_path);
3224 bubble_casette_status[drv].bank = bank;
3228 void EMU::close_bubble_casette(int drv)
3230 if(drv < USE_BUBBLE) {
3231 vm->close_bubble_casette(drv);
3232 clear_media_status(&bubble_casette_status[drv]);
3234 out_message(_T("Bubble%d: Ejected"), drv + BASE_BUBBLE_NUM);
3236 out_message(_T("Bubble: Ejected"));
3241 bool EMU::is_bubble_casette_inserted(int drv)
3243 if(drv < USE_BUBBLE) {
3244 return vm->is_bubble_casette_inserted(drv);
3250 bool EMU::is_bubble_casette_protected(int drv)
3252 if(drv < USE_BUBBLE) {
3253 return vm->is_bubble_casette_protected(drv);
3259 void EMU::is_bubble_casette_protected(int drv, bool flag)
3261 if(drv < USE_BUBBLE) {
3262 vm->is_bubble_casette_protected(drv, flag);
3270 #ifdef USE_LED_DEVICE
3271 uint32_t EMU::get_led_status()
3273 return vm->get_led_status();
3278 #ifdef USE_SOUND_VOLUME
3279 void EMU::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
3281 vm->set_sound_device_volume(ch, decibel_l, decibel_r);
3285 void EMU::update_config()
3287 vm->update_config();
3291 // ----------------------------------------------------------------------------
3293 // ----------------------------------------------------------------------------
3296 #define STATE_VERSION 2
3298 void EMU::save_state(const _TCHAR* file_path)
3300 FILEIO* fio = new FILEIO();
3303 if(config.compress_state) {
3304 fio->Gzopen(file_path, FILEIO_WRITE_BINARY);
3307 if(!fio->IsOpened()) {
3308 fio->Fopen(file_path, FILEIO_WRITE_BINARY);
3310 if(fio->IsOpened()) {
3311 // save state file version
3312 fio->FputUint32(STATE_VERSION);
3314 process_config_state((void *)fio, false);
3315 // save inserted medias
3317 fio->Fwrite(&cart_status, sizeof(cart_status), 1);
3319 #ifdef USE_FLOPPY_DISK
3320 fio->Fwrite(floppy_disk_status, sizeof(floppy_disk_status), 1);
3321 fio->Fwrite(d88_file, sizeof(d88_file), 1);
3323 #ifdef USE_QUICK_DISK
3324 fio->Fwrite(&quick_disk_status, sizeof(quick_disk_status), 1);
3326 #ifdef USE_HARD_DISK
3327 fio->Fwrite(&hard_disk_status, sizeof(hard_disk_status), 1);
3330 fio->Fwrite(&tape_status, sizeof(tape_status), 1);
3332 #ifdef USE_COMPACT_DISC
3333 fio->Fwrite(&compact_disc_status, sizeof(compact_disc_status), 1);
3335 #ifdef USE_LASER_DISC
3336 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);
3339 fio->Fwrite(&bubble_casette_status, sizeof(bubble_casette_status), 1);
3342 vm->process_state(fio, false);
3343 // end of state file
3344 fio->FputInt32_LE(-1);
3351 void EMU::load_state(const _TCHAR* file_path)
3353 if(FILEIO::IsFileExisting(file_path)) {
3356 config.romaji_to_kana = false;
3359 save_state(create_local_path(_T("$temp$.sta")));
3360 if(!load_state_tmp(file_path)) {
3361 out_debug_log(_T("failed to load state file\n"));
3362 load_state_tmp(create_local_path(_T("$temp$.sta")));
3364 FILEIO::RemoveFile(create_local_path(_T("$temp$.sta")));
3368 bool EMU::load_state_tmp(const _TCHAR* file_path)
3370 bool result = false;
3371 FILEIO* fio = new FILEIO();
3374 if(config.compress_state) {
3375 fio->Gzopen(file_path, FILEIO_READ_BINARY);
3378 if(!fio->IsOpened()) {
3379 fio->Fopen(file_path, FILEIO_READ_BINARY);
3381 if(fio->IsOpened()) {
3382 // check state file version
3383 if(fio->FgetUint32() == STATE_VERSION) {
3385 if(process_config_state((void *)fio, true)) {
3386 // load inserted medias
3388 fio->Fread(&cart_status, sizeof(cart_status), 1);
3390 #ifdef USE_FLOPPY_DISK
3391 fio->Fread(floppy_disk_status, sizeof(floppy_disk_status), 1);
3392 fio->Fread(d88_file, sizeof(d88_file), 1);
3394 #ifdef USE_QUICK_DISK
3395 fio->Fread(&quick_disk_status, sizeof(quick_disk_status), 1);
3397 #ifdef USE_HARD_DISK
3398 fio->Fread(&hard_disk_status, sizeof(hard_disk_status), 1);
3401 fio->Fread(&tape_status, sizeof(tape_status), 1);
3403 #ifdef USE_COMPACT_DISC
3404 fio->Fread(&compact_disc_status, sizeof(compact_disc_status), 1);
3406 #ifdef USE_LASER_DISC
3407 fio->Fread(&laser_disc_status, sizeof(laser_disc_status), 1);
3410 fio->Fread(&bubble_casette_status, sizeof(bubble_casette_status), 1);
3412 // check if virtual machine should be reinitialized
3413 bool reinitialize = false;
3415 reinitialize |= (cpu_type != config.cpu_type);
3416 cpu_type = config.cpu_type;
3418 #ifdef USE_DIPSWITCH
3419 reinitialize |= (dipswitch != config.dipswitch);
3420 dipswitch = config.dipswitch;
3422 #ifdef USE_SOUND_TYPE
3423 reinitialize |= (sound_type != config.sound_type);
3424 sound_type = config.sound_type;
3426 #ifdef USE_PRINTER_TYPE
3427 reinitialize |= (printer_type != config.printer_type);
3428 printer_type = config.printer_type;
3430 if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
3431 config.sound_frequency = 6; // default: 48KHz
3433 if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
3434 config.sound_latency = 1; // default: 100msec
3436 reinitialize |= (sound_frequency != config.sound_frequency);
3437 reinitialize |= (sound_latency != config.sound_latency);
3438 sound_frequency = config.sound_frequency;
3439 sound_latency = config.sound_latency;
3444 // reinitialize virtual machine
3450 # if defined(_USE_QT)
3451 osd->reset_vm_node();
3452 osd->update_keyname_table();
3453 osd->reset_screen_buffer();
3455 vm->initialize_sound(sound_rate, sound_samples);
3456 #ifdef USE_SOUND_VOLUME
3457 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
3458 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
3465 // restore inserted medias
3469 if(vm->process_state(fio, true)) {
3470 // check end of state
3471 result = (fio->FgetInt32_LE() == -1);
3482 const _TCHAR *EMU::state_file_path(int num)
3484 return create_local_path(_T("%s.sta%d"), _T(CONFIG_NAME), num);