+ SetWindowText(hwnd,
+ cfg.win_name_always ? window_name : icon_name);
+ break;
+ }
+ if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
+ SetWindowText(hwnd, window_name);
+
+ if (cfg.lockfont && cfg.locksize) {
+ /* A resize, well it better be a minimize. */
+ reset_window(-1);
+ } else {
+
+ int width, height, w, h;
+
+ width = LOWORD(lParam);
+ height = HIWORD(lParam);
+
+ if (!resizing) {
+ if (wParam == SIZE_MAXIMIZED) {
+ was_zoomed = 1;
+ prev_rows = rows;
+ prev_cols = cols;
+ if (cfg.lockfont) {
+ w = width / font_width;
+ if (w < 1) w = 1;
+ h = height / font_height;
+ if (h < 1) h = 1;
+
+ term_size(h, w, cfg.savelines);
+ }
+ reset_window(0);
+ } else if (wParam == SIZE_RESTORED && was_zoomed) {
+ was_zoomed = 0;
+ if (cfg.lockfont)
+ term_size(prev_rows, prev_cols, cfg.savelines);
+ reset_window(0);
+ }
+ /* This is an unexpected resize, these will normally happen
+ * if the window is too large. Probably either the user
+ * selected a huge font or the screen size has changed.
+ *
+ * This is also called with minimize.
+ */
+ else reset_window(-1);
+ }
+
+ /*
+ * Don't call back->size in mid-resize. (To prevent
+ * massive numbers of resize events getting sent
+ * down the connection during an NT opaque drag.)
+ */
+ if (resizing) {
+ if (!cfg.locksize && !alt_pressed) {
+ need_backend_resize = TRUE;
+ w = (width-cfg.window_border*2) / font_width;
+ if (w < 1) w = 1;
+ h = (height-cfg.window_border*2) / font_height;
+ if (h < 1) h = 1;
+
+ cfg.height = h;
+ cfg.width = w;
+ } else
+ reset_window(0);
+ }
+ }
+ return 0;
+ case WM_VSCROLL:
+ switch (LOWORD(wParam)) {
+ case SB_BOTTOM:
+ term_scroll(-1, 0);
+ break;
+ case SB_TOP:
+ term_scroll(+1, 0);
+ break;
+ case SB_LINEDOWN:
+ term_scroll(0, +1);
+ break;
+ case SB_LINEUP:
+ term_scroll(0, -1);
+ break;
+ case SB_PAGEDOWN:
+ term_scroll(0, +rows / 2);
+ break;
+ case SB_PAGEUP:
+ term_scroll(0, -rows / 2);
+ break;
+ case SB_THUMBPOSITION:
+ case SB_THUMBTRACK:
+ term_scroll(1, HIWORD(wParam));
+ break;
+ }
+ break;
+ case WM_PALETTECHANGED:
+ if ((HWND) wParam != hwnd && pal != NULL) {
+ HDC hdc = get_ctx();
+ if (hdc) {
+ if (RealizePalette(hdc) > 0)
+ UpdateColors(hdc);
+ free_ctx(hdc);
+ }
+ }
+ break;
+ case WM_QUERYNEWPALETTE:
+ if (pal != NULL) {
+ HDC hdc = get_ctx();
+ if (hdc) {
+ if (RealizePalette(hdc) > 0)
+ UpdateColors(hdc);
+ free_ctx(hdc);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ /*
+ * Add the scan code and keypress timing to the random
+ * number noise.
+ */
+ noise_ultralight(lParam);
+
+ /*
+ * We don't do TranslateMessage since it disassociates the
+ * resulting CHAR message from the KEYDOWN that sparked it,
+ * which we occasionally don't want. Instead, we process
+ * KEYDOWN, and call the Win32 translator functions so that
+ * we get the translations under _our_ control.
+ */
+ {
+ unsigned char buf[20];
+ int len;
+
+ if (wParam == VK_PROCESSKEY) {
+ MSG m;
+ m.hwnd = hwnd;
+ m.message = WM_KEYDOWN;
+ m.wParam = wParam;
+ m.lParam = lParam & 0xdfff;
+ TranslateMessage(&m);
+ } else {
+ len = TranslateKey(message, wParam, lParam, buf);
+ if (len == -1)
+ return DefWindowProc(hwnd, message, wParam, lParam);
+
+ if (len != 0) {
+ /*
+ * We need not bother about stdin backlogs
+ * here, because in GUI PuTTY we can't do
+ * anything about it anyway; there's no means
+ * of asking Windows to hold off on KEYDOWN
+ * messages. We _have_ to buffer everything
+ * we're sent.
+ */
+ ldisc_send(buf, len);
+ show_mouseptr(0);
+ }
+ }
+ }
+ return 0;
+ case WM_INPUTLANGCHANGE:
+ {
+ /* wParam == Font number */
+ /* lParam == Locale */
+ char lbuf[20];
+ HKL NewInputLocale = (HKL) lParam;
+
+ // lParam == GetKeyboardLayout(0);
+
+ GetLocaleInfo(LOWORD(NewInputLocale),
+ LOCALE_IDEFAULTANSICODEPAGE, lbuf, sizeof(lbuf));
+
+ kbd_codepage = atoi(lbuf);
+ }
+ break;
+ case WM_IME_COMPOSITION:
+ {
+ HIMC hIMC;
+ int n;
+ char *buff;
+
+ if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
+ osVersion.dwPlatformId == VER_PLATFORM_WIN32s) break; /* no Unicode */
+
+ if ((lParam & GCS_RESULTSTR) == 0) /* Composition unfinished. */
+ break; /* fall back to DefWindowProc */
+
+ hIMC = ImmGetContext(hwnd);
+ n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
+
+ if (n > 0) {
+ buff = (char*) smalloc(n);
+ ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n);
+ luni_send((unsigned short *)buff, n / 2);
+ free(buff);
+ }
+ ImmReleaseContext(hwnd, hIMC);
+ return 1;
+ }
+
+ case WM_IME_CHAR:
+ if (wParam & 0xFF00) {
+ unsigned char buf[2];
+
+ buf[1] = wParam;
+ buf[0] = wParam >> 8;
+ lpage_send(kbd_codepage, buf, 2);
+ } else {
+ char c = (unsigned char) wParam;
+ lpage_send(kbd_codepage, &c, 1);
+ }
+ return (0);
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ /*
+ * Nevertheless, we are prepared to deal with WM_CHAR
+ * messages, should they crop up. So if someone wants to
+ * post the things to us as part of a macro manoeuvre,
+ * we're ready to cope.
+ */
+ {
+ char c = (unsigned char)wParam;
+ lpage_send(CP_ACP, &c, 1);
+ }
+ return 0;
+ case WM_SETCURSOR:
+ if (send_raw_mouse && LOWORD(lParam) == HTCLIENT) {
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ return TRUE;
+ }
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+/*
+ * Move the system caret. (We maintain one, even though it's
+ * invisible, for the benefit of blind people: apparently some
+ * helper software tracks the system caret, so we should arrange to
+ * have one.)
+ */
+void sys_cursor(int x, int y)
+{
+ COMPOSITIONFORM cf;
+ HIMC hIMC;
+
+ if (!has_focus) return;
+
+ SetCaretPos(x * font_width + offset_width,
+ y * font_height + offset_height);
+
+ /* IMM calls on Win98 and beyond only */
+ if(osVersion.dwPlatformId == VER_PLATFORM_WIN32s) return; /* 3.11 */
+
+ if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
+ osVersion.dwMinorVersion == 0) return; /* 95 */
+
+ /* we should have the IMM functions */
+ hIMC = ImmGetContext(hwnd);
+ cf.dwStyle = CFS_POINT;
+ cf.ptCurrentPos.x = x * font_width;
+ cf.ptCurrentPos.y = y * font_height;
+ ImmSetCompositionWindow(hIMC, &cf);
+
+ ImmReleaseContext(hwnd, hIMC);
+}
+
+/*
+ * Draw a line of text in the window, at given character
+ * coordinates, in given attributes.
+ *
+ * We are allowed to fiddle with the contents of `text'.
+ */
+void do_text(Context ctx, int x, int y, char *text, int len,
+ unsigned long attr, int lattr)
+{
+ COLORREF fg, bg, t;
+ int nfg, nbg, nfont;
+ HDC hdc = ctx;
+ RECT line_box;
+ int force_manual_underline = 0;
+ int fnt_width = font_width * (1 + (lattr != LATTR_NORM));
+ int char_width = fnt_width;
+ int text_adjust = 0;
+ static int *IpDx = 0, IpDxLEN = 0;
+
+ if (attr & ATTR_WIDE)
+ char_width *= 2;
+
+ if (len > IpDxLEN || IpDx[0] != char_width) {
+ int i;
+ if (len > IpDxLEN) {
+ sfree(IpDx);
+ IpDx = smalloc((len + 16) * sizeof(int));
+ IpDxLEN = (len + 16);
+ }
+ for (i = 0; i < IpDxLEN; i++)
+ IpDx[i] = char_width;
+ }
+
+ /* Only want the left half of double width lines */
+ if (lattr != LATTR_NORM && x*2 >= cols)
+ return;
+
+ x *= fnt_width;
+ y *= font_height;
+ x += offset_width;
+ y += offset_height;
+
+ if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || big_cursor)) {
+ attr &= ATTR_CUR_AND | (bold_mode != BOLD_COLOURS ? ATTR_BOLD : 0);
+ attr ^= ATTR_CUR_XOR;
+ }
+
+ nfont = 0;
+ if (cfg.vtmode == VT_POORMAN && lattr != LATTR_NORM) {
+ /* Assume a poorman font is borken in other ways too. */
+ lattr = LATTR_WIDE;
+ } else
+ switch (lattr) {
+ case LATTR_NORM:
+ break;
+ case LATTR_WIDE:
+ nfont |= FONT_WIDE;
+ break;
+ default:
+ nfont |= FONT_WIDE + FONT_HIGH;
+ break;
+ }
+ if (attr & ATTR_NARROW)
+ nfont |= FONT_NARROW;
+
+ /* Special hack for the VT100 linedraw glyphs. */
+ if ((attr & CSET_MASK) == 0x2300) {
+ if (text[0] >= (char) 0xBA && text[0] <= (char) 0xBD) {
+ switch ((unsigned char) (text[0])) {
+ case 0xBA:
+ text_adjust = -2 * font_height / 5;
+ break;
+ case 0xBB:
+ text_adjust = -1 * font_height / 5;
+ break;
+ case 0xBC:
+ text_adjust = font_height / 5;
+ break;
+ case 0xBD:
+ text_adjust = 2 * font_height / 5;
+ break;
+ }
+ if (lattr == LATTR_TOP || lattr == LATTR_BOT)
+ text_adjust *= 2;
+ attr &= ~CSET_MASK;
+ text[0] = (char) (unitab_xterm['q'] & CHAR_MASK);
+ attr |= (unitab_xterm['q'] & CSET_MASK);
+ if (attr & ATTR_UNDER) {
+ attr &= ~ATTR_UNDER;
+ force_manual_underline = 1;
+ }
+ }
+ }
+
+ /* Anything left as an original character set is unprintable. */
+ if (DIRECT_CHAR(attr)) {
+ attr &= ~CSET_MASK;
+ attr |= 0xFF00;
+ memset(text, 0xFD, len);
+ }
+
+ /* OEM CP */
+ if ((attr & CSET_MASK) == ATTR_OEMCP)
+ nfont |= FONT_OEM;
+
+ nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
+ nbg = 2 * ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
+ if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD))
+ nfont |= FONT_BOLD;
+ if (und_mode == UND_FONT && (attr & ATTR_UNDER))
+ nfont |= FONT_UNDERLINE;
+ another_font(nfont);
+ if (!fonts[nfont]) {
+ if (nfont & FONT_UNDERLINE)
+ force_manual_underline = 1;
+ /* Don't do the same for manual bold, it could be bad news. */
+
+ nfont &= ~(FONT_BOLD | FONT_UNDERLINE);
+ }
+ another_font(nfont);
+ if (!fonts[nfont])
+ nfont = FONT_NORMAL;
+ if (attr & ATTR_REVERSE) {
+ t = nfg;
+ nfg = nbg;
+ nbg = t;
+ }
+ if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD))
+ nfg++;
+ if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK))
+ nbg++;
+ fg = colours[nfg];
+ bg = colours[nbg];
+ SelectObject(hdc, fonts[nfont]);
+ SetTextColor(hdc, fg);
+ SetBkColor(hdc, bg);
+ SetBkMode(hdc, OPAQUE);
+ line_box.left = x;
+ line_box.top = y;
+ line_box.right = x + char_width * len;
+ line_box.bottom = y + font_height;
+
+ /* Only want the left half of double width lines */
+ if (line_box.right > font_width*cols+offset_width)
+ line_box.right = font_width*cols+offset_width;
+
+ /* We're using a private area for direct to font. (512 chars.) */
+ if (dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) {
+ /* Ho Hum, dbcs fonts are a PITA! */
+ /* To display on W9x I have to convert to UCS */
+ static wchar_t *uni_buf = 0;
+ static int uni_len = 0;
+ int nlen, mptr;
+ if (len > uni_len) {
+ sfree(uni_buf);
+ uni_buf = smalloc((uni_len = len) * sizeof(wchar_t));
+ }
+
+ for(nlen = mptr = 0; mptr<len; mptr++) {
+ uni_buf[nlen] = 0xFFFD;
+ if (IsDBCSLeadByteEx(font_codepage, (BYTE) text[mptr])) {
+ IpDx[nlen] += char_width;
+ MultiByteToWideChar(font_codepage, MB_USEGLYPHCHARS,
+ text+mptr, 2, uni_buf+nlen, 1);
+ mptr++;
+ }
+ else
+ {
+ MultiByteToWideChar(font_codepage, MB_USEGLYPHCHARS,
+ text+mptr, 1, uni_buf+nlen, 1);
+ }
+ nlen++;
+ }
+ if (nlen <= 0)
+ return; /* Eeek! */
+
+ ExtTextOutW(hdc, x,
+ y - font_height * (lattr == LATTR_BOT) + text_adjust,
+ ETO_CLIPPED | ETO_OPAQUE, &line_box, uni_buf, nlen, IpDx);
+ if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
+ SetBkMode(hdc, TRANSPARENT);
+ ExtTextOutW(hdc, x - 1,
+ y - font_height * (lattr ==
+ LATTR_BOT) + text_adjust,
+ ETO_CLIPPED, &line_box, uni_buf, nlen, IpDx);
+ }
+
+ IpDx[0] = -1;
+ } else if (DIRECT_FONT(attr)) {
+ ExtTextOut(hdc, x,
+ y - font_height * (lattr == LATTR_BOT) + text_adjust,
+ ETO_CLIPPED | ETO_OPAQUE, &line_box, text, len, IpDx);
+ if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
+ SetBkMode(hdc, TRANSPARENT);
+
+ /* GRR: This draws the character outside it's box and can leave
+ * 'droppings' even with the clip box! I suppose I could loop it
+ * one character at a time ... yuk.
+ *
+ * Or ... I could do a test print with "W", and use +1 or -1 for this
+ * shift depending on if the leftmost column is blank...
+ */
+ ExtTextOut(hdc, x - 1,
+ y - font_height * (lattr ==
+ LATTR_BOT) + text_adjust,
+ ETO_CLIPPED, &line_box, text, len, IpDx);
+ }
+ } else {
+ /* And 'normal' unicode characters */
+ static WCHAR *wbuf = NULL;
+ static int wlen = 0;
+ int i;
+ if (wlen < len) {
+ sfree(wbuf);
+ wlen = len;
+ wbuf = smalloc(wlen * sizeof(WCHAR));
+ }
+ for (i = 0; i < len; i++)
+ wbuf[i] = (WCHAR) ((attr & CSET_MASK) + (text[i] & CHAR_MASK));
+
+ ExtTextOutW(hdc, x,
+ y - font_height * (lattr == LATTR_BOT) + text_adjust,
+ ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx);
+
+ /* And the shadow bold hack. */
+ if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
+ SetBkMode(hdc, TRANSPARENT);
+ ExtTextOutW(hdc, x - 1,
+ y - font_height * (lattr ==
+ LATTR_BOT) + text_adjust,
+ ETO_CLIPPED, &line_box, wbuf, len, IpDx);
+ }
+ }
+ if (lattr != LATTR_TOP && (force_manual_underline ||
+ (und_mode == UND_LINE
+ && (attr & ATTR_UNDER)))) {
+ HPEN oldpen;
+ int dec = descent;
+ if (lattr == LATTR_BOT)
+ dec = dec * 2 - font_height;
+
+ oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, fg));
+ MoveToEx(hdc, x, y + dec, NULL);
+ LineTo(hdc, x + len * char_width, y + dec);
+ oldpen = SelectObject(hdc, oldpen);
+ DeleteObject(oldpen);
+ }
+}
+
+void do_cursor(Context ctx, int x, int y, char *text, int len,
+ unsigned long attr, int lattr)
+{
+
+ int fnt_width;
+ int char_width;
+ HDC hdc = ctx;
+ int ctype = cfg.cursor_type;
+
+ if ((attr & TATTR_ACTCURS) && (ctype == 0 || big_cursor)) {
+ if (((attr & CSET_MASK) | (unsigned char) *text) != UCSWIDE) {
+ do_text(ctx, x, y, text, len, attr, lattr);
+ return;
+ }
+ ctype = 2;
+ attr |= TATTR_RIGHTCURS;
+ }
+
+ fnt_width = char_width = font_width * (1 + (lattr != LATTR_NORM));
+ if (attr & ATTR_WIDE)
+ char_width *= 2;
+ x *= fnt_width;
+ y *= font_height;
+ x += offset_width;
+ y += offset_height;
+
+ if ((attr & TATTR_PASCURS) && (ctype == 0 || big_cursor)) {
+ POINT pts[5];
+ HPEN oldpen;
+ pts[0].x = pts[1].x = pts[4].x = x;
+ pts[2].x = pts[3].x = x + char_width - 1;
+ pts[0].y = pts[3].y = pts[4].y = y;
+ pts[1].y = pts[2].y = y + font_height - 1;
+ oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23]));
+ Polyline(hdc, pts, 5);
+ oldpen = SelectObject(hdc, oldpen);
+ DeleteObject(oldpen);
+ } else if ((attr & (TATTR_ACTCURS | TATTR_PASCURS)) && ctype != 0) {
+ int startx, starty, dx, dy, length, i;
+ if (ctype == 1) {
+ startx = x;
+ starty = y + descent;
+ dx = 1;
+ dy = 0;
+ length = char_width;
+ } else {
+ int xadjust = 0;
+ if (attr & TATTR_RIGHTCURS)
+ xadjust = char_width - 1;
+ startx = x + xadjust;
+ starty = y;
+ dx = 0;
+ dy = 1;
+ length = font_height;
+ }
+ if (attr & TATTR_ACTCURS) {
+ HPEN oldpen;
+ oldpen =
+ SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23]));
+ MoveToEx(hdc, startx, starty, NULL);
+ LineTo(hdc, startx + dx * length, starty + dy * length);
+ oldpen = SelectObject(hdc, oldpen);
+ DeleteObject(oldpen);
+ } else {
+ for (i = 0; i < length; i++) {
+ if (i % 2 == 0) {
+ SetPixel(hdc, startx, starty, colours[23]);
+ }
+ startx += dx;
+ starty += dy;
+ }
+ }
+ }
+}
+
+/* This function gets the actual width of a character in the normal font.
+ */
+int CharWidth(Context ctx, int uc) {
+ HDC hdc = ctx;
+ int ibuf = 0;
+
+ /* If the font max is the same as the font ave width then this
+ * function is a no-op.
+ */
+ if (!font_dualwidth) return 1;
+
+ switch (uc & CSET_MASK) {
+ case ATTR_ASCII:
+ uc = unitab_line[uc & 0xFF];
+ break;
+ case ATTR_LINEDRW:
+ uc = unitab_xterm[uc & 0xFF];
+ break;
+ case ATTR_SCOACS:
+ uc = unitab_scoacs[uc & 0xFF];
+ break;
+ }
+ if (DIRECT_FONT(uc)) {
+ if (dbcs_screenfont) return 1;
+
+ /* Speedup, I know of no font where ascii is the wrong width */
+ if ((uc&CHAR_MASK) >= ' ' && (uc&CHAR_MASK)<= '~')
+ return 1;
+
+ if ( (uc & CSET_MASK) == ATTR_ACP ) {
+ SelectObject(hdc, fonts[FONT_NORMAL]);
+ } else if ( (uc & CSET_MASK) == ATTR_OEMCP ) {
+ another_font(FONT_OEM);
+ if (!fonts[FONT_OEM]) return 0;
+
+ SelectObject(hdc, fonts[FONT_OEM]);
+ } else
+ return 0;
+
+ if ( GetCharWidth32(hdc, uc&CHAR_MASK, uc&CHAR_MASK, &ibuf) != 1 &&
+ GetCharWidth(hdc, uc&CHAR_MASK, uc&CHAR_MASK, &ibuf) != 1)
+ return 0;
+ } else {
+ /* Speedup, I know of no font where ascii is the wrong width */
+ if (uc >= ' ' && uc <= '~') return 1;
+
+ SelectObject(hdc, fonts[FONT_NORMAL]);
+ if ( GetCharWidth32W(hdc, uc, uc, &ibuf) == 1 )
+ /* Okay that one worked */ ;
+ else if ( GetCharWidthW(hdc, uc, uc, &ibuf) == 1 )
+ /* This should work on 9x too, but it's "less accurate" */ ;
+ else
+ return 0;
+ }
+
+ ibuf += font_width / 2 -1;
+ ibuf /= font_width;
+
+ return ibuf;
+}
+
+/*
+ * Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of ASCII
+ * codes. Returns number of bytes used or zero to drop the message
+ * or -1 to forward the message to windows.
+ */
+static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
+ unsigned char *output)
+{
+ BYTE keystate[256];
+ int scan, left_alt = 0, key_down, shift_state;
+ int r, i, code;
+ unsigned char *p = output;
+ static int alt_sum = 0;
+
+ HKL kbd_layout = GetKeyboardLayout(0);
+
+ static WORD keys[3];
+ static int compose_char = 0;
+ static WPARAM compose_key = 0;
+
+ r = GetKeyboardState(keystate);
+ if (!r)
+ memset(keystate, 0, sizeof(keystate));
+ else {
+#if 0
+#define SHOW_TOASCII_RESULT
+ { /* Tell us all about key events */
+ static BYTE oldstate[256];
+ static int first = 1;
+ static int scan;
+ int ch;
+ if (first)
+ memcpy(oldstate, keystate, sizeof(oldstate));
+ first = 0;
+
+ if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT) {
+ debug(("+"));
+ } else if ((HIWORD(lParam) & KF_UP)
+ && scan == (HIWORD(lParam) & 0xFF)) {
+ debug((". U"));
+ } else {
+ debug((".\n"));
+ if (wParam >= VK_F1 && wParam <= VK_F20)
+ debug(("K_F%d", wParam + 1 - VK_F1));
+ else
+ switch (wParam) {
+ case VK_SHIFT:
+ debug(("SHIFT"));
+ break;
+ case VK_CONTROL:
+ debug(("CTRL"));
+ break;
+ case VK_MENU:
+ debug(("ALT"));
+ break;
+ default:
+ debug(("VK_%02x", wParam));
+ }
+ if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
+ debug(("*"));
+ debug((", S%02x", scan = (HIWORD(lParam) & 0xFF)));
+
+ ch = MapVirtualKeyEx(wParam, 2, kbd_layout);
+ if (ch >= ' ' && ch <= '~')
+ debug((", '%c'", ch));
+ else if (ch)
+ debug((", $%02x", ch));
+
+ if (keys[0])
+ debug((", KB0=%02x", keys[0]));
+ if (keys[1])
+ debug((", KB1=%02x", keys[1]));
+ if (keys[2])
+ debug((", KB2=%02x", keys[2]));
+
+ if ((keystate[VK_SHIFT] & 0x80) != 0)
+ debug((", S"));
+ if ((keystate[VK_CONTROL] & 0x80) != 0)
+ debug((", C"));
+ if ((HIWORD(lParam) & KF_EXTENDED))
+ debug((", E"));
+ if ((HIWORD(lParam) & KF_UP))
+ debug((", U"));
+ }
+
+ if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT);
+ else if ((HIWORD(lParam) & KF_UP))
+ oldstate[wParam & 0xFF] ^= 0x80;
+ else
+ oldstate[wParam & 0xFF] ^= 0x81;
+
+ for (ch = 0; ch < 256; ch++)
+ if (oldstate[ch] != keystate[ch])
+ debug((", M%02x=%02x", ch, keystate[ch]));
+
+ memcpy(oldstate, keystate, sizeof(oldstate));
+ }
+#endif
+
+ if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) {
+ keystate[VK_RMENU] = keystate[VK_MENU];
+ }
+
+
+ /* Nastyness with NUMLock - Shift-NUMLock is left alone though */
+ if ((cfg.funky_type == 3 ||
+ (cfg.funky_type <= 1 && app_keypad_keys && !cfg.no_applic_k))
+ && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) {
+
+ wParam = VK_EXECUTE;
+
+ /* UnToggle NUMLock */
+ if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0)
+ keystate[VK_NUMLOCK] ^= 1;
+ }
+
+ /* And write back the 'adjusted' state */
+ SetKeyboardState(keystate);
+ }
+
+ /* Disable Auto repeat if required */
+ if (repeat_off && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT)
+ return 0;
+
+ if ((HIWORD(lParam) & KF_ALTDOWN) && (keystate[VK_RMENU] & 0x80) == 0)
+ left_alt = 1;
+
+ key_down = ((HIWORD(lParam) & KF_UP) == 0);
+
+ /* Make sure Ctrl-ALT is not the same as AltGr for ToAscii unless told. */
+ if (left_alt && (keystate[VK_CONTROL] & 0x80)) {
+ if (cfg.ctrlaltkeys)
+ keystate[VK_MENU] = 0;
+ else {
+ keystate[VK_RMENU] = 0x80;
+ left_alt = 0;
+ }
+ }
+
+ alt_pressed = (left_alt && key_down);
+
+ scan = (HIWORD(lParam) & (KF_UP | KF_EXTENDED | 0xFF));
+ shift_state = ((keystate[VK_SHIFT] & 0x80) != 0)
+ + ((keystate[VK_CONTROL] & 0x80) != 0) * 2;
+
+ /* Note if AltGr was pressed and if it was used as a compose key */
+ if (!compose_state) {
+ compose_key = 0x100;
+ if (cfg.compose_key) {
+ if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED))
+ compose_key = wParam;
+ }
+ if (wParam == VK_APPS)
+ compose_key = wParam;
+ }
+
+ if (wParam == compose_key) {
+ if (compose_state == 0
+ && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0) compose_state =
+ 1;
+ else if (compose_state == 1 && (HIWORD(lParam) & KF_UP))
+ compose_state = 2;
+ else
+ compose_state = 0;
+ } else if (compose_state == 1 && wParam != VK_CONTROL)
+ compose_state = 0;
+
+ /*
+ * Record that we pressed key so the scroll window can be reset, but
+ * be careful to avoid Shift-UP/Down
+ */
+ if (wParam != VK_SHIFT && wParam != VK_PRIOR && wParam != VK_NEXT) {
+ seen_key_event = 1;
+ }
+
+ /* Make sure we're not pasting */
+ if (key_down)
+ term_nopaste();
+
+ if (compose_state > 1 && left_alt)
+ compose_state = 0;
+
+ /* Sanitize the number pad if not using a PC NumPad */
+ if (left_alt || (app_keypad_keys && !cfg.no_applic_k
+ && cfg.funky_type != 2)
+ || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state) {
+ if ((HIWORD(lParam) & KF_EXTENDED) == 0) {
+ int nParam = 0;
+ switch (wParam) {
+ case VK_INSERT:
+ nParam = VK_NUMPAD0;
+ break;
+ case VK_END:
+ nParam = VK_NUMPAD1;
+ break;
+ case VK_DOWN:
+ nParam = VK_NUMPAD2;
+ break;
+ case VK_NEXT:
+ nParam = VK_NUMPAD3;
+ break;
+ case VK_LEFT:
+ nParam = VK_NUMPAD4;
+ break;
+ case VK_CLEAR:
+ nParam = VK_NUMPAD5;
+ break;
+ case VK_RIGHT:
+ nParam = VK_NUMPAD6;
+ break;
+ case VK_HOME:
+ nParam = VK_NUMPAD7;
+ break;
+ case VK_UP:
+ nParam = VK_NUMPAD8;
+ break;
+ case VK_PRIOR:
+ nParam = VK_NUMPAD9;
+ break;
+ case VK_DELETE:
+ nParam = VK_DECIMAL;
+ break;
+ }
+ if (nParam) {
+ if (keystate[VK_NUMLOCK] & 1)
+ shift_state |= 1;
+ wParam = nParam;
+ }
+ }
+ }
+
+ /* If a key is pressed and AltGr is not active */
+ if (key_down && (keystate[VK_RMENU] & 0x80) == 0 && !compose_state) {
+ /* Okay, prepare for most alts then ... */
+ if (left_alt)
+ *p++ = '\033';
+
+ /* Lets see if it's a pattern we know all about ... */
+ if (wParam == VK_PRIOR && shift_state == 1) {
+ SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
+ return 0;
+ }
+ if (wParam == VK_NEXT && shift_state == 1) {
+ SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
+ return 0;
+ }
+ if (wParam == VK_INSERT && shift_state == 1) {
+ term_do_paste();
+ return 0;
+ }
+ if (left_alt && wParam == VK_F4 && cfg.alt_f4) {
+ return -1;
+ }
+ if (left_alt && wParam == VK_SPACE && cfg.alt_space) {
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
+ return -1;
+ }
+ if (left_alt && wParam == VK_RETURN && cfg.fullscreenonaltenter) {
+ flip_full_screen();
+ return -1;
+ }
+ /* Control-Numlock for app-keypad mode switch */
+ if (wParam == VK_PAUSE && shift_state == 2) {
+ app_keypad_keys ^= 1;
+ return 0;
+ }
+
+ /* Nethack keypad */
+ if (cfg.nethack_keypad && !left_alt) {
+ switch (wParam) {
+ case VK_NUMPAD1:
+ *p++ = shift_state ? 'B' : 'b';
+ return p - output;
+ case VK_NUMPAD2:
+ *p++ = shift_state ? 'J' : 'j';
+ return p - output;
+ case VK_NUMPAD3:
+ *p++ = shift_state ? 'N' : 'n';
+ return p - output;
+ case VK_NUMPAD4:
+ *p++ = shift_state ? 'H' : 'h';
+ return p - output;
+ case VK_NUMPAD5:
+ *p++ = shift_state ? '.' : '.';
+ return p - output;
+ case VK_NUMPAD6:
+ *p++ = shift_state ? 'L' : 'l';
+ return p - output;
+ case VK_NUMPAD7:
+ *p++ = shift_state ? 'Y' : 'y';
+ return p - output;
+ case VK_NUMPAD8:
+ *p++ = shift_state ? 'K' : 'k';
+ return p - output;
+ case VK_NUMPAD9:
+ *p++ = shift_state ? 'U' : 'u';
+ return p - output;
+ }
+ }
+
+ /* Application Keypad */
+ if (!left_alt) {
+ int xkey = 0;
+
+ if (cfg.funky_type == 3 ||
+ (cfg.funky_type <= 1 &&
+ app_keypad_keys && !cfg.no_applic_k)) switch (wParam) {
+ case VK_EXECUTE:
+ xkey = 'P';
+ break;
+ case VK_DIVIDE:
+ xkey = 'Q';
+ break;
+ case VK_MULTIPLY:
+ xkey = 'R';
+ break;
+ case VK_SUBTRACT:
+ xkey = 'S';
+ break;
+ }
+ if (app_keypad_keys && !cfg.no_applic_k)
+ switch (wParam) {
+ case VK_NUMPAD0:
+ xkey = 'p';
+ break;
+ case VK_NUMPAD1:
+ xkey = 'q';
+ break;
+ case VK_NUMPAD2:
+ xkey = 'r';
+ break;
+ case VK_NUMPAD3:
+ xkey = 's';
+ break;
+ case VK_NUMPAD4:
+ xkey = 't';
+ break;
+ case VK_NUMPAD5:
+ xkey = 'u';
+ break;
+ case VK_NUMPAD6:
+ xkey = 'v';
+ break;
+ case VK_NUMPAD7:
+ xkey = 'w';
+ break;
+ case VK_NUMPAD8:
+ xkey = 'x';
+ break;
+ case VK_NUMPAD9:
+ xkey = 'y';
+ break;
+
+ case VK_DECIMAL:
+ xkey = 'n';
+ break;
+ case VK_ADD:
+ if (cfg.funky_type == 2) {
+ if (shift_state)
+ xkey = 'l';
+ else
+ xkey = 'k';
+ } else if (shift_state)
+ xkey = 'm';
+ else
+ xkey = 'l';
+ break;
+
+ case VK_DIVIDE:
+ if (cfg.funky_type == 2)
+ xkey = 'o';
+ break;
+ case VK_MULTIPLY:
+ if (cfg.funky_type == 2)
+ xkey = 'j';
+ break;
+ case VK_SUBTRACT:
+ if (cfg.funky_type == 2)
+ xkey = 'm';
+ break;
+
+ case VK_RETURN:
+ if (HIWORD(lParam) & KF_EXTENDED)
+ xkey = 'M';
+ break;
+ }
+ if (xkey) {
+ if (vt52_mode) {
+ if (xkey >= 'P' && xkey <= 'S')
+ p += sprintf((char *) p, "\x1B%c", xkey);
+ else
+ p += sprintf((char *) p, "\x1B?%c", xkey);
+ } else
+ p += sprintf((char *) p, "\x1BO%c", xkey);
+ return p - output;
+ }
+ }
+
+ if (wParam == VK_BACK && shift_state == 0) { /* Backspace */
+ *p++ = (cfg.bksp_is_delete ? 0x7F : 0x08);
+ *p++ = 0;
+ return -2;
+ }
+ if (wParam == VK_TAB && shift_state == 1) { /* Shift tab */
+ *p++ = 0x1B;
+ *p++ = '[';
+ *p++ = 'Z';
+ return p - output;
+ }
+ if (wParam == VK_SPACE && shift_state == 2) { /* Ctrl-Space */
+ *p++ = 0;
+ return p - output;
+ }
+ if (wParam == VK_SPACE && shift_state == 3) { /* Ctrl-Shift-Space */
+ *p++ = 160;
+ return p - output;
+ }
+ if (wParam == VK_CANCEL && shift_state == 2) { /* Ctrl-Break */
+ *p++ = 3;
+ *p++ = 0;
+ return -2;
+ }
+ if (wParam == VK_PAUSE) { /* Break/Pause */
+ *p++ = 26;
+ *p++ = 0;
+ return -2;
+ }
+ /* Control-2 to Control-8 are special */
+ if (shift_state == 2 && wParam >= '2' && wParam <= '8') {
+ *p++ = "\000\033\034\035\036\037\177"[wParam - '2'];
+ return p - output;
+ }
+ if (shift_state == 2 && wParam == 0xBD) {
+ *p++ = 0x1F;
+ return p - output;
+ }
+ if (shift_state == 2 && wParam == 0xDF) {
+ *p++ = 0x1C;
+ return p - output;
+ }
+ if (shift_state == 0 && wParam == VK_RETURN && cr_lf_return) {
+ *p++ = '\r';
+ *p++ = '\n';
+ return p - output;
+ }
+
+ /*
+ * Next, all the keys that do tilde codes. (ESC '[' nn '~',
+ * for integer decimal nn.)
+ *
+ * We also deal with the weird ones here. Linux VCs replace F1
+ * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but
+ * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w
+ * respectively.
+ */
+ code = 0;
+ switch (wParam) {
+ case VK_F1:
+ code = (keystate[VK_SHIFT] & 0x80 ? 23 : 11);
+ break;
+ case VK_F2:
+ code = (keystate[VK_SHIFT] & 0x80 ? 24 : 12);
+ break;
+ case VK_F3:
+ code = (keystate[VK_SHIFT] & 0x80 ? 25 : 13);
+ break;
+ case VK_F4:
+ code = (keystate[VK_SHIFT] & 0x80 ? 26 : 14);
+ break;
+ case VK_F5:
+ code = (keystate[VK_SHIFT] & 0x80 ? 28 : 15);
+ break;
+ case VK_F6:
+ code = (keystate[VK_SHIFT] & 0x80 ? 29 : 17);
+ break;
+ case VK_F7:
+ code = (keystate[VK_SHIFT] & 0x80 ? 31 : 18);
+ break;
+ case VK_F8:
+ code = (keystate[VK_SHIFT] & 0x80 ? 32 : 19);
+ break;
+ case VK_F9:
+ code = (keystate[VK_SHIFT] & 0x80 ? 33 : 20);
+ break;
+ case VK_F10:
+ code = (keystate[VK_SHIFT] & 0x80 ? 34 : 21);
+ break;
+ case VK_F11:
+ code = 23;
+ break;
+ case VK_F12:
+ code = 24;
+ break;
+ case VK_F13:
+ code = 25;
+ break;
+ case VK_F14:
+ code = 26;
+ break;
+ case VK_F15:
+ code = 28;
+ break;
+ case VK_F16:
+ code = 29;
+ break;
+ case VK_F17:
+ code = 31;
+ break;
+ case VK_F18:
+ code = 32;
+ break;
+ case VK_F19:
+ code = 33;
+ break;
+ case VK_F20:
+ code = 34;
+ break;
+ }
+ if ((shift_state&2) == 0) switch (wParam) {
+ case VK_HOME:
+ code = 1;
+ break;
+ case VK_INSERT:
+ code = 2;
+ break;
+ case VK_DELETE:
+ code = 3;
+ break;
+ case VK_END:
+ code = 4;
+ break;
+ case VK_PRIOR:
+ code = 5;
+ break;
+ case VK_NEXT:
+ code = 6;