} 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 {
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);
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);
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];
/*
*/
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;
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);
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;
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;
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;
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);
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
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;
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;
* Prepare the mouse handler.
*/
lastact = MA_NOTHING;
- lastbtn = MB_NOTHING;
+ lastbtn = MBT_NOTHING;
dbltime = GetDoubleClickTime();
/*
return NULL;
}
+/*
+ * 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.
*/
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 :
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 */
#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);
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:
* 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);
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) {