OSDN Git Service

[UI][Qt][OSD][LOG] CDROM: May works with new messaging framework.
[csp-qt/common_source_project-fm7.git] / source / src / emu.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.08.18 -
6
7         [ win32 emulation i/f ]
8 */
9
10 #if defined(_USE_QT)
11 #include <string>
12 #endif
13
14 #include "emu.h"
15 #if defined(USE_DEBUGGER)
16 #include "vm/debugger.h"
17 #endif
18 #include "vm/vm.h"
19 #include "fifo.h"
20 #include "fileio.h"
21
22 #include "osdcall_types.h"
23
24 // ----------------------------------------------------------------------------
25 // initialize
26 // ----------------------------------------------------------------------------
27 static const int sound_frequency_table[8] = {
28         2000, 4000, 8000, 11025, 22050, 44100,
29 #ifdef OVERRIDE_SOUND_FREQ_48000HZ
30         OVERRIDE_SOUND_FREQ_48000HZ,
31 #else
32         48000,
33 #endif
34         96000,
35 };
36 static const double sound_latency_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};
37
38 #if defined(_USE_QT)
39 // Please permit at least them m(.. )m
40 //extern void get_long_full_path_name(_TCHAR* src, _TCHAR* dst);
41 #include <string>
42 #include <memory>
43 #endif
44
45 #if defined(_USE_QT)
46 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)
47 #elif defined(OSD_WIN32)
48 EMU::EMU(HWND hwnd, HINSTANCE hinst) : EMU_TEMPLATE(hwnd, hinst)
49 #else
50 EMU::EMU() : EMU()
51 #endif
52 {
53         message_count = 0;
54         // store main window handle
55 #ifdef USE_FLOPPY_DISK
56         // initialize d88 file info
57         memset(d88_file, 0, sizeof(d88_file));
58 #endif
59 #ifdef USE_BUBBLE
60         // initialize d88 file info
61         memset(b77_file, 0, sizeof(b77_file));
62 #endif
63         // load sound config
64
65         if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
66                 config.sound_frequency = 6;     // default: 48KHz
67         }
68         if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
69                 config.sound_latency = 1;       // default: 100msec
70         }
71         sound_frequency = config.sound_frequency;
72         sound_latency = config.sound_latency;
73         sound_rate = sound_frequency_table[config.sound_frequency];
74         sound_samples = (int)(sound_rate * sound_latency_table[config.sound_latency] + 0.5);
75
76 #ifdef USE_CPU_TYPE
77         cpu_type = config.cpu_type;
78 #endif
79 #ifdef USE_DIPSWITCH
80         dipswitch = config.dipswitch;
81 #endif
82 #ifdef USE_SOUND_TYPE
83         sound_type = config.sound_type;
84 #endif
85 #ifdef USE_PRINTER_TYPE
86         printer_type = config.printer_type;
87 #endif
88 #ifdef USE_SERIAL_TYPE
89         serial_type = config.serial_type;
90 #endif
91 #ifdef USE_BUBBLE
92         // initialize b77 file info
93         memset(b77_file, 0, sizeof(b77_file));
94 #endif
95
96         // initialize osd
97 #if defined(OSD_QT)
98         osd = new OSD(p, csp_logger);
99         osd->main_window_handle = hwnd;
100         //osd->p_glv = hinst;
101         osd->host_cpus = 4;
102 #elif defined(OSD_WIN32)
103         osd = new OSD();
104         osd->main_window_handle = hwnd;
105         osd->instance_handle = hinst;
106 #endif
107         int presented_rate, presented_samples;
108         osd->initialize(sound_rate, sound_samples, &presented_rate, &presented_samples);
109         sound_rate = presented_rate;
110         sound_samples = presented_samples;
111         // initialize vm
112         vm = new VM(this);
113         osd->vm = vm;
114 # if defined(_USE_QT)
115         osd->reset_vm_node();
116         osd->update_keyname_table();
117 # endif
118 #ifdef USE_AUTO_KEY
119         initialize_auto_key();
120 #endif
121 #ifdef USE_DEBUGGER
122         initialize_debugger();
123 #endif
124         now_waiting_in_debugger = false;
125         initialize_media();
126         vm->initialize_sound(sound_rate, sound_samples);
127 #ifdef USE_SOUND_VOLUME
128         for(int i = 0; i < USE_SOUND_VOLUME; i++) {
129                 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
130         }
131 #endif
132 #ifdef USE_HARD_DISK
133         for(int drv = 0; drv < USE_HARD_DISK; drv++) {
134                 if(config.last_hard_disk_path[drv][0] != _T('\0') && FILEIO::IsFileExisting(config.last_hard_disk_path[drv])) {
135                         vm->open_hard_disk(drv, config.last_hard_disk_path[drv]);
136                         my_tcscpy_s(hard_disk_status[drv].path, _MAX_PATH, config.last_hard_disk_path[drv]);
137                 }
138         }
139 #endif
140         vm->reset();
141         now_suspended = false;
142 }
143
144 EMU::~EMU()
145 {
146 #ifdef USE_AUTO_KEY
147         release_auto_key();
148 #endif
149 #ifdef USE_DEBUGGER
150         release_debugger();
151 #endif
152         osd->lock_vm();
153         delete vm;
154         vm = nullptr;
155         osd->vm = nullptr;
156         osd->unlock_vm();
157         osd->release();
158         delete osd;
159 #ifdef _DEBUG_LOG
160         release_debug_log();
161 #endif
162 }
163
164 // messaging proxies.
165 // These are mostly used for replying mounting virtual media.
166 // 20230125 K.O
167 void EMU::osdcall_string(EMU_MEDIA_TYPE::type_t media_type, int drive,EMU_MESSAGE_TYPE::type_t message_type, _TCHAR* message)
168 {
169         __LIKELY_IF(osd != nullptr) {
170                 osd->string_message_from_emu(media_type, drive, message_type, message);
171         }
172 }
173
174 void EMU::osdcall_int(EMU_MEDIA_TYPE::type_t media_type, int drive, EMU_MESSAGE_TYPE::type_t message_type, int64_t data)
175 {
176         __LIKELY_IF(osd != nullptr) {
177                 osd->int_message_from_emu(media_type, drive, message_type, data);
178         }
179 }
180
181
182 #ifdef OSD_QT
183 EmuThreadClass *EMU::get_parent_handler()
184 {
185         return osd->get_parent_handler();
186 }
187
188 void EMU::set_parent_handler(EmuThreadClass *p, DrawThreadClass *q)
189 {
190         osd->set_parent_thread(p);
191         osd->set_draw_thread(q);
192 }
193
194 void EMU::set_host_cpus(int v)
195 {
196         osd->host_cpus = (v <= 0) ? 1 : v;
197 }
198
199 int EMU::get_host_cpus()
200 {
201         return osd->host_cpus;
202 }
203 #endif
204
205 // ----------------------------------------------------------------------------
206 // drive machine
207 // ----------------------------------------------------------------------------
208
209 double EMU::get_frame_rate()
210 {
211         return vm->get_frame_rate();
212 }
213
214 int EMU::get_frame_interval()
215 {
216         static int prev_interval = 0;
217         static double prev_fps = -1;
218         double fps = vm->get_frame_rate();
219         if(prev_fps != fps) {
220                 prev_interval = (int)(1024. * 1000. / fps + 0.5);
221                 prev_fps = fps;
222         }
223         return prev_interval;
224 }
225
226 bool EMU::is_frame_skippable()
227 {
228         return vm->is_frame_skippable();
229 }
230
231 const bool EMU::is_use_state()
232 {
233 #ifdef USE_STATE
234         return true;
235 #else
236         return false;
237 #endif
238 }
239 int EMU::run()
240 {
241 #if defined(USE_DEBUGGER) && defined(USE_STATE)
242         if(request_save_state >= 0 || request_load_state >= 0) {
243                 if(request_save_state >= 0) {
244                         save_state(state_file_path(request_save_state));
245                 } else {
246                         load_state(state_file_path(request_load_state));
247                 }
248                 // NOTE: vm instance may be reinitialized in load_state
249                 // ToDo: Support multiple debuggers. 20230110 K.O
250                 if(!is_debugger_enabled(debugger_cpu_index)) {
251                         for(int i = 0; i < 8; i++) {
252                                 if(is_debugger_enabled(i)) {
253                                         debugger_cpu_index = i;
254                                         debugger_target_id = vm->get_cpu(debugger_cpu_index)->this_device_id;
255                                         break;
256                                 }
257                         }
258                 }
259                 if(is_debugger_enabled(debugger_cpu_index)) {
260                         if(!(vm->get_device(debugger_target_id) != NULL && vm->get_device(debugger_target_id)->get_debugger() != NULL)) {
261                                 debugger_target_id = vm->get_cpu(debugger_cpu_index)->this_device_id;
262                         }
263                         DEBUGGER *cpu_debugger = (DEBUGGER *)vm->get_cpu(debugger_cpu_index)->get_debugger();
264                         cpu_debugger->now_going = false;
265                         cpu_debugger->now_debugging = true;
266                         debugger_thread_param.vm = vm;
267                 } else {
268                         close_debugger(debugger_cpu_index);
269                 }
270                 request_save_state = request_load_state = -1;
271         }
272 #endif
273         if(now_suspended) {
274                 osd->restore();
275                 now_suspended = false;
276         }
277         osd->update_input();
278 #ifdef USE_AUTO_KEY
279         update_auto_key();
280 #endif
281 //#ifdef USE_JOYSTICK
282 //      update_joystick();
283 //#endif
284
285 #ifdef USE_SOCKET
286 #if !defined(_USE_QT) // Temporally
287         osd->update_socket();
288 #endif
289 #endif
290         update_media();
291
292         // virtual machine may be driven to fill sound buffer
293         int extra_frames = 0;
294         osd->update_sound(&extra_frames);
295
296         // drive virtual machine
297         if(extra_frames == 0) {
298                 osd->lock_vm();
299                 vm->run();
300                 extra_frames = 1;
301                 osd->unlock_vm();
302         }
303         osd->add_extra_frames(extra_frames);
304         return extra_frames;
305 }
306
307 void EMU::reset()
308 {
309 #ifdef USE_AUTO_KEY
310         stop_auto_key();
311         config.romaji_to_kana = false;
312 #endif
313
314         // check if virtual machine should be reinitialized
315         bool reinitialize = false;
316 #ifdef USE_CPU_TYPE
317         reinitialize |= (cpu_type != config.cpu_type);
318         cpu_type = config.cpu_type;
319 #endif
320 #ifdef USE_DIPSWITCH
321         reinitialize |= (dipswitch != config.dipswitch);
322         dipswitch = config.dipswitch;
323 #endif
324 #ifdef USE_SOUND_TYPE
325         reinitialize |= (sound_type != config.sound_type);
326         sound_type = config.sound_type;
327 #endif
328 #ifdef USE_PRINTER_TYPE
329         reinitialize |= (printer_type != config.printer_type);
330         printer_type = config.printer_type;
331 #endif
332 #ifdef USE_SERIAL_TYPE
333         reinitialize |= (serial_type != config.serial_type);
334         serial_type = config.serial_type;
335 #endif
336         if(reinitialize) {
337                 // stop sound
338                 osd->stop_sound();
339                 // reinitialize virtual machine
340                 osd->lock_vm();
341                 delete vm;
342                 vm = nullptr;
343                 osd->vm = nullptr;
344                 vm = new VM(this);
345                 osd->vm = vm;;
346 #if defined(_USE_QT)
347                 osd->reset_vm_node();
348                 osd->update_keyname_table();
349                 osd->reset_screen_buffer();
350 #endif
351                 int presented_rate;
352                 int presented_samples;
353                 sound_rate = sound_frequency_table[config.sound_frequency];
354                 sound_samples = (int)(sound_rate * sound_latency_table[config.sound_latency] + 0.5);
355                 osd->initialize_sound(sound_rate, sound_samples, &presented_rate, &presented_samples);
356                 if((sound_rate != presented_rate) ||
357                    (sound_samples != presented_samples)) {
358                         sound_rate = presented_rate;
359                         sound_samples = presented_samples;
360                 }
361                 vm->initialize_sound(sound_rate, sound_samples);
362 #ifdef USE_SOUND_VOLUME
363                 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
364                         vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
365                 }
366 #endif
367                 // restore inserted medias
368                 restore_media();
369                 vm->reset();
370                 osd->unlock_vm();
371         } else {
372                 // reset virtual machine
373                 osd->lock_vm();
374                 vm->reset();
375                 osd->unlock_vm();
376         }
377
378 #if !defined(_USE_QT) // Temporally
379         // restart recording
380         osd->restart_record_sound();
381         osd->restart_record_video();
382 #endif
383 }
384
385 #ifdef USE_SPECIAL_RESET
386 void EMU::special_reset(int num)
387 {
388         if(num < 0) return;
389         if(num >= USE_SPECIAL_RESET) return;
390 #ifdef USE_AUTO_KEY
391         stop_auto_key();
392         config.romaji_to_kana = false;
393 #endif
394
395         // reset virtual machine
396         osd->lock_vm();
397         vm->special_reset(num);
398         osd->unlock_vm();
399         // restart recording
400 #if !defined(_USE_QT) // Temporally
401         restart_record_sound();
402         restart_record_video();
403 #endif
404 }
405 #endif
406
407 #ifdef USE_NOTIFY_POWER_OFF
408 void EMU::notify_power_off()
409 {
410         vm->notify_power_off();
411         osd->notify_power_off(); // To GUI 20230120 K.O
412 }
413 #endif
414
415 void EMU::power_off()
416 {
417         osd->power_off();
418 }
419
420 void EMU::suspend()
421 {
422         if(!now_suspended) {
423                 osd->suspend();
424                 now_suspended = true;
425         }
426 }
427
428 void EMU::lock_vm()
429 {
430         osd->lock_vm();
431 }
432
433 void EMU::unlock_vm()
434 {
435         osd->unlock_vm();
436 }
437
438 void EMU::force_unlock_vm()
439 {
440         osd->force_unlock_vm();
441 }
442
443 bool EMU::is_vm_locked()
444 {
445         return osd->is_vm_locked();
446 }
447
448 // ----------------------------------------------------------------------------
449 // input
450 // ----------------------------------------------------------------------------
451
452
453 void EMU::key_down(int code, bool extended, bool repeat)
454 {
455 #ifdef USE_AUTO_KEY
456         if(code == 0x10) {
457                 shift_pressed = true;
458         }
459         if(config.romaji_to_kana) {
460                 if(!repeat) {
461                         // Page Up, Page Down, End, Home, Left, Up, Right, Down, Ins, Del, Help, and F1-F12
462                         if((code >= 0x21 && code <= 0x2f) || (code >= 0x70 && code <= 0x7b)) {
463                                 if(shift_pressed) {
464                                         auto_key_buffer->write(code | 0x100);
465                                 } else {
466                                         auto_key_buffer->write(code);
467                                 }
468                                 if(!is_auto_key_running()) {
469                                         start_auto_key();
470                                 }
471                         }
472                 }
473         } else if(!is_auto_key_running())
474 #endif
475         osd->key_down(code, extended, repeat);
476 //      printf("KEY DOWN: %04X EXT=%d REPEAT=%d\n", code, extended, repeat);
477 }
478
479 void EMU::key_up(int code, bool extended)
480 {
481 #ifdef USE_AUTO_KEY
482         if(code == 0x10) {
483                 shift_pressed = false;
484         }
485         if(config.romaji_to_kana) {
486                 // do nothing
487         } else if(!is_auto_key_running())
488 #endif
489         osd->key_up(code, extended);
490 //      printf("KEY UP: %04X EXT=%d\n", code, extended);
491 }
492
493 void EMU::key_char(char code)
494 {
495 #ifdef USE_AUTO_KEY
496         if(config.romaji_to_kana) {
497                 set_auto_key_char(code);
498         }
499 #endif
500 }
501
502 #ifdef USE_KEY_LOCKED
503 bool EMU::get_caps_locked()
504 {
505         return vm->get_caps_locked();
506 }
507
508 bool EMU::get_kana_locked()
509 {
510         return vm->get_kana_locked();
511 }
512 #endif
513
514 void EMU::key_lost_focus()
515 {
516         osd->key_lost_focus();
517 }
518
519 #ifdef ONE_BOARD_MICRO_COMPUTER
520 void EMU::press_button(int num)
521 {
522         int code = vm_buttons[num].code;
523
524         if(code) {
525                 osd->key_down_native(code, false);
526                 osd->get_key_buffer()[code] = KEY_KEEP_FRAMES;
527         } else {
528                 // code=0: reset virtual machine
529                 vm->reset();
530         }
531 }
532 #endif
533
534 #ifdef USE_MOUSE
535 void EMU::enable_mouse()
536 {
537         osd->enable_mouse();
538 }
539
540 void EMU::disable_mouse()
541 {
542         osd->disable_mouse();
543 }
544
545 void EMU::toggle_mouse()
546 {
547         osd->toggle_mouse();
548 }
549
550 bool EMU::is_mouse_enabled()
551 {
552         return osd->is_mouse_enabled();
553 }
554 #endif
555
556 #ifdef USE_AUTO_KEY
557 static const int auto_key_table_base[][2] = {
558         // 0x100: shift
559         // 0x200: kana
560         // 0x400: alphabet
561         // 0x800: ALPHABET
562         // 0x1000 : LOCK
563         // 0x2000 : UNLOCK
564         {0x08,  0x000 | 0x08},  // BS
565         {0x09,  0x000 | 0x09},  // Tab
566         {0x0d,  0x000 | 0x0d},  // Enter
567         {0x1b,  0x000 | 0x1b},  // Escape
568         {0x20,  0x000 | 0x20},  // ' '
569 #ifdef AUTO_KEY_US
570         {0x21,  0x100 | 0x31},  // '!'
571         {0x22,  0x100 | 0xba},  // '"'
572         {0x23,  0x100 | 0x33},  // '#'
573         {0x24,  0x100 | 0x34},  // '$'
574         {0x25,  0x100 | 0x35},  // '%'
575         {0x26,  0x100 | 0x37},  // '&'
576         {0x27,  0x000 | 0xba},  // '''
577         {0x28,  0x100 | 0x39},  // '('
578         {0x29,  0x100 | 0x30},  // ')'
579         {0x2a,  0x100 | 0x38},  // '*'
580         {0x2b,  0x100 | 0xde},  // '+'
581         {0x2c,  0x000 | 0xbc},  // ','
582         {0x2d,  0x000 | 0xbd},  // '-'
583         {0x2e,  0x000 | 0xbe},  // '.'
584         {0x2f,  0x000 | 0xbf},  // '/'
585 #else
586         {0x21,  0x100 | 0x31},  // '!'
587         {0x22,  0x100 | 0x32},  // '"'
588         {0x23,  0x100 | 0x33},  // '#'
589         {0x24,  0x100 | 0x34},  // '$'
590         {0x25,  0x100 | 0x35},  // '%'
591         {0x26,  0x100 | 0x36},  // '&'
592         {0x27,  0x100 | 0x37},  // '''
593         {0x28,  0x100 | 0x38},  // '('
594         {0x29,  0x100 | 0x39},  // ')'
595         {0x2a,  0x100 | 0xba},  // '*'
596         {0x2b,  0x100 | 0xbb},  // '+'
597         {0x2c,  0x000 | 0xbc},  // ','
598         {0x2d,  0x000 | 0xbd},  // '-'
599         {0x2e,  0x000 | 0xbe},  // '.'
600         {0x2f,  0x000 | 0xbf},  // '/'
601 #endif
602         {0x30,  0x000 | 0x30},  // '0'
603         {0x31,  0x000 | 0x31},  // '1'
604         {0x32,  0x000 | 0x32},  // '2'
605         {0x33,  0x000 | 0x33},  // '3'
606         {0x34,  0x000 | 0x34},  // '4'
607         {0x35,  0x000 | 0x35},  // '5'
608         {0x36,  0x000 | 0x36},  // '6'
609         {0x37,  0x000 | 0x37},  // '7'
610         {0x38,  0x000 | 0x38},  // '8'
611         {0x39,  0x000 | 0x39},  // '9'
612 #ifdef AUTO_KEY_US
613         {0x3a,  0x100 | 0xbb},  // ':'
614         {0x3b,  0x000 | 0xbb},  // ';'
615         {0x3c,  0x100 | 0xbc},  // '<'
616         {0x3d,  0x000 | 0xde},  // '='
617         {0x3e,  0x100 | 0xbe},  // '>'
618         {0x3f,  0x100 | 0xbf},  // '?'
619         {0x40,  0x100 | 0x32},  // '@'
620 #else
621         {0x3a,  0x000 | 0xba},  // ':'
622         {0x3b,  0x000 | 0xbb},  // ';'
623         {0x3c,  0x100 | 0xbc},  // '<'
624         {0x3d,  0x100 | 0xbd},  // '='
625         {0x3e,  0x100 | 0xbe},  // '>'
626         {0x3f,  0x100 | 0xbf},  // '?'
627         {0x40,  0x000 | 0xc0},  // '@'
628 #endif
629         {0x41,  0x400 | 0x41},  // 'A'
630         {0x42,  0x400 | 0x42},  // 'B'
631         {0x43,  0x400 | 0x43},  // 'C'
632         {0x44,  0x400 | 0x44},  // 'D'
633         {0x45,  0x400 | 0x45},  // 'E'
634         {0x46,  0x400 | 0x46},  // 'F'
635         {0x47,  0x400 | 0x47},  // 'G'
636         {0x48,  0x400 | 0x48},  // 'H'
637         {0x49,  0x400 | 0x49},  // 'I'
638         {0x4a,  0x400 | 0x4a},  // 'J'
639         {0x4b,  0x400 | 0x4b},  // 'K'
640         {0x4c,  0x400 | 0x4c},  // 'L'
641         {0x4d,  0x400 | 0x4d},  // 'M'
642         {0x4e,  0x400 | 0x4e},  // 'N'
643         {0x4f,  0x400 | 0x4f},  // 'O'
644         {0x50,  0x400 | 0x50},  // 'P'
645         {0x51,  0x400 | 0x51},  // 'Q'
646         {0x52,  0x400 | 0x52},  // 'R'
647         {0x53,  0x400 | 0x53},  // 'S'
648         {0x54,  0x400 | 0x54},  // 'T'
649         {0x55,  0x400 | 0x55},  // 'U'
650         {0x56,  0x400 | 0x56},  // 'V'
651         {0x57,  0x400 | 0x57},  // 'W'
652         {0x58,  0x400 | 0x58},  // 'X'
653         {0x59,  0x400 | 0x59},  // 'Y'
654         {0x5a,  0x400 | 0x5a},  // 'Z'
655 #ifdef AUTO_KEY_US
656         {0x5b,  0x000 | 0xc0},  // '['
657         {0x5c,  0x000 | 0xe2},  // '\'
658         {0x5d,  0x000 | 0xdb},  // ']'
659         {0x5e,  0x100 | 0x36},  // '^'
660         {0x5f,  0x100 | 0xbd},  // '_'
661         {0x60,  0x000 | 0xdd},  // '`'
662 #else
663         {0x5b,  0x000 | 0xdb},  // '['
664         {0x5c,  0x000 | 0xdc},  // '\'
665         {0x5d,  0x000 | 0xdd},  // ']'
666         {0x5e,  0x000 | 0xde},  // '^'
667         {0x5f,  0x100 | 0xe2},  // '_'
668         {0x60,  0x100 | 0xc0},  // '`'
669 #endif
670         {0x61,  0x800 | 0x41},  // 'a'
671         {0x62,  0x800 | 0x42},  // 'b'
672         {0x63,  0x800 | 0x43},  // 'c'
673         {0x64,  0x800 | 0x44},  // 'd'
674         {0x65,  0x800 | 0x45},  // 'e'
675         {0x66,  0x800 | 0x46},  // 'f'
676         {0x67,  0x800 | 0x47},  // 'g'
677         {0x68,  0x800 | 0x48},  // 'h'
678         {0x69,  0x800 | 0x49},  // 'i'
679         {0x6a,  0x800 | 0x4a},  // 'j'
680         {0x6b,  0x800 | 0x4b},  // 'k'
681         {0x6c,  0x800 | 0x4c},  // 'l'
682         {0x6d,  0x800 | 0x4d},  // 'm'
683         {0x6e,  0x800 | 0x4e},  // 'n'
684         {0x6f,  0x800 | 0x4f},  // 'o'
685         {0x70,  0x800 | 0x50},  // 'p'
686         {0x71,  0x800 | 0x51},  // 'q'
687         {0x72,  0x800 | 0x52},  // 'r'
688         {0x73,  0x800 | 0x53},  // 's'
689         {0x74,  0x800 | 0x54},  // 't'
690         {0x75,  0x800 | 0x55},  // 'u'
691         {0x76,  0x800 | 0x56},  // 'v'
692         {0x77,  0x800 | 0x57},  // 'w'
693         {0x78,  0x800 | 0x58},  // 'x'
694         {0x79,  0x800 | 0x59},  // 'y'
695         {0x7a,  0x800 | 0x5a},  // 'z'
696 #ifdef AUTO_KEY_US
697         {0x7b,  0x100 | 0xc0},  // '{'
698         {0x7c,  0x100 | 0xe2},  // '|'
699         {0x7d,  0x100 | 0xdb},  // '}'
700         {0x7e,  0x100 | 0xdd},  // '~'
701 #else
702         {0x7b,  0x100 | 0xdb},  // '{'
703         {0x7c,  0x100 | 0xdc},  // '|'
704         {0x7d,  0x100 | 0xdd},  // '}'
705         {0x7e,  0x100 | 0xde},  // '~'
706 #endif
707         {-1, -1},
708 };
709
710 static const int auto_key_table_kana_base[][2] = {
711         {0xa1,  0x300 | 0xbe},  // '。'
712         {0xa2,  0x300 | 0xdb},  // '「'
713         {0xa3,  0x300 | 0xdd},  // '」'
714         {0xa4,  0x300 | 0xbc},  // '、'
715         {0xa5,  0x300 | 0xbf},  // '・'
716         {0xa6,  0x300 | 0x30},  // 'ヲ'
717         {0xa7,  0x300 | 0x33},  // 'ァ'
718         {0xa8,  0x300 | 0x45},  // 'ィ'
719         {0xa9,  0x300 | 0x34},  // 'ゥ'
720         {0xaa,  0x300 | 0x35},  // 'ェ'
721         {0xab,  0x300 | 0x36},  // 'ォ'
722         {0xac,  0x300 | 0x37},  // 'ャ'
723         {0xad,  0x300 | 0x38},  // 'ュ'
724         {0xae,  0x300 | 0x39},  // 'ョ'
725         {0xaf,  0x300 | 0x5a},  // 'ッ'
726         {0xb0,  0x200 | 0xdc},  // 'ー'
727         {0xb1,  0x200 | 0x33},  // 'ア'
728         {0xb2,  0x200 | 0x45},  // 'イ'
729         {0xb3,  0x200 | 0x34},  // 'ウ'
730         {0xb4,  0x200 | 0x35},  // 'エ'
731         {0xb5,  0x200 | 0x36},  // 'オ'
732         {0xb6,  0x200 | 0x54},  // 'カ'
733         {0xb7,  0x200 | 0x47},  // 'キ'
734         {0xb8,  0x200 | 0x48},  // 'ク'
735         {0xb9,  0x200 | 0xba},  // 'ケ'
736         {0xba,  0x200 | 0x42},  // 'コ'
737         {0xbb,  0x200 | 0x58},  // 'サ'
738         {0xbc,  0x200 | 0x44},  // 'シ'
739         {0xbd,  0x200 | 0x52},  // 'ス'
740         {0xbe,  0x200 | 0x50},  // 'セ'
741         {0xbf,  0x200 | 0x43},  // 'ソ'
742         {0xc0,  0x200 | 0x51},  // 'タ'
743         {0xc1,  0x200 | 0x41},  // 'チ'
744         {0xc2,  0x200 | 0x5a},  // 'ツ'
745         {0xc3,  0x200 | 0x57},  // 'テ'
746         {0xc4,  0x200 | 0x53},  // 'ト'
747         {0xc5,  0x200 | 0x55},  // 'ナ'
748         {0xc6,  0x200 | 0x49},  // 'ニ'
749         {0xc7,  0x200 | 0x31},  // 'ヌ'
750         {0xc8,  0x200 | 0xbc},  // 'ネ'
751         {0xc9,  0x200 | 0x4b},  // 'ノ'
752         {0xca,  0x200 | 0x46},  // 'ハ'
753         {0xcb,  0x200 | 0x56},  // 'ヒ'
754         {0xcc,  0x200 | 0x32},  // 'フ'
755         {0xcd,  0x200 | 0xde},  // 'ヘ'
756         {0xce,  0x200 | 0xbd},  // 'ホ'
757         {0xcf,  0x200 | 0x4a},  // 'マ'
758         {0xd0,  0x200 | 0x4e},  // 'ミ'
759         {0xd1,  0x200 | 0xdd},  // 'ム'
760         {0xd2,  0x200 | 0xbf},  // 'メ'
761         {0xd3,  0x200 | 0x4d},  // 'モ'
762         {0xd4,  0x200 | 0x37},  // 'ヤ'
763         {0xd5,  0x200 | 0x38},  // 'ユ'
764         {0xd6,  0x200 | 0x39},  // 'ヨ'
765         {0xd7,  0x200 | 0x4f},  // 'ラ'
766         {0xd8,  0x200 | 0x4c},  // 'リ'
767         {0xd9,  0x200 | 0xbe},  // 'ル'
768         {0xda,  0x200 | 0xbb},  // 'レ'
769         {0xdb,  0x200 | 0xe2},  // 'ロ'
770         {0xdc,  0x200 | 0x30},  // 'ワ'
771         {0xdd,  0x200 | 0x59},  // 'ン'
772         {0xde,  0x200 | 0xc0},  // '゙'
773         {0xdf,  0x200 | 0xdb},  // '゚'
774         {-1, -1},
775 };
776
777 static const int auto_key_table_50on_base[][2] = {
778         {0xa1,  0x300 | 0xbf},  // '。'
779         {0xa2,  0x300 | 0xdb},  // '「'
780         {0xa3,  0x300 | 0xdd},  // '」'
781         {0xa4,  0x300 | 0xbe},  // '、'
782         {0xa5,  0x300 | 0xe2},  // '・'
783         {0xa6,  0x200 | 0xbf},  // 'ヲ'
784         {0xa7,  0x300 | 0x31},  // 'ァ'
785         {0xa8,  0x300 | 0x32},  // 'ィ'
786         {0xa9,  0x300 | 0x33},  // 'ゥ'
787         {0xaa,  0x300 | 0x34},  // 'ェ'
788         {0xab,  0x300 | 0x35},  // 'ォ'
789         {0xac,  0x300 | 0x4e},  // 'ャ'
790         {0xad,  0x300 | 0x4d},  // 'ュ'
791         {0xae,  0x300 | 0xbc},  // 'ョ'
792         {0xaf,  0x300 | 0x43},  // 'ッ'
793         {0xb0,  0x300 | 0xba},  // 'ー'
794         {0xb1,  0x200 | 0x31},  // 'ア'
795         {0xb2,  0x200 | 0x32},  // 'イ'
796         {0xb3,  0x200 | 0x33},  // 'ウ'
797         {0xb4,  0x200 | 0x34},  // 'エ'
798         {0xb5,  0x200 | 0x35},  // 'オ'
799         {0xb6,  0x200 | 0x51},  // 'カ'
800         {0xb7,  0x200 | 0x57},  // 'キ'
801         {0xb8,  0x200 | 0x45},  // 'ク'
802         {0xb9,  0x200 | 0x52},  // 'ケ'
803         {0xba,  0x200 | 0x54},  // 'コ'
804         {0xbb,  0x200 | 0x41},  // 'サ'
805         {0xbc,  0x200 | 0x53},  // 'シ'
806         {0xbd,  0x200 | 0x44},  // 'ス'
807         {0xbe,  0x200 | 0x46},  // 'セ'
808         {0xbf,  0x200 | 0x47},  // 'ソ'
809         {0xc0,  0x200 | 0x5a},  // 'タ'
810         {0xc1,  0x200 | 0x58},  // 'チ'
811         {0xc2,  0x200 | 0x43},  // 'ツ'
812         {0xc3,  0x200 | 0x56},  // 'テ'
813         {0xc4,  0x200 | 0x42},  // 'ト'
814         {0xc5,  0x200 | 0x36},  // 'ナ'
815         {0xc6,  0x200 | 0x37},  // 'ニ'
816         {0xc7,  0x200 | 0x38},  // 'ヌ'
817         {0xc8,  0x200 | 0x39},  // 'ネ'
818         {0xc9,  0x200 | 0x30},  // 'ノ'
819         {0xca,  0x200 | 0x59},  // 'ハ'
820         {0xcb,  0x200 | 0x55},  // 'ヒ'
821         {0xcc,  0x200 | 0x49},  // 'フ'
822         {0xcd,  0x200 | 0x4f},  // 'ヘ'
823         {0xce,  0x200 | 0x50},  // 'ホ'
824         {0xcf,  0x200 | 0x48},  // 'マ'
825         {0xd0,  0x200 | 0x4a},  // 'ミ'
826         {0xd1,  0x200 | 0x4b},  // 'ム'
827         {0xd2,  0x200 | 0x4c},  // 'メ'
828         {0xd3,  0x200 | 0xbb},  // 'モ'
829         {0xd4,  0x200 | 0x4e},  // 'ヤ'
830         {0xd5,  0x200 | 0x4d},  // 'ユ'
831         {0xd6,  0x200 | 0xbc},  // 'ヨ'
832         {0xd7,  0x200 | 0xbd},  // 'ラ'
833         {0xd8,  0x200 | 0xde},  // 'リ'
834         {0xd9,  0x200 | 0xdc},  // 'ル'
835         {0xda,  0x200 | 0xc0},  // 'レ'
836         {0xdb,  0x200 | 0xdb},  // 'ロ'
837         {0xdc,  0x200 | 0xbe},  // 'ワ'
838         {0xdd,  0x200 | 0xe2},  // 'ン'
839         {0xde,  0x200 | 0xba},  // '゙'
840         {0xdf,  0x200 | 0xdd},  // '゚'
841         {-1, -1},
842 };
843
844 static const struct {
845         const char *romaji;
846         const uint8_t kana[4];
847 } romaji_table[] = {
848         {"ltsu",        {0xaf, 0x00}},
849         {"xtsu",        {0xaf, 0x00}},
850         {"ltu",         {0xaf, 0x00}},
851         {"xtu",         {0xaf, 0x00}},
852         {"bya",         {0xcb, 0xde, 0xac, 0x00}},
853         {"byi",         {0xcb, 0xde, 0xa8, 0x00}},
854         {"byu",         {0xcb, 0xde, 0xad, 0x00}},
855         {"bye",         {0xcb, 0xde, 0xaa, 0x00}},
856         {"byo",         {0xcb, 0xde, 0xae, 0x00}},
857         {"cha",         {0xc1, 0xac, 0x00}},
858         {"chi",         {0xc1, 0x00}},
859         {"chu",         {0xc1, 0xad, 0x00}},
860         {"che",         {0xc1, 0xaa, 0x00}},
861         {"cho",         {0xc1, 0xae, 0x00}},
862         {"cya",         {0xc1, 0xac, 0x00}},
863         {"cyi",         {0xc1, 0xa8, 0x00}},
864         {"cyu",         {0xc1, 0xad, 0x00}},
865         {"cye",         {0xc1, 0xaa, 0x00}},
866         {"cyo",         {0xc1, 0xae, 0x00}},
867         {"dha",         {0xc3, 0xde, 0xac, 0x00}},
868         {"dhi",         {0xc3, 0xde, 0xa8, 0x00}},
869         {"dhu",         {0xc3, 0xde, 0xad, 0x00}},
870         {"dhe",         {0xc3, 0xde, 0xaa, 0x00}},
871         {"dho",         {0xc3, 0xde, 0xae, 0x00}},
872         {"dwa",         {0xc4, 0xde, 0xa7, 0x00}},
873         {"dwi",         {0xc4, 0xde, 0xa8, 0x00}},
874         {"dwu",         {0xc4, 0xde, 0xa9, 0x00}},
875         {"dwe",         {0xc4, 0xde, 0xaa, 0x00}},
876         {"dwo",         {0xc4, 0xde, 0xab, 0x00}},
877         {"dya",         {0xc1, 0xde, 0xac, 0x00}},
878         {"dyi",         {0xc1, 0xde, 0xa8, 0x00}},
879         {"dyu",         {0xc1, 0xde, 0xad, 0x00}},
880         {"dye",         {0xc1, 0xde, 0xaa, 0x00}},
881         {"dyo",         {0xc1, 0xde, 0xae, 0x00}},
882         {"fwa",         {0xcc, 0xa7, 0x00}},
883         {"fwi",         {0xcc, 0xa8, 0x00}},
884         {"fwu",         {0xcc, 0xa9, 0x00}},
885         {"fwe",         {0xcc, 0xaa, 0x00}},
886         {"fwo",         {0xcc, 0xab, 0x00}},
887         {"fya",         {0xcc, 0xac, 0x00}},
888         {"fyi",         {0xcc, 0xa8, 0x00}},
889         {"fyu",         {0xcc, 0xad, 0x00}},
890         {"fye",         {0xcc, 0xaa, 0x00}},
891         {"fyo",         {0xcc, 0xae, 0x00}},
892         {"gwa",         {0xb8, 0xde, 0xa7, 0x00}},
893         {"gwi",         {0xb8, 0xde, 0xa8, 0x00}},
894         {"gwu",         {0xb8, 0xde, 0xa9, 0x00}},
895         {"gwe",         {0xb8, 0xde, 0xaa, 0x00}},
896         {"gwo",         {0xb8, 0xde, 0xab, 0x00}},
897         {"gya",         {0xb7, 0xde, 0xac, 0x00}},
898         {"gyi",         {0xb7, 0xde, 0xa8, 0x00}},
899         {"gyu",         {0xb7, 0xde, 0xad, 0x00}},
900         {"gye",         {0xb7, 0xde, 0xaa, 0x00}},
901         {"gyo",         {0xb7, 0xde, 0xae, 0x00}},
902         {"hya",         {0xcb, 0xac, 0x00}},
903         {"hyi",         {0xcb, 0xa8, 0x00}},
904         {"hyu",         {0xcb, 0xad, 0x00}},
905         {"hye",         {0xcb, 0xaa, 0x00}},
906         {"hyo",         {0xcb, 0xae, 0x00}},
907         {"jya",         {0xbc, 0xde, 0xac, 0x00}},
908         {"jyi",         {0xbc, 0xde, 0xa8, 0x00}},
909         {"jyu",         {0xbc, 0xde, 0xad, 0x00}},
910         {"jye",         {0xbc, 0xde, 0xaa, 0x00}},
911         {"jyo",         {0xbc, 0xde, 0xae, 0x00}},
912         {"kya",         {0xb7, 0xac, 0x00}},
913         {"kyi",         {0xb7, 0xa8, 0x00}},
914         {"kyu",         {0xb7, 0xad, 0x00}},
915         {"kye",         {0xb7, 0xaa, 0x00}},
916         {"kyo",         {0xb7, 0xae, 0x00}},
917         {"lya",         {0xac, 0x00}},
918         {"lyi",         {0xa8, 0x00}},
919         {"lyu",         {0xad, 0x00}},
920         {"lye",         {0xaa, 0x00}},
921         {"lyo",         {0xae, 0x00}},
922         {"mya",         {0xd0, 0xac, 0x00}},
923         {"myi",         {0xd0, 0xa8, 0x00}},
924         {"myu",         {0xd0, 0xad, 0x00}},
925         {"mye",         {0xd0, 0xaa, 0x00}},
926         {"myo",         {0xd0, 0xae, 0x00}},
927         {"nya",         {0xc6, 0xac, 0x00}},
928         {"nyi",         {0xc6, 0xa8, 0x00}},
929         {"nyu",         {0xc6, 0xad, 0x00}},
930         {"nye",         {0xc6, 0xaa, 0x00}},
931         {"nyo",         {0xc6, 0xae, 0x00}},
932         {"pya",         {0xcb, 0xdf, 0xac, 0x00}},
933         {"pyi",         {0xcb, 0xdf, 0xa8, 0x00}},
934         {"pyu",         {0xcb, 0xdf, 0xad, 0x00}},
935         {"pye",         {0xcb, 0xdf, 0xaa, 0x00}},
936         {"pyo",         {0xcb, 0xdf, 0xae, 0x00}},
937         {"qwa",         {0xb8, 0xa7, 0x00}},
938         {"qwi",         {0xb8, 0xa8, 0x00}},
939         {"qwu",         {0xb8, 0xa9, 0x00}},
940         {"qwe",         {0xb8, 0xaa, 0x00}},
941         {"qwo",         {0xb8, 0xab, 0x00}},
942         {"qya",         {0xb8, 0xac, 0x00}},
943         {"qyi",         {0xb8, 0xa8, 0x00}},
944         {"qyu",         {0xb8, 0xad, 0x00}},
945         {"qye",         {0xb8, 0xaa, 0x00}},
946         {"qyo",         {0xb8, 0xae, 0x00}},
947         {"rya",         {0xd8, 0xac, 0x00}},
948         {"ryi",         {0xd8, 0xa8, 0x00}},
949         {"ryu",         {0xd8, 0xad, 0x00}},
950         {"rye",         {0xd8, 0xaa, 0x00}},
951         {"ryo",         {0xd8, 0xae, 0x00}},
952         {"sha",         {0xbc, 0xac, 0x00}},
953         {"shi",         {0xbc, 0x00}},
954         {"shu",         {0xbc, 0xad, 0x00}},
955         {"she",         {0xbc, 0xaa, 0x00}},
956         {"sho",         {0xbc, 0xae, 0x00}},
957         {"swa",         {0xbd, 0xa7, 0x00}},
958         {"swi",         {0xbd, 0xa8, 0x00}},
959         {"swu",         {0xbd, 0xa9, 0x00}},
960         {"swe",         {0xbd, 0xaa, 0x00}},
961         {"swo",         {0xbd, 0xab, 0x00}},
962         {"sya",         {0xbc, 0xac, 0x00}},
963         {"syi",         {0xbc, 0xa8, 0x00}},
964         {"syu",         {0xbc, 0xad, 0x00}},
965         {"sye",         {0xbc, 0xaa, 0x00}},
966         {"syo",         {0xbc, 0xae, 0x00}},
967         {"tha",         {0xc3, 0xac, 0x00}},
968         {"thi",         {0xc3, 0xa8, 0x00}},
969         {"thu",         {0xc3, 0xad, 0x00}},
970         {"the",         {0xc3, 0xaa, 0x00}},
971         {"tho",         {0xc3, 0xae, 0x00}},
972         {"tsa",         {0xc2, 0xa7, 0x00}},
973         {"tsi",         {0xc2, 0xa8, 0x00}},
974         {"tsu",         {0xc2, 0x00}},
975         {"tse",         {0xc2, 0xaa, 0x00}},
976         {"tso",         {0xc2, 0xab, 0x00}},
977         {"twa",         {0xc4, 0xa7, 0x00}},
978         {"twi",         {0xc4, 0xa8, 0x00}},
979         {"twu",         {0xc4, 0xa9, 0x00}},
980         {"twe",         {0xc4, 0xaa, 0x00}},
981         {"two",         {0xc4, 0xab, 0x00}},
982         {"tya",         {0xc1, 0xac, 0x00}},
983         {"tyi",         {0xc1, 0xa8, 0x00}},
984         {"tyu",         {0xc1, 0xad, 0x00}},
985         {"tye",         {0xc1, 0xaa, 0x00}},
986         {"tyo",         {0xc1, 0xae, 0x00}},
987         {"vya",         {0xb3, 0xde, 0xac, 0x00}},
988         {"vyi",         {0xb3, 0xde, 0xa8, 0x00}},
989         {"vyu",         {0xb3, 0xde, 0xad, 0x00}},
990         {"vye",         {0xb3, 0xde, 0xaa, 0x00}},
991         {"vyo",         {0xb3, 0xde, 0xae, 0x00}},
992         {"wha",         {0xb3, 0xa7, 0x00}},
993         {"whi",         {0xb3, 0xa8, 0x00}},
994         {"whu",         {0xb3, 0x00}},
995         {"whe",         {0xb3, 0xaa, 0x00}},
996         {"who",         {0xb3, 0xab, 0x00}},
997         {"xya",         {0xac, 0x00}},
998         {"xyi",         {0xa8, 0x00}},
999         {"xyu",         {0xad, 0x00}},
1000         {"xye",         {0xaa, 0x00}},
1001         {"xyo",         {0xae, 0x00}},
1002         {"zya",         {0xbc, 0xde, 0xac, 0x00}},
1003         {"zyi",         {0xbc, 0xde, 0xa8, 0x00}},
1004         {"zyu",         {0xbc, 0xde, 0xad, 0x00}},
1005         {"zye",         {0xbc, 0xde, 0xaa, 0x00}},
1006         {"zyo",         {0xbc, 0xde, 0xae, 0x00}},
1007         {"ba",          {0xca, 0xde, 0x00}},
1008         {"bi",          {0xcb, 0xde, 0x00}},
1009         {"bu",          {0xcc, 0xde, 0x00}},
1010         {"be",          {0xcd, 0xde, 0x00}},
1011         {"bo",          {0xce, 0xde, 0x00}},
1012         {"ca",          {0xb6, 0x00}},
1013         {"ci",          {0xbc, 0x00}},
1014         {"cu",          {0xb8, 0x00}},
1015         {"ce",          {0xbe, 0x00}},
1016         {"co",          {0xba, 0x00}},
1017         {"da",          {0xc0, 0xde, 0x00}},
1018         {"di",          {0xc1, 0xde, 0x00}},
1019         {"du",          {0xc2, 0xde, 0x00}},
1020         {"de",          {0xc3, 0xde, 0x00}},
1021         {"do",          {0xc4, 0xde, 0x00}},
1022         {"fa",          {0xcc, 0xa7, 0x00}},
1023         {"fi",          {0xcc, 0xa8, 0x00}},
1024         {"fu",          {0xcc, 0x00}},
1025         {"fe",          {0xcc, 0xaa, 0x00}},
1026         {"fo",          {0xcc, 0xab, 0x00}},
1027         {"ga",          {0xb6, 0xde, 0x00}},
1028         {"gi",          {0xb7, 0xde, 0x00}},
1029         {"gu",          {0xb8, 0xde, 0x00}},
1030         {"ge",          {0xb9, 0xde, 0x00}},
1031         {"go",          {0xba, 0xde, 0x00}},
1032         {"ha",          {0xca, 0x00}},
1033         {"hi",          {0xcb, 0x00}},
1034         {"hu",          {0xcc, 0x00}},
1035         {"he",          {0xcd, 0x00}},
1036         {"ho",          {0xce, 0x00}},
1037         {"ja",          {0xbc, 0xde, 0xac, 0x00}},
1038         {"ji",          {0xbc, 0xde, 0x00}},
1039         {"ju",          {0xbc, 0xde, 0xad, 0x00}},
1040         {"je",          {0xbc, 0xde, 0xaa, 0x00}},
1041         {"jo",          {0xbc, 0xde, 0xae, 0x00}},
1042         {"ka",          {0xb6, 0x00}},
1043         {"ki",          {0xb7, 0x00}},
1044         {"ku",          {0xb8, 0x00}},
1045         {"ke",          {0xb9, 0x00}},
1046         {"ko",          {0xba, 0x00}},
1047         {"la",          {0xa7, 0x00}},
1048         {"li",          {0xa8, 0x00}},
1049         {"lu",          {0xa9, 0x00}},
1050         {"le",          {0xaa, 0x00}},
1051         {"lo",          {0xab, 0x00}},
1052         {"ma",          {0xcf, 0x00}},
1053         {"mi",          {0xd0, 0x00}},
1054         {"mu",          {0xd1, 0x00}},
1055         {"me",          {0xd2, 0x00}},
1056         {"mo",          {0xd3, 0x00}},
1057         {"na",          {0xc5, 0x00}},
1058         {"ni",          {0xc6, 0x00}},
1059         {"nu",          {0xc7, 0x00}},
1060         {"ne",          {0xc8, 0x00}},
1061         {"no",          {0xc9, 0x00}},
1062 //      {"nn",          {0xdd, 0x00}},
1063         {"pa",          {0xca, 0xdf, 0x00}},
1064         {"pi",          {0xcb, 0xdf, 0x00}},
1065         {"pu",          {0xcc, 0xdf, 0x00}},
1066         {"pe",          {0xcd, 0xdf, 0x00}},
1067         {"po",          {0xce, 0xdf, 0x00}},
1068         {"qa",          {0xb8, 0xa7, 0x00}},
1069         {"qi",          {0xb8, 0xa8, 0x00}},
1070         {"qu",          {0xb8, 0x00}},
1071         {"qe",          {0xb8, 0xaa, 0x00}},
1072         {"qo",          {0xb8, 0xab, 0x00}},
1073         {"ra",          {0xd7, 0x00}},
1074         {"ri",          {0xd8, 0x00}},
1075         {"ru",          {0xd9, 0x00}},
1076         {"re",          {0xda, 0x00}},
1077         {"ro",          {0xdb, 0x00}},
1078         {"sa",          {0xbb, 0x00}},
1079         {"si",          {0xbc, 0x00}},
1080         {"su",          {0xbd, 0x00}},
1081         {"se",          {0xbe, 0x00}},
1082         {"so",          {0xbf, 0x00}},
1083         {"ta",          {0xc0, 0x00}},
1084         {"ti",          {0xc1, 0x00}},
1085         {"tu",          {0xc2, 0x00}},
1086         {"te",          {0xc3, 0x00}},
1087         {"to",          {0xc4, 0x00}},
1088         {"va",          {0xb3, 0xde, 0xa7, 0x00}},
1089         {"vi",          {0xb3, 0xde, 0xa8, 0x00}},
1090         {"vu",          {0xb3, 0xde, 0x00}},
1091         {"ve",          {0xb3, 0xde, 0xaa, 0x00}},
1092         {"vo",          {0xb3, 0xde, 0xab, 0x00}},
1093         {"wa",          {0xdc, 0x00}},
1094         {"wi",          {0xb3, 0xa8, 0x00}},
1095         {"wu",          {0xb3, 0x00}},
1096         {"we",          {0xb3, 0xaa, 0x00}},
1097         {"wo",          {0xa6, 0x00}},
1098         {"xa",          {0xa7, 0x00}},
1099         {"xi",          {0xa8, 0x00}},
1100         {"xu",          {0xa9, 0x00}},
1101         {"xe",          {0xaa, 0x00}},
1102         {"xo",          {0xab, 0x00}},
1103         {"ya",          {0xd4, 0x00}},
1104         {"yi",          {0xb2, 0x00}},
1105         {"yu",          {0xd5, 0x00}},
1106         {"ye",          {0xb2, 0xaa, 0x00}},
1107         {"yo",          {0xd6, 0x00}},
1108         {"za",          {0xbb, 0xde, 0x00}},
1109         {"zi",          {0xbc, 0xde, 0x00}},
1110         {"zu",          {0xbd, 0xde, 0x00}},
1111         {"ze",          {0xbe, 0xde, 0x00}},
1112         {"zo",          {0xbf, 0xde, 0x00}},
1113         {"a",           {0xb1, 0x00}},
1114         {"i",           {0xb2, 0x00}},
1115         {"u",           {0xb3, 0x00}},
1116         {"e",           {0xb4, 0x00}},
1117         {"o",           {0xb5, 0x00}},
1118         {"[",           {0xa2, 0x00}},
1119         {"]",           {0xa3, 0x00}},
1120         {"-",           {0xb0, 0x00}},
1121         {",",           {0xa4, 0x00}},
1122         {".",           {0xa1, 0x00}},
1123         {"/",           {0xa5, 0x00}},
1124         // Pass through kana key codes.
1125         {"\x0bc",       {0xa4, 0x00}},
1126         {"\x0bd",   {0xb0, 0x00}},
1127         {"\x0be",       {0xa1, 0x00}},
1128         {"\x0bf",       {0xa5, 0x00}},
1129         {"\x0db",       {0xa2, 0x00}},
1130         {"\x0dd",       {0xa3, 0x00}},
1131         {"",            {0x00}},
1132 };
1133
1134 void EMU::initialize_auto_key()
1135 {
1136         auto_key_buffer = new FIFO(65536);
1137         auto_key_buffer->clear();
1138         auto_key_phase = auto_key_shift = 0;
1139         shift_pressed = false;
1140         osd->now_auto_key = false;
1141 }
1142
1143 void EMU::release_auto_key()
1144 {
1145         if(auto_key_buffer) {
1146                 auto_key_buffer->release();
1147                 delete auto_key_buffer;
1148         }
1149 }
1150
1151 int EMU::get_auto_key_code(int code)
1152 {
1153         static int auto_key_table[256];
1154         static bool initialized = false;
1155 #ifdef USE_KEYBOARD_TYPE
1156         static int keyboard_type = -1;
1157
1158         if(keyboard_type != config.keyboard_type) {
1159                 initialized = false;
1160                 keyboard_type = config.keyboard_type;
1161         }
1162 #endif
1163         if(!initialized) {
1164                 memset(auto_key_table, 0, sizeof(auto_key_table));
1165                 for(int i = 0;; i++) {
1166                         if(auto_key_table_base[i][0] == -1) {
1167                                 break;
1168                         }
1169                         auto_key_table[auto_key_table_base[i][0]] = auto_key_table_base[i][1];
1170                 }
1171 #if defined(_X1TURBO) || defined(_X1TURBOZ)
1172                 // FIXME
1173                 if(config.keyboard_type) {
1174                         for(int i = 0;; i++) {
1175                                 if(auto_key_table_50on_base[i][0] == -1) {
1176                                         break;
1177                                 }
1178                                 auto_key_table[auto_key_table_50on_base[i][0]] = auto_key_table_50on_base[i][1];
1179                         }
1180                 } else
1181 #endif
1182                 for(int i = 0;; i++) {
1183                         if(auto_key_table_kana_base[i][0] == -1) {
1184                                 break;
1185                         }
1186                         auto_key_table[auto_key_table_kana_base[i][0]] = auto_key_table_kana_base[i][1];
1187                 }
1188 #ifdef USE_VM_AUTO_KEY_TABLE
1189                 for(int i = 0;; i++) {
1190                         if(vm_auto_key_table_base[i][0] == -1) {
1191                                 break;
1192                         }
1193                         auto_key_table[vm_auto_key_table_base[i][0]] = vm_auto_key_table_base[i][1];
1194                 }
1195 #endif
1196                 initialized = true;
1197         }
1198         return auto_key_table[code];
1199 }
1200
1201 void EMU::set_auto_key_code(int code)
1202 {
1203         if(code == 0xf2 || (code = get_auto_key_code(code)) != 0) {
1204                 if(code == 0x08 || code == 0x09 || code == 0x0d || code == 0x1b || code == 0x20 || code == 0xf2) {
1205                         // VK_BACK, VK_TAB, VK_RETURN, VK_ESCAPE, VK_SPACE, VK_OEM_COPY(Katakana/Hiragana)
1206                         auto_key_buffer->write(code);
1207 #ifdef USE_AUTO_KEY_NUMPAD
1208                 } else if(code >= 0x30 && code <= 0x39) {
1209                         // numpad
1210                         auto_key_buffer->write(code - 0x30 + 0x60);
1211 #endif
1212                 } else if(code & 0x200) {
1213                         // kana
1214                         auto_key_buffer->write(code & 0x1ff);
1215                 } else {
1216                         // ank other than alphabet and kana
1217                         auto_key_buffer->write(0xf2); // kana unlock
1218                         auto_key_buffer->write(code & 0x1ff);
1219                         auto_key_buffer->write(0xf2); // kana lock
1220                 }
1221                 if(!is_auto_key_running()) {
1222                         start_auto_key();
1223                 }
1224         }
1225 }
1226
1227 void EMU::set_auto_key_list(char *buf, int size)
1228 {
1229 #if defined(USE_KEY_LOCKED)
1230         bool prev_caps = get_caps_locked();
1231         bool prev_kana = get_kana_locked();
1232 #else
1233         bool prev_caps = false;
1234         bool prev_kana = false;
1235 #endif
1236         auto_key_buffer->clear();
1237
1238         for(int i = 0; i < size; i++) {
1239                 int code = buf[i] & 0xff;
1240                 if((0x81 <= code && code <= 0x9f) || 0xe0 <= code) {
1241                         i++;    // kanji ?
1242                         continue;
1243                 } else if(code == 0x0a) {
1244                         continue;       // cr-lf
1245                 }
1246                 if((code = get_auto_key_code(code)) != 0) {
1247                         // kana lock
1248                         bool kana = ((code & 0x200) != 0);
1249                         if(prev_kana != kana) {
1250                                 auto_key_buffer->write(0xf2);
1251                         }
1252                         prev_kana = kana;
1253                         // check handakuon
1254                         if(i < (size - 1)) {
1255                                 bool dakuon_lock = false;
1256                                 bool handakuon_lock = false;
1257 #if defined(USE_TWO_STROKE_AUTOKEY_HANDAKUON)
1258                                 if((buf[i + 1] & 0xff) == 0xdf) { // Is Handakuon
1259                                         for(int jj = 0; ; jj++) {
1260                                                 if(kana_handakuon_keyboard_table[jj][0] == -1) break;
1261                                                 if(kana_handakuon_keyboard_table[jj][0] == (buf[i] & 0xff)) { // Found
1262                                                         handakuon_lock = true;
1263                                                         for(int l = 1; l < 6; l++) {
1264                                                                 int n_code = kana_handakuon_keyboard_table[jj][l];
1265                                                                 if(n_code == 0x00) break;
1266                                                                 if(n_code & (0x100 | 0x400 | 0x800)) {
1267                                                                         auto_key_buffer->write((n_code & 0x30ff)| 0x100);
1268                                                                 } else {
1269                                                                         auto_key_buffer->write(n_code & 0x30ff);
1270                                                                 }
1271                                                         }
1272                                                         break;
1273                                                 }
1274                                         }
1275                                         if(handakuon_lock) {
1276                                                 i++;
1277                                                 continue;
1278                                         }
1279                                 }
1280 #endif
1281 #if defined(USE_TWO_STROKE_AUTOKEY_DAKUON)
1282                                 if((buf[i + 1] & 0xff) == 0xde) { // Is Dakuon
1283                                         for(int jj = 0; ; jj++) {
1284                                                 if(kana_dakuon_keyboard_table[jj][0] == -1) break;
1285                                                 if(kana_dakuon_keyboard_table[jj][0] == (buf[i] & 0xff)) { // Found
1286                                                         dakuon_lock = true;
1287                                                         for(int l = 1; l < 6; l++) {
1288                                                                 int n_code = kana_dakuon_keyboard_table[jj][l];
1289                                                                 if(n_code == 0x00) break;
1290                                                                 if(n_code & (0x100 | 0x400 | 0x800)) {
1291                                                                         auto_key_buffer->write((n_code & 0x30ff)| 0x100);
1292                                                                 } else {
1293                                                                         auto_key_buffer->write(n_code & 0x30ff);
1294                                                                 }
1295                                                         }
1296                                                         break;
1297                                                 }
1298                                         }
1299                                         if(dakuon_lock) {
1300                                                 i++;
1301                                                 continue;
1302                                         }
1303                                 }
1304 #endif
1305                         }
1306 #if defined(USE_AUTO_KEY_CAPS_LOCK)
1307                         // use caps lock key to switch uppercase/lowercase of alphabet
1308                         // USE_AUTO_KEY_CAPS_LOCK shows the caps lock key code
1309                         bool caps = ((code & 0x400) != 0);
1310                         if(prev_caps != caps) {
1311                                 auto_key_buffer->write(USE_AUTO_KEY_CAPS_LOCK);
1312                         }
1313                         prev_caps = caps;
1314 #endif
1315 #if defined(USE_AUTO_KEY_CAPS_LOCK) || defined(USE_AUTO_KEY_NO_CAPS)
1316                         code &= ~(0x400 | 0x800); // don't press shift key for both alphabet and ALPHABET
1317 #elif defined(USE_KEY_LOCKED)
1318                         if(get_caps_locked()) {
1319                                 code &= ~0x400; // don't press shift key for ALPHABET
1320                         } else {
1321                                 code &= ~0x800; // don't press shift key for alphabet
1322                         }
1323 #elif defined(USE_AUTO_KEY_CAPS)
1324                         code &= ~0x400; // don't press shift key for ALPHABET
1325 #else
1326                         code &= ~0x800; // don't press shift key for alphabet
1327 #endif
1328                         if(code & (0x100 | 0x400 | 0x800)) {
1329                                 auto_key_buffer->write((code & 0xff) | 0x100);
1330                         } else {
1331                                 auto_key_buffer->write(code & 0xff);
1332                         }
1333                 }
1334         }
1335         // release kana lock
1336         if(prev_kana) {
1337                 auto_key_buffer->write(0xf2);
1338         }
1339 #if defined(USE_AUTO_KEY_CAPS_LOCK)
1340         // release caps lock
1341         if(prev_caps) {
1342                 auto_key_buffer->write(USE_AUTO_KEY_CAPS_LOCK);
1343         }
1344 #endif
1345 }
1346
1347 bool is_alphabet(char code)
1348 {
1349         return (code >= 'a' && code <= 'z');
1350 }
1351
1352 bool is_vowel(char code)
1353 {
1354         return (code == 'a' || code == 'i' || code == 'u' || code == 'e' || code == 'o');
1355 }
1356
1357 bool is_consonant(char code)
1358 {
1359         return (is_alphabet(code) && !is_vowel(code));
1360 }
1361
1362 void EMU::set_auto_key_char(char code)
1363 {
1364         static char codes[5] = {0};
1365         if(code == 1) {
1366                 // start
1367 #ifdef USE_KEY_LOCKED
1368                 if(!get_kana_locked())
1369 #endif
1370                 set_auto_key_code(0xf2);
1371                 memset(codes, 0, sizeof(codes));
1372         } else if(code == 0) {
1373                 // end
1374                 if(codes[3] == 'n') {
1375                         set_auto_key_code(0xdd); // 'ン'
1376                 }
1377                 set_auto_key_code(0xf2);
1378                 memset(codes, 0, sizeof(codes));
1379         } else if(code == 0x08 || code == 0x09 || code == 0x0d || code == 0x1b || code == 0x20) {
1380                 if(codes[3] == 'n') {
1381                         set_auto_key_code(0xdd); // 'ン'
1382                 }
1383                 set_auto_key_code(code);
1384                 memset(codes, 0, sizeof(codes));
1385 #ifdef USE_AUTO_KEY_NUMPAD
1386         } else if(code >= 0x30 && code <= 0x39) {
1387                 if(codes[3] == 'n') {
1388                         set_auto_key_code(0xdd); // 'ン'
1389                 }
1390                 set_auto_key_code(code);
1391                 memset(codes, 0, sizeof(codes));
1392 #endif
1393         } else {
1394                 codes[0] = codes[1];
1395                 codes[1] = codes[2];
1396                 codes[2] = codes[3];
1397                 codes[3] = (code >= 'A' && code <= 'Z') ? ('a' + (code - 'A')) : code & 0xff;
1398                 codes[4] = '\0';
1399
1400                 if(codes[2] == 'n' && !is_vowel(codes[3])) {
1401                         set_auto_key_code(0xdd); // 'ン'
1402                         if(codes[3] == 'n') {
1403                                 memset(codes, 0, sizeof(codes));
1404                                 return;
1405                         }
1406                 } else if(codes[2] == codes[3] && is_consonant(codes[3])) {
1407                         set_auto_key_code(0xaf); // 'ッ'
1408                         return;
1409                 }
1410                 for(int i = 0;; i++) {
1411                         size_t len = strlen(romaji_table[i].romaji);
1412                         int comp = -1;
1413                         if(len == 0) {
1414                                 // end of table
1415                                 if(!(is_alphabet(codes[3])) /*&& !((codes[3] >= 0x2c) && (codes[3] <= 0x2e)) && !((codes[3] == 0x5b) || (codes[3] == 0x5d))*/) {
1416                                         set_auto_key_code(codes[3]);
1417                                         memset(codes, 0, sizeof(codes));
1418                                 }
1419                                 break;
1420                         } else if(len == 1) {
1421                                 comp = strcmp(romaji_table[i].romaji, &codes[3]);
1422                         } else if(len == 2) {
1423                                 comp = strcmp(romaji_table[i].romaji, &codes[2]);
1424                         } else if(len == 3) {
1425                                 comp = strcmp(romaji_table[i].romaji, &codes[1]);
1426                         } else if(len == 4) {
1427                                 comp = strcmp(romaji_table[i].romaji, &codes[0]);
1428                         }
1429                         if(comp == 0) {
1430                                 for(int j = 0; j < 4; j++) {
1431                                         if(!romaji_table[i].kana[j]) {
1432                                                 break;
1433                                         }
1434                                         if(j == 0) {
1435                                                 bool handakuon_found = false;
1436                                                 bool dakuon_found = false;
1437 #if defined(USE_TWO_STROKE_AUTOKEY_HANDAKUON)
1438                                                 if(romaji_table[i].kana[1] == 0xdf) {
1439                                                         // HANDAKUON
1440                                                         for(int jj = 0;;jj++) {
1441                                                                 if(kana_handakuon_keyboard_table[jj][0] == -1) break;
1442                                                                 if(kana_handakuon_keyboard_table[jj][0] == romaji_table[i].kana[0]) {
1443                                                                         for(int l = 1; l < 6; l++) {
1444                                                                                 if(kana_handakuon_keyboard_table[jj][l] == 0x00) break;
1445                                                                                 auto_key_buffer->write(kana_handakuon_keyboard_table[jj][l] & 0x31ff);
1446                                                                                 if(!is_auto_key_running()) {
1447                                                                                         start_auto_key();
1448                                                                                 }
1449                                                                         }
1450                                                                         handakuon_found = true;
1451                                                                         j += 1;
1452                                                                         break;
1453                                                                 }
1454                                                         }
1455                                                 }
1456 #endif
1457 #if defined(USE_TWO_STROKE_AUTOKEY_DAKUON)
1458                                                 if(romaji_table[i].kana[1] == 0xde) {
1459                                                         // DAKUON
1460                                                         for(int jj = 0;;jj++) {
1461                                                                 if(kana_dakuon_keyboard_table[jj][0] == -1) break;
1462                                                                 if(kana_dakuon_keyboard_table[jj][0] == romaji_table[i].kana[0]) {
1463                                                                         for(int l = 1; l < 6; l++) {
1464                                                                                 if(kana_dakuon_keyboard_table[jj][l] == 0x00) break;
1465                                                                                 auto_key_buffer->write(kana_dakuon_keyboard_table[jj][l] & 0x31ff);
1466                                                                         }
1467                                                                         if(!is_auto_key_running()) {
1468                                                                                 start_auto_key();
1469                                                                         }
1470                                                                         j += 1;
1471                                                                         dakuon_found = true;
1472                                                                         break;
1473                                                                 }
1474                                                         }
1475                                                 }
1476 #endif
1477                                                 if((handakuon_found) || (dakuon_found)) {
1478                                                         continue;
1479                                                 }
1480                                         }
1481                                         set_auto_key_code(romaji_table[i].kana[j]);
1482                                 }
1483                                 memset(codes, 0, sizeof(codes));
1484                                 break;
1485                         }
1486                 }
1487         }
1488 }
1489
1490 void EMU::start_auto_key()
1491 {
1492         auto_key_phase = 1;
1493         auto_key_shift = 0;
1494         osd->now_auto_key = true;
1495 }
1496
1497 void EMU::stop_auto_key()
1498 {
1499         if(auto_key_shift) {
1500                 osd->key_up_native(VK_LSHIFT);
1501         }
1502         auto_key_phase = auto_key_shift = 0;
1503         osd->now_auto_key = false;
1504 }
1505
1506 #ifndef USE_AUTO_KEY_SHIFT
1507 #define USE_AUTO_KEY_SHIFT 0
1508 #endif
1509 #ifndef VK_LSHIFT
1510 #define VK_LSHIFT 0xA0
1511 #endif
1512
1513 void EMU::update_auto_key()
1514 {
1515         switch(auto_key_phase) {
1516         case 1:
1517                 if(auto_key_buffer && !auto_key_buffer->empty()) {
1518                         // update shift key status
1519                         int shift = auto_key_buffer->read_not_remove(0) & 0x100;
1520                         if(shift && !auto_key_shift) {
1521                                 osd->key_down_native(VK_LSHIFT, false);
1522                         } else if(!shift && auto_key_shift) {
1523                                 osd->key_up_native(VK_LSHIFT);
1524                         }
1525                         auto_key_shift = shift;
1526                         auto_key_phase++;
1527                         break;
1528                 }
1529         case 3 + USE_AUTO_KEY_SHIFT:
1530                 if(auto_key_buffer && !auto_key_buffer->empty()) {
1531                         if(!(auto_key_buffer->read_not_remove(0) & 0x2000)) {
1532                                 osd->key_down_native(auto_key_buffer->read_not_remove(0) & 0xff, false);
1533 //                              printf("Press key: %04X\n", auto_key_buffer->read_not_remove(0));
1534                         }
1535                 }
1536                 auto_key_phase++;
1537                 break;
1538         case USE_AUTO_KEY + USE_AUTO_KEY_SHIFT:
1539                 if(auto_key_buffer && !auto_key_buffer->empty()) {
1540                         if(!(auto_key_buffer->read_not_remove(0) & 0x1000)) {
1541                                 osd->key_up_native(auto_key_buffer->read_not_remove(0) & 0xff);
1542 //                              printf("Release key: %04X\n", auto_key_buffer->read_not_remove(0));
1543                         }
1544                 }
1545                 auto_key_phase++;
1546                 break;
1547         case USE_AUTO_KEY_RELEASE + USE_AUTO_KEY_SHIFT:
1548                 if(auto_key_buffer && !auto_key_buffer->empty()) {
1549                         // wait enough while vm analyzes one line
1550                         if(auto_key_buffer->read() == 0xd) {
1551                                 auto_key_phase++;
1552                                 break;
1553                         }
1554                 }
1555         case 30:
1556                 if(auto_key_buffer && !auto_key_buffer->empty()) {
1557                         auto_key_phase = 1;
1558                 } else {
1559                         stop_auto_key();
1560                 }
1561                 break;
1562         default:
1563                 if(auto_key_phase) {
1564                         auto_key_phase++;
1565                 }
1566         }
1567 }
1568 #endif
1569
1570 #ifdef USE_JOYSTICK
1571 void EMU::update_joystick()
1572 {
1573         uint8_t *key_buffer = osd->get_key_buffer();
1574
1575         uint32_t *joyp = osd->get_joy_buffer();
1576         uint32_t joy_buffer[4];
1577         memset(joy_status, 0, sizeof(joy_status));
1578         for(int i = 0; i < 4; i++) {
1579                 joy_buffer[i] = joyp[i];
1580         }
1581         osd->release_joy_buffer(joyp);
1582
1583         for(int i = 0; i < 4; i++) {
1584                 for(int j = 0; j < 16; j++) {
1585                         if(config.joy_buttons[i][j] < 0) {
1586                                 int code = -config.joy_buttons[i][j];
1587                                 if(code < 256 && key_buffer[code]) {
1588                                         joy_status[i] |= (1 << j);
1589                                         //printf("%d %d %02x %02x\n", i, j, config.joy_buttons[i][j], joy_status[i]);
1590                                 }
1591                         } else {
1592                                 int stick = config.joy_buttons[i][j] >> 5;
1593                                 int button = config.joy_buttons[i][j] & 0x1f;
1594                                 if(stick < 4 && (joy_buffer[stick & 3] & (1 << button))) {
1595                                         joy_status[i] |= (1 << j);
1596                                         //printf("%d %d %02x %02x\n", i, j, config.joy_buttons[i][j], joy_status[i]);
1597                                 }
1598                         }
1599                 }
1600         }
1601 }
1602 #endif
1603
1604 const uint8_t* EMU::get_key_buffer()
1605 {
1606         return (const uint8_t*)osd->get_key_buffer();
1607 }
1608
1609 #ifdef USE_JOYSTICK
1610 const uint32_t* EMU::get_joy_buffer()
1611 {
1612         // Update joystick data per query joystick buffer.
1613         update_joystick();
1614         return (const uint32_t*)joy_status;
1615 }
1616 void EMU::release_joy_buffer(const uint32_t* ptr)
1617 {
1618         // ToDo: Unlock buffer.
1619 }
1620 #endif
1621
1622 #ifdef USE_MOUSE
1623 const int32_t* EMU::get_mouse_buffer()
1624 {
1625         return (const int32_t*)osd->get_mouse_buffer();
1626 }
1627 void EMU::release_mouse_buffer(const int32_t* ptr)
1628 {
1629         // ToDo: Unlock buffer.
1630         osd->release_mouse_buffer((int32_t*)ptr);
1631 }
1632 const int32_t EMU::get_mouse_button()
1633 {
1634         return (const int32_t)osd->get_mouse_button();
1635 }
1636
1637 #endif
1638
1639 // ----------------------------------------------------------------------------
1640 // screen
1641 // ----------------------------------------------------------------------------
1642
1643 double EMU::get_window_mode_power(int mode)
1644 {
1645         return osd->get_window_mode_power(mode);
1646 }
1647
1648 int EMU::get_window_mode_width(int mode)
1649 {
1650         return osd->get_window_mode_width(mode);
1651 }
1652
1653 int EMU::get_window_mode_height(int mode)
1654 {
1655         return osd->get_window_mode_height(mode);
1656 }
1657
1658 void EMU::set_host_window_size(int window_width, int window_height, bool window_mode)
1659 {
1660         osd->set_host_window_size(window_width, window_height, window_mode);
1661 }
1662
1663 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)
1664 {
1665         osd->set_vm_screen_size(screen_width, screen_height, window_width, window_height, window_width_aspect, window_height_aspect);
1666 }
1667
1668 void EMU::set_vm_screen_lines(int lines)
1669 {
1670         osd->set_vm_screen_lines(lines);
1671 }
1672
1673
1674 int EMU::get_vm_window_width()
1675 {
1676         return osd->get_vm_window_width();
1677 }
1678
1679 int EMU::get_vm_window_height()
1680 {
1681         return osd->get_vm_window_height();
1682 }
1683
1684 int EMU::get_vm_window_width_aspect()
1685 {
1686         return osd->get_vm_window_width_aspect();
1687 }
1688
1689 int EMU::get_vm_window_height_aspect()
1690 {
1691         return osd->get_vm_window_height_aspect();
1692 }
1693
1694 #if defined(USE_MINIMUM_RENDERING)
1695 bool EMU::is_screen_changed()
1696 {
1697         return vm->is_screen_changed();
1698 }
1699 #endif
1700
1701 int EMU::draw_screen()
1702 {
1703 #ifdef ONE_BOARD_MICRO_COMPUTER
1704         if(now_waiting_in_debugger) {
1705                 osd->reload_bitmap();
1706         }
1707 #endif
1708         return osd->draw_screen();
1709 }
1710
1711 scrntype_t* EMU::get_screen_buffer(int y)
1712 {
1713         return osd->get_vm_screen_buffer(y);
1714 }
1715
1716 #ifdef USE_SCREEN_FILTER
1717 void EMU::screen_skip_line(bool skip_line)
1718 {
1719         osd->screen_skip_line = skip_line;
1720 }
1721 #endif
1722
1723 #ifdef ONE_BOARD_MICRO_COMPUTER
1724 void EMU::get_invalidated_rect(int *left, int *top, int *right, int *bottom)
1725 {
1726 #ifdef MAX_DRAW_RANGES
1727         for(int i = 0; i < MAX_DRAW_RANGES; i++) {
1728 #else
1729         for(int i = 0; i < vm->max_draw_ranges(); i++) { // for TK-80BS
1730 #endif
1731                 int x1 = vm_ranges[i].x;
1732                 int y1 = vm_ranges[i].y;
1733                 int x2 = x1 + vm_ranges[i].width;
1734                 int y2 = y1 + vm_ranges[i].height;
1735
1736                 *left   = (i == 0) ? x1 : min(x1, *left  );
1737                 *top    = (i == 0) ? y1 : min(y1, *top   );
1738                 *right  = (i == 0) ? x2 : max(x2, *right );
1739                 *bottom = (i == 0) ? y2 : max(y2, *bottom);
1740         }
1741 }
1742
1743 void EMU::reload_bitmap()
1744 {
1745         osd->reload_bitmap();
1746 }
1747 #endif
1748
1749 #ifdef OSD_WIN32
1750 void EMU::invalidate_screen()
1751 {
1752         osd->invalidate_screen();
1753 }
1754
1755 void EMU::update_screen(HDC hdc)
1756 {
1757         osd->update_screen(hdc);
1758 }
1759 #endif
1760
1761 void EMU::capture_screen()
1762 {
1763         osd->capture_screen();
1764 }
1765
1766 bool EMU::start_record_video(int fps)
1767 {
1768         return osd->start_record_video(fps);
1769 }
1770
1771 void EMU::stop_record_video()
1772 {
1773         osd->stop_record_video();
1774 }
1775
1776 bool EMU::is_video_recording()
1777 {
1778         return osd->now_record_video;
1779 }
1780
1781 // ----------------------------------------------------------------------------
1782 // sound
1783 // ----------------------------------------------------------------------------
1784
1785 void EMU::mute_sound()
1786 {
1787         osd->mute_sound();
1788 }
1789
1790 void EMU::start_record_sound()
1791 {
1792         osd->start_record_sound();
1793 }
1794
1795 void EMU::stop_record_sound()
1796 {
1797         osd->stop_record_sound();
1798 }
1799
1800 bool EMU::is_sound_recording()
1801 {
1802         return osd->now_record_sound;
1803 }
1804
1805 // ----------------------------------------------------------------------------
1806 // video
1807 // ----------------------------------------------------------------------------
1808
1809 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
1810 void EMU::get_video_buffer()
1811 {
1812         osd->get_video_buffer();
1813 }
1814
1815 void EMU::mute_video_dev(bool l, bool r)
1816 {
1817         osd->mute_video_dev(l, r);
1818 }
1819 #endif
1820
1821 #ifdef USE_MOVIE_PLAYER
1822 bool EMU::open_movie_file(const _TCHAR* file_path)
1823 {
1824         return osd->open_movie_file(file_path);
1825 }
1826
1827 void EMU::close_movie_file()
1828 {
1829         osd->close_movie_file();
1830 }
1831
1832 void EMU::play_movie()
1833 {
1834         osd->play_movie();
1835 }
1836
1837 void EMU::stop_movie()
1838 {
1839         osd->stop_movie();
1840 }
1841
1842 void EMU::pause_movie()
1843 {
1844         osd->pause_movie();
1845 }
1846
1847 double EMU::get_movie_frame_rate()
1848 {
1849         return osd->get_movie_frame_rate();
1850 }
1851
1852 int EMU::get_movie_sound_rate()
1853 {
1854         return osd->get_movie_sound_rate();
1855 }
1856
1857 void EMU::set_cur_movie_frame(int frame, bool relative)
1858 {
1859         osd->set_cur_movie_frame(frame, relative);
1860 }
1861
1862 uint32_t EMU::get_cur_movie_frame()
1863 {
1864         return osd->get_cur_movie_frame();
1865 }
1866 #endif
1867
1868 #ifdef USE_VIDEO_CAPTURE
1869 int EMU::get_cur_capture_dev_index()
1870 {
1871         return osd->get_cur_capture_dev_index();
1872 }
1873
1874 int EMU::get_num_capture_devs()
1875 {
1876         return osd->get_num_capture_devs();
1877 }
1878
1879 _TCHAR* EMU::get_capture_dev_name(int index)
1880 {
1881         return osd->get_capture_dev_name(index);
1882 }
1883
1884 void EMU::open_capture_dev(int index, bool pin)
1885 {
1886         osd->open_capture_dev(index, pin);
1887 }
1888
1889 void EMU::close_capture_dev()
1890 {
1891         osd->close_capture_dev();
1892 }
1893
1894 void EMU::show_capture_dev_filter()
1895 {
1896         osd->show_capture_dev_filter();
1897 }
1898
1899 void EMU::show_capture_dev_pin()
1900 {
1901         osd->show_capture_dev_pin();
1902 }
1903
1904 void EMU::show_capture_dev_source()
1905 {
1906         osd->show_capture_dev_source();
1907 }
1908
1909 void EMU::set_capture_dev_channel(int ch)
1910 {
1911         osd->set_capture_dev_channel(ch);
1912 }
1913 #endif
1914
1915 // ----------------------------------------------------------------------------
1916 // printer
1917 // ----------------------------------------------------------------------------
1918
1919 #ifdef USE_PRINTER
1920 void EMU::create_bitmap(bitmap_t *bitmap, int width, int height)
1921 {
1922         osd->create_bitmap(bitmap, width, height);
1923 }
1924
1925 void EMU::release_bitmap(bitmap_t *bitmap)
1926 {
1927         osd->release_bitmap(bitmap);
1928 }
1929
1930 void EMU::create_font(font_t *font, const _TCHAR *family, int width, int height, int rotate, bool bold, bool italic)
1931 {
1932         osd->create_font(font, family, width, height, rotate, bold, italic);
1933 }
1934
1935 void EMU::release_font(font_t *font)
1936 {
1937         osd->release_font(font);
1938 }
1939
1940 void EMU::create_pen(pen_t *pen, int width, uint8_t r, uint8_t g, uint8_t b)
1941 {
1942         osd->create_pen(pen, width, r, g, b);
1943 }
1944
1945 void EMU::release_pen(pen_t *pen)
1946 {
1947         osd->release_pen(pen);
1948 }
1949
1950 void EMU::clear_bitmap(bitmap_t *bitmap, uint8_t r, uint8_t g, uint8_t b)
1951 {
1952         osd->clear_bitmap(bitmap, r, g, b);
1953 }
1954
1955 int EMU::get_text_width(bitmap_t *bitmap, font_t *font, const char *text)
1956 {
1957         return osd->get_text_width(bitmap, font, text);
1958 }
1959
1960 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)
1961 {
1962         osd->draw_text_to_bitmap(bitmap, font, x, y, text, r, g, b);
1963 }
1964
1965 void EMU::draw_line_to_bitmap(bitmap_t *bitmap, pen_t *pen, int sx, int sy, int ex, int ey)
1966 {
1967         osd->draw_line_to_bitmap(bitmap, pen, sx, sy, ex, ey);
1968 }
1969
1970 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)
1971 {
1972         osd->draw_rectangle_to_bitmap(bitmap, x, y, width, height, r, g, b);
1973 }
1974
1975 void EMU::draw_point_to_bitmap(bitmap_t *bitmap, int x, int y, uint8_t r, uint8_t g, uint8_t b)
1976 {
1977         osd->draw_point_to_bitmap(bitmap, x, y, r, g, b);
1978 }
1979
1980 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)
1981 {
1982         osd->stretch_bitmap(dest, dest_x, dest_y, dest_width, dest_height, source, source_x, source_y, source_width, source_height);
1983 }
1984
1985 void EMU::write_bitmap_to_file(bitmap_t *bitmap, const _TCHAR *file_path)
1986 {
1987         osd->write_bitmap_to_file(bitmap, file_path);
1988 }
1989 #endif
1990
1991 // ----------------------------------------------------------------------------
1992 // socket
1993 // ----------------------------------------------------------------------------
1994
1995 #ifdef USE_SOCKET
1996 SOCKET EMU::get_socket(int ch)
1997 {
1998         return osd->get_socket(ch);
1999 }
2000
2001 void EMU::notify_socket_connected(int ch)
2002 {
2003         osd->notify_socket_connected(ch);
2004 }
2005
2006 void EMU::notify_socket_disconnected(int ch)
2007 {
2008         osd->notify_socket_disconnected(ch);
2009 }
2010
2011 bool EMU::initialize_socket_tcp(int ch)
2012 {
2013         return osd->initialize_socket_tcp(ch);
2014 }
2015
2016 bool EMU::initialize_socket_udp(int ch)
2017 {
2018         return osd->initialize_socket_udp(ch);
2019 }
2020
2021 bool EMU::connect_socket(int ch, uint32_t ipaddr, int port)
2022 {
2023         return osd->connect_socket(ch, ipaddr, port);
2024 }
2025
2026 void EMU::disconnect_socket(int ch)
2027 {
2028         osd->disconnect_socket(ch);
2029 }
2030
2031 bool EMU::listen_socket(int ch)
2032 {
2033         return osd->listen_socket(ch);
2034 }
2035
2036 void EMU::send_socket_data_tcp(int ch)
2037 {
2038         osd->send_socket_data_tcp(ch);
2039 }
2040
2041 void EMU::send_socket_data_udp(int ch, uint32_t ipaddr, int port)
2042 {
2043         osd->send_socket_data_udp(ch, ipaddr, port);
2044 }
2045
2046 void EMU::send_socket_data(int ch)
2047 {
2048         osd->send_socket_data(ch);
2049 }
2050
2051 void EMU::recv_socket_data(int ch)
2052 {
2053         osd->recv_socket_data(ch);
2054 }
2055 #endif
2056
2057 // ----------------------------------------------------------------------------
2058 // MIDI
2059 // ----------------------------------------------------------------------------
2060
2061 #ifdef USE_MIDI
2062 void EMU::send_to_midi(uint8_t data, int ch, double timestamp_usec)
2063 {
2064         osd->send_to_midi(data, ch, timestamp_usec);
2065 }
2066
2067 bool EMU::recv_from_midi(uint8_t *data, int ch, double timestamp_usec)
2068 {
2069         return osd->recv_from_midi(data, ch, timestamp_usec);
2070 }
2071 // ToDo: Will implement timeout function.
2072 bool EMU::send_to_midi_timeout(uint8_t data, int ch, uint64_t timeout_ms, double timestamp_usec)
2073 {
2074         // ToDo: will implement handshake.
2075         // Q: Need to check VM's timeout status?
2076         return osd->send_to_midi_timeout(data, ch, timeout_ms, timestamp_usec);
2077 }
2078
2079 bool EMU::recv_from_midi_timeout(uint8_t* data, int ch, uint64_t timeout_ms, double timestamp_usec)
2080 {
2081         // ToDo: will implement handshake.
2082         // Q: Need to check VM's timeout status?
2083         return osd->recv_from_midi_timeout(data, ch, timeout_ms, timestamp_usec);
2084 }
2085
2086 //void EMU::notify_timeout_sending_to_midi(int ch)
2087 //{
2088 //      vm->notify_timeout_sending_to_midi(ch);
2089 //}
2090 //void EMU::notify_timeout_receiving_from_midi(int ch)
2091 //{
2092 //      vm->notify_timeout_receiving_from_midi(ch);
2093 //}
2094
2095 void EMU::reset_to_midi(int ch, double timestamp_usec)
2096 {
2097         osd->reset_to_midi(ch, timestamp_usec);
2098 }
2099
2100 void EMU::initialize_midi_device(bool handshake_from_midi, bool handshake_to_midi, int ch)
2101 {
2102         osd->initialize_midi_device(handshake_from_midi, handshake_to_midi, ch);
2103 }
2104
2105 //void EMU::ready_receive_from_midi(int ch, double timestamp_usec)
2106 //{
2107 //      vm->ready_receive_from_midi(ch, timestamp_usec);
2108 //}
2109
2110 void EMU::ready_send_to_midi(int ch, double timestamp_usec)
2111 {
2112         osd->ready_send_to_midi(ch,timestamp_usec);
2113 }
2114
2115 void EMU::request_stop_to_receive_from_midi(int ch, double timestamp_usec)
2116 {
2117         osd->request_stop_to_receive_from_midi(ch, timestamp_usec);
2118 }
2119
2120 //void EMU::request_stop_to_send_to_midi(int ch, double timestamp_usec)
2121 //{
2122 //      vm->request_stop_to_send_to_midi(ch, timestamp_usec);
2123 //}
2124
2125
2126 #endif
2127 // ---------------------------------------------------------------------------
2128 // debugger (some functions needed by libCSPcommon_vm 20190221 K.O)
2129 // ---------------------------------------------------------------------------
2130
2131 void EMU::start_waiting_in_debugger()
2132 {
2133 #ifdef USE_DEBUGGER
2134         now_waiting_in_debugger = true;
2135 #endif
2136         osd->mute_sound();
2137 #ifdef USE_DEBUGGER
2138         osd->start_waiting_in_debugger();
2139 #endif
2140 }
2141
2142 void EMU::finish_waiting_in_debugger()
2143 {
2144 #ifdef USE_DEBUGGER
2145         osd->finish_waiting_in_debugger();
2146         now_waiting_in_debugger = false;
2147         osd->unmute_sound();
2148 #endif
2149 }
2150
2151 void EMU::process_waiting_in_debugger()
2152 {
2153 #ifdef USE_DEBUGGER
2154         osd->process_waiting_in_debugger();
2155 #else
2156         osd->sleep(10);
2157 #endif
2158 }
2159
2160 // ----------------------------------------------------------------------------
2161 // debug log
2162 // ----------------------------------------------------------------------------
2163
2164 #ifdef _DEBUG_LOG
2165 void EMU::initialize_debug_log()
2166 {
2167         _TCHAR path[_MAX_PATH];
2168         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
2169 }
2170
2171 void EMU::release_debug_log()
2172 {
2173         if(debug_log) {
2174                 fclose(debug_log);
2175                 debug_log = NULL;
2176         }
2177 }
2178 #endif
2179
2180 #ifdef _DEBUG_LOG
2181 static _TCHAR prev_buffer[2048] = {0};
2182 #endif
2183
2184 void EMU::out_debug_log(const _TCHAR* format, ...)
2185 {
2186         common_initialize();
2187
2188 #ifdef _DEBUG_LOG
2189         va_list ap;
2190         _TCHAR buffer[2048];
2191
2192         va_start(ap, format);
2193         my_vstprintf_s(buffer, 2048, format, ap);
2194         va_end(ap);
2195
2196         if(_tcscmp(prev_buffer, buffer) == 0) {
2197                 return;
2198         }
2199         my_tcscpy_s(prev_buffer, 2048, buffer);
2200
2201 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
2202         std::shared_ptr<CSP_Logger> lp = csp_logger;
2203         lp->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_EMU, "%s", buffer);
2204 #else
2205         if(debug_log) {
2206                 _ftprintf(debug_log, _T("(%f uS) %s"), vm->get_current_usec(), buffer);
2207                 static int size = 0;
2208                 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
2209                         fclose(debug_log);
2210                         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
2211                         size = 0;
2212                 }
2213         }
2214 #endif
2215 #endif
2216 }
2217
2218 void EMU::force_out_debug_log(const _TCHAR* format, ...)
2219 {
2220 #ifdef _DEBUG_LOG
2221         va_list ap;
2222         _TCHAR buffer[1024];
2223
2224         va_start(ap, format);
2225         my_vstprintf_s(buffer, 1024, format, ap);
2226         va_end(ap);
2227         my_tcscpy_s(prev_buffer, 1024, buffer);
2228
2229 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
2230         std::shared_ptr<CSP_Logger> lp = csp_logger;
2231     lp->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_EMU, "%s", buffer);
2232 #else
2233         if(debug_log) {
2234                 _ftprintf(debug_log, _T("%s"), buffer);
2235                 static int size = 0;
2236                 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
2237                         fclose(debug_log);
2238                         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
2239                         size = 0;
2240                 }
2241         }
2242 #endif
2243 #endif
2244 }
2245
2246 void EMU::out_message(const _TCHAR* format, ...)
2247 {
2248 //#if defined(_USE_QT)
2249 //      _TCHAR mes_buf[1024];
2250 //#endif
2251         va_list ap;
2252         va_start(ap, format);
2253         my_vstprintf_s(message, 1024, format, ap); // Security for MSVC:C6386.
2254 //#if defined(_USE_QT)
2255 //      memset(mes_buf, 0x00, sizeof(mes_buf));
2256 //      my_vstprintf_s(mes_buf, 1024, format, ap); // Security for MSVC:C6386.
2257 //      csp_logger->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_EMU, "%s", mes_buf);
2258 //#endif
2259         va_end(ap);
2260         message_count = 4; // 4sec
2261 }
2262
2263 // ----------------------------------------------------------------------------
2264 // misc
2265 // ----------------------------------------------------------------------------
2266
2267
2268 void EMU::sleep(uint32_t ms)
2269 {
2270         osd->sleep(ms);
2271 }
2272
2273
2274 // ----------------------------------------------------------------------------
2275 // user interface
2276 // ----------------------------------------------------------------------------
2277
2278 static uint8_t hex2uint8(char *value)
2279 {
2280         char tmp[3];
2281         memset(tmp, 0, sizeof(tmp));
2282         memcpy(tmp, value, 2);
2283         return (uint8_t)strtoul(tmp, NULL, 16);
2284 }
2285
2286 static uint16_t hex2uint16(char *value)
2287 {
2288         char tmp[5];
2289         memset(tmp, 0, sizeof(tmp));
2290         memcpy(tmp, value, 4);
2291         return (uint16_t)strtoul(tmp, NULL, 16);
2292 }
2293
2294 static bool hex2bin(const _TCHAR* file_path, const _TCHAR* dest_path)
2295 {
2296         bool result = false;
2297         FILEIO *fio_s = new FILEIO();
2298         if(fio_s->Fopen(file_path, FILEIO_READ_BINARY)) {
2299                 int length = 0;
2300                 char line[1024];
2301                 uint8_t buffer[0x10000];
2302                 memset(buffer, 0xff, sizeof(buffer));
2303                 while(fio_s->Fgets(line, sizeof(line)) != NULL) {
2304                         if(line[0] != ':') continue;
2305                         int bytes = hex2uint8(line + 1);
2306                         int offset = hex2uint16(line + 3);
2307                         uint8_t record_type = hex2uint8(line + 7);
2308                         if(record_type == 0x01) break;
2309                         if(record_type != 0x00) continue;
2310                         for(int i = 0; i < bytes; i++) {
2311                                 if((offset + i) < (int)sizeof(buffer)) {
2312                                         if(length < (offset + i)) {
2313                                                 length = offset + i;
2314                                         }
2315                                         buffer[offset + i] = hex2uint8(line + 9 + 2 * i);
2316                                 }
2317                         }
2318                 }
2319                 if(length > 0) {
2320                         FILEIO *fio_d = new FILEIO();
2321                         if(fio_d->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
2322                                 fio_d->Fwrite(buffer, length, 1);
2323                                 fio_d->Fclose();
2324                                 result = true;
2325                         }
2326                         delete fio_d;
2327                 }
2328                 fio_s->Fclose();
2329         }
2330         delete fio_s;
2331         return result;
2332 }
2333
2334 void EMU::initialize_media()
2335 {
2336 #ifdef USE_CART
2337         memset(&cart_status, 0, sizeof(cart_status));
2338 #endif
2339 #ifdef USE_FLOPPY_DISK
2340         memset(floppy_disk_status, 0, sizeof(floppy_disk_status));
2341 #endif
2342 #ifdef USE_QUICK_DISK
2343         memset(&quick_disk_status, 0, sizeof(quick_disk_status));
2344 #endif
2345 #ifdef USE_HARD_DISK
2346         memset(&hard_disk_status, 0, sizeof(hard_disk_status));
2347 #endif
2348 #ifdef USE_TAPE
2349         memset(&tape_status, 0, sizeof(tape_status));
2350 #endif
2351 #ifdef USE_COMPACT_DISC
2352         memset(&compact_disc_status, 0, sizeof(compact_disc_status));
2353 #endif
2354 #ifdef USE_LASER_DISC
2355         memset(&laser_disc_status, 0, sizeof(laser_disc_status));
2356 #endif
2357 #ifdef USE_BUBBLE
2358         memset(&bubble_casette_status, 0, sizeof(bubble_casette_status));
2359 #endif
2360 }
2361
2362 #if defined(_USE_QT)
2363 extern void DLL_PREFIX_I Convert_CP932_to_UTF8(char *dst, char *src, int n_limit, int i_limit);
2364 #endif
2365
2366 void EMU::update_media()
2367 {
2368 #ifdef USE_FLOPPY_DISK
2369         for(int drv = 0; drv < USE_FLOPPY_DISK; drv++) {
2370                 if(floppy_disk_status[drv].wait_count != 0 && --floppy_disk_status[drv].wait_count == 0) {
2371                         vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK);
2372 #if USE_FLOPPY_DISK > 1
2373                         out_message(_T("FD%d: %s"), drv + BASE_FLOPPY_DISK_NUM, floppy_disk_status[drv].path);
2374 #else
2375                         out_message(_T("FD: %s"), floppy_disk_status[drv].path);
2376 #endif
2377                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2378                         mess |= ((is_floppy_disk_protected(drv)) ? EMU_MESSAGE_TYPE::WRITE_PROTECT : 0);
2379                         osdcall_string(EMU_MEDIA_TYPE::FLOPPY_DISK | (floppy_disk_status[drv].bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK),
2380                                                    drv,
2381                                                    mess,
2382                                                    floppy_disk_status[drv].path);
2383                 }
2384         }
2385 #endif
2386 #ifdef USE_QUICK_DISK
2387         for(int drv = 0; drv < USE_QUICK_DISK; drv++) {
2388                 if(quick_disk_status[drv].wait_count != 0 && --quick_disk_status[drv].wait_count == 0) {
2389                         vm->open_quick_disk(drv, quick_disk_status[drv].path);
2390 #if USE_QUICK_DISK > 1
2391                         out_message(_T("QD%d: %s"), drv + BASE_QUICK_DISK_NUM, quick_disk_status[drv].path);
2392 #else
2393                         out_message(_T("QD: %s"), quick_disk_status[drv].path);
2394 #endif
2395                         // ToDo: Write Protect
2396                         osdcall_string(EMU_MEDIA_TYPE::QUICK_DISK,
2397                                                    drv,
2398                                                    EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2399                                                    (_TCHAR *)quick_disk_status[drv].path);
2400                 }
2401         }
2402 #endif
2403 #ifdef USE_HARD_DISK
2404         for(int drv = 0; drv < USE_HARD_DISK; drv++) {
2405                 if(hard_disk_status[drv].wait_count != 0 && --hard_disk_status[drv].wait_count == 0) {
2406                         vm->open_hard_disk(drv, hard_disk_status[drv].path);
2407 #if USE_HARD_DISK > 1
2408                         out_message(_T("HD%d: %s"), drv + BASE_HARD_DISK_NUM, hard_disk_status[drv].path);
2409 #else
2410                         out_message(_T("HD: %s"), hard_disk_status[drv].path);
2411 #endif
2412                         osdcall_string(EMU_MEDIA_TYPE::HARD_DISK,
2413                                                    drv,
2414                                                    EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2415                                                    (_TCHAR *)hard_disk_status[drv].path);
2416                 }
2417         }
2418 #endif
2419 #ifdef USE_TAPE
2420         for(int drv = 0; drv < USE_TAPE; drv++) {
2421                 if(tape_status[drv].wait_count != 0 && --tape_status[drv].wait_count == 0) {
2422                         if(tape_status[drv].play) {
2423                                 vm->play_tape(drv, tape_status[drv].path);
2424                         } else {
2425                                 vm->rec_tape(drv, tape_status[drv].path);
2426                         }
2427 #if USE_TAPE > 1
2428                         out_message(_T("CMT%d: %s"), drv + BASE_TAPE_NUM, tape_status[drv].path);
2429 #else
2430                         out_message(_T("CMT: %s"), tape_status[drv].path);
2431 #endif
2432                         // ToDo: Write protect.
2433                         EMU_MESSAGE_TYPE::type_t mess;
2434                         mess =  (tape_status[drv].play) ? EMU_MESSAGE_TYPE::PLAY : EMU_MESSAGE_TYPE::RECORD;
2435                         mess |= EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2436                         osdcall_string(EMU_MEDIA_TYPE::TAPE,
2437                                                    drv,
2438                                                    mess,
2439                                                    (_TCHAR *)tape_status[drv].path);
2440                 }
2441         }
2442 #endif
2443 #ifdef USE_COMPACT_DISC
2444         for(int drv = 0; drv < USE_COMPACT_DISC; drv++) {
2445                 if(compact_disc_status[drv].wait_count != 0 && --compact_disc_status[drv].wait_count == 0) {
2446                         vm->open_compact_disc(drv, compact_disc_status[drv].path);
2447                         //printf(_T("update_media(): LOAD CDROM: %s\n"), compact_disc_status[drv].path);
2448 #if USE_COMPACT_DISC > 1
2449                         out_message(_T("CD%d: %s"), drv + BASE_COMPACT_DISC_NUM, compact_disc_status[drv].path);
2450 #else
2451                         out_message(_T("CD: %s"), compact_disc_status[drv].path);
2452 #endif
2453                         osdcall_string(EMU_MEDIA_TYPE::COMPACT_DISC,
2454                                                    drv,
2455                                                    EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2456                                                    (_TCHAR *)compact_disc_status[drv].path);
2457                 }
2458         }
2459 #endif
2460 #ifdef USE_LASER_DISC
2461         for(int drv = 0; drv < USE_LASER_DISC; drv++) {
2462                 if(laser_disc_status[drv].wait_count != 0 && --laser_disc_status[drv].wait_count == 0) {
2463                         vm->open_laser_disc(drv, laser_disc_status[drv].path);
2464 #if USE_LASER_DISC > 1
2465                         out_message(_T("LD%d: %s"), drv + BASE_LASER_DISC_NUM, laser_disc_status[drv].path);
2466 #else
2467                         out_message(_T("LD: %s"), laser_disc_status[drv].path);
2468 #endif
2469                         osdcall_string(EMU_MEDIA_TYPE::LASER_DISC,
2470                                                    drv,
2471                                                    EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2472                                                    (_TCHAR *)laser_disc_status[drv].path);
2473                 }
2474         }
2475 #endif
2476 #ifdef USE_BUBBLE
2477         for(int drv = 0; drv < USE_BUBBLE; drv++) {
2478                 if(bubble_casette_status[drv].wait_count != 0 && --bubble_casette_status[drv].wait_count == 0) {
2479                         vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK);
2480 #if USE_BUBBLE > 1
2481                         out_message(_T("Bubble%d: %s"), drv + BASE_BUBBLE_NUM, bubble_casette_status[drv].path);
2482 #else
2483                         out_message(_T("Bubble: %s"), bubble_casette_status[drv].path);
2484 #endif
2485                         // ToDo: Write protect.
2486                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2487                         mess |= ((is_bubble_casette_protected(drv)) ? EMU_MESSAGE_TYPE::WRITE_PROTECT : 0);
2488
2489                         osdcall_string(EMU_MEDIA_TYPE::BUBBLE_CASETTE | (bubble_casette_status[drv].bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK),
2490                                                    drv,
2491                                                    mess,
2492                                                    (_TCHAR *)bubble_casette_status[drv].path);
2493                 }
2494         }
2495 #endif
2496 }
2497
2498 void EMU::restore_media()
2499 {
2500 #ifdef USE_CART
2501         for(int drv = 0; drv < USE_CART; drv++) {
2502                 if(cart_status[drv].path[0] != _T('\0')) {
2503                         if(check_file_extension(cart_status[drv].path, _T(".hex")) && hex2bin(cart_status[drv].path, create_local_path(_T("hex2bin.$$$")))) {
2504                                 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
2505                                 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
2506                         } else {
2507                                 vm->open_cart(drv, cart_status[drv].path);
2508                         }
2509                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2510                         // ToDo: write protect
2511                         osdcall_string(EMU_MEDIA_TYPE::CARTRIDGE,
2512                                                    drv,
2513                                                    mess,
2514                                                    cart_status[drv].path);
2515
2516                 }
2517         }
2518 #endif
2519 #ifdef USE_FLOPPY_DISK
2520         for(int drv = 0; drv < USE_FLOPPY_DISK; drv++) {
2521                 if(floppy_disk_status[drv].path[0] != _T('\0')) {
2522                         vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK);
2523                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2524                         mess |= ((is_floppy_disk_protected(drv)) ? EMU_MESSAGE_TYPE::WRITE_PROTECT : 0);
2525                         osdcall_string(EMU_MEDIA_TYPE::FLOPPY_DISK | (floppy_disk_status[drv].bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK),
2526                                                    drv,
2527                                                    mess,
2528                                                    floppy_disk_status[drv].path);
2529                 }
2530         }
2531 #endif
2532 #ifdef USE_QUICK_DISK
2533         for(int drv = 0; drv < USE_QUICK_DISK; drv++) {
2534                 if(quick_disk_status[drv].path[0] != _T('\0')) {
2535                         vm->open_quick_disk(drv, quick_disk_status[drv].path);
2536
2537                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2538                         // ToDo: write protect
2539                         osdcall_string(EMU_MEDIA_TYPE::QUICK_DISK,
2540                                                    drv,
2541                                                    mess,
2542                                                    quick_disk_status[drv].path);
2543                 }
2544         }
2545 #endif
2546 #ifdef USE_HARD_DISK
2547         for(int drv = 0; drv < USE_HARD_DISK; drv++) {
2548                 if(hard_disk_status[drv].path[0] != _T('\0')) {
2549                         vm->open_hard_disk(drv, hard_disk_status[drv].path);
2550                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2551                         osdcall_string(EMU_MEDIA_TYPE::HARD_DISK,
2552                                                    drv,
2553                                                    mess,
2554                                                    quick_disk_status[drv].path);
2555                 }
2556         }
2557 #endif
2558 #ifdef USE_TAPE
2559         for(int drv = 0; drv < USE_TAPE; drv++) {
2560                 if(tape_status[drv].path[0] != _T('\0')) {
2561                         if(tape_status[drv].play) {
2562                                 vm->play_tape(drv, tape_status[drv].path);
2563                                 EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2564                                 osdcall_string(EMU_MEDIA_TYPE::TAPE,
2565                                                            drv,
2566                                                            mess,
2567                                                            tape_status[drv].path);
2568                         } else {
2569                                 tape_status[drv].path[0] = _T('\0');
2570                         }
2571                 }
2572         }
2573 #endif
2574 #ifdef USE_COMPACT_DISC
2575         for(int drv = 0; drv < USE_COMPACT_DISC; drv++) {
2576                 if(compact_disc_status[drv].path[0] != _T('\0')) {
2577                         vm->open_compact_disc(drv, compact_disc_status[drv].path);
2578                         //printf(_T("restore_media(): LOAD CDROM: %s\n"), compact_disc_status[drv].path);
2579                         osdcall_string(EMU_MEDIA_TYPE::COMPACT_DISC,
2580                                                    drv,
2581                                                    EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2582                                                    (_TCHAR*)compact_disc_status[drv].path);
2583                 }
2584         }
2585 #endif
2586 #ifdef USE_LASER_DISC
2587         for(int drv = 0; drv < USE_LASER_DISC; drv++) {
2588                 if(laser_disc_status[drv].path[0] != _T('\0')) {
2589                         vm->open_laser_disc(drv, laser_disc_status[drv].path);
2590                         osdcall_string(EMU_MEDIA_TYPE::LASER_DISC,
2591                                                    drv,
2592                                                    EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2593                                                    laser_disc_status[drv].path);
2594                 }
2595         }
2596 #endif
2597 #ifdef USE_BUBBLE
2598         for(int drv = 0; drv < USE_BUBBLE; drv++) {
2599                 if(bubble_casette_status[drv].path[0] != _T('\0')) {
2600                         vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
2601                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2602                         mess |= ((is_bubble_casette_protected(drv)) ? EMU_MESSAGE_TYPE::WRITE_PROTECT : 0);
2603
2604                         osdcall_string(EMU_MEDIA_TYPE::BUBBLE_CASETTE | (bubble_casette_status[drv].bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK),
2605                                                    drv,
2606                                                    mess,
2607                                                    (_TCHAR *)bubble_casette_status[drv].path);
2608                 }
2609         }
2610 #endif
2611 }
2612
2613 #ifdef USE_CART
2614 void EMU::open_cart(int drv, const _TCHAR* file_path)
2615 {
2616         if(drv < USE_CART) {
2617                 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
2618                         vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
2619                         FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
2620                 } else {
2621                         vm->open_cart(drv, file_path);
2622                 }
2623                 my_tcscpy_s(cart_status[drv].path, _MAX_PATH, file_path);
2624                 out_message(_T("Cart%d: %s"), drv + 1, file_path);
2625                 osdcall_string(EMU_MEDIA_TYPE::CARTRIDGE,
2626                                            drv,
2627                                            EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2628                                            (_TCHAR *)file_path);
2629 #if !defined(_USE_QT)
2630                 // restart recording
2631                 bool s = osd->now_record_sound;
2632                 bool v = osd->now_record_video;
2633                 stop_record_sound();
2634                 stop_record_video();
2635
2636                 if(s) osd->start_record_sound();
2637                 if(v) osd->start_record_video(-1);
2638 #endif
2639         }
2640 }
2641
2642 void EMU::close_cart(int drv)
2643 {
2644         if(drv < USE_CART) {
2645                 vm->close_cart(drv);
2646                 clear_media_status(&cart_status[drv]);
2647 #if USE_CART > 1
2648                 out_message(_T("Cart%d: Ejected"), drv + BASE_CART_NUM);
2649 #else
2650                 out_message(_T("Cart: Ejected"));
2651 #endif
2652                 osdcall_int(EMU_MEDIA_TYPE::CARTRIDGE,
2653                                         drv,
2654                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
2655                                         0);
2656 #if !defined(_USE_QT)
2657                 // stop recording
2658                 stop_record_video();
2659                 stop_record_sound();
2660 #endif
2661         }
2662 }
2663
2664 bool EMU::is_cart_inserted(int drv)
2665 {
2666         if(drv < USE_CART) {
2667                 return vm->is_cart_inserted(drv);
2668         } else {
2669                 return false;
2670         }
2671 }
2672 #endif
2673
2674 #ifdef USE_FLOPPY_DISK
2675 bool EMU::create_blank_floppy_disk(const _TCHAR* file_path, uint8_t type)
2676 {
2677         /*
2678                 type: 0x00 = 2D, 0x10 = 2DD, 0x20 = 2HD
2679         */
2680         struct {
2681                 char title[17];
2682                 uint8_t rsrv[9];
2683                 uint8_t protect;
2684                 uint8_t type;
2685                 uint32_t size;
2686                 uint32_t trkptr[164];
2687         } d88_hdr;
2688
2689         memset(&d88_hdr, 0, sizeof(d88_hdr));
2690         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "BLANK");
2691         d88_hdr.type = type;
2692         d88_hdr.size = sizeof(d88_hdr);
2693
2694         FILEIO *fio = new FILEIO();
2695         if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
2696                 fio->Fwrite(&d88_hdr, sizeof(d88_hdr), 1);
2697                 fio->Fclose();
2698         }
2699         delete fio;
2700         return true;
2701 }
2702
2703 void EMU::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
2704 {
2705         if(drv < USE_FLOPPY_DISK) {
2706                 d88_file[drv].bank_num = 0;
2707                 d88_file[drv].cur_bank = -1;
2708                 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
2709                         FILEIO *fio = new FILEIO();
2710                         if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
2711                                 try {
2712                                         fio->Fseek(0, FILEIO_SEEK_END);
2713                                         uint32_t file_size = fio->Ftell(), file_offset = 0;
2714                                         while(file_offset + 0x2b0 <= file_size && d88_file[drv].bank_num < MAX_D88_BANKS) {
2715                                                 fio->Fseek(file_offset, FILEIO_SEEK_SET);
2716 #ifdef _UNICODE
2717                                                 char tmp[18];
2718                                                 fio->Fread(tmp, 17, 1);
2719                                                 tmp[17] = 0;
2720         #if defined(_USE_QT)
2721                                                 memset(d88_file[drv].disk_name[d88_file[drv].bank_num], 0x00, 128);
2722                                                 if(strlen(tmp) > 0) {
2723                                                         Convert_CP932_to_UTF8(d88_file[drv].disk_name[d88_file[drv].bank_num], tmp, 127, 17);
2724                                                 }
2725         #else /* not _USE_QT */
2726                                                 MultiByteToWideChar(CP_ACP, 0, tmp, -1, d88_file[drv].disk_name[d88_file[drv].bank_num], 18);
2727         #endif
2728 #else
2729                                                 fio->Fread(d88_file[drv].disk_name[d88_file[drv].bank_num], 17, 1);
2730                                                 d88_file[drv].disk_name[d88_file[drv].bank_num][17] = 0;
2731 #endif
2732                                                 fio->Fseek(file_offset + 0x1c, FILEIO_SEEK_SET);
2733                                                 file_offset += fio->FgetUint32_LE();
2734                                                 d88_file[drv].bank_num++;
2735                                         }
2736                                         my_tcscpy_s(d88_file[drv].path, _MAX_PATH, file_path);
2737                                         d88_file[drv].cur_bank = bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK;
2738                                 } catch(...) {
2739                                         d88_file[drv].bank_num = 0;
2740                                 }
2741                                 fio->Fclose();
2742                         }
2743                         delete fio;
2744                 }
2745
2746                 if(vm->is_floppy_disk_inserted(drv)) {
2747                         vm->close_floppy_disk(drv);
2748                         // wait 0.5sec
2749                         floppy_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
2750 #if USE_FLOPPY_DISK > 1
2751                         out_message(_T("FD%d: Ejected"), drv + BASE_FLOPPY_DISK_NUM);
2752 #else
2753                         out_message(_T("FD: Ejected"));
2754 #endif
2755                         osdcall_int(EMU_MEDIA_TYPE::FLOPPY_DISK,
2756                                                 drv,
2757                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
2758                                                 0);
2759         } else if(floppy_disk_status[drv].wait_count == 0) {
2760                         vm->open_floppy_disk(drv, file_path, bank & EMU_MEDIA_TYPE::EMU_SLOT_MASK);
2761 #if USE_FLOPPY_DISK > 1
2762                         out_message(_T("FD%d: %s"), drv + BASE_FLOPPY_DISK_NUM, file_path);
2763 #else
2764                         out_message(_T("FD: %s"), file_path);
2765 #endif
2766                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
2767                         mess |= ((is_floppy_disk_protected(drv)) ? EMU_MESSAGE_TYPE::WRITE_PROTECT : 0);
2768                         osdcall_string(EMU_MEDIA_TYPE::FLOPPY_DISK | (bank & EMU_MEDIA_TYPE::MULTIPLE_SLOT_MASK),
2769                                                    drv,
2770                                                    mess,
2771                                                    (_TCHAR *)file_path);
2772                 }
2773                 my_tcscpy_s(floppy_disk_status[drv].path, _MAX_PATH, file_path);
2774                 floppy_disk_status[drv].bank = bank;
2775         }
2776 }
2777
2778
2779 void EMU::close_floppy_disk(int drv)
2780 {
2781         if(drv < USE_FLOPPY_DISK) {
2782                 d88_file[drv].bank_num = 0;
2783                 d88_file[drv].cur_bank = -1;
2784
2785                 vm->close_floppy_disk(drv);
2786                 clear_media_status(&floppy_disk_status[drv]);
2787 #if USE_FLOPPY_DISK > 1
2788                 out_message(_T("FD%d: Ejected"), drv + BASE_FLOPPY_DISK_NUM);
2789 #else
2790                 out_message(_T("FD: Ejected"));
2791 #endif
2792                 osdcall_int(EMU_MEDIA_TYPE::FLOPPY_DISK,
2793                                         drv,
2794                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
2795                                         0);
2796         }
2797 }
2798
2799 bool EMU::is_floppy_disk_connected(int drv)
2800 {
2801         if(drv < USE_FLOPPY_DISK) {
2802                 return vm->is_floppy_disk_connected(drv);
2803         } else {
2804                 return false;
2805         }
2806 }
2807
2808 bool EMU::is_floppy_disk_inserted(int drv)
2809 {
2810         if(drv < USE_FLOPPY_DISK) {
2811                 return vm->is_floppy_disk_inserted(drv);
2812         } else {
2813                 return false;
2814         }
2815 }
2816
2817 void EMU::is_floppy_disk_protected(int drv, bool value)
2818 {
2819         if(drv < USE_FLOPPY_DISK) {
2820                 vm->is_floppy_disk_protected(drv, value);
2821         }
2822         EMU_MESSAGE_TYPE::type_t mess =
2823                 (value) ?
2824                 (EMU_MESSAGE_TYPE::WRITE_PROTECT | EMU_MESSAGE_TYPE::MEDIA_OTHERS)
2825                 : EMU_MESSAGE_TYPE::MEDIA_OTHERS;
2826         osdcall_int(EMU_MEDIA_TYPE::FLOPPY_DISK,
2827                                 drv,
2828                                 mess,
2829                                 0);
2830 }
2831
2832 bool EMU::is_floppy_disk_protected(int drv)
2833 {
2834         if(drv < USE_FLOPPY_DISK) {
2835                 return vm->is_floppy_disk_protected(drv);
2836         } else {
2837                 return false;
2838         }
2839 }
2840
2841 uint32_t EMU::is_floppy_disk_accessed()
2842 {
2843         return vm->is_floppy_disk_accessed();
2844 }
2845
2846 uint32_t EMU::floppy_disk_indicator_color()
2847 {
2848         return vm->floppy_disk_indicator_color();
2849 }
2850
2851 #endif
2852
2853 #ifdef USE_QUICK_DISK
2854 void EMU::open_quick_disk(int drv, const _TCHAR* file_path)
2855 {
2856         if(drv < USE_QUICK_DISK) {
2857                 if(vm->is_quick_disk_inserted(drv)) {
2858                         vm->close_quick_disk(drv);
2859                         // wait 0.5sec
2860                         quick_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
2861 #if USE_QUICK_DISK > 1
2862                         out_message(_T("QD%d: Ejected"), drv + BASE_QUICK_DISK_NUM);
2863 #else
2864                         out_message(_T("QD: Ejected"));
2865 #endif
2866                         osdcall_int(EMU_MEDIA_TYPE::QUICK_DISK,
2867                                                 drv,
2868                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
2869                                                 0);
2870                 } else if(quick_disk_status[drv].wait_count == 0) {
2871                         vm->open_quick_disk(drv, file_path);
2872 #if USE_QUICK_DISK > 1
2873                         out_message(_T("QD%d: %s"), drv + BASE_QUICK_DISK_NUM, file_path);
2874 #else
2875                         out_message(_T("QD: %s"), file_path);
2876 #endif
2877                         osdcall_string(EMU_MEDIA_TYPE::QUICK_DISK,
2878                                                         drv,
2879                                                         EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
2880                                                         (_TCHAR*)file_path);
2881                 }
2882                 my_tcscpy_s(quick_disk_status[drv].path, _MAX_PATH, file_path);
2883         }
2884 }
2885
2886 void EMU::close_quick_disk(int drv)
2887 {
2888         if(drv < USE_QUICK_DISK) {
2889                 vm->close_quick_disk(drv);
2890                 clear_media_status(&quick_disk_status[drv]);
2891 #if USE_QUICK_DISK > 1
2892                 out_message(_T("QD%d: Ejected"), drv + BASE_QUICK_DISK_NUM);
2893 #else
2894                 out_message(_T("QD: Ejected"));
2895 #endif
2896                 osdcall_int(EMU_MEDIA_TYPE::QUICK_DISK,
2897                                         drv,
2898                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
2899                                         0);
2900         }
2901 }
2902
2903 bool EMU::is_quick_disk_inserted(int drv)
2904 {
2905         if(drv < USE_QUICK_DISK) {
2906                 return vm->is_quick_disk_inserted(drv);
2907         } else {
2908                 return false;
2909         }
2910 }
2911
2912 bool EMU::is_quick_disk_connected(int drv)
2913 {
2914         if(drv < USE_QUICK_DISK) {
2915                 return vm->is_quick_disk_connected(drv);
2916         } else {
2917                 return false;
2918         }
2919 }
2920
2921 uint32_t EMU::is_quick_disk_accessed()
2922 {
2923         return vm->is_quick_disk_accessed();
2924 }
2925 #endif
2926
2927 #ifdef USE_HARD_DISK
2928 bool EMU::create_blank_hard_disk(const _TCHAR* file_path, int sector_size, int sectors, int surfaces, int cylinders)
2929 {
2930         if(check_file_extension(file_path, _T(".nhd"))) {
2931                 // T98-Next
2932                 const char sig_nhd[] = "T98HDDIMAGE.R0";
2933                 typedef struct nhd_header_s {
2934                         char sig[16];
2935                         char comment[256];
2936                         int32_t header_size;    // +272
2937                         int32_t cylinders;      // +276
2938                         int16_t surfaces;       // +280
2939                         int16_t sectors;        // +282
2940                         int16_t sector_size;    // +284
2941                         uint8_t reserved[0xe2];
2942                 } nhd_header_t;
2943                 nhd_header_t header;
2944
2945                 memset(&header, 0, sizeof(header));
2946                 strcpy(header.sig, "T98HDDIMAGE.R0");
2947                 header.header_size = sizeof(header);
2948                 header.cylinders = cylinders;
2949                 header.surfaces = surfaces;
2950                 header.sectors = sectors;
2951                 header.sector_size = sector_size;
2952
2953                 FILEIO *fio = new FILEIO();
2954                 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
2955                         fio->Fwrite(&header, sizeof(header), 1);
2956                         void *empty = calloc(sector_size, 1);
2957 #if 0
2958                         fio->Fwrite(empty, sector_size, sectors * surfaces * cylinders);
2959 #else
2960                         for(int i = 0; i < sectors * surfaces * cylinders; i++) {
2961                                 fio->Fwrite(empty, sector_size, 1);
2962                         }
2963 #endif
2964                         free(empty);
2965                         fio->Fclose();
2966                 }
2967                 delete fio;
2968                 return true;
2969         } else if(check_file_extension(file_path, _T(".hdi"))) {
2970                 // ANEX86
2971                 typedef struct hdi_header_s {
2972                         int32_t dummy;          // + 0
2973                         int32_t hdd_type;       // + 4
2974                         int32_t header_size;    // + 8
2975                         int32_t hdd_size;       // +12
2976                         int32_t sector_size;    // +16
2977                         int32_t sectors;        // +20
2978                         int32_t surfaces;       // +24
2979                         int32_t cylinders;      // +28
2980                         uint8_t padding[0x1000 - sizeof(int32_t) * 8];
2981                 } hdi_header_t;
2982                 hdi_header_t header;
2983
2984                 memset(&header, 0, sizeof(header));
2985                 header.hdd_type = 0; // ???
2986                 header.header_size = sizeof(header);
2987                 header.hdd_size = sector_size * sectors * surfaces * cylinders;
2988                 header.sector_size = sector_size;
2989                 header.sectors = sectors;
2990                 header.surfaces = surfaces;
2991                 header.cylinders = cylinders;
2992
2993                 FILEIO *fio = new FILEIO();
2994                 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
2995                         fio->Fwrite(&header, sizeof(header), 1);
2996                         void *empty = calloc(sector_size, 1);
2997 #if 0
2998                         fio->Fwrite(empty, sector_size, sectors * surfaces * cylinders);
2999 #else
3000                         for(int i = 0; i < sectors * surfaces * cylinders; i++) {
3001                                 fio->Fwrite(empty, sector_size, 1);
3002                         }
3003 #endif
3004                         free(empty);
3005                         fio->Fclose();
3006                 }
3007                 delete fio;
3008                 return true;
3009         }
3010         // unknown extension
3011         return false;
3012 }
3013
3014 void EMU::open_hard_disk(int drv, const _TCHAR* file_path)
3015 {
3016         if(drv < USE_HARD_DISK) {
3017                 if(vm->is_hard_disk_inserted(drv)) {
3018                         vm->close_hard_disk(drv);
3019                         // wait 0.5sec
3020                         hard_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3021 #if USE_HARD_DISK > 1
3022                         out_message(_T("HD%d: Unmounted"), drv + BASE_HARD_DISK_NUM);
3023 #else
3024                         out_message(_T("HD: Unmounted"));
3025 #endif
3026                         osdcall_int(EMU_MEDIA_TYPE::HARD_DISK,
3027                                                         drv,
3028                                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3029                                                         0);
3030                 } else if(hard_disk_status[drv].wait_count == 0) {
3031                         vm->open_hard_disk(drv, file_path);
3032 #if USE_HARD_DISK > 1
3033                         out_message(_T("HD%d: %s"), drv + BASE_HARD_DISK_NUM, file_path);
3034 #else
3035                         out_message(_T("HD: %s"), file_path);
3036 #endif
3037                         osdcall_string(EMU_MEDIA_TYPE::HARD_DISK,
3038                                                         drv,
3039                                                         EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
3040                                                         (_TCHAR*)file_path);
3041                 }
3042                 my_tcscpy_s(hard_disk_status[drv].path, _MAX_PATH, file_path);
3043                 my_tcscpy_s(config.last_hard_disk_path[drv], _MAX_PATH, file_path);
3044         }
3045 }
3046
3047 void EMU::close_hard_disk(int drv)
3048 {
3049         if(drv < USE_HARD_DISK) {
3050                 vm->close_hard_disk(drv);
3051                 clear_media_status(&hard_disk_status[drv]);
3052 #if USE_HARD_DISK > 1
3053                 out_message(_T("HD%d: Unmounted"), drv + BASE_HARD_DISK_NUM);
3054 #else
3055                 out_message(_T("HD: Unmounted"));
3056 #endif
3057                 osdcall_int(EMU_MEDIA_TYPE::HARD_DISK,
3058                                                 drv,
3059                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3060                                                 0);
3061                 config.last_hard_disk_path[drv][0] = '\0';
3062         }
3063 }
3064
3065 bool EMU::is_hard_disk_inserted(int drv)
3066 {
3067         if(drv < USE_HARD_DISK) {
3068                 return vm->is_hard_disk_inserted(drv);
3069         } else {
3070                 return false;
3071         }
3072 }
3073
3074 uint32_t EMU::is_hard_disk_accessed()
3075 {
3076         return vm->is_hard_disk_accessed();
3077 }
3078
3079 #endif
3080
3081 #ifdef USE_TAPE
3082 void EMU::play_tape(int drv, const _TCHAR* file_path)
3083 {
3084         if(drv < USE_TAPE) {
3085                 if(vm->is_tape_inserted(drv)) {
3086                         vm->close_tape(drv);
3087                         // wait 0.5sec
3088                         tape_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3089 #if USE_TAPE > 1
3090                         out_message(_T("CMT%d: Ejected"), drv + BASE_TAPE_NUM);
3091 #else
3092                         out_message(_T("CMT: Ejected"));
3093 #endif
3094                         osdcall_int(EMU_MEDIA_TYPE::TAPE,
3095                                                 drv,
3096                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3097                                                 0);
3098                 } else if(tape_status[drv].wait_count == 0) {
3099                         vm->play_tape(drv, file_path);
3100 #if USE_TAPE > 1
3101                         out_message(_T("CMT%d: %s"), drv + BASE_TAPE_NUM, file_path);
3102 #else
3103                         out_message(_T("CMT: %s"), file_path);
3104 #endif
3105                         osdcall_string(EMU_MEDIA_TYPE::TAPE,
3106                                                         drv,
3107                                                         EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
3108                                                         (_TCHAR*)file_path);
3109                 }
3110                 my_tcscpy_s(tape_status[drv].path, _MAX_PATH, file_path);
3111                 tape_status[drv].play = true;
3112         }
3113 }
3114
3115 void EMU::rec_tape(int drv, const _TCHAR* file_path)
3116 {
3117         if(drv < USE_TAPE) {
3118                 if(vm->is_tape_inserted(drv)) {
3119                         vm->close_tape(drv);
3120                         // wait 0.5sec
3121                         tape_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3122 #if USE_TAPE > 1
3123                         out_message(_T("CMT%d: Ejected"), drv + BASE_TAPE_NUM);
3124 #else
3125                         out_message(_T("CMT: Ejected"));
3126 #endif
3127                         osdcall_int(EMU_MEDIA_TYPE::TAPE,
3128                                                 drv,
3129                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3130                                                 0);
3131                 } else if(tape_status[drv].wait_count == 0) {
3132                         vm->rec_tape(drv, file_path);
3133 #if USE_TAPE > 1
3134                         out_message(_T("CMT%d: %s"), drv + BASE_TAPE_NUM, file_path);
3135 #else
3136                         out_message(_T("CMT: %s"), file_path);
3137 #endif
3138                         osdcall_string(EMU_MEDIA_TYPE::TAPE,
3139                                                         drv,
3140                                                    EMU_MESSAGE_TYPE::MEDIA_MOUNTED | EMU_MESSAGE_TYPE::RECORD,
3141                                                         (_TCHAR*)file_path);
3142                 }
3143                 my_tcscpy_s(tape_status[drv].path, _MAX_PATH, file_path);
3144                 tape_status[drv].play = false;
3145         }
3146 }
3147
3148 void EMU::close_tape(int drv)
3149 {
3150         if(drv < USE_TAPE) {
3151                 vm->close_tape(drv);
3152                 clear_media_status(&tape_status[drv]);
3153 #if USE_TAPE > 1
3154                 out_message(_T("CMT%d: Ejected"), drv + BASE_TAPE_NUM);
3155 #else
3156                 out_message(_T("CMT: Ejected"));
3157 #endif
3158                 osdcall_int(EMU_MEDIA_TYPE::TAPE,
3159                                         drv,
3160                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3161                                         0);
3162         }
3163 }
3164
3165 bool EMU::is_tape_inserted(int drv)
3166 {
3167         if(drv < USE_TAPE) {
3168                 return vm->is_tape_inserted(drv);
3169         } else {
3170                 return false;
3171         }
3172 }
3173
3174 bool EMU::is_tape_playing(int drv)
3175 {
3176         if(drv < USE_TAPE) {
3177                 return vm->is_tape_playing(drv);
3178         } else {
3179                 return false;
3180         }
3181 }
3182
3183 bool EMU::is_tape_recording(int drv)
3184 {
3185         if(drv < USE_TAPE) {
3186                 return vm->is_tape_recording(drv);
3187         } else {
3188                 return false;
3189         }
3190 }
3191
3192 int EMU::get_tape_position(int drv)
3193 {
3194         if(drv < USE_TAPE) {
3195                 return vm->get_tape_position(drv);
3196         } else {
3197                 return 0;
3198         }
3199 }
3200
3201 const _TCHAR* EMU::get_tape_message(int drv)
3202 {
3203         if(drv < USE_TAPE) {
3204                 return vm->get_tape_message(drv);
3205         } else {
3206                 return NULL;
3207         }
3208 }
3209
3210 void EMU::push_play(int drv)
3211 {
3212         if(drv < USE_TAPE) {
3213                 vm->push_play(drv);
3214                 osdcall_int(EMU_MEDIA_TYPE::TAPE,
3215                                         drv,
3216                                         EMU_MESSAGE_TYPE::TAPE_PLAY,
3217                                         0);
3218         }
3219 }
3220
3221 void EMU::push_stop(int drv)
3222 {
3223         if(drv < USE_TAPE) {
3224                 vm->push_stop(drv);
3225                 osdcall_int(EMU_MEDIA_TYPE::TAPE,
3226                                         drv,
3227                                         EMU_MESSAGE_TYPE::TAPE_STOP,
3228                                         0);
3229         }
3230 }
3231
3232 void EMU::push_fast_forward(int drv)
3233 {
3234         if(drv < USE_TAPE) {
3235                 vm->push_fast_forward(drv);
3236                 osdcall_int(EMU_MEDIA_TYPE::TAPE,
3237                                         drv,
3238                                         EMU_MESSAGE_TYPE::TAPE_FF,
3239                                         0);
3240         }
3241 }
3242
3243 void EMU::push_fast_rewind(int drv)
3244 {
3245         if(drv < USE_TAPE) {
3246                 vm->push_fast_rewind(drv);
3247                 osdcall_int(EMU_MEDIA_TYPE::TAPE,
3248                                         drv,
3249                                         EMU_MESSAGE_TYPE::TAPE_REW,
3250                                         0);
3251         }
3252 }
3253
3254 void EMU::push_apss_forward(int drv)
3255 {
3256         if(drv < USE_TAPE) {
3257                 vm->push_apss_forward(drv);
3258                 osdcall_int(EMU_MEDIA_TYPE::TAPE,
3259                                         drv,
3260                                         EMU_MESSAGE_TYPE::TAPE_APSS_FF,
3261                                         0);
3262         }
3263 }
3264
3265 void EMU::push_apss_rewind(int drv)
3266 {
3267         if(drv < USE_TAPE) {
3268                 vm->push_apss_rewind(drv);
3269                 osdcall_int(EMU_MEDIA_TYPE::TAPE,
3270                                         drv,
3271                                         EMU_MESSAGE_TYPE::TAPE_APSS_REW,
3272                                         0);
3273         }
3274 }
3275 #endif
3276
3277 #ifdef USE_COMPACT_DISC
3278 void EMU::open_compact_disc(int drv, const _TCHAR* file_path)
3279 {
3280         if(drv < USE_COMPACT_DISC) {
3281                 //printf(_T("open_compact_disc(): CALLED: %s\n"), file_path);
3282                 if(vm->is_compact_disc_inserted(drv)) {
3283                         vm->close_compact_disc(drv);
3284                         // wait 0.5sec
3285                         clear_media_status(&compact_disc_status[drv]);
3286                         compact_disc_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3287 #if USE_COMPACT_DISC > 1
3288                         out_message(_T("CD%d: Ejected"), drv + BASE_COMPACT_DISC_NUM);
3289 #else
3290                         out_message(_T("CD: Ejected"));
3291 #endif
3292                         osdcall_int(EMU_MEDIA_TYPE::COMPACT_DISC,
3293                                                 drv,
3294                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3295                                                 0);
3296                 } else if(compact_disc_status[drv].wait_count == 0) {
3297                         vm->open_compact_disc(drv, file_path);
3298                         //printf(_T("open_compact_disc(): LOAD CDROM: %s\n"), file_path);
3299 #if USE_COMPACT_DISC > 1
3300                         out_message(_T("CD%d: %s"), drv + BASE_COMPACT_DISC_NUM, file_path);
3301 #else
3302                         out_message(_T("CD: %s"), file_path);
3303 #endif
3304                         osdcall_string(EMU_MEDIA_TYPE::COMPACT_DISC,
3305                                                         drv,
3306                                                         EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
3307                                                         (_TCHAR*)file_path);
3308                 }
3309                 my_tcscpy_s(compact_disc_status[drv].path,  _MAX_PATH, file_path);
3310         }
3311 }
3312
3313 void EMU::close_compact_disc(int drv)
3314 {
3315         if(drv < USE_COMPACT_DISC) {
3316                 vm->close_compact_disc(drv);
3317                 clear_media_status(&compact_disc_status[drv]);
3318                 compact_disc_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3319 #if USE_COMPACT_DISC > 1
3320                 out_message(_T("CD%d: Ejected"), drv + BASE_COMPACT_DISC_NUM);
3321 #else
3322                 out_message(_T("CD: Ejected"));
3323 #endif
3324                 osdcall_int(EMU_MEDIA_TYPE::COMPACT_DISC,
3325                                         drv,
3326                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3327                                         0);
3328         }
3329 }
3330
3331 bool EMU::is_compact_disc_inserted(int drv)
3332 {
3333         if(drv < USE_COMPACT_DISC) {
3334                 return vm->is_compact_disc_inserted(drv);
3335         } else {
3336                 return false;
3337         }
3338 }
3339
3340 uint32_t EMU::is_compact_disc_accessed()
3341 {
3342         return vm->is_compact_disc_accessed();
3343 }
3344 #endif
3345
3346 #ifdef USE_LASER_DISC
3347 void EMU::open_laser_disc(int drv, const _TCHAR* file_path)
3348 {
3349         if(drv < USE_LASER_DISC) {
3350                 if(vm->is_laser_disc_inserted(drv)) {
3351                         vm->close_laser_disc(drv);
3352                         // wait 0.5sec
3353                         laser_disc_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3354 #if USE_LASER_DISC > 1
3355                         out_message(_T("LD%d: Ejected"), drv + BASE_LASER_DISC_NUM);
3356 #else
3357                         out_message(_T("LD: Ejected"));
3358 #endif
3359                         osdcall_int(EMU_MEDIA_TYPE::LASER_DISC,
3360                                                 drv,
3361                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3362                                                 0);
3363                 } else if(laser_disc_status[drv].wait_count == 0) {
3364                         vm->open_laser_disc(drv, file_path);
3365 #if USE_LASER_DISC > 1
3366                         out_message(_T("LD%d: %s"), drv + BASE_LASER_DISC_NUM, file_path);
3367 #else
3368                         out_message(_T("LD: %s"), file_path);
3369 #endif
3370                         osdcall_string(EMU_MEDIA_TYPE::LASER_DISC,
3371                                                         drv,
3372                                                         EMU_MESSAGE_TYPE::MEDIA_MOUNTED,
3373                                                         (_TCHAR*)file_path);
3374                 }
3375                 my_tcscpy_s(laser_disc_status[drv].path, _MAX_PATH, file_path);
3376         }
3377 }
3378
3379 void EMU::close_laser_disc(int drv)
3380 {
3381         if(drv < USE_LASER_DISC) {
3382                 vm->close_laser_disc(drv);
3383                 clear_media_status(&laser_disc_status[drv]);
3384 #if USE_LASER_DISC > 1
3385                 out_message(_T("LD%d: Ejected"), drv + BASE_LASER_DISC_NUM);
3386 #else
3387                 out_message(_T("LD: Ejected"));
3388 #endif
3389                 osdcall_int(EMU_MEDIA_TYPE::LASER_DISC,
3390                                         drv,
3391                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3392                                         0);
3393         }
3394 }
3395
3396 bool EMU::is_laser_disc_inserted(int drv)
3397 {
3398         if(drv < USE_LASER_DISC) {
3399                 return vm->is_laser_disc_inserted(drv);
3400         } else {
3401                 return false;
3402         }
3403 }
3404
3405 uint32_t EMU::is_laser_disc_accessed()
3406 {
3407         return vm->is_laser_disc_accessed();
3408 }
3409
3410 #endif
3411
3412 #ifdef USE_BINARY_FILE
3413 void EMU::load_binary(int drv, const _TCHAR* file_path)
3414 {
3415         if(drv < USE_BINARY_FILE) {
3416                 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
3417                         vm->load_binary(drv, create_local_path(_T("hex2bin.$$$")));
3418                         FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
3419                 } else {
3420                         vm->load_binary(drv, file_path);
3421                 }
3422                 osdcall_string(EMU_MEDIA_TYPE::BINARY,
3423                                            drv,
3424                                            EMU_MESSAGE_TYPE::MEDIA_MOUNTED | EMU_MESSAGE_TYPE::LOAD,
3425                                            (_TCHAR*)file_path);
3426 #if USE_BINARY_FILE > 1
3427                 out_message(_T("Load Binary%d: %s"), drv + BASE_BINARY_FILE_NUM, file_path);
3428 #else
3429                 out_message(_T("Load Binary: %s"), file_path);
3430 #endif
3431         }
3432 }
3433
3434 void EMU::save_binary(int drv, const _TCHAR* file_path)
3435 {
3436         if(drv < USE_BINARY_FILE) {
3437                 vm->save_binary(drv, file_path);
3438 #if USE_BINARY_FILE > 1
3439                 out_message(_T("Save Binary%d: %s"), drv + BASE_BINARY_FILE_NUM, file_path);
3440 #else
3441                 out_message(_T("Save Binary: %s"), file_path);
3442 #endif
3443                 osdcall_string(EMU_MEDIA_TYPE::BINARY,
3444                                            drv,
3445                                            EMU_MESSAGE_TYPE::MEDIA_MOUNTED | EMU_MESSAGE_TYPE::SAVE,
3446                                            (_TCHAR*)file_path);
3447         }
3448 }
3449
3450 #endif
3451 #ifdef USE_BUBBLE
3452 void EMU::open_bubble_casette(int drv, const _TCHAR* file_path, int bank)
3453 {
3454         if(drv < USE_BUBBLE) {
3455                 if(vm->is_bubble_casette_inserted(drv)) {
3456                         vm->close_bubble_casette(drv);
3457                         // wait 0.5sec
3458                         bubble_casette_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
3459 #if USE_BUBBLE > 1
3460                         out_message(_T("Bubble%d: Ejected"), drv + BASE_BUBBLE_NUM);
3461 #else
3462                         out_message(_T("Bubble: Ejected"));
3463 #endif
3464                         osdcall_int(EMU_MEDIA_TYPE::BUBBLE_CASETTE,
3465                                                 drv,
3466                                                 EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3467                                                 0);
3468                 } else if(bubble_casette_status[drv].wait_count == 0) {
3469                         vm->open_bubble_casette(drv, file_path, bank);
3470 #if USE_BUBBLE > 1
3471                         out_message(_T("Bubble%d: %s"), drv + BASE_BUBBLE_NUM, file_path);
3472 #else
3473                         out_message(_T("Bubble: %s"), file_path);
3474 #endif
3475                         EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_MOUNTED;
3476                         mess |= ((is_bubble_casette_protected(drv)) ? EMU_MESSAGE_TYPE::WRITE_PROTECT : 0);
3477                         osdcall_string(EMU_MEDIA_TYPE::BUBBLE_CASETTE | (bank & EMU_MEDIA_TYPE::MULTIPLE_SLOT_MASK),
3478                                                         drv,
3479                                                         mess,
3480                                                         (_TCHAR*)file_path);
3481                 }
3482                 my_tcscpy_s(bubble_casette_status[drv].path, _MAX_PATH, file_path);
3483                 bubble_casette_status[drv].bank = bank;
3484         }
3485 }
3486
3487 void EMU::close_bubble_casette(int drv)
3488 {
3489         if(drv < USE_BUBBLE) {
3490                 vm->close_bubble_casette(drv);
3491                 clear_media_status(&bubble_casette_status[drv]);
3492 #if USE_BUBBLE > 1
3493                 out_message(_T("Bubble%d: Ejected"), drv + BASE_BUBBLE_NUM);
3494 #else
3495                 out_message(_T("Bubble: Ejected"));
3496 #endif
3497                 osdcall_int(EMU_MEDIA_TYPE::BUBBLE_CASETTE,
3498                                         drv,
3499                                         EMU_MESSAGE_TYPE::MEDIA_REMOVED,
3500                                         0);
3501         }
3502 }
3503
3504 bool EMU::is_bubble_casette_inserted(int drv)
3505 {
3506         if(drv < USE_BUBBLE) {
3507                 return vm->is_bubble_casette_inserted(drv);
3508         } else {
3509                 return false;
3510         }
3511 }
3512
3513 bool EMU::is_bubble_casette_protected(int drv)
3514 {
3515         if(drv < USE_BUBBLE) {
3516                 return vm->is_bubble_casette_protected(drv);
3517         } else {
3518                 return false;
3519         }
3520 }
3521
3522 void EMU::is_bubble_casette_protected(int drv, bool flag)
3523 {
3524         if(drv < USE_BUBBLE) {
3525                 vm->is_bubble_casette_protected(drv, flag);
3526                 EMU_MESSAGE_TYPE::type_t mess = EMU_MESSAGE_TYPE::MEDIA_OTHERS;
3527                 mess |= ((flag) ? EMU_MESSAGE_TYPE::WRITE_PROTECT : 0);
3528                 osdcall_int(EMU_MEDIA_TYPE::BUBBLE_CASETTE,
3529                                         drv,
3530                                         mess,
3531                                         0);
3532                 return;
3533         } else {
3534                 return;
3535         }
3536 }
3537 #endif
3538
3539 #ifdef USE_LED_DEVICE
3540 uint32_t EMU::get_led_status()
3541 {
3542         return vm->get_led_status();
3543 }
3544 #endif
3545
3546
3547 #ifdef USE_SOUND_VOLUME
3548 void EMU::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
3549 {
3550         vm->set_sound_device_volume(ch, decibel_l, decibel_r);
3551 }
3552 #endif
3553
3554 void EMU::update_config()
3555 {
3556         vm->update_config();
3557 }
3558
3559
3560 // ----------------------------------------------------------------------------
3561 // state
3562 // ----------------------------------------------------------------------------
3563
3564 #ifdef USE_STATE
3565 #define STATE_VERSION   2
3566
3567 void EMU::save_state(const _TCHAR* file_path)
3568 {
3569         FILEIO* fio = new FILEIO();
3570         osd->lock_vm();
3571 #ifdef USE_ZLIB
3572         if(config.compress_state) {
3573                 fio->Gzopen(file_path, FILEIO_WRITE_BINARY);
3574         }
3575 #endif
3576         if(!fio->IsOpened()) {
3577                 fio->Fopen(file_path, FILEIO_WRITE_BINARY);
3578         }
3579         if(fio->IsOpened()) {
3580                 // save state file version
3581                 fio->FputUint32(STATE_VERSION);
3582                 // save config
3583                 process_config_state((void *)fio, false);
3584                 // save inserted medias
3585 #ifdef USE_CART
3586                 fio->Fwrite(&cart_status, sizeof(cart_status), 1);
3587 #endif
3588 #ifdef USE_FLOPPY_DISK
3589                 fio->Fwrite(floppy_disk_status, sizeof(floppy_disk_status), 1);
3590                 fio->Fwrite(d88_file, sizeof(d88_file), 1);
3591 #endif
3592 #ifdef USE_QUICK_DISK
3593                 fio->Fwrite(&quick_disk_status, sizeof(quick_disk_status), 1);
3594 #endif
3595 #ifdef USE_HARD_DISK
3596                 fio->Fwrite(&hard_disk_status, sizeof(hard_disk_status), 1);
3597 #endif
3598 #ifdef USE_TAPE
3599                 fio->Fwrite(&tape_status, sizeof(tape_status), 1);
3600 #endif
3601 #ifdef USE_COMPACT_DISC
3602                 fio->Fwrite(&compact_disc_status, sizeof(compact_disc_status), 1);
3603 #endif
3604 #ifdef USE_LASER_DISC
3605                 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);
3606 #endif
3607 #ifdef USE_BUBBLE
3608                 fio->Fwrite(&bubble_casette_status, sizeof(bubble_casette_status), 1);
3609 #endif
3610                 // save vm state
3611                 vm->process_state(fio, false);
3612                 // end of state file
3613                 fio->FputInt32_LE(-1);
3614                 fio->Fclose();
3615         }
3616         osd->unlock_vm();
3617         delete fio;
3618 }
3619
3620 void EMU::load_state(const _TCHAR* file_path)
3621 {
3622         if(FILEIO::IsFileExisting(file_path)) {
3623 #ifdef USE_AUTO_KEY
3624                 stop_auto_key();
3625                 config.romaji_to_kana = false;
3626 #endif
3627
3628                 save_state(create_local_path(_T("$temp$.sta")));
3629                 if(!load_state_tmp(file_path)) {
3630                         out_debug_log(_T("failed to load state file\n"));
3631                         load_state_tmp(create_local_path(_T("$temp$.sta")));
3632                 }
3633                 FILEIO::RemoveFile(create_local_path(_T("$temp$.sta")));
3634         }
3635 }
3636
3637 bool EMU::load_state_tmp(const _TCHAR* file_path)
3638 {
3639         bool result = false;
3640         FILEIO* fio = new FILEIO();
3641         osd->lock_vm();
3642 #ifdef USE_ZLIB
3643         if(config.compress_state) {
3644                 fio->Gzopen(file_path, FILEIO_READ_BINARY);
3645         }
3646 #endif
3647         if(!fio->IsOpened()) {
3648                 fio->Fopen(file_path, FILEIO_READ_BINARY);
3649         }
3650         if(fio->IsOpened()) {
3651                 // check state file version
3652                 if(fio->FgetUint32() == STATE_VERSION) {
3653                         // load config
3654                         if(process_config_state((void *)fio, true)) {
3655                                 // load inserted medias
3656 #ifdef USE_CART
3657                                 fio->Fread(&cart_status, sizeof(cart_status), 1);
3658 #endif
3659 #ifdef USE_FLOPPY_DISK
3660                                 fio->Fread(floppy_disk_status, sizeof(floppy_disk_status), 1);
3661                                 fio->Fread(d88_file, sizeof(d88_file), 1);
3662 #endif
3663 #ifdef USE_QUICK_DISK
3664                                 fio->Fread(&quick_disk_status, sizeof(quick_disk_status), 1);
3665 #endif
3666 #ifdef USE_HARD_DISK
3667                                 fio->Fread(&hard_disk_status, sizeof(hard_disk_status), 1);
3668 #endif
3669 #ifdef USE_TAPE
3670                                 fio->Fread(&tape_status, sizeof(tape_status), 1);
3671 #endif
3672 #ifdef USE_COMPACT_DISC
3673                                 fio->Fread(&compact_disc_status, sizeof(compact_disc_status), 1);
3674 #endif
3675 #ifdef USE_LASER_DISC
3676                                 fio->Fread(&laser_disc_status, sizeof(laser_disc_status), 1);
3677 #endif
3678 #ifdef USE_BUBBLE
3679                                 fio->Fread(&bubble_casette_status, sizeof(bubble_casette_status), 1);
3680 #endif
3681                                 // check if virtual machine should be reinitialized
3682                                 bool reinitialize = false;
3683 #ifdef USE_CPU_TYPE
3684                                 reinitialize |= (cpu_type != config.cpu_type);
3685                                 cpu_type = config.cpu_type;
3686 #endif
3687 #ifdef USE_DIPSWITCH
3688                                 reinitialize |= (dipswitch != config.dipswitch);
3689                                 dipswitch = config.dipswitch;
3690 #endif
3691 #ifdef USE_SOUND_TYPE
3692                                 reinitialize |= (sound_type != config.sound_type);
3693                                 sound_type = config.sound_type;
3694 #endif
3695 #ifdef USE_PRINTER_TYPE
3696                                 reinitialize |= (printer_type != config.printer_type);
3697                                 printer_type = config.printer_type;
3698 #endif
3699 #ifdef USE_SERIAL_TYPE
3700                                 reinitialize |= (serial_type != config.serial_type);
3701                                 serial_type = config.serial_type;
3702 #endif
3703                                 if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
3704                                         config.sound_frequency = 6;     // default: 48KHz
3705                                 }
3706                                 if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
3707                                         config.sound_latency = 1;       // default: 100msec
3708                                 }
3709                                 reinitialize |= (sound_frequency != config.sound_frequency);
3710                                 reinitialize |= (sound_latency != config.sound_latency);
3711                                 sound_frequency = config.sound_frequency;
3712                                 sound_latency = config.sound_latency;
3713
3714                                 if(reinitialize) {
3715                                         // stop sound
3716                                         //osd->lock_vm();
3717                                         // reinitialize virtual machine
3718                                         osd->stop_sound();
3719                                         delete vm;
3720                                         osd->vm = nullptr;
3721                                         vm = new VM(this);
3722                                         osd->vm = vm;
3723 # if defined(_USE_QT)
3724                                         osd->reset_vm_node();
3725                                         osd->update_keyname_table();
3726                                         osd->reset_screen_buffer();
3727 # endif
3728                                         vm->initialize_sound(sound_rate, sound_samples);
3729 #ifdef USE_SOUND_VOLUME
3730                                         for(int i = 0; i < USE_SOUND_VOLUME; i++) {
3731                                                 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
3732                                         }
3733 #endif
3734                                         restore_media();
3735                                         vm->reset();
3736                                         //osd->unlock_vm();
3737                                 } else {
3738                                         // restore inserted medias
3739                                         restore_media();
3740                                 }
3741                                 // load vm state
3742                                 if(vm->process_state(fio, true)) {
3743                                         // check end of state
3744                                         result = (fio->FgetInt32_LE() == -1);
3745                                 }
3746                         }
3747                 }
3748                 fio->Fclose();
3749         }
3750         osd->unlock_vm();
3751         delete fio;
3752         return result;
3753 }
3754
3755 const _TCHAR *EMU::state_file_path(int num)
3756 {
3757         return create_local_path(_T("%s.sta%d"), _T(CONFIG_NAME), num);
3758 }
3759 #endif