OSDN Git Service

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