2008-11-23  Aidan Kehoe  <kehoea@parhasard.net>

	* 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);
 }
