Wez Furlong's patch to add xterm mouse reporting and proper mouse
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 6 May 2001 14:20:41 +0000 (14:20 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 6 May 2001 14:20:41 +0000 (14:20 +0000)
wheel support.

git-svn-id: svn://svn.tartarus.org/sgt/putty@1097 cda61777-01e9-0310-a592-d414129be87e

Makefile
putty.h
terminal.c
window.c

index 8380c5c..07135ff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -54,7 +54,7 @@
 # LFLAGS = /debug
 
 # Disable debug and incremental linking and compiling
-CFLAGS = /nologo /W3 /O1 /D_WINDOWS
+CFLAGS = /nologo /W3 /O1 /D_WINDOWS /D_WIN32_WINDOWS=0x401
 LFLAGS = /incremental:no /fixed
 
 # Use MSVC DLL
diff --git a/putty.h b/putty.h
index 06d5d50..0bca719 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -111,7 +111,10 @@ typedef enum {
 } Telnet_Special;
 
 typedef enum {
-    MB_NOTHING, MB_SELECT, MB_EXTEND, MB_PASTE
+    MBT_NOTHING,
+    MBT_LEFT, MBT_MIDDLE, MBT_RIGHT,   /* `raw' button designations */
+    MBT_SELECT, MBT_EXTEND, MBT_PASTE, /* `cooked' button designations */
+    MBT_WHEEL_UP, MBT_WHEEL_DOWN       /* mouse wheel */
 } Mouse_Button;
 
 typedef enum {
@@ -314,6 +317,8 @@ void palette_reset (void);
 void write_clip (void *, int, int);
 void get_clip (void **, int *);
 void optimised_move (int, int, int);
+void set_raw_mouse_mode(int);
+Mouse_Button translate_button(Mouse_Button b);
 void connection_fatal(char *, ...);
 void fatalbox (char *, ...);
 void beep (int);
@@ -368,7 +373,7 @@ void term_paint (Context, int, int, int, int);
 void term_scroll (int, int);
 void term_pwron (void);
 void term_clrsb (void);
-void term_mouse (Mouse_Button, Mouse_Action, int, int);
+void term_mouse (Mouse_Button, Mouse_Action, int, int, int, int);
 void term_deselect (void);
 void term_update (void);
 void term_invalidate(void);
index b5b79e9..c3a4e2c 100644 (file)
@@ -104,6 +104,8 @@ static int blink_is_real;          /* Actually blink blinking text */
 static int term_echoing;               /* Does terminal want local echo? */
 static int term_editing;               /* Does terminal want local edit? */
 
+static int xterm_mouse;                /* send mouse messages to app */
+
 static unsigned long cset_attr[2];
 
 /*
@@ -725,6 +727,7 @@ static void insch (int n) {
  */
 static void toggle_mode (int mode, int query, int state) {
     long ticks;
+
     if (query) switch (mode) {
       case 1:                         /* application cursor keys */
        app_cursor_keys = state;
@@ -782,6 +785,14 @@ static void toggle_mode (int mode, int query, int state) {
        swap_screen (state);
        disptop = 0;
        break;
+      case 1000:                      /* xterm mouse 1 */
+       xterm_mouse = state ? 1 : 0;
+       set_raw_mouse_mode(state);
+       break;
+      case 1002:                      /* xterm mouse 2 */
+       xterm_mouse = state ? 2: 0;
+       set_raw_mouse_mode(state);
+       break;
     } else switch (mode) {
       case 4:                         /* set insert mode */
        compatibility(VT102);
@@ -1259,6 +1270,12 @@ void term_out(void) {
                break;
              case 'a':      /* move right N cols */
                compatibility(ANSI);
+             case ANSI('c', '>'):      /* report xterm version */
+               compatibility(OTHER);
+               /* this reports xterm version 136 so that VIM can
+                use the drag messages from the mouse reporting */
+               ldisc_send("\033[>0;136;0c", 11);
+               break;
              case 'C':
                move (curs.x + def(esc_args[0], 1), curs.y, 1);
                seen_disp_event = TRUE;
@@ -2238,7 +2255,8 @@ static void sel_spread (void) {
     incpos(selend);
 }
 
-void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
+void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y,
+                int shift, int ctrl) {
     pos selpoint;
     unsigned long *ldata;
     
@@ -2259,12 +2277,64 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
     if ((ldata[cols]&LATTR_MODE) != LATTR_NORM)
        selpoint.x /= 2;
 
-    if (b == MB_SELECT && a == MA_CLICK) {
+    if (xterm_mouse) {
+       int encstate = 0, r, c;
+       char abuf[16];
+       static int is_down = 0;
+
+       switch(b) {
+         case MBT_LEFT:
+           encstate = 0x20;    /* left button down */
+           break;
+         case MBT_MIDDLE:
+           encstate = 0x21;
+           break;
+         case MBT_RIGHT:
+           encstate = 0x22;
+           break;
+         case MBT_WHEEL_UP:
+           encstate = 0x60;
+           break;
+         case MBT_WHEEL_DOWN:
+           encstate = 0x61;
+           break;
+       }
+       switch(a) {
+         case MA_DRAG:
+           if (xterm_mouse == 1)
+               return;
+           encstate += 0x20;
+           break;
+         case MA_RELEASE:
+           encstate = 0x23;
+           is_down = 0;
+           break;
+         case MA_CLICK:
+           if (is_down == b)
+               return;
+           is_down = b;
+           break;
+       }
+       if (shift)
+           encstate += 0x04;
+       if (ctrl)
+           encstate += 0x10;
+       r = y + 33;
+       c = x + 33;
+
+       sprintf(abuf, "\033[M%c%c%c", encstate, c, r);
+       ldisc_send(abuf, 6);
+       return;
+    }
+
+    b = translate_button(b);
+
+    if (b == MBT_SELECT && a == MA_CLICK) {
        deselect();
        selstate = ABOUT_TO;
        selanchor = selpoint;
        selmode = SM_CHAR;
-    } else if (b == MB_SELECT && (a == MA_2CLK || a == MA_3CLK)) {
+    } else if (b == MBT_SELECT && (a == MA_2CLK || a == MA_3CLK)) {
        deselect();
        selmode = (a == MA_2CLK ? SM_WORD : SM_LINE);
        selstate = DRAGGING;
@@ -2272,11 +2342,11 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
        selend = selstart;
        incpos(selend);
        sel_spread();
-    } else if ((b == MB_SELECT && a == MA_DRAG) ||
-              (b == MB_EXTEND && a != MA_RELEASE)) {
+    } else if ((b == MBT_SELECT && a == MA_DRAG) ||
+              (b == MBT_EXTEND && a != MA_RELEASE)) {
        if (selstate == ABOUT_TO && poseq(selanchor, selpoint))
            return;
-       if (b == MB_EXTEND && a != MA_DRAG && selstate == SELECTED) {
+       if (b == MBT_EXTEND && a != MA_DRAG && selstate == SELECTED) {
            if (posdiff(selpoint,selstart) < posdiff(selend,selstart)/2) {
                selanchor = selend;
                decpos(selanchor);
@@ -2298,7 +2368,7 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
            incpos(selend);
        }
        sel_spread();
-    } else if ((b == MB_SELECT || b == MB_EXTEND) && a == MA_RELEASE) {
+    } else if ((b == MBT_SELECT || b == MBT_EXTEND) && a == MA_RELEASE) {
        if (selstate == DRAGGING) {
            /*
             * We've completed a selection. We now transfer the
@@ -2308,7 +2378,7 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
            selstate = SELECTED;
        } else
            selstate = NO_SELECTION;
-    } else if (b == MB_PASTE && (a==MA_CLICK || a==MA_2CLK || a==MA_3CLK)) {
+    } else if (b == MBT_PASTE && (a==MA_CLICK || a==MA_2CLK || a==MA_3CLK)) {
        char *data;
        int len;
 
index 1805088..6f3eb49 100644 (file)
--- a/window.c
+++ b/window.c
@@ -103,6 +103,10 @@ static HBITMAP caretbm;
 static int dbltime, lasttime, lastact;
 static Mouse_Button lastbtn;
 
+/* this allows xterm-style mouse handling. */
+static int send_raw_mouse = 0;
+static int wheel_accumulator = 0;
+
 static char *window_name, *icon_name;
 
 static int compose_state = 0;
@@ -475,7 +479,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
      * Prepare the mouse handler.
      */
     lastact = MA_NOTHING;
-    lastbtn = MB_NOTHING;
+    lastbtn = MBT_NOTHING;
     dbltime = GetDoubleClickTime();
 
     /*
@@ -667,6 +671,15 @@ char *do_select(SOCKET skt, int startup) {
 }
 
 /*
+ * set or clear the "raw mouse message" mode
+ */
+void set_raw_mouse_mode(int activate)
+{
+    send_raw_mouse = activate;
+    SetCursor(LoadCursor(NULL, activate ? IDC_ARROW : IDC_IBEAM));
+}
+
+/*
  * Print a message box and close the connection.
  */
 void connection_fatal(char *fmt, ...) {
@@ -1047,9 +1060,14 @@ void request_resize (int w, int h, int refont) {
                  SWP_NOMOVE | SWP_NOZORDER);
 }
 
-static void click (Mouse_Button b, int x, int y) {
+static void click (Mouse_Button b, int x, int y, int shift, int ctrl) {
     int thistime = GetMessageTime();
 
+    if (send_raw_mouse) {
+       term_mouse(b, MA_CLICK, x, y, shift, ctrl);
+       return;
+    }
+
     if (lastbtn == b && thistime - lasttime < dbltime) {
        lastact = (lastact == MA_CLICK ? MA_2CLK :
                   lastact == MA_2CLK ? MA_3CLK :
@@ -1059,10 +1077,23 @@ static void click (Mouse_Button b, int x, int y) {
        lastact = MA_CLICK;
     }
     if (lastact != MA_NOTHING)
-       term_mouse (b, lastact, x, y);
+       term_mouse (b, lastact, x, y, shift, ctrl);
     lasttime = thistime;
 }
 
+/*
+ * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT)
+ * into a cooked one (SELECT, EXTEND, PASTE).
+ */
+Mouse_Button translate_button(Mouse_Button button) {
+    if (button == MBT_LEFT)
+       return MBT_SELECT;
+    if (button == MBT_MIDDLE)
+       return cfg.mouse_is_xterm ? MBT_PASTE : MBT_EXTEND;
+    if (button == MBT_RIGHT)
+       return cfg.mouse_is_xterm ? MBT_EXTEND : MBT_PASTE;
+}
+
 static void show_mouseptr(int show) {
     static int cursor_visible = 1;
     if (!cfg.hide_mouseptr)            /* override if this feature disabled */
@@ -1354,46 +1385,74 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
 
 #define TO_CHR_X(x) (((x)<0 ? (x)-font_width+1 : (x)) / font_width)
 #define TO_CHR_Y(y) (((y)<0 ? (y)-font_height+1: (y)) / 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);
+                   term_mouse(b,
+                              MA_RELEASE,
+                              TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)),
+                              wParam & MK_SHIFT, wParam & MK_CONTROL);
+               } else {
+                   /* trigger a scroll */
+                   term_scroll(0, b == MBT_WHEEL_UP ? -rows/2 : rows/2);
+               }
+           }
+           return 0;
+       }
       case WM_LBUTTONDOWN:
-        show_mouseptr(1);
-       click (MB_SELECT, TO_CHR_X(X_POS(lParam)),
-              TO_CHR_Y(Y_POS(lParam)));
-        SetCapture(hwnd);
-       return 0;
-      case WM_LBUTTONUP:
-        show_mouseptr(1);
-       term_mouse (MB_SELECT, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
-                   TO_CHR_Y(Y_POS(lParam)));
-        ReleaseCapture();
-       return 0;
       case WM_MBUTTONDOWN:
-        show_mouseptr(1);
-        SetCapture(hwnd);
-       click (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND,
-              TO_CHR_X(X_POS(lParam)),
-              TO_CHR_Y(Y_POS(lParam)));
-       return 0;
-      case WM_MBUTTONUP:
-        show_mouseptr(1);
-       term_mouse (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND,
-                   MA_RELEASE, TO_CHR_X(X_POS(lParam)),
-                   TO_CHR_Y(Y_POS(lParam)));
-        ReleaseCapture();
-       return 0;
       case WM_RBUTTONDOWN:
-        show_mouseptr(1);
-        SetCapture(hwnd);
-       click (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE,
-              TO_CHR_X(X_POS(lParam)),
-              TO_CHR_Y(Y_POS(lParam)));
-       return 0;
+      case WM_LBUTTONUP:
+      case WM_MBUTTONUP:
       case WM_RBUTTONUP:
-        show_mouseptr(1);
-       term_mouse (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE,
-                   MA_RELEASE, TO_CHR_X(X_POS(lParam)),
-                   TO_CHR_Y(Y_POS(lParam)));
-        ReleaseCapture();
+       {
+           int button, press;
+           switch (message) {
+             case WM_LBUTTONDOWN: button = MBT_LEFT;   press = 1; break;
+             case WM_MBUTTONDOWN: button = MBT_MIDDLE; press = 1; break;
+             case WM_RBUTTONDOWN: button = MBT_RIGHT;  press = 1; break;
+             case WM_LBUTTONUP:   button = MBT_LEFT;   press = 0; break;
+             case WM_MBUTTONUP:   button = MBT_MIDDLE; press = 0; break;
+             case WM_RBUTTONUP:   button = MBT_RIGHT;  press = 0; break;
+           }
+           show_mouseptr(1);
+           if (press) {
+               click (button,
+                      TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)),
+                      wParam & MK_SHIFT, wParam & MK_CONTROL);
+               SetCapture(hwnd);
+           } else {
+               term_mouse (button, MA_RELEASE,
+                           TO_CHR_X(X_POS(lParam)), TO_CHR_Y(Y_POS(lParam)),
+                           wParam & MK_SHIFT, wParam & MK_CONTROL);
+               ReleaseCapture();
+           }
+       }
        return 0;
       case WM_MOUSEMOVE:
         show_mouseptr(1);
@@ -1406,13 +1465,13 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
        if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {
            Mouse_Button b;
            if (wParam & MK_LBUTTON)
-               b = MB_SELECT;
+               b = MBT_SELECT;
            else if (wParam & MK_MBUTTON)
-               b = cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND;
+               b = cfg.mouse_is_xterm ? MBT_PASTE : MBT_EXTEND;
            else
-               b = cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE;
+               b = cfg.mouse_is_xterm ? MBT_EXTEND : MBT_PASTE;
            term_mouse (b, MA_DRAG, TO_CHR_X(X_POS(lParam)),
-                       TO_CHR_Y(Y_POS(lParam)));
+                       TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT, wParam & MK_CONTROL);
        }
        return 0;
       case WM_NCMOUSEMOVE:
@@ -1655,11 +1714,16 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
         * post the things to us as part of a macro manoeuvre,
         * we're ready to cope.
         */
-       {
-           char c = xlat_kbd2tty((unsigned char)wParam);
-           ldisc_send (&c, 1);
+               {
+                   char c = xlat_kbd2tty((unsigned char)wParam);
+                   ldisc_send (&c, 1);
        }
        return 0;
+               case WM_SETCURSOR:
+               if (send_raw_mouse) {
+                   SetCursor(LoadCursor(NULL, IDC_ARROW));
+                   return TRUE;
+               }
     }
 
     return DefWindowProc (hwnd, message, wParam, lParam);
@@ -2157,8 +2221,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
             return 0;
        }
         if (wParam == VK_INSERT && shift_state == 1) {
-            term_mouse (MB_PASTE, MA_CLICK, 0, 0);
-            term_mouse (MB_PASTE, MA_RELEASE, 0, 0);
+            term_mouse (MBT_PASTE, MA_CLICK, 0, 0, 0, 0);
+            term_mouse (MBT_PASTE, MA_RELEASE, 0, 0, 0, 0);
             return 0;
         }
        if (left_alt && wParam == VK_F4 && cfg.alt_f4) {