Robert de Bath's asynchronous-connect patch. Helps a lot in port
[u/mdw/putty] / window.c
index 37b3a00..378634f 100644 (file)
--- a/window.c
+++ b/window.c
 #define VK_PROCESSKEY 0xE5
 #endif
 
+/* Needed for mouse wheel support and not defined in earlier SDKs. */
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+
 static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                        unsigned char *output);
@@ -72,6 +77,7 @@ static int pending_netevent = 0;
 static WPARAM pend_netevent_wParam = 0;
 static LPARAM pend_netevent_lParam = 0;
 static void enact_pending_netevent(void);
+static void flash_window(int mode);
 
 static time_t last_movement = 0;
 
@@ -122,6 +128,8 @@ static char *window_name, *icon_name;
 
 static int compose_state = 0;
 
+static OSVERSIONINFO osVersion;
+
 /* Dummy routine, only required in plink. */
 void ldisc_update(int echo, int edit)
 {
@@ -160,6 +168,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
      * config box. */
     defuse_showwindow();
 
+    {
+       ZeroMemory(&osVersion, sizeof(osVersion));
+       osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+       if (!GetVersionEx ( (OSVERSIONINFO *) &osVersion)) {
+            MessageBox(NULL, "Windows refuses to report a version",
+                       "PuTTY Fatal Error", MB_OK | MB_ICONEXCLAMATION);
+           return 1;
+        }
+    }
+
     /*
      * Process the command line.
      */
@@ -297,6 +315,14 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
            }
        }
 
+       /*
+        * Trim leading whitespace off the hostname if it's there.
+        */
+       {
+           int space = strspn(cfg.host, " \t");
+           memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
+       }
+
        /* See if host is of the form user@host */
        if (cfg.host[0] != '\0') {
            char *atsign = strchr(cfg.host, '@');
@@ -560,6 +586,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
      * Finally show the window!
      */
     ShowWindow(hwnd, show);
+    SetForegroundWindow(hwnd);
 
     /*
      * Open the initial log file if there is one.
@@ -631,11 +658,14 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                term_out();
            term_update();
            ShowCaret(hwnd);
+
+           flash_window(1);           /* maintain */
+
            if (in_vbell)
                /* Hmm, term_update didn't want to do an update too soon ... */
                timer_id = SetTimer(hwnd, 1, 50, NULL);
            else if (!has_focus)
-               timer_id = SetTimer(hwnd, 1, 2000, NULL);
+               timer_id = SetTimer(hwnd, 1, 500, NULL);
            else
                timer_id = SetTimer(hwnd, 1, 100, NULL);
            long_timer = 1;
@@ -676,7 +706,8 @@ char *do_select(SOCKET skt, int startup)
     int msg, events;
     if (startup) {
        msg = WM_NETEVENT;
-       events = FD_READ | FD_WRITE | FD_OOB | FD_CLOSE;
+       events = (FD_CONNECT | FD_READ | FD_WRITE |
+                 FD_OOB | FD_CLOSE | FD_ACCEPT);
     } else {
        msg = events = 0;
     }
@@ -1099,7 +1130,8 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl)
 {
     int thistime = GetMessageTime();
 
-    if (send_raw_mouse) {
+    if (send_raw_mouse && !(cfg.mouse_override && shift)) {
+       lastbtn = MBT_NOTHING;
        term_mouse(b, MA_CLICK, x, y, shift, ctrl);
        return;
     }
@@ -1129,6 +1161,7 @@ Mouse_Button translate_button(Mouse_Button button)
        return cfg.mouse_is_xterm ? MBT_PASTE : MBT_EXTEND;
     if (button == MBT_RIGHT)
        return cfg.mouse_is_xterm ? MBT_EXTEND : MBT_PASTE;
+    return 0;                         /* shouldn't happen */
 }
 
 static void show_mouseptr(int show)
@@ -1461,6 +1494,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
          case IDM_ABOUT:
            showabout(hwnd);
            break;
+          case SC_KEYMENU:
+           /*
+            * We get this if the System menu has been activated.
+            * This might happen from within TranslateKey, in which
+            * case it really wants to be followed by a `space'
+            * character to actually _bring the menu up_ rather
+            * than just sitting there in `ready to appear' state.
+            */
+           if( lParam == 0 )
+               PostMessage(hwnd, WM_CHAR, ' ', 0);
+           break;
          default:
            if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {
                SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);
@@ -1544,6 +1588,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                button = MBT_RIGHT;
                press = 0;
                break;
+             default:
+               button = press = 0;    /* shouldn't happen */
            }
            show_mouseptr(1);
            if (press) {
@@ -1571,11 +1617,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {
            Mouse_Button b;
            if (wParam & MK_LBUTTON)
-               b = MBT_SELECT;
+               b = MBT_LEFT;
            else if (wParam & MK_MBUTTON)
-               b = cfg.mouse_is_xterm ? MBT_PASTE : MBT_EXTEND;
+               b = MBT_MIDDLE;
            else
-               b = cfg.mouse_is_xterm ? MBT_EXTEND : MBT_PASTE;
+               b = MBT_RIGHT;
            term_mouse(b, MA_DRAG, TO_CHR_X(X_POS(lParam)),
                       TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
                       wParam & MK_CONTROL);
@@ -1621,12 +1667,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        pending_netevent = TRUE;
        pend_netevent_wParam = wParam;
        pend_netevent_lParam = lParam;
+       if (WSAGETSELECTEVENT(lParam) != FD_READ)
+           enact_pending_netevent();
+
        time(&last_movement);
        return 0;
       case WM_SETFOCUS:
        has_focus = TRUE;
        CreateCaret(hwnd, caretbm, font_width, font_height);
        ShowCaret(hwnd);
+       flash_window(0);               /* stop */
        compose_state = 0;
        term_out();
        term_update();
@@ -1829,10 +1879,19 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                len = TranslateKey(message, wParam, lParam, buf);
                if (len == -1)
                    return DefWindowProc(hwnd, message, wParam, lParam);
-               ldisc_send(buf, len);
 
-               if (len > 0)
+               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;
@@ -1851,6 +1910,31 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            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];
@@ -1894,8 +1978,27 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
  */
 void sys_cursor(int x, int y)
 {
-    if (has_focus)
-       SetCaretPos(x * font_width, y * font_height);
+    COMPOSITIONFORM cf;
+    HIMC hIMC;
+
+    if (!has_focus) return;
+    
+    SetCaretPos(x * font_width, y * font_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);
 }
 
 /*
@@ -2206,7 +2309,6 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
     int scan, left_alt = 0, key_down, shift_state;
     int r, i, code;
     unsigned char *p = output;
-    static int alt_state = 0;
     static int alt_sum = 0;
 
     HKL kbd_layout = GetKeyboardLayout(0);
@@ -2440,16 +2542,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            return 0;
        }
        if (wParam == VK_INSERT && shift_state == 1) {
-           term_mouse(MBT_PASTE, MA_CLICK, 0, 0, 0, 0);
-           term_mouse(MBT_PASTE, MA_RELEASE, 0, 0, 0, 0);
+           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) {
-           alt_state = 0;
-           PostMessage(hwnd, WM_CHAR, ' ', 0);
            SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
            return -1;
        }
@@ -2709,6 +2808,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
          case VK_F20:
            code = 34;
            break;
+       }
+       if ((shift_state&2) == 0) switch (wParam) {
          case VK_HOME:
            code = 1;
            break;
@@ -2737,8 +2838,37 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            return p - output;
        }
 
-       if (cfg.funky_type == 5 && code >= 11 && code <= 24) {
-           p += sprintf((char *) p, "\x1B[%c", code + 'M' - 11);
+       if (cfg.funky_type == 5 &&     /* SCO function keys */
+           code >= 11 && code <= 34) {
+           char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
+           int index = 0;
+           switch (wParam) {
+             case VK_F1: index = 0; break;
+             case VK_F2: index = 1; break;
+             case VK_F3: index = 2; break;
+             case VK_F4: index = 3; break;
+             case VK_F5: index = 4; break;
+             case VK_F6: index = 5; break;
+             case VK_F7: index = 6; break;
+             case VK_F8: index = 7; break;
+             case VK_F9: index = 8; break;
+             case VK_F10: index = 9; break;
+             case VK_F11: index = 10; break;
+             case VK_F12: index = 11; break;
+           }
+           if (keystate[VK_SHIFT] & 0x80) index += 12;
+           if (keystate[VK_CONTROL] & 0x80) index += 24;
+           p += sprintf((char *) p, "\x1B[%c", codes[index]);
+           return p - output;
+       }
+       if (cfg.funky_type == 5 &&     /* SCO small keypad */
+           code >= 1 && code <= 6) {
+           char codes[] = "HL.FIG";
+           if (code == 3) {
+               *p++ = '\x7F';
+           } else {
+               p += sprintf((char *) p, "\x1B[%c", codes[code-1]);
+           }
            return p - output;
        }
        if ((vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) {
@@ -2843,7 +2973,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 #ifdef SHOW_TOASCII_RESULT
        if (r == 1 && !key_down) {
            if (alt_sum) {
-               if (utf || dbcs_screenfont)
+               if (in_utf || dbcs_screenfont)
                    debug((", (U+%04x)", alt_sum));
                else
                    debug((", LCH(%d)", alt_sum));
@@ -2887,11 +3017,20 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 
                if (!key_down) {
                    if (alt_sum) {
-                       if (utf || dbcs_screenfont) {
+                       if (in_utf || dbcs_screenfont) {
                            keybuf = alt_sum;
                            luni_send(&keybuf, 1);
                        } else {
                            ch = (char) alt_sum;
+                           /*
+                            * 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(&ch, 1);
                        }
                        alt_sum = 0;
@@ -2903,6 +3042,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                    lpage_send(kbd_codepage, cbuf + !left_alt,
                               1 + !!left_alt);
                }
+               show_mouseptr(0);
            }
 
            /* This is so the ALT-Numpad and dead keys work correctly. */
@@ -2914,23 +3054,19 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        if (!left_alt)
            keys[0] = 0;
        /* If we will be using alt_sum fix the 256s */
-       else if (keys[0] && (utf || dbcs_screenfont))
+       else if (keys[0] && (in_utf || dbcs_screenfont))
            keys[0] = 10;
     }
 
-    /* ALT alone may or may not want to bring up the System menu */
-    if (wParam == VK_MENU) {
-       if (cfg.alt_only) {
-           if (message == WM_SYSKEYDOWN)
-               alt_state = 1;
-           else if (message == WM_SYSKEYUP && alt_state)
-               PostMessage(hwnd, WM_CHAR, ' ', 0);
-           if (message == WM_SYSKEYUP)
-               alt_state = 0;
-       } else
-           return 0;
-    } else
-       alt_state = 0;
+    /*
+     * ALT alone may or may not want to bring up the System menu.
+     * If it's not meant to, we return 0 on presses or releases of
+     * ALT, to show that we've swallowed the keystroke. Otherwise
+     * we return -1, which means Windows will give the keystroke
+     * its default handling (i.e. bring up the System menu).
+     */
+    if (wParam == VK_MENU && !cfg.alt_only)
+       return 0;
 
     return -1;
 }
@@ -3142,7 +3278,7 @@ void get_clip(wchar_t ** p, int *len)
        clipdata = NULL;
        return;
     } else if (OpenClipboard(NULL)) {
-       if (clipdata = GetClipboardData(CF_UNICODETEXT)) {
+       if ((clipdata = GetClipboardData(CF_UNICODETEXT))) {
            CloseClipboard();
            *p = GlobalLock(clipdata);
            if (*p) {
@@ -3150,7 +3286,7 @@ void get_clip(wchar_t ** p, int *len)
                *len = p2 - *p;
                return;
            }
-       } else if (clipdata = GetClipboardData(CF_TEXT)) {
+       } else if ( (clipdata = GetClipboardData(CF_TEXT)) ) {
            char *s;
            int i;
            CloseClipboard();
@@ -3205,6 +3341,42 @@ void fatalbox(char *fmt, ...)
 }
 
 /*
+ * Manage window caption / taskbar flashing, if enabled.
+ * 0 = stop, 1 = maintain, 2 = start
+ */
+static void flash_window(int mode)
+{
+    static long last_flash = 0;
+    static int flashing = 0;
+    if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) {
+       /* stop */
+       if (flashing) {
+           FlashWindow(hwnd, FALSE);
+           flashing = 0;
+       }
+
+    } else if (mode == 2) {
+       /* start */
+       if (!flashing) {
+           last_flash = GetTickCount();
+           flashing = 1;
+           FlashWindow(hwnd, TRUE);
+       }
+
+    } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) {
+       /* maintain */
+       if (flashing) {
+           long now = GetTickCount();
+           long fdiff = now - last_flash;
+           if (fdiff < 0 || fdiff > 450) {
+               last_flash = now;
+               FlashWindow(hwnd, TRUE);        /* toggle */
+           }
+       }
+    }
+}
+
+/*
  * Beep.
  */
 void beep(int mode)
@@ -3238,4 +3410,8 @@ void beep(int mode)
            cfg.beep = BELL_DEFAULT;
        }
     }
+    /* Otherwise, either visual bell or disabled; do nothing here */
+    if (!has_focus) {
+       flash_window(2);               /* start */
+    }
 }