From 01c034ad857128c51482a563befb374e38ebe668 Mon Sep 17 00:00:00 2001 From: simon Date: Sun, 6 May 2001 14:20:41 +0000 Subject: [PATCH] Wez Furlong's patch to add xterm mouse reporting and proper mouse wheel support. git-svn-id: svn://svn.tartarus.org/sgt/putty@1097 cda61777-01e9-0310-a592-d414129be87e --- Makefile | 2 +- putty.h | 9 +++- terminal.c | 86 +++++++++++++++++++++++++++++---- window.c | 158 +++++++++++++++++++++++++++++++++++++++++++------------------ 4 files changed, 197 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index 8380c5cf..07135ffd 100644 --- 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 06d5d509..0bca719c 100644 --- 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); diff --git a/terminal.c b/terminal.c index b5b79e91..c3a4e2cb 100644 --- a/terminal.c +++ b/terminal.c @@ -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; diff --git a/window.c b/window.c index 1805088a..6f3eb492 100644 --- 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) { -- 2.11.0