From deb443f9553ad16eebc29416360b8f80ec4b1c3c Mon Sep 17 00:00:00 2001 From: "K.Ohta" Date: Mon, 24 Oct 2016 02:09:21 +0900 Subject: [PATCH] [VM][KEYBOARD] Add ROMAJI-KANA conversion.(When set SUPPORT_ROMA_KANA_CONVERSION). See scan2fmkeycode() of vm/fm7/keyboard.cpp. --- source/src/config.cpp | 5 + source/src/config.h | 2 + source/src/romakana.cpp | 538 +++++++++++++++++++++++++++++++++++++++ source/src/romakana.h | 58 +++++ source/src/vm/fm7/fm7.h | 2 + source/src/vm/fm7/fm7_keyboard.h | 6 +- source/src/vm/fm7/keyboard.cpp | 78 +++++- 7 files changed, 686 insertions(+), 3 deletions(-) create mode 100644 source/src/romakana.cpp create mode 100644 source/src/romakana.h diff --git a/source/src/config.cpp b/source/src/config.cpp index 44358d5ca..2bcc153cd 100644 --- a/source/src/config.cpp +++ b/source/src/config.cpp @@ -169,6 +169,8 @@ void initialize_config() config.sound_fdd = 1; config.sound_relay = 0; config.sound_buttons = 0; + + config.roma_kana_conversion = false; #endif } @@ -442,6 +444,8 @@ void load_config(const _TCHAR *config_path) config.log_to_syslog = MyGetPrivateProfileBool(_T("Emulator"), _T("WriteToSyslog"), config.log_to_syslog, config_path); config.log_to_console = MyGetPrivateProfileBool(_T("Emulator"), _T("WriteToConsole"), config.log_to_console, config_path); + config.roma_kana_conversion = MyGetPrivateProfileInt(_T("Emulator"), _T("RomaKana"), config.roma_kana_conversion, config_path); + for(int ii = 0; ii < (CSP_LOG_TYPE_VM_DEVICE_END - CSP_LOG_TYPE_VM_DEVICE_0 + 1); ii++) { uint32_t flags = 0; flags = MyGetPrivateProfileInt(_T("Emulator"), create_string(_T("SyslogEnabled%d"), ii), 0x0000, config_path); @@ -693,6 +697,7 @@ void save_config(const _TCHAR *config_path) MyWritePrivateProfileBool(_T("Emulator"), _T("WriteToSyslog"), config.log_to_syslog, config_path); MyWritePrivateProfileBool(_T("Emulator"), _T("WriteToConsole"), config.log_to_console, config_path); + MyWritePrivateProfileInt(_T("Emulator"), _T("RomaKana"), config.roma_kana_conversion, config_path); for(int ii = 0; ii < (CSP_LOG_TYPE_VM_DEVICE_END - CSP_LOG_TYPE_VM_DEVICE_0 + 1); ii++) { uint32_t flags = 0; diff --git a/source/src/config.h b/source/src/config.h index 7a10e8acf..7edf90a1f 100644 --- a/source/src/config.h +++ b/source/src/config.h @@ -176,6 +176,8 @@ typedef struct { int sound_fdd; int sound_relay; int sound_buttons; + + bool roma_kana_conversion; #endif } config_t; diff --git a/source/src/romakana.cpp b/source/src/romakana.cpp new file mode 100644 index 000000000..cab33be31 --- /dev/null +++ b/source/src/romakana.cpp @@ -0,0 +1,538 @@ +/* + Skelton for retropc emulator + + Author : K.Ohta + Date : 2016.10.23- + + [ Romaji -> Kana conversion ] +*/ + +#include "common.h" +#include "vm.h" +#include "romakana.h" + +#if defined(SUPPORT_ROMA_KANA_CONVERSION) + +_TCHAR detect_shiin(const _TCHAR src, bool *b_dakuon, bool *b_handakuon, bool *b_chi, bool *b_kigou) +{ + _TCHAR base_code; + *b_dakuon = false; + *b_handakuon = false; + *b_chi = false; + *b_kigou = false; + switch(src) { + case 'X': + case 'x': + base_code = KANA_SMALL_A; + break; + case 'K': + case 'k': + base_code = KANA_KA; // KA + break; + case 'S': + case 's': + base_code = KANA_SA; // SA + break; + case 'T': + case 't': + base_code = KANA_TA; // TA + break; + case 'N': + case 'n': + base_code = KANA_NA; // NA + break; + case 'H': + case 'h': + base_code = KANA_HA; // HA + break; + case 'M': + case 'm': + base_code = KANA_MA; // MA + break; + case 'Y': + case 'y': + base_code = KANA_YA; // YA + break; + case 'R': + case 'r': + base_code = KANA_RA; // RA + break; + case 'W': + case 'w': + base_code = KANA_WA; // WA + break; + case 'G': + case 'g': + base_code = KANA_KA; + *b_dakuon = true; + break; + case 'Z': + case 'z': + base_code = KANA_SA; + *b_dakuon = true; + break; + case 'D': + case 'd': + base_code = KANA_TA; + *b_dakuon = true; + break; + case 'B': + case 'b': + base_code = KANA_HA; + *b_dakuon = true; + break; + case 'P': + case 'p': + base_code = KANA_HA; + *b_handakuon = true; + break; + case 'C': + case 'c': + base_code = 0; + *b_chi = true; + break; + case '-': + base_code = KANA_ONBIKI; + *b_kigou = true; + break; + case '`': + base_code = KANA_DAKUON; + *b_kigou = true; + break; + case '{': + base_code = KANA_HANDAKUON; + *b_kigou = true; + break; + case '[': + base_code = KANA_UPPER_KAKKO; + *b_kigou = true; + break; + case ']': + base_code = KANA_DOWNER_KAKKO; + *b_kigou = true; + break; + case ',': + base_code = KANA_COMMA; + *b_kigou = true; + break; + case '.': + base_code = KANA_MARU; + *b_kigou = true; + break; + case '/': + base_code = KANA_NAKAGURO; + *b_kigou = true; + break; + default: + base_code = 0; + break; + } + return base_code; +} + +int detect_boin(_TCHAR src, _TCHAR base_code, bool *b_xya, bool *b_tsu, bool *b_nn) +{ + int code = -1; + *b_xya = false; + *b_tsu = false; + *b_nn = false; + switch(src) + { + case 'A': + case 'a': + code = 0; + break; + case 'I': + case 'i': + code = 1; + break; + case 'U': + case 'u': + code = 2; + break; + case 'E': + case 'e': + code = 3; + break; + case 'O': + case 'o': + code = 4; + break; + case 'Y': + case 'y': + *b_xya = true; + code = -1; + break; + case 'S': // TSU + case 's': + if((base_code & 0x00ff) == 0x00c0) { + code = -2; + *b_tsu = true; + } + break; + case 'N': // NN + case 'n': + code = -3; + *b_nn = true; + break; + } + return code; +} + +_TCHAR detect_xya(const _TCHAR c, _TCHAR base_code) +{ + bool b_dummy1; + bool b_dummy2; + bool b_dummy3; + int r_code = detect_boin(c, base_code, &b_dummy1, &b_dummy2, &b_dummy3); + switch(r_code) { + case 0: // Kya + return KANA_SMALL_YA; + break; + case 2: // Kyu + return KANA_SMALL_YU; + break; + case 4: // Kyo + return KANA_SMALL_YO; + break; + default: + return 0; + break; + } + return 0; +} + + +_TCHAR detect_w(const _TCHAR c, _TCHAR base_code) +{ + bool b_dummy1; + bool b_dummy2; + bool b_dummy3; + int r_code = detect_boin(c, base_code, &b_dummy1, &b_dummy2, &b_dummy3); + switch(r_code) { + case 0: // Wa + return KANA_WA; + break; + case 4: // Wo + return KANA_WO; + break; + default: + return 0; + break; + } + return 0; +} + +extern "C" { +int alphabet_to_kana(const _TCHAR *src, _TCHAR *dst, int *dstlen) +{ + int srclen; + bool b_boin = false; + bool b_shiin = false; + bool b_x = false; + bool b_dakuon = false; + bool b_handakuon = false; + bool b_xya = false; + bool b_tsu = false; + bool b_chi = false; + bool b_nn = false; + bool b_kigou = false; + int dstp = 0; + int dlen; + int i, j; + _TCHAR base_code = 0; + if((src == NULL) || (dst == NULL) || (dstlen == NULL)) return -1; + srclen = strlen(src); + dlen = *dstlen; + if((dlen <= 0) || (srclen <= 0)) return -1; + i = 0; + j = 0; + do { + base_code = detect_shiin((const _TCHAR)src[i], &b_dakuon, &b_handakuon, &b_chi, &b_kigou); + if(b_kigou) { + if(base_code != 0) { + if(j < dlen) { + dst[j++] = base_code; + } + } + i++; + } else if(base_code != 0) { + if((i + 1) >= srclen) { + *dstlen = 0; + return 0; + } + if((base_code & 0x00ff) == KANA_WA) { + _TCHAR c_code = detect_w((const _TCHAR)src[i + 1], base_code); + if(c_code != 0) { + if(j < dlen) { + dst[j++] = c_code; + } + i += 2; + } else { + if(j < dlen) { + dst[j++] = src[i]; + } + if(j < dlen) { + dst[j++] = src[i + 1]; + } + i += 2; + } + } else if((base_code & 0x00ff) == KANA_SMALL_A) { + int c_code = 0; + c_code = detect_boin((const _TCHAR)src[i + 1], base_code, &b_xya, &b_tsu, &b_nn); + if(c_code >= 0) { + if(j < dlen) { + dst[j++] = KANA_SMALL_A + c_code; + } + i += 2; + } else { + if(b_xya) { + if((i + 2) < srclen) { + _TCHAR rr = detect_xya((const _TCHAR)src[i + 2], base_code); + if(rr != 0) { + if(j < dlen) { + dst[j++] = rr; + } + } else { + if(j < dlen) { + dst[j++] = src[i]; + } + if(j < dlen) { + dst[j++] = src[i + 1]; + } + if(j < dlen) { + dst[j++] = src[i + 2]; + } + } + i += 3; + } else { + *dstlen = 0; + return 0; + } + } else { + if((i + 2) < srclen) { + if(j < dlen) { + dst[j++] = src[i]; + } + if(j < dlen) { + dst[j++] = src[i + 1]; + } + i += 2; + } else { + *dstlen = 0; + return 0; + } + } + } + } else { + int code = detect_boin((const _TCHAR)src[i + 1], base_code, &b_xya, &b_tsu, &b_nn); + if(b_nn) { + if(j < dlen) { + dst[j++] = KANA_NN; + } + i += 2; + } else if(code >= 0) { + if(j < dlen) { + if((base_code & 0x00ff) == KANA_YA) { + switch(code) { + case 0: + dst[j++] = base_code; + break; + case 2: + dst[j++] = base_code + 1; + break; + case 4: + dst[j++] = base_code + 2; + break; + default: + dst[j++] = src[i]; + if(j < dlen) { + dst[j++] = src[i + 1]; + } + break; + } + } else { + dst[j++] = base_code + code; + } + } + if(b_dakuon) { + if(j < dlen) { + dst[j++] = KANA_DAKUON; + } + } else if(b_handakuon) { + if(j < dlen) { + dst[j++] = KANA_HANDAKUON; + } + } + i += 2; + + } else { + _TCHAR next_code = 0; + if(b_xya) { + if((i + 2) >= srclen) { + *dstlen = 0; + return 0; + } + uint32_t bc = base_code & 0x00ff; + if(((bc >= KANA_KA) && (bc <= KANA_MA)) || (bc == KANA_RA)) { + // Ky*, Sy*, Ty*, Ny*, My*, Hy*, Ry*, Zy*, Dy*, By*, Py* + next_code = detect_xya((const _TCHAR)src[i + 2], base_code); + if(next_code != 0) { + if(j < dlen) { + dst[j] = base_code + 1; + j++; + i += 2; + } + if(b_dakuon) { + if(j < dlen) { + dst[j] = KANA_DAKUON; + j++; + } + } else if(b_handakuon) { + if(j < dlen) { + dst[j] = KANA_HANDAKUON; + j++; + } + } + if(j < dlen) { + dst[j] = next_code; + j++; + i++; + } + } else { + i += 2; + } + } else { + if(j < dlen) { + dst[j++] = src[i]; + } + if(j < dlen) { + dst[j++] = src[i + 1]; + } + if(j < dlen) { + dst[j++] = src[i + 2]; + } + i += 3; + } + } else if(b_tsu) { + if((i + 2) >= srclen) { + *dstlen = 0; + return 0; + } + uint32_t bc = base_code & 0x00ff; + if((src[i + 2] == 'u') || (src[i + 2] == 'U')) { + if(j < dlen) { + dst[j++] = KANA_TA + 2; // TU + } + i += 3; + } else { + if(j < dlen) { + dst[j++] = src[i]; + } + if(j < dlen) { + dst[j++] = src[i + 1]; + } + if(j < dlen) { + dst[j++] = src[i + 2]; + } + i += 3; + } + } else { + if(j < dlen) { + dst[j++] = src[i++]; + } + if(j < dlen) { + dst[j++] = src[i++]; + } + } + } + } + } else { // Not shiin + if(b_chi) { + if((i + 2) < srclen) { + if((src[i + 1] == 'H') || (src[i + 1] == 'h')) { + int code = detect_boin((const _TCHAR)src[i + 2], base_code, &b_xya, &b_tsu, &b_nn); + _TCHAR ccode = 0; + if(code >= 0) { + switch(code) { + case 0: // Cha + case 2: // Chu + case 3: // Che + case 4: // Cho + ccode = KANA_TA + 1; + break; + } + if(ccode != 0) { + if(j < dlen) { + dst[j++] = ccode; + } + if(j < dlen) { + if(code == 3) { // Che + dst[j++] = KANA_SMALL_E; + } else { + dst[j++] = (code >> 1) + KANA_SMALL_YA; + } + } + } else { + if(code == 1) { + if(j < dlen) { + dst[j++] = KANA_TA + 1; + } + } else { + if(j < dlen) { + dst[j++] = src[i]; + } + if(j < dlen) { + dst[j++] = src[i + 1]; + } + if(j < dlen) { + dst[j++] = src[i + 2]; + } + } + } + i += 3; + } else { + if(j < dlen) { + dst[j++] = src[i]; + } + if(j < dlen) { + dst[j++] = src[i + 1]; + } + i += 2; + } + } else { // Not cha-cho + if(j < dlen) { + dst[j++] = src[i++]; + } + } + } else { + *dstlen = 0; + return 0; + } + } else { // Not chi + if(base_code != 0) { + if(j < dlen) { + dst[j++] = src[i]; + } + break; // over srclen. + } + int code = detect_boin((const _TCHAR)src[i], base_code, &b_xya, &b_tsu, &b_nn); + if(code >= 0) { + if(j < dlen) { + dst[j++] = code + KANA_A; + } + } else { + if(j < dlen) { + dst[j++] = src[i]; + } + } + i++; + } + } + } while((i <= srclen) && (j < dlen)); + *dstlen = j; + if(j <= 0) return 0; + return i; +} +} +#endif //defined(SUPPORT_ROMA_KANA_CONVERSION) diff --git a/source/src/romakana.h b/source/src/romakana.h new file mode 100644 index 000000000..0476e6d59 --- /dev/null +++ b/source/src/romakana.h @@ -0,0 +1,58 @@ +/* + Skelton for retropc emulator + + Author : K.Ohta + Date : 2016.10.23- + + [ Romaji -> Kana conversion ] +*/ + +#ifndef _ROMAKANA_H +#define _ROMAKANA_H + +#if defined(SUPPORT_ROMA_KANA_CONVERSION) +#define KANA_MARU 0x00a1 +#define KANA_UPPER_KAKKO 0x00a2 +#define KANA_DOWNER_KAKKO 0x00a3 +#define KANA_COMMA 0x00a4 +#define KANA_NAKAGURO 0x00a5 +#define KANA_WO 0x00a6 +#define KANA_SMALL_A 0x00a7 +#define KANA_SMALL_I 0x00a8 +#define KANA_SMALL_U 0x00a9 +#define KANA_SMALL_E 0x00aa +#define KANA_SMALL_O 0x00ab +#define KANA_SMALL_YA 0x00ac +#define KANA_SMALL_YU 0x00ad +#define KANA_SMALL_YO 0x00ae +#define KANA_SMALL_TU 0x00af +#define KANA_ONBIKI 0x00b0 +#define KANA_A 0x00b1 +#define KANA_KA 0x00b6 +#define KANA_SA 0x00bb +#define KANA_TA 0x00c0 +#define KANA_NA 0x00c5 +#define KANA_HA 0x00ca +#define KANA_MA 0x00cf +#define KANA_YA 0x00d4 +#define KANA_RA 0x00d7 +#define KANA_WA 0x00dc +#define KANA_NN 0x00dd +#define KANA_DAKUON 0x00de +#define KANA_HANDAKUON 0x00df + +extern "C" { +// Convert romaji -> kana. +// ARG: +// src : src string (ASCII) +// dst : dst string (KANA = iso2022-jp + 0x80) see http://charset.7jp.net/jis.html . +// +// -1 : Illegal +// 0 : Not converted +// 1 : convert +// 2 : convert, but, another candicate exiusts. + extern int alphabet_to_kana(const _TCHAR *src, _TCHAR *dst, int *dstlen); +} +#endif // defined(SUPPORT_ROMA_KANA_CONVERSION) + +#endif diff --git a/source/src/vm/fm7/fm7.h b/source/src/vm/fm7/fm7.h index c057704f4..b0a837b4d 100644 --- a/source/src/vm/fm7/fm7.h +++ b/source/src/vm/fm7/fm7.h @@ -38,6 +38,8 @@ #define USE_DEBUGGER #define DATAREC_SOUND #define USE_DIG_RESOLUTION +#define SUPPORT_ROMA_KANA_CONVERSION + #if defined(_USE_QT) #define USE_SOUND_FILES 3 #define USE_SOUND_FILES_FDD diff --git a/source/src/vm/fm7/fm7_keyboard.h b/source/src/vm/fm7/fm7_keyboard.h index 16a659910..33bdb83a4 100644 --- a/source/src/vm/fm7/fm7_keyboard.h +++ b/source/src/vm/fm7/fm7_keyboard.h @@ -41,7 +41,11 @@ class KEYBOARD : public DEVICE { uint32_t keycode_7; int keymode; - private: +#if defined(SUPPORT_ROMA_KANA_CONVERSION) + _TCHAR romakana_buffer[16]; + int romakana_ptr; +#endif +private: bool ctrl_pressed; bool lshift_pressed; bool rshift_pressed; diff --git a/source/src/vm/fm7/keyboard.cpp b/source/src/vm/fm7/keyboard.cpp index ad508e640..4f4bf092d 100644 --- a/source/src/vm/fm7/keyboard.cpp +++ b/source/src/vm/fm7/keyboard.cpp @@ -5,12 +5,16 @@ * History : * Feb 12, 2015 : Initial */ - +#include "fm7.h" #include "../../fifo.h" #include "../device.h" #include "fm7_keyboard.h" - #include "keyboard_tables.h" + +#if defined(SUPPORT_ROMA_KANA_CONVERSION) +#include "../../romakana.h" +#endif + #if defined(_FM77AV_VARIANTS) #include "../beep.h" #include "fm77av_hidden_message_keyboard.h" @@ -163,11 +167,27 @@ uint16_t KEYBOARD::scan2fmkeycode(uint8_t sc) keyptr = graph_key; } } else if(kana_pressed) { +#if defined(SUPPORT_ROMA_KANA_CONVERSION) + if(config.roma_kana_conversion) { + if(shift_pressed) { + keyptr = standard_shift_key; + } else { + keyptr = standard_key; + } + } else { + if(shift_pressed) { + keyptr = kana_shift_key; + } else { + keyptr = kana_key; + } + } +#else if(shift_pressed) { keyptr = kana_shift_key; } else { keyptr = kana_key; } +#endif } else { // Standard stdkey = true; if(shift_pressed) { @@ -239,6 +259,56 @@ uint16_t KEYBOARD::scan2fmkeycode(uint8_t sc) } } } +#if defined(SUPPORT_ROMA_KANA_CONVERSION) + else if(kana_pressed) { + int i = 0; + if(((retval >= '`') && (retval <= 'z')) || + ((retval >= '@') && (retval <= 'Z')) || + ((retval >= ',') && (retval <= '/')) || + ((retval == '[') || (retval == ']')) || + ((retval == '{') || (retval == '}'))) { + if(romakana_ptr < sizeof(romakana_buffer)) { + romakana_buffer[romakana_ptr++] = retval; + _TCHAR kana_buffer[16]; + int kana_len = sizeof(kana_buffer); + memset(kana_buffer, 0x00, sizeof(kana_buffer)); + + if(alphabet_to_kana((const _TCHAR *)romakana_buffer, kana_buffer, &kana_len) > 0) { + int r; + if(kana_len > 0) { + for(i = 0; i < kana_len; i++) { + r = kana_buffer[i]; + if(r == KANA_WO) { + r = (KANA_WA + 1) & 0x00ff; + } else { + r = r & 0x00ff; + } + key_fifo->write(r); + } + } + memset(romakana_buffer, 0x00, sizeof(romakana_buffer)); + romakana_ptr = 0; + } + retval = 0; + } else { // Discard + for(i = 0; i < sizeof(romakana_buffer); i++) { + key_fifo->write(romakana_buffer[i]); + } + retval = 0; + memset(romakana_buffer, 0x00, sizeof(romakana_buffer)); + romakana_ptr = 0; + } + } else { + if(romakana_ptr > 0) { + for(i = 0; i < romakana_ptr; i++) { + key_fifo->write(romakana_buffer[i]); + } + memset(romakana_buffer, 0x00, sizeof(romakana_buffer)); + romakana_ptr = 0; + } + } + } +#endif return retval; } @@ -626,6 +696,10 @@ void KEYBOARD::reset_unchange_mode(void) event_hidden1_av = -1; hidden1_ptr = 0; #endif +#if defined(SUPPORT_ROMA_KANA_CONVERSION) + memset(romakana_buffer, 0x00, sizeof(romakana_buffer)); + romakana_ptr = 0; +#endif // Bus this->write_signals(&break_line, 0x00); #if defined(_FM77AV_VARIANTS) -- 2.11.0