Add a new back-end function to return the exit code of the remote
[u/mdw/putty] / window.c
index 1b61b6c..5990101 100644 (file)
--- a/window.c
+++ b/window.c
 #define VK_PROCESSKEY 0xE5
 #endif
 
-/* Needed for mouse wheel support and not defined in earlier SDKs. */
+/* Mouse wheel support. */
 #ifndef WM_MOUSEWHEEL
-#define WM_MOUSEWHEEL 0x020A
+#define WM_MOUSEWHEEL 0x020A          /* not defined in earlier SDKs */
+#endif
+#ifndef WHEEL_DELTA
+#define WHEEL_DELTA 120
 #endif
 
 static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
@@ -81,6 +84,7 @@ static void init_fonts(int, int);
 static void another_font(int);
 static void deinit_fonts(void);
 static void set_input_locale(HKL);
+static int do_mouse_wheel_msg(UINT message, WPARAM wParam, LPARAM lParam);
 
 static int is_full_screen(void);
 static void make_full_screen(void);
@@ -100,9 +104,12 @@ 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 void sys_cursor_update(void);
 
 static time_t last_movement = 0;
 
+static int caret_x = -1, caret_y = -1;
+
 #define FONT_NORMAL 0
 #define FONT_BOLD 1
 #define FONT_UNDERLINE 2
@@ -152,6 +159,8 @@ static int compose_state = 0;
 
 static OSVERSIONINFO osVersion;
 
+static UINT wm_mousewheel = WM_MOUSEWHEEL;
+
 /* Dummy routine, only required in plink. */
 void ldisc_update(int echo, int edit)
 {
@@ -201,6 +210,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     }
 
     /*
+     * If we're running a version of Windows that doesn't support
+     * WM_MOUSEWHEEL, find out what message number we should be
+     * using instead.
+     */
+    if (osVersion.dwMajorVersion < 4 ||
+       (osVersion.dwMajorVersion == 4 && 
+        osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT))
+       wm_mousewheel = RegisterWindowMessage("MSWHEEL_ROLLMSG");
+
+    /*
      * See if we can find our Help file.
      */
     {
@@ -704,7 +723,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                timer_id = 0;
            }
            HideCaret(hwnd);
-           term_out();
+           if (GetCapture() != hwnd)
+               term_out();
            term_update();
            ShowCaret(hwnd);
 
@@ -1498,7 +1518,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
       case WM_TIMER:
        if (pending_netevent)
            enact_pending_netevent();
-       term_out();
+       if (GetCapture() != hwnd)
+           term_out();
        noise_regular();
        HideCaret(hwnd);
        term_update();
@@ -1846,45 +1867,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
 #define TO_CHR_X(x) ((((x)<0 ? (x)-font_width+1 : (x))-offset_width) / font_width)
 #define TO_CHR_Y(y) ((((y)<0 ? (y)-font_height+1: (y))-offset_height) / font_height)
-#define WHEEL_DELTA 120
-      case WM_MOUSEWHEEL:
-       {
-           wheel_accumulator += (short) HIWORD(wParam);
-           wParam = LOWORD(wParam);
-
-           /* process events when the threshold is reached */
-           while (abs(wheel_accumulator) >= WHEEL_DELTA) {
-               int b;
-
-               /* reduce amount for next time */
-               if (wheel_accumulator > 0) {
-                   b = MBT_WHEEL_UP;
-                   wheel_accumulator -= WHEEL_DELTA;
-               } else if (wheel_accumulator < 0) {
-                   b = MBT_WHEEL_DOWN;
-                   wheel_accumulator += WHEEL_DELTA;
-               } else
-                   break;
-
-               if (send_raw_mouse) {
-                   /* send a mouse-down followed by a mouse up */
-                   
-                   term_mouse(b,
-                              MA_CLICK,
-                              TO_CHR_X(X_POS(lParam)),
-                              TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
-                              wParam & MK_CONTROL, is_alt_pressed());
-                   term_mouse(b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
-                              TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
-                              wParam & MK_CONTROL, is_alt_pressed());
-               } else {
-                   /* trigger a scroll */
-                   term_scroll(0,
-                               b == MBT_WHEEL_UP ? -rows / 2 : rows / 2);
-               }
-           }
-           return 0;
-       }
       case WM_LBUTTONDOWN:
       case WM_MBUTTONDOWN:
       case WM_RBUTTONDOWN:
@@ -1957,7 +1939,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
         */
        noise_ultralight(lParam);
 
-       if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {
+       if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) &&
+           GetCapture() == hwnd) {
            Mouse_Button b;
            if (wParam & MK_LBUTTON)
                b = MBT_LEFT;
@@ -2062,6 +2045,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        show_mouseptr(1);
        has_focus = FALSE;
        DestroyCaret();
+       caret_x = caret_y = -1;        /* ensure caret is replaced next time */
        term_out();
        term_update();
        break;
@@ -2178,6 +2162,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
       case WM_FULLSCR_ON_MAX:
        fullscr_on_max = TRUE;
        break;
+      case WM_MOVE:
+       sys_cursor_update();
+       break;
       case WM_SIZE:
 #ifdef RDB_DEBUG_PATCH
        debug((27, "WM_SIZE %s (%d,%d)",
@@ -2261,6 +2248,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                    reset_window(0);
            }
        }
+       sys_cursor_update();
        return 0;
       case WM_VSCROLL:
        switch (LOWORD(wParam)) {
@@ -2370,6 +2358,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        /* wParam == Font number */
        /* lParam == Locale */
        set_input_locale((HKL)lParam);
+       sys_cursor_update();
        break;
       case WM_IME_NOTIFY:
        if(wParam == IMN_SETOPENSTATUS) {
@@ -2442,6 +2431,56 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            return TRUE;
        }
+      default:
+       if (message == wm_mousewheel) {
+           int shift_pressed=0, control_pressed=0, alt_pressed=0;
+
+           if (message == WM_MOUSEWHEEL) {
+               wheel_accumulator += (short)HIWORD(wParam);
+               shift_pressed=LOWORD(wParam) & MK_SHIFT;
+               control_pressed=LOWORD(wParam) & MK_CONTROL;
+           } else {
+               BYTE keys[256];
+               wheel_accumulator += (int)wParam;
+               if (GetKeyboardState(keys)!=0) {
+                   shift_pressed=keys[VK_SHIFT]&0x80;
+                   control_pressed=keys[VK_CONTROL]&0x80;
+               }
+           }
+
+           /* process events when the threshold is reached */
+           while (abs(wheel_accumulator) >= WHEEL_DELTA) {
+               int b;
+
+               /* reduce amount for next time */
+               if (wheel_accumulator > 0) {
+                   b = MBT_WHEEL_UP;
+                   wheel_accumulator -= WHEEL_DELTA;
+               } else if (wheel_accumulator < 0) {
+                   b = MBT_WHEEL_DOWN;
+                   wheel_accumulator += WHEEL_DELTA;
+               } else
+                   break;
+
+               if (send_raw_mouse &&
+                   !(cfg.mouse_override && shift_pressed)) {
+                   /* send a mouse-down followed by a mouse up */
+                   term_mouse(b,
+                              MA_CLICK,
+                              TO_CHR_X(X_POS(lParam)),
+                              TO_CHR_Y(Y_POS(lParam)), shift_pressed,
+                              control_pressed, is_alt_pressed());
+                   term_mouse(b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
+                              TO_CHR_Y(Y_POS(lParam)), shift_pressed,
+                              control_pressed, is_alt_pressed());
+               } else {
+                   /* trigger a scroll */
+                   term_scroll(0,
+                               b == MBT_WHEEL_UP ? -rows / 2 : rows / 2);
+               }
+           }
+           return 0;
+       }
     }
 
     return DefWindowProc(hwnd, message, wParam, lParam);
@@ -2455,13 +2494,35 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
  */
 void sys_cursor(int x, int y)
 {
+    int cx, cy;
+
+    if (!has_focus) return;
+
+    /*
+     * Avoid gratuitously re-updating the cursor position and IMM
+     * window if there's no actual change required.
+     */
+    cx = x * font_width + offset_width;
+    cy = y * font_height + offset_height;
+    if (cx == caret_x && cy == caret_y)
+       return;
+    caret_x = cx;
+    caret_y = cy;
+
+    sys_cursor_update();
+}
+
+static void sys_cursor_update(void)
+{
     COMPOSITIONFORM cf;
     HIMC hIMC;
 
     if (!has_focus) return;
-    
-    SetCaretPos(x * font_width + offset_width,
-               y * font_height + offset_height);
+
+    if (caret_x < 0 || caret_y < 0)
+       return;
+
+    SetCaretPos(caret_x, caret_y);
 
     /* IMM calls on Win98 and beyond only */
     if(osVersion.dwPlatformId == VER_PLATFORM_WIN32s) return; /* 3.11 */
@@ -2472,8 +2533,8 @@ void sys_cursor(int x, int y)
     /* we should have the IMM functions */
     hIMC = ImmGetContext(hwnd);
     cf.dwStyle = CFS_POINT;
-    cf.ptCurrentPos.x = x * font_width + offset_width;
-    cf.ptCurrentPos.y = y * font_height + offset_height;
+    cf.ptCurrentPos.x = caret_x;
+    cf.ptCurrentPos.y = caret_y;
     ImmSetCompositionWindow(hIMC, &cf);
 
     ImmReleaseContext(hwnd, hIMC);