diff --git a/src/conio/win32cio.c b/src/conio/win32cio.c index 0f9330ff4b96c0b7daa830628c3351026f43d2b9..10a27dcb69a1b711f54a465e830a55715bf28b63 100644 --- a/src/conio/win32cio.c +++ b/src/conio/win32cio.c @@ -31,28 +31,41 @@ #include "vidmodes.h" #include "win32cio.h" -CIOLIBEXPORT const struct keyvals keyval[] = +CIOLIBEXPORT const struct keyvals keyval[WIN32_KEYVALS] = { - {VK_BACK, 0x08, 0x08, 0x7f, 0x0e00}, - {VK_TAB, 0x09, 0x0f00, 0x9400, 0xa500}, - {VK_RETURN, 0x0d, 0x0d, 0x0a, 0xa600}, - {VK_ESCAPE, 0x1b, 0x1b, 0x1b, 0x0100}, - {VK_SPACE, 0x20, 0x20, 0x0300, 0x20,}, - {'0', '0', ')', 0, 0x8100}, + {VK_BACK, 0x08, 0x08, 0x7f, 0x0e00}, // 0x08 + {VK_TAB, 0x09, 0x0f00, 0x9400, 0xa500}, // 0x09 + {VK_RETURN, 0x0d, 0x0d, 0x0a, 0xa600}, // 0x0d + {VK_ESCAPE, 0x1b, 0x1b, 0x1b, 0x0100}, // 0x1b + {VK_SPACE, 0x20, 0x20, 0x0300, 0x20,}, // 0x20 + {VK_PRIOR, 0x4900, 0x4900, 0x8400, 0x9900}, // 0x21 + {VK_NEXT, 0x5100, 0x5100, 0x7600, 0xa100}, // 0x22 + {VK_END, 0x4f00, 0x4f00, 0x7500, 0x9f00}, // 0x23 + {VK_HOME, 0x4700, 0x4700, 0x7700, 0x9700}, // 0x24 + {VK_LEFT, 0x4b00, 0x4b00, 0x7300, 0x9b00}, // 0x25 + + {VK_UP, 0x4800, 0x4800, 0x8d00, 0x9800}, // 0x26 + {VK_RIGHT, 0x4d00, 0x4d00, 0x7400, 0x9d00}, // 0x27 + {VK_DOWN, 0x5000, 0x5000, 0x9100, 0xa000}, // 0x28 + {VK_INSERT, CIO_KEY_IC, CIO_KEY_SHIFT_IC, CIO_KEY_CTRL_IC, CIO_KEY_ALT_IC}, // 0x2d + {VK_DELETE, CIO_KEY_DC, CIO_KEY_SHIFT_DC, CIO_KEY_CTRL_DC, CIO_KEY_CTRL_IC}, // 0x2e + {'0', '0', ')', 0, 0x8100}, // 0x30 {'1', '1', '!', 0, 0x7800}, {'2', '2', '@', 0x0300, 0x7900}, {'3', '3', '#', 0, 0x7a00}, {'4', '4', '$', 0, 0x7b00}, + {'5', '5', '%', 0, 0x7c00}, {'6', '6', '^', 0x1e, 0x7d00}, {'7', '7', '&', 0, 0x7e00}, {'8', '8', '*', 0, 0x7f00}, {'9', '9', '(', 0, 0x8000}, - {'A', 'a', 'A', 0x01, 0x1e00}, + {'A', 'a', 'A', 0x01, 0x1e00}, // 0x41 {'B', 'b', 'B', 0x02, 0x3000}, {'C', 'c', 'C', 0x03, 0x2e00}, {'D', 'd', 'D', 0x04, 0x2000}, {'E', 'e', 'E', 0x05, 0x1200}, + {'F', 'f', 'F', 0x06, 0x2100}, {'G', 'g', 'G', 0x07, 0x2200}, {'H', 'h', 'H', 0x08, 0x2300}, @@ -63,6 +76,7 @@ CIOLIBEXPORT const struct keyvals keyval[] = {'M', 'm', 'M', 0x0d, 0x3200}, {'N', 'n', 'N', 0x0e, 0x3100}, {'O', 'o', 'O', 0x0f, 0x1800}, + {'P', 'p', 'P', 0x10, 0x1900}, {'Q', 'q', 'Q', 0x11, 0x1000}, {'R', 'r', 'R', 0x12, 0x1300}, @@ -73,18 +87,9 @@ CIOLIBEXPORT const struct keyvals keyval[] = {'W', 'w', 'W', 0x17, 0x1100}, {'X', 'x', 'X', 0x18, 0x2d00}, {'Y', 'y', 'Y', 0x19, 0x1500}, + {'Z', 'z', 'Z', 0x1a, 0x2c00}, - {VK_PRIOR, 0x4900, 0x4900, 0x8400, 0x9900}, - {VK_NEXT, 0x5100, 0x5100, 0x7600, 0xa100}, - {VK_END, 0x4f00, 0x4f00, 0x7500, 0x9f00}, - {VK_HOME, 0x4700, 0x4700, 0x7700, 0x9700}, - {VK_LEFT, 0x4b00, 0x4b00, 0x7300, 0x9b00}, - {VK_UP, 0x4800, 0x4800, 0x8d00, 0x9800}, - {VK_RIGHT, 0x4d00, 0x4d00, 0x7400, 0x9d00}, - {VK_DOWN, 0x5000, 0x5000, 0x9100, 0xa000}, - {VK_INSERT, CIO_KEY_IC, CIO_KEY_SHIFT_IC, CIO_KEY_CTRL_IC, CIO_KEY_ALT_IC}, - {VK_DELETE, CIO_KEY_DC, CIO_KEY_SHIFT_DC, CIO_KEY_CTRL_DC, CIO_KEY_CTRL_IC}, - {VK_NUMPAD0, '0', 0x5200, 0x9200, 0}, + {VK_NUMPAD0, '0', 0x5200, 0x9200, 0}, // 0x60 {VK_NUMPAD1, '1', 0x4f00, 0x7500, 0}, {VK_NUMPAD2, '2', 0x5000, 0x9100, 0}, {VK_NUMPAD3, '3', 0x5100, 0x7600, 0}, @@ -93,16 +98,18 @@ CIOLIBEXPORT const struct keyvals keyval[] = {VK_NUMPAD6, '6', 0x4d00, 0x7400, 0}, {VK_NUMPAD7, '7', 0x4700, 0x7700, 0}, {VK_NUMPAD8, '8', 0x4800, 0x8d00, 0}, + {VK_NUMPAD9, '9', 0x4900, 0x8400, 0}, - {VK_MULTIPLY, '*', '*', 0x9600, 0x3700}, - {VK_ADD, '+', '+', 0x9000, 0x4e00}, - {VK_SUBTRACT, '-', '-', 0x8e00, 0x4a00}, - {VK_DECIMAL, '.', '.', 0x5300, 0x9300}, - {VK_DIVIDE, '/', '/', 0x9500, 0xa400}, - {VK_F1, 0x3b00, 0x5400, 0x5e00, 0x6800}, + {VK_MULTIPLY, '*', '*', 0x9600, 0x3700}, // 0x6a + {VK_ADD, '+', '+', 0x9000, 0x4e00}, // 0x6b + {VK_SUBTRACT, '-', '-', 0x8e00, 0x4a00}, // 0x6d + {VK_DECIMAL, '.', '.', 0x5300, 0x9300}, // 0x6e + {VK_DIVIDE, '/', '/', 0x9500, 0xa400}, // 0x6f + {VK_F1, 0x3b00, 0x5400, 0x5e00, 0x6800}, // 0x70 {VK_F2, 0x3c00, 0x5500, 0x5f00, 0x6900}, {VK_F3, 0x3d00, 0x5600, 0x6000, 0x6a00}, {VK_F4, 0x3e00, 0x5700, 0x6100, 0x6b00}, + {VK_F5, 0x3f00, 0x5800, 0x6200, 0x6c00}, {VK_F6, 0x4000, 0x5900, 0x6300, 0x6d00}, {VK_F7, 0x4100, 0x5a00, 0x6400, 0x6e00}, @@ -110,19 +117,19 @@ CIOLIBEXPORT const struct keyvals keyval[] = {VK_F9, 0x4300, 0x5c00, 0x6600, 0x7000}, {VK_F10, 0x4400, 0x5d00, 0x6700, 0x7100}, {VK_F11, 0x8500, 0x8700, 0x8900, 0x8b00}, - {VK_F12, 0x8600, 0x8800, 0x8a00, 0x8c00}, - {0xdc, '\\', '|', 0x1c, 0x2b00}, - {0xbf, '/', '?', 0, 0x3500}, - {0xbd, '-', '_', 0x1f, 0x8200}, - {0xbb, '=', '+', 0, 0x8300}, - {0xdb, '[', '{', 0x1b, 0x1a00}, - {0xdd, ']', '}', 0x1d, 0x1b00}, - {0xba, ';', ':', 0, 0x2700}, - {0xde, '\'', '"', 0, 0x2800}, - {0xbc, ',', '<', 0, 0x3300}, - {0xbe, '.', '>', 0, 0x3400}, - {0xc0, '`', '~', 0, 0x2900}, - {0, 0, 0, 0, 0} /** END **/ + {VK_F12, 0x8600, 0x8800, 0x8a00, 0x8c00}, // 0x7b + {0xba, ';', ':', 0, 0x2700}, // VK_OEM_1 + {0xbb, '=', '+', 0, 0x8300}, // VK_OEM_PLUS + + {0xbc, ',', '<', 0, 0x3300}, // VK_OEM_COMMA + {0xbd, '-', '_', 0x1f, 0x8200}, // VK_OEM_MINUS + {0xbe, '.', '>', 0, 0x3400}, // VK_OEM_PERIOD + {0xbf, '/', '?', 0, 0x3500}, // VK_OEM_2 + {0xdb, '[', '{', 0x1b, 0x1a00}, // VK_OEM_4 + {0xdc, '\\', '|', 0x1c, 0x2b00}, // VK_OEM_5 + {0xdd, ']', '}', 0x1d, 0x1b00}, // VK_OEM_6 + {0xde, '\'', '"', 0, 0x2800}, // VK_OEM_7 + {0xc0, '`', '~', 0, 0x2900}, // VK_OEM_3 }; static uint8_t *win32cio_buffer = NULL; @@ -205,28 +212,142 @@ static unsigned char WintoDOSAttr(WORD newattr) return(ret); } +int +win32_keyval_cmp(const void *key, const void *memb) +{ + const WORD *k = key; + int i = *k; + const struct keyvals *m = memb; + + return i - m->VirtualKeyCode; +} + static int win32_getchcode(WORD code, DWORD state) { - int i; + struct keyvals *k = bsearch(&code, keyval, WIN32_KEYVALS, sizeof(keyval[0]), win32_keyval_cmp); + + if (k) { + if(state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) + return(k->ALT); + if(state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) + return(k->CTRL); + if((state & (CAPSLOCK_ON)) && isalpha(k->Key)) { + if(!(state & SHIFT_PRESSED)) + return(k->Shift); + } + else { + if(state & (SHIFT_PRESSED)) + return(k->Shift); + } + return(k->Key); + } + return(0); +} - for(i=0;keyval[i].Key;i++) { - if(keyval[i].VirtualKeyCode==code) { - if(state & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) - return(keyval[i].ALT); - if(state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) - return(keyval[i].CTRL); - if((state & (CAPSLOCK_ON)) && isalpha(keyval[i].Key)) { - if(!(state & SHIFT_PRESSED)) - return(keyval[i].Shift); +static bool +handle_bios_key(uint32_t *bios_key, bool *bios_key_parsing, bool *zero_first, void (*accept_key)(uint16_t key)) +{ + uint8_t ch; + bool ret = false; + + if (*bios_key > 0 && *bios_key_parsing) { + if (*zero_first) { + // Unicode character + ch = cpchar_from_unicode_cpoint(getcodepage(), *bios_key, 0); + if (ch != 0) + MessageBeep(MB_ICONWARNING); + else { + accept_key(ch); + ret = true; } + } + else { + // Codepage character + ch = *bios_key; + accept_key(ch); + ret = true; + } + } + *bios_key = 0; + *bios_key_parsing = false; + *zero_first = false; + return ret; +} + +static uint32_t bios_key = 0; +static bool bios_key_parsing = false; +static bool zero_first = false; +static WORD lastch = 0; + +static void +set_last_key(uint16_t key) +{ + if (key) { + if (key == 0xe0) + lastch = CIO_KEY_LITERAL_E0; + else + lastch = key; + } +} + +bool +win32_bios_keyup_handler(WORD wParam, void (*accept_key)(uint16_t key)) +{ + if (bios_key_parsing) { + if (wParam == VK_MENU) { + return handle_bios_key(&bios_key, &bios_key_parsing, &zero_first, accept_key); + } + } + return false; +} + +bool +win32_bios_keydown_handler(WORD wParam, void (*accept_key)(uint16_t key)) +{ + if (bios_key_parsing) { + if (wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9) { + if (bios_key == 0 && wParam == VK_NUMPAD0) + zero_first = true; else { - if(state & (SHIFT_PRESSED)) - return(keyval[i].Shift); + bool terminate_bios = false; + if (zero_first) { + if (bios_key >= 429496730 || + (bios_key == 429496729 && wParam > VK_NUMPAD5)) { + terminate_bios = true; + } + } + else { + if (bios_key >= 26 || + (bios_key == 25 && wParam > VK_NUMPAD5)) { + terminate_bios = true; + } + } + if (terminate_bios) { + handle_bios_key(&bios_key, &bios_key_parsing, &zero_first, accept_key); + } + else { + bios_key *= 10; + bios_key += (wParam - VK_NUMPAD0); + return true; + } } - return(keyval[i].Key); + } + else { + // Yeah, it keeps sending this in GDI mode... + if (wParam == VK_MENU) + return true; + handle_bios_key(&bios_key, &bios_key_parsing, &zero_first, accept_key); } } - return(0); + else { + if (wParam == VK_MENU) { + bios_key = 0; + bios_key_parsing = true; + zero_first = false; + return true; + } + } + return false; } static int win32_keyboardio(int isgetch) @@ -234,7 +355,6 @@ static int win32_keyboardio(int isgetch) INPUT_RECORD input; DWORD num=0; HANDLE h; - static WORD lastch; if((h=GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) return(0); @@ -298,6 +418,8 @@ static int win32_keyboardio(int isgetch) #endif if(input.Event.KeyEvent.bKeyDown) { + if (win32_bios_keydown_handler(input.Event.KeyEvent.wVirtualKeyCode, set_last_key)) + break; /* Is this an AltGr key? */ if(((input.Event.KeyEvent.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_CTRL_PRESSED)) == (RIGHT_ALT_PRESSED|LEFT_CTRL_PRESSED)) && (BYTE)input.Event.KeyEvent.uChar.AsciiChar) { @@ -315,8 +437,12 @@ static int win32_keyboardio(int isgetch) } if (lastch == 0xe0) lastch = CIO_KEY_LITERAL_E0; - } else if(input.Event.KeyEvent.wVirtualKeyCode == VK_MENU) - lastch=(BYTE)input.Event.KeyEvent.uChar.AsciiChar; + } else { + /* These two lines were added twenty years ago for Edit->Paste support of EX-ASCII */ + //if(input.Event.KeyEvent.wVirtualKeyCode == VK_MENU) + // lastch=(BYTE)input.Event.KeyEvent.uChar.AsciiChar; + win32_bios_keyup_handler(input.Event.KeyEvent.wVirtualKeyCode, set_last_key); + } break; case MOUSE_EVENT: @@ -361,6 +487,7 @@ static int win32_keyboardio(int isgetch) } } } + break; } } } diff --git a/src/conio/win32cio.h b/src/conio/win32cio.h index ed88724f2a8cda9b7425b7e221bd9d916fc6d129..05da263c9a3a4b1ddf5f1cae1ca058dc12062f3f 100644 --- a/src/conio/win32cio.h +++ b/src/conio/win32cio.h @@ -68,8 +68,12 @@ void win32_getcustomcursor(int *s, int *e, int *r, int *b, int *v); void win32_setcustomcursor(int s, int e, int r, int b, int v); int win32_getvideoflags(void); int win32_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint16_t b); +int win32_keyval_cmp(const void *key, const void *memb); +bool win32_bios_keyup_handler(WORD wParam, void (*accept_key)(uint16_t key)); +bool win32_bios_keydown_handler(WORD wParam, void (*accept_key)(uint16_t key)); -extern const struct keyvals keyval[]; +#define WIN32_KEYVALS 89 +extern const struct keyvals keyval[WIN32_KEYVALS]; #ifdef __cplusplus } #endif diff --git a/src/conio/win32gdi.c b/src/conio/win32gdi.c index 4382a5ad4d30b710df958356f6861299f1f38d62..3aa8711dbe1cf5e58b6781f1557c1725761bf753 100644 --- a/src/conio/win32gdi.c +++ b/src/conio/win32gdi.c @@ -867,86 +867,90 @@ magic_message(MSG msg) return false; } - if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP) - return false; + WORD wParam = msg.wParam; + if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP) { + return win32_bios_keyup_handler(wParam, gdi_add_key); + } + + if (win32_bios_keydown_handler(wParam, gdi_add_key)) + return true; - for (i = 0; keyval[i].VirtualKeyCode != 0; i++) { - if (keyval[i].VirtualKeyCode == msg.wParam) { - if (msg.lParam & (1 << 29)) { - if (mods & (WMOD_CTRL | WMOD_LCTRL | WMOD_RCTRL)) { - // On Windows, AltGr maps to Alt + Ctrl, so don't handle it here. - return false; + struct keyvals *k = bsearch(&wParam, keyval, WIN32_KEYVALS, sizeof(keyval[0]), win32_keyval_cmp); + + if (k) { + if (msg.lParam & (1 << 29)) { + if (mods & (WMOD_CTRL | WMOD_LCTRL | WMOD_RCTRL)) { + // On Windows, AltGr maps to Alt + Ctrl, so don't handle it here. + return false; + } + if (k->ALT > 255) { + if (k->VirtualKeyCode == VK_LEFT) { + gdi_snap(false); } - if (keyval[i].ALT > 255) { - if (keyval[i].VirtualKeyCode == VK_LEFT) { - gdi_snap(false); - } - else if (keyval[i].VirtualKeyCode == VK_RIGHT) { - gdi_snap(true); - } - else if (keyval[i].VirtualKeyCode == VK_RETURN) { - fullscreen = !fullscreen; - if (fullscreen) { - HMONITOR hm = MonitorFromWindow(win, MONITOR_DEFAULTTONEAREST); - if (hm) { - MONITORINFO mi = {sizeof(mi)}; - if (GetMonitorInfo(hm, &mi)) { - WINDOWINFO wi = { - .cbSize = sizeof(WINDOWINFO) - }; - if (GetWindowInfo(win, &wi)) { - window_left = wi.rcWindow.left; - window_top = wi.rcWindow.top; - } - pthread_mutex_lock(&vstatlock); - window_scaling = (float)vstat.scaling; - pthread_mutex_unlock(&vstatlock); - SetWindowLongPtr(win, GWL_STYLE, STYLE); - PostMessageW(win, WM_USER_SETPOS, mi.rcMonitor.left, mi.rcMonitor.top); - PostMessageW(win, WM_USER_SETSIZE, mi.rcMonitor.right - mi.rcMonitor.left + 1, mi.rcMonitor.bottom - mi.rcMonitor.top + 1); + else if (k->VirtualKeyCode == VK_RIGHT) { + gdi_snap(true); + } + else if (k->VirtualKeyCode == VK_RETURN) { + fullscreen = !fullscreen; + if (fullscreen) { + HMONITOR hm = MonitorFromWindow(win, MONITOR_DEFAULTTONEAREST); + if (hm) { + MONITORINFO mi = {sizeof(mi)}; + if (GetMonitorInfo(hm, &mi)) { + WINDOWINFO wi = { + .cbSize = sizeof(WINDOWINFO) + }; + if (GetWindowInfo(win, &wi)) { + window_left = wi.rcWindow.left; + window_top = wi.rcWindow.top; } - else - fullscreen = false; + pthread_mutex_lock(&vstatlock); + window_scaling = (float)vstat.scaling; + pthread_mutex_unlock(&vstatlock); + SetWindowLongPtr(win, GWL_STYLE, STYLE); + PostMessageW(win, WM_USER_SETPOS, mi.rcMonitor.left, mi.rcMonitor.top); + PostMessageW(win, WM_USER_SETSIZE, mi.rcMonitor.right - mi.rcMonitor.left + 1, mi.rcMonitor.bottom - mi.rcMonitor.top + 1); } else fullscreen = false; } - else { - int w, h; - - bitmap_get_scaled_win_size(window_scaling, &w, &h, 0, 0); - SetWindowLongPtr(win, GWL_STYLE, STYLE); - PostMessageW(win, WM_USER_SETSIZE, w, h); - PostMessageW(win, WM_USER_SETPOS, window_left, window_top); - } + else + fullscreen = false; } - if (keyval[i].ALT == 0x6b00) { // ALT-F4 - gdi_add_key(CIO_KEY_QUIT); + else { + int w, h; + + bitmap_get_scaled_win_size(window_scaling, &w, &h, 0, 0); + SetWindowLongPtr(win, GWL_STYLE, STYLE); + PostMessageW(win, WM_USER_SETSIZE, w, h); + PostMessageW(win, WM_USER_SETPOS, window_left, window_top); } - else - gdi_add_key(keyval[i].ALT); - return true; } - } - else if (mods & (WMOD_CTRL | WMOD_LCTRL | WMOD_RCTRL)) { - if (keyval[i].CTRL > 255) { - gdi_add_key(keyval[i].CTRL); - return true; + if (k->ALT == 0x6b00) { // ALT-F4 + gdi_add_key(CIO_KEY_QUIT); } + else + gdi_add_key(k->ALT); + return true; } - else if (mods & (WMOD_SHIFT | WMOD_LSHIFT | WMOD_RSHIFT)) { - if (keyval[i].Shift > 255) { - gdi_add_key(keyval[i].Shift); - return true; - } + } + else if (mods & (WMOD_CTRL | WMOD_LCTRL | WMOD_RCTRL)) { + if (k->CTRL > 255) { + gdi_add_key(k->CTRL); + return true; } - else { - if (keyval[i].Key > 255) { - gdi_add_key(keyval[i].Key); - return true; - } + } + else if (mods & (WMOD_SHIFT | WMOD_LSHIFT | WMOD_RSHIFT)) { + if (k->Shift > 255) { + gdi_add_key(k->Shift); + return true; + } + } + else { + if (k->Key > 255) { + gdi_add_key(k->Key); + return true; } - break; } } break; diff --git a/src/conio/x_events.c b/src/conio/x_events.c index 21535d4c23dd9dc3e650df50c105af1e7d2ce6ac..9db7f6707f8c99837e8a9d676ff8613fe5134ef4 100644 --- a/src/conio/x_events.c +++ b/src/conio/x_events.c @@ -1993,13 +1993,11 @@ x11_event(XEvent *ev) /* Keyboard Events */ case KeyRelease: - { - if (bios_key_parsing) { - KeySym ks = x11.XLookupKeysym((XKeyEvent *)ev, 0); - // If Mod1 (ie: ALT) is released, *and* the only bytes were KP numbers, do the BIOS thing. - if (ks == XK_Alt_L || ks == XK_Alt_R) { - handle_bios_key(&bios_key, &bios_key_parsing, &zero_first); - } + if (bios_key_parsing) { + KeySym ks = x11.XLookupKeysym((XKeyEvent *)ev, 0); + // If Mod1 (ie: ALT) is released, *and* the only bytes were KP numbers, do the BIOS thing. + if (ks == XK_Alt_L || ks == XK_Alt_R) { + handle_bios_key(&bios_key, &bios_key_parsing, &zero_first); } } break; diff --git a/src/syncterm/CHANGES b/src/syncterm/CHANGES index 19aaa9a370bc34ad2ba52dde7e7168dab7784acc..6e23034bcd50812b2f106c8bb916c1295953d65f 100644 --- a/src/syncterm/CHANGES +++ b/src/syncterm/CHANGES @@ -1,6 +1,7 @@ Version 1.4b ------------ Fix crashes in text modes due to rip code being called +Add support for ALT+XXX and ALT+0XXXXX key entry Version 1.4a ------------