diff --git a/putty.h b/putty.h index 0ee3a7b6..e413552c 100644 --- a/putty.h +++ b/putty.h @@ -363,7 +363,8 @@ typedef enum { 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 */ + MBT_WHEEL_UP, MBT_WHEEL_DOWN, /* vertical mouse wheel */ + MBT_WHEEL_LEFT, MBT_WHEEL_RIGHT /* horizontal mouse wheel */ } Mouse_Button; typedef enum { diff --git a/terminal/terminal.c b/terminal/terminal.c index e4063b66..34a8b2f2 100644 --- a/terminal/terminal.c +++ b/terminal/terminal.c @@ -7223,6 +7223,14 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, encstate = 0x41; wheel = true; break; + case MBT_WHEEL_LEFT: + encstate = 0x42; + wheel = true; + break; + case MBT_WHEEL_RIGHT: + encstate = 0x43; + wheel = true; + break; case MBT_NOTHING: assert( a == MA_MOVE ); encstate = 0x03; // release; no buttons pressed diff --git a/unix/window.c b/unix/window.c index dbb0ec69..934311f2 100644 --- a/unix/window.c +++ b/unix/window.c @@ -169,7 +169,7 @@ struct GtkFrontend { guint32 input_event_time; /* Timestamp of the most recent input event. */ GtkWidget *dialogs[DIALOG_SLOT_LIMIT]; #if GTK_CHECK_VERSION(3,4,0) - gdouble cumulative_scroll; + gdouble cumulative_hscroll, cumulative_vscroll; #endif /* Cached things out of conf that we refer to a lot */ int bold_style; @@ -2111,8 +2111,8 @@ void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data) #define SCROLL_INCREMENT_LINES 5 #if GTK_CHECK_VERSION(3,4,0) -gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, - gdouble ex, gdouble ey) +gboolean scroll_internal(GtkFrontend *inst, gdouble xdelta, gdouble ydelta, + guint state, gdouble ex, gdouble ey) { int x, y; bool shift, ctrl, alt, raw_mouse_mode; @@ -2130,22 +2130,22 @@ gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, !(shift && conf_get_bool(inst->conf, CONF_mouse_override))); - inst->cumulative_scroll += delta * SCROLL_INCREMENT_LINES; + inst->cumulative_vscroll += ydelta * SCROLL_INCREMENT_LINES; if (!raw_mouse_mode) { - int scroll_lines = (int)inst->cumulative_scroll; /* rounds toward 0 */ + int scroll_lines = (int)inst->cumulative_vscroll; /* rounds toward 0 */ if (scroll_lines) { term_scroll(inst->term, 0, scroll_lines); - inst->cumulative_scroll -= scroll_lines; + inst->cumulative_vscroll -= scroll_lines; } return true; } else { - int scroll_events = (int)(inst->cumulative_scroll / + int scroll_events = (int)(inst->cumulative_vscroll / SCROLL_INCREMENT_LINES); if (scroll_events) { int button; - inst->cumulative_scroll -= scroll_events * SCROLL_INCREMENT_LINES; + inst->cumulative_vscroll -= scroll_events * SCROLL_INCREMENT_LINES; if (scroll_events > 0) { button = MBT_WHEEL_DOWN; @@ -2159,6 +2159,35 @@ gboolean scroll_internal(GtkFrontend *inst, gdouble delta, guint state, MA_CLICK, x, y, shift, ctrl, alt); } } + + /* + * Now do the same for horizontal scrolling. But because we + * _only_ use that for passing through to mouse reporting, we + * don't even collect the scroll deltas while not in + * raw_mouse_mode. (Otherwise there would likely be a huge + * unexpected lurch when raw_mouse_mode was enabled!) + */ + inst->cumulative_hscroll += xdelta * SCROLL_INCREMENT_LINES; + scroll_events = (int)(inst->cumulative_hscroll / + SCROLL_INCREMENT_LINES); + if (scroll_events) { + int button; + + inst->cumulative_hscroll -= scroll_events * SCROLL_INCREMENT_LINES; + + if (scroll_events > 0) { + button = MBT_WHEEL_RIGHT; + } else { + button = MBT_WHEEL_LEFT; + scroll_events = -scroll_events; + } + + while (scroll_events-- > 0) { + term_mouse(inst->term, button, translate_button(button), + MA_CLICK, x, y, shift, ctrl, alt); + } + } + return true; } } @@ -2260,7 +2289,7 @@ gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) #if GTK_CHECK_VERSION(3,4,0) gdouble dx, dy; if (gdk_event_get_scroll_deltas((GdkEvent *)event, &dx, &dy)) { - return scroll_internal(inst, dy, event->state, event->x, event->y); + return scroll_internal(inst, dx, dy, event->state, event->x, event->y); } else if (!gdk_event_get_scroll_direction((GdkEvent *)event, &dir)) { return false; } @@ -5276,7 +5305,8 @@ void new_session_window(Conf *conf, const char *geometry_string) inst->wintitle = inst->icontitle = NULL; inst->drawtype = DRAWTYPE_DEFAULT; #if GTK_CHECK_VERSION(3,4,0) - inst->cumulative_scroll = 0.0; + inst->cumulative_vscroll = 0.0; + inst->cumulative_hscroll = 0.0; #endif inst->drawing_area_setup_needed = true; diff --git a/windows/window.c b/windows/window.c index 63cc58ed..e59bebce 100644 --- a/windows/window.c +++ b/windows/window.c @@ -74,6 +74,9 @@ #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL 0x020A /* not defined in earlier SDKs */ #endif +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E /* not defined in earlier SDKs */ +#endif #ifndef WHEEL_DELTA #define WHEEL_DELTA 120 #endif @@ -3403,10 +3406,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, process_clipdata((HGLOBAL)lParam, wParam); return 0; default: - if (message == wm_mousewheel || message == WM_MOUSEWHEEL) { + if (message == wm_mousewheel || message == WM_MOUSEWHEEL + || message == WM_MOUSEHWHEEL) { bool shift_pressed = false, control_pressed = false; - if (message == WM_MOUSEWHEEL) { + if (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL) { wheel_accumulator += (short)HIWORD(wParam); shift_pressed=LOWORD(wParam) & MK_SHIFT; control_pressed=LOWORD(wParam) & MK_CONTROL; @@ -3425,10 +3429,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, /* reduce amount for next time */ if (wheel_accumulator > 0) { - b = MBT_WHEEL_UP; + b = message == WM_MOUSEHWHEEL ? MBT_WHEEL_RIGHT : MBT_WHEEL_UP; wheel_accumulator -= WHEEL_DELTA; } else if (wheel_accumulator < 0) { - b = MBT_WHEEL_DOWN; + b = message == WM_MOUSEHWHEEL ? MBT_WHEEL_LEFT : MBT_WHEEL_DOWN; wheel_accumulator += WHEEL_DELTA; } else break; @@ -3448,7 +3452,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, TO_CHR_Y(p.y), shift_pressed, control_pressed, is_alt_pressed()); } /* else: not sure when this can fail */ - } else { + } else if (message != WM_MOUSEHWHEEL) { /* trigger a scroll */ term_scroll(term, 0, b == MBT_WHEEL_UP ?