2008-11-23 Aidan Kehoe * ldiscucs.c (luni_send): Check for negative length and treat that specially, as in ldisc_send(). * windows/window.c (WndProc): Pass TranslateKey a wchar_t buffer, treat the text it returns as Unicode. * windows/window.c (TranslateKey): Accept a wchar_t* output buffer, not unsigned char*. Accept output_count, giving the length of the output buffer. Explicitly use swprintf and wide strings when manipulating this buffer. Call ToUnicodeEx instead of ToAsciiEx on Windows NT 4 and above, avoiding the problem that characters available in the keyboard layout but not in the keyboard's associated locale get dropped. Index: windows/window.c =================================================================== --- windows/window.c (Revision 8320) +++ windows/window.c (Arbeitskopie) @@ -78,7 +78,7 @@ static Mouse_Button translate_button(Mouse_Button button); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, - unsigned char *output); + wchar_t *output, size_t output_count); static void cfgtopalette(void); static void systopalette(void); static void init_palette(void); @@ -2864,7 +2864,7 @@ * we get the translations under _our_ control. */ { - unsigned char buf[20]; + wchar_t buf[20]; int len; if (wParam == VK_PROCESSKEY) { /* IME PROCESS key */ @@ -2877,7 +2877,7 @@ TranslateMessage(&m); } else break; /* pass to Windows for default processing */ } else { - len = TranslateKey(message, wParam, lParam, buf); + len = TranslateKey(message, wParam, lParam, buf, lenof(buf)); if (len == -1) return DefWindowProc(hwnd, message, wParam, lParam); @@ -2900,7 +2900,7 @@ */ term_seen_key_event(term); if (ldisc) - ldisc_send(ldisc, buf, len, 1); + luni_send(ldisc, buf, len, 1); show_mouseptr(0); } } @@ -3554,18 +3554,18 @@ } /* - * Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of ASCII - * codes. Returns number of bytes used, zero to drop the message, + * Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of wchar_t. + * Returns number of wchar_t used, zero to drop the message, * -1 to forward the message to Windows, or another negative number * to indicate a NUL-terminated "special" string. */ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, - unsigned char *output) + wchar_t *output, size_t output_count) { BYTE keystate[256]; int scan, left_alt = 0, key_down, shift_state; int r, i, code; - unsigned char *p = output; + wchar_t *p = output; static int alt_sum = 0; HKL kbd_layout = GetKeyboardLayout(0); @@ -3942,11 +3942,14 @@ if (xkey) { if (term->vt52_mode) { if (xkey >= 'P' && xkey <= 'S') - p += sprintf((char *) p, "\x1B%c", xkey); + p += swprintf(p, output_count - (p - output), + L"\x1B%c", xkey); else - p += sprintf((char *) p, "\x1B?%c", xkey); + p += swprintf(p, output_count - (p - output), + L"\x1B?%c", xkey); } else - p += sprintf((char *) p, "\x1BO%c", xkey); + p += swprintf(p, output_count - (p - output), + L"\x1BO%c", xkey); return p - output; } } @@ -4106,7 +4109,8 @@ code = "\0\2\1\4\5\3\6"[code]; if (term->vt52_mode && code > 0 && code <= 6) { - p += sprintf((char *) p, "\x1B%c", " HLMEIG"[code]); + p += swprintf(p, output_count - (p - output), + L"\x1B%c", L" HLMEIG"[code]); return p - output; } @@ -4130,16 +4134,18 @@ } if (keystate[VK_SHIFT] & 0x80) index += 12; if (keystate[VK_CONTROL] & 0x80) index += 24; - p += sprintf((char *) p, "\x1B[%c", codes[index]); + p += swprintf(p, output_count - (p - output), + L"\x1B[%c", codes[index]); return p - output; } if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ code >= 1 && code <= 6) { - char codes[] = "HL.FIG"; + wchar_t codes[] = L"HL.FIG"; if (code == 3) { *p++ = '\x7F'; } else { - p += sprintf((char *) p, "\x1B[%c", codes[code-1]); + p += swprintf(p, output_count - (p - output), + L"\x1B[%c", codes[code-1]); } return p - output; } @@ -4150,29 +4156,33 @@ if (code > 21) offt++; if (term->vt52_mode) - p += sprintf((char *) p, "\x1B%c", code + 'P' - 11 - offt); + p += swprintf(p, output_count - (p - output), L"\x1B%c", + code + 'P' - 11 - offt); else - p += - sprintf((char *) p, "\x1BO%c", code + 'P' - 11 - offt); + p += swprintf(p, output_count - (p - output), + L"\x1BO%c", code + 'P' - 11 - offt); return p - output; } if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { - p += sprintf((char *) p, "\x1B[[%c", code + 'A' - 11); + p += swprintf(p, output_count - (p - output), + L"\x1B[[%c", code + 'A' - 11); return p - output; } if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { if (term->vt52_mode) - p += sprintf((char *) p, "\x1B%c", code + 'P' - 11); + p += swprintf(p, output_count - (p - output), code + 'P' - 11); else - p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11); + p += swprintf(p, output_count - (p - output), + L"\x1BO%c", code + 'P' - 11); return p - output; } if (cfg.rxvt_homeend && (code == 1 || code == 4)) { - p += sprintf((char *) p, code == 1 ? "\x1B[H" : "\x1BOw"); + p += swprintf(p, output_count - (p - output), + code == 1 ? L"\x1B[H" : L"\x1BOw"); return p - output; } if (code) { - p += sprintf((char *) p, "\x1B[%d~", code); + p += swprintf(p, output_count - (p - output), L"\x1B[%d~", code); return p - output; } @@ -4201,7 +4211,8 @@ } if (xkey) { if (term->vt52_mode) - p += sprintf((char *) p, "\x1B%c", xkey); + p += swprintf(p, output_count - (p - output), + L"\x1B%c", xkey); else { int app_flg = (term->app_cursor_keys && !cfg.no_applic_c); #if 0 @@ -4227,9 +4238,11 @@ app_flg = !app_flg; if (app_flg) - p += sprintf((char *) p, "\x1BO%c", xkey); + p += swprintf(p, output_count - (p - output), + L"\x1BO%c", xkey); else - p += sprintf((char *) p, "\x1B[%c", xkey); + p += swprintf(p, output_count - (p - output), + L"\x1B[%c", xkey); } return p - output; } @@ -4262,26 +4275,26 @@ keystate[VK_CAPITAL] = 0; } - /* XXX how do we know what the max size of the keys array should - * be is? There's indication on MS' website of an Inquire/InquireEx - * functioning returning a KBINFO structure which tells us. */ if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) { - /* XXX 'keys' parameter is declared in MSDN documentation as - * 'LPWORD lpChar'. - * The experience of a French user indicates that on - * Win98, WORD[] should be passed in, but on Win2K, it should - * be BYTE[]. German WinXP and my Win2K with "US International" - * driver corroborate this. - * Experimentally I've conditionalised the behaviour on the - * Win9x/NT split, but I suspect it's worse than that. - * See wishlist item `win-dead-keys' for more horrible detail - * and speculations. */ - BYTE keybs[3]; - int i; - r = ToAsciiEx(wParam, scan, keystate, (LPWORD)keybs, 0, kbd_layout); - for (i=0; i<3; i++) keys[i] = keybs[i]; + r = ToUnicodeEx(wParam, scan, keystate, keys, + lenof(keys), 0, kbd_layout); } else { - r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout); + /* XXX how do we know what the max size of the keys array should + * be is? There's indication on MS' website of an Inquire/InquireEx + * functioning returning a KBINFO structure which tells us. */ + r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout); + if (r > 0) { + /* The conversion to the local, probably not Unicode + encoding, succeeded. Convert the text to Unicode to have + it understood by the rest of our code. */ + unsigned char codePageBuffer[3]; + for (i = 0; i < r; ++i) { + codePageBuffer[i] = (unsigned char)keys[i]; + } + /* Translate */ + mb_to_wc (kbd_codepage, MB_USEGLYPHCHARS, codePageBuffer, + lenof (codePageBuffer), keys, lenof (keys)); + } } #ifdef SHOW_TOASCII_RESULT if (r == 1 && !key_down) { @@ -4314,7 +4327,7 @@ p = output; for (i = 0; i < r; i++) { - unsigned char ch = (unsigned char) keys[i]; + wchar_t ch = keys[i]; if (compose_state == 2 && (ch & 0x80) == 0 && ch > ' ') { compose_char = ch; @@ -4346,7 +4359,7 @@ if (ldisc) luni_send(ldisc, &keybuf, 1, 1); } else { - ch = (char) alt_sum; + ch = (wchar_t) alt_sum; /* * We need not bother about stdin * backlogs here, because in GUI PuTTY @@ -4358,30 +4371,29 @@ */ term_seen_key_event(term); if (ldisc) - ldisc_send(ldisc, &ch, 1, 1); + luni_send(ldisc, &ch, 1, 1); } alt_sum = 0; } else { term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, &ch, 1, 1); + luni_send(ldisc, &ch, 1, 1); } } else { if(capsOn && ch < 0x80) { - WCHAR cbuf[2]; + wchar_t cbuf[2]; cbuf[0] = 27; cbuf[1] = xlat_uskbd2cyrllic(ch); term_seen_key_event(term); if (ldisc) luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } else { - char cbuf[2]; + wchar_t cbuf[2]; cbuf[0] = '\033'; cbuf[1] = ch; term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, - cbuf+!left_alt, 1+!!left_alt, 1); + luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } } show_mouseptr(0); Index: ldiscucs.c =================================================================== --- ldiscucs.c (Revision 8320) +++ ldiscucs.c (Arbeitskopie) @@ -40,9 +40,16 @@ int ratio = (in_utf(ldisc->term))?3:1; char *linebuffer; int linesize; - int i; + int i, saved_len = len; char *p; + if (len < 0) { + /* Less than zero means a nul-terminated special string; we want to + * include the nul in the translated text, so we add one to the + * result of wcslen. */ + len = wcslen (widebuf) + 1; + } + linesize = len * ratio * 2; linebuffer = snewn(linesize, char); @@ -74,7 +81,8 @@ p = linebuffer; } if (p > linebuffer) - ldisc_send(ldisc, linebuffer, p - linebuffer, interactive); + ldisc_send(ldisc, linebuffer, + len == saved_len ? p - linebuffer : saved_len, interactive); sfree(linebuffer); }