diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 39d1be93135..2900bf1a6cf 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -260,7 +260,7 @@ typedef enum { /** Mouse button up event. */ GHOST_kEventButtonUp, /** - * Mouse wheel event. + * Vertical/Horizontal mouse wheel event. * * \note #GHOST_GetEventData returns #GHOST_TEventWheelData. */ @@ -577,9 +577,16 @@ typedef struct { GHOST_TabletData tablet; } GHOST_TEventButtonData; +typedef enum { + GHOST_kEventWheelAxisVertical = 0, + GHOST_kEventWheelAxisHorizontal = 1, +} GHOST_TEventWheelAxis; + typedef struct { + /** Which mouse wheel is used. */ + GHOST_TEventWheelAxis axis; /** Displacement of a mouse wheel. */ - int32_t z; + int32_t value; } GHOST_TEventWheelData; typedef enum { diff --git a/intern/ghost/intern/GHOST_EventPrinter.cc b/intern/ghost/intern/GHOST_EventPrinter.cc index 3aa517deab4..f7de68cd84a 100644 --- a/intern/ghost/intern/GHOST_EventPrinter.cc +++ b/intern/ghost/intern/GHOST_EventPrinter.cc @@ -80,7 +80,9 @@ bool GHOST_EventPrinter::processEvent(const GHOST_IEvent *event) } case GHOST_kEventWheel: { const GHOST_TEventWheelData *wheelData = static_cast(data); - std::cout << "GHOST_kEventWheel, z: " << wheelData->z; + std::cout << "GHOST_kEventWheel, axis: " + << (wheelData->axis == GHOST_kEventWheelAxisVertical ? "vertical" : "horizontal") + << ", value: " << wheelData->value; handled = true; break; } diff --git a/intern/ghost/intern/GHOST_EventWheel.hh b/intern/ghost/intern/GHOST_EventWheel.hh index 680f397f01f..c0a2f802535 100644 --- a/intern/ghost/intern/GHOST_EventWheel.hh +++ b/intern/ghost/intern/GHOST_EventWheel.hh @@ -22,16 +22,17 @@ class GHOST_EventWheel : public GHOST_Event { * Constructor. * \param msec: The time this event was generated. * \param window: The window of this event. - * \param z: The displacement of the mouse wheel. + * \param axis: The axis of the mouse wheel. + * \param value: The displacement of the mouse wheel. */ - GHOST_EventWheel(uint64_t msec, GHOST_IWindow *window, int32_t z) + GHOST_EventWheel(uint64_t msec, GHOST_IWindow *window, GHOST_TEventWheelAxis axis, int32_t value) : GHOST_Event(msec, GHOST_kEventWheel, window) { - m_wheelEventData.z = z; + m_wheelEventData.axis = axis; + m_wheelEventData.value = value; m_data = &m_wheelEventData; } protected: - /** The z-displacement of the mouse wheel. */ GHOST_TEventWheelData m_wheelEventData; }; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 0c496686ddd..ef3444e92be 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -1743,17 +1743,16 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) /* Standard scroll-wheel case, if no swiping happened, * and no momentum (kinetic scroll) works. */ if (!m_multiTouchScroll && momentumPhase == NSEventPhaseNone) { - double deltaF = event.deltaY; - - if (deltaF == 0.0) { - deltaF = event.deltaX; /* Make blender decide if it's horizontal scroll. */ + if (event.deltaX != 0.0) { + const int32_t delta = event.deltaX > 0.0 ? 1 : -1; + pushEvent(new GHOST_EventWheel( + event.timestamp * 1000, window, GHOST_kEventWheelAxisHorizontal, delta)); } - if (deltaF == 0.0) { - break; /* Discard trackpad delta=0 events. */ + if (event.deltaY != 0.0) { + const int32_t delta = event.deltaY > 0.0 ? 1 : -1; + pushEvent(new GHOST_EventWheel( + event.timestamp * 1000, window, GHOST_kEventWheelAxisVertical, delta)); } - - const int32_t delta = deltaF > 0.0 ? 1 : -1; - pushEvent(new GHOST_EventWheel(event.timestamp * 1000, window, delta)); } else { const NSPoint mousePos = event.locationInWindow; diff --git a/intern/ghost/intern/GHOST_SystemSDL.cc b/intern/ghost/intern/GHOST_SystemSDL.cc index 17bdc6bf67e..021fdfda556 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cc +++ b/intern/ghost/intern/GHOST_SystemSDL.cc @@ -605,7 +605,8 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event) GHOST_WindowSDL *window = findGhostWindow( SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID)); assert(window != nullptr); - g_event = new GHOST_EventWheel(event_ms, window, sdl_sub_evt.y); + g_event = new GHOST_EventWheel( + event_ms, window, GHOST_kEventWheelAxisVertical, sdl_sub_evt.y); break; } case SDL_KEYDOWN: diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index 7ecba893ce0..e9f7d5edd7e 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -4110,13 +4110,19 @@ static void pointer_handle_frame(void *data, wl_pointer * /*wl_pointer*/) } /* Done evaluating scroll input, generate the events. */ - - /* Discrete X axis currently unsupported. */ if (ps.discrete_xy[0] || ps.discrete_xy[1]) { + if (ps.discrete_xy[0]) { + seat->system->pushEvent_maybe_pending(new GHOST_EventWheel( + ps.has_event_ms ? ps.event_ms : seat->system->getMilliSeconds(), + win, + GHOST_kEventWheelAxisHorizontal, + ps.discrete_xy[0])); + } if (ps.discrete_xy[1]) { seat->system->pushEvent_maybe_pending(new GHOST_EventWheel( ps.has_event_ms ? ps.event_ms : seat->system->getMilliSeconds(), win, + GHOST_kEventWheelAxisVertical, -ps.discrete_xy[1])); } ps.discrete_xy[0] = 0; @@ -4949,7 +4955,10 @@ static void tablet_tool_handle_frame(void *data, } case GWL_TabletTool_EventTypes::Wheel: { seat->system->pushEvent_maybe_pending( - new GHOST_EventWheel(event_ms, win, -tablet_tool->frame_pending.wheel.clicks)); + new GHOST_EventWheel(event_ms, + win, + GHOST_kEventWheelAxisVertical, + -tablet_tool->frame_pending.wheel.clicks)); break; } } diff --git a/intern/ghost/intern/GHOST_SystemWin32.cc b/intern/ghost/intern/GHOST_SystemWin32.cc index f15aff4ba9e..c4d7c77f747 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cc +++ b/intern/ghost/intern/GHOST_SystemWin32.cc @@ -1217,13 +1217,13 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind GHOST_TABLET_DATA_NONE); } -void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, - WPARAM wParam, - LPARAM /*lParam*/) +void GHOST_SystemWin32::processWheelEventVertical(GHOST_WindowWin32 *window, + WPARAM wParam, + LPARAM /*lParam*/) { GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - int acc = system->m_wheelDeltaAccum; + int acc = system->m_wheelDeltaAccumVertical; int delta = GET_WHEEL_DELTA_WPARAM(wParam); if (acc * delta < 0) { @@ -1235,10 +1235,37 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, acc = abs(acc); while (acc >= WHEEL_DELTA) { - system->pushEvent(new GHOST_EventWheel(getMessageTime(system), window, direction)); + system->pushEvent(new GHOST_EventWheel( + getMessageTime(system), window, GHOST_kEventWheelAxisVertical, direction)); acc -= WHEEL_DELTA; } - system->m_wheelDeltaAccum = acc * direction; + system->m_wheelDeltaAccumVertical = acc * direction; +} + +/** This is almost the same as #processWheelEventVertical. */ +void GHOST_SystemWin32::processWheelEventHorizontal(GHOST_WindowWin32 *window, + WPARAM wParam, + LPARAM /*lParam*/) +{ + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); + + int acc = system->m_wheelDeltaAccumHorizontal; + int delta = GET_WHEEL_DELTA_WPARAM(wParam); + + if (acc * delta < 0) { + /* Scroll direction reversed. */ + acc = 0; + } + acc += delta; + int direction = (acc >= 0) ? 1 : -1; + acc = abs(acc); + + while (acc >= WHEEL_DELTA) { + system->pushEvent(new GHOST_EventWheel( + getMessageTime(system), window, GHOST_kEventWheelAxisHorizontal, direction)); + acc -= WHEEL_DELTA; + } + system->m_wheelDeltaAccumHorizontal = acc * direction; } GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RAWINPUT const &raw) @@ -1994,13 +2021,18 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, * since DefWindowProc propagates it up the parent chain * until it finds a window that processes it. */ - processWheelEvent(window, wParam, lParam); + processWheelEventVertical(window, wParam, lParam); eventHandled = true; #ifdef BROKEN_PEEK_TOUCHPAD PostMessage(hwnd, WM_USER, 0, 0); #endif break; } + case WM_MOUSEHWHEEL: { + processWheelEventHorizontal(window, wParam, lParam); + eventHandled = true; + break; + } case WM_SETCURSOR: { /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor * to move within a window and mouse input is not captured. @@ -2072,7 +2104,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, * If the windows use different input queues, the message is sent asynchronously, * so the window is activated immediately. */ - system->m_wheelDeltaAccum = 0; + system->m_wheelDeltaAccumVertical = 0; + system->m_wheelDeltaAccumHorizontal = 0; event = processWindowEvent( LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window); /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL diff --git a/intern/ghost/intern/GHOST_SystemWin32.hh b/intern/ghost/intern/GHOST_SystemWin32.hh index 923d86d3def..1845f89daaa 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.hh +++ b/intern/ghost/intern/GHOST_SystemWin32.hh @@ -369,12 +369,20 @@ class GHOST_SystemWin32 : public GHOST_System { const int32_t screen_co[2]); /** - * Handles a mouse wheel event. + * Handles a vertical mouse wheel event. * \param window: The window receiving the event (the active window). * \param wParam: The wParam from the `wndproc`. * \param lParam: The lParam from the `wndproc`. */ - static void processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam); + static void processWheelEventVertical(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam); + + /** + * Handles a horizontal mouse wheel event. + * \param window: The window receiving the event (the active window). + * \param wParam: The wParam from the `wndproc`. + * \param lParam: The lParam from the `wndproc`. + */ + static void processWheelEventHorizontal(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam); /** * Creates a key event and updates the key data stored locally (m_modifierKeys). @@ -479,8 +487,9 @@ class GHOST_SystemWin32 : public GHOST_System { /** Console status. */ bool m_consoleStatus; - /** Wheel delta accumulator. */ - int m_wheelDeltaAccum; + /** Wheel delta accumulators. */ + int m_wheelDeltaAccumVertical; + int m_wheelDeltaAccumHorizontal; }; inline void GHOST_SystemWin32::handleKeyboardChange() diff --git a/intern/ghost/intern/GHOST_SystemX11.cc b/intern/ghost/intern/GHOST_SystemX11.cc index cd08c6eec40..7d6b072d2cf 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cc +++ b/intern/ghost/intern/GHOST_SystemX11.cc @@ -1268,13 +1268,13 @@ void GHOST_SystemX11::processEvent(XEvent *xe) /* process wheel mouse events and break, only pass on press events */ if (xbe.button == Button4) { if (xbe.type == ButtonPress) { - g_event = new GHOST_EventWheel(event_ms, window, 1); + g_event = new GHOST_EventWheel(event_ms, window, GHOST_kEventWheelAxisVertical, 1); } break; } if (xbe.button == Button5) { if (xbe.type == ButtonPress) { - g_event = new GHOST_EventWheel(event_ms, window, -1); + g_event = new GHOST_EventWheel(event_ms, window, GHOST_kEventWheelAxisVertical, -1); } break; } diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c index 1ec4cbede5e..eefd1d65f96 100644 --- a/intern/ghost/test/gears/GHOST_C-Test.c +++ b/intern/ghost/test/gears/GHOST_C-Test.c @@ -289,7 +289,7 @@ bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData) #endif case GHOST_kEventWheel: { wheelData = (GHOST_TEventWheelData *)GHOST_GetEventData(hEvent); - if (wheelData->z > 0) { + if (wheelData->value > 0) { view_rotz += 5.f; } else { diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp index 0ea87408360..a6b5184fe2d 100644 --- a/intern/ghost/test/gears/GHOST_Test.cpp +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -459,7 +459,7 @@ bool Application::processEvent(const GHOST_IEvent *event) #endif case GHOST_kEventWheel: { GHOST_TEventWheelData *wheelData = (GHOST_TEventWheelData *)event->getData(); - if (wheelData->z > 0) { + if (wheelData->value > 0) { view_rotz += 5.f; } else { diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index ac28f8d05ae..d06ac87c214 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -939,7 +939,9 @@ def km_view2d(_params): ("view2d.pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None), ("view2d.pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None), ("view2d.scroll_right", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("view2d.scroll_right", {"type": 'WHEELRIGHTMOUSE', "value": 'PRESS'}, None), ("view2d.scroll_left", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("view2d.scroll_left", {"type": 'WHEELLEFTMOUSE', "value": 'PRESS'}, None), ("view2d.scroll_down", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None), ("view2d.scroll_up", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None), ("view2d.ndof", {"type": 'NDOF_MOTION', "value": 'ANY'}, None), diff --git a/source/blender/makesrna/intern/rna_wm.cc b/source/blender/makesrna/intern/rna_wm.cc index f38c9ef78dd..bb100496e29 100644 --- a/source/blender/makesrna/intern/rna_wm.cc +++ b/source/blender/makesrna/intern/rna_wm.cc @@ -71,6 +71,8 @@ static const EnumPropertyItem event_mouse_type_items[] = { {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, CTX_N_(BLT_I18NCONTEXT_UI_EVENTS, "Wheel Down"), ""}, {WHEELINMOUSE, "WHEELINMOUSE", 0, CTX_N_(BLT_I18NCONTEXT_UI_EVENTS, "Wheel In"), ""}, {WHEELOUTMOUSE, "WHEELOUTMOUSE", 0, CTX_N_(BLT_I18NCONTEXT_UI_EVENTS, "Wheel Out"), ""}, + {WHEELLEFTMOUSE, "WHEELLEFTMOUSE", 0, CTX_N_(BLT_I18NCONTEXT_UI_EVENTS, "Wheel Left"), ""}, + {WHEELRIGHTMOUSE, "WHEELRIGHTMOUSE", 0, CTX_N_(BLT_I18NCONTEXT_UI_EVENTS, "Wheel Right"), ""}, {0, nullptr, 0, nullptr, nullptr}, }; @@ -236,6 +238,8 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", "WhDown"}, {WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", "WhIn"}, {WHEELOUTMOUSE, "WHEELOUTMOUSE", 0, "Wheel Out", "WhOut"}, + {WHEELLEFTMOUSE, "WHEELLEFTMOUSE", 0, "Wheel Left", "WhLeft"}, + {WHEELRIGHTMOUSE, "WHEELRIGHTMOUSE", 0, "Wheel Right", "WhRight"}, RNA_ENUM_ITEM_SEPR, {EVT_AKEY, "A", 0, "A", ""}, {EVT_BKEY, "B", 0, "B", ""}, diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 5a947fa5b69..90952c1ad9e 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -6257,13 +6257,25 @@ void wm_event_add_ghostevent(wmWindowManager *wm, customdata); int click_step; - if (wheelData->z > 0) { - event.type = WHEELUPMOUSE; - click_step = wheelData->z; + if (wheelData->axis == GHOST_kEventWheelAxisVertical) { + if (wheelData->value > 0) { + event.type = WHEELUPMOUSE; + click_step = wheelData->value; + } + else { + event.type = WHEELDOWNMOUSE; + click_step = -wheelData->value; + } } else { - event.type = WHEELDOWNMOUSE; - click_step = -wheelData->z; + if (wheelData->value > 0) { + event.type = WHEELRIGHTMOUSE; + click_step = wheelData->value; + } + else { + event.type = WHEELLEFTMOUSE; + click_step = -wheelData->value; + } } BLI_assert(click_step != 0); diff --git a/source/blender/windowmanager/wm_event_types.hh b/source/blender/windowmanager/wm_event_types.hh index cab34ba4bda..bc4a29669ed 100644 --- a/source/blender/windowmanager/wm_event_types.hh +++ b/source/blender/windowmanager/wm_event_types.hh @@ -76,16 +76,20 @@ enum wmEventType : int16_t { * ignore all but the most recent MOUSEMOVE (for better performance), * paint and drawing tools however will want to handle these. */ INBETWEEN_MOUSEMOVE = 0x0011, + /* Horizontal scrolling events. */ + WHEELLEFTMOUSE = 0x0014, /* 20 */ + WHEELRIGHTMOUSE = 0x0015, /* 21 */ /* Maximum keyboard value (inclusive). */ -#define _EVT_MOUSE_MAX 0x0011 /* 17 */ +#define _EVT_MOUSE_MAX 0x0015 /* 21 */ /* IME event, GHOST_kEventImeCompositionStart in ghost. */ - WM_IME_COMPOSITE_START = 0x0014, + WM_IME_COMPOSITE_START = 0x0016, + /* 0x0017 is MOUSESMARTZOOM. */ /* IME event, GHOST_kEventImeComposition in ghost. */ - WM_IME_COMPOSITE_EVENT = 0x0015, + WM_IME_COMPOSITE_EVENT = 0x0018, /* IME event, GHOST_kEventImeCompositionEnd in ghost. */ - WM_IME_COMPOSITE_END = 0x0016, + WM_IME_COMPOSITE_END = 0x0019, /* Tablet/Pen Specific Events. */ TABLET_STYLUS = 0x001a, @@ -424,7 +428,9 @@ enum wmEventType : int16_t { BUTTON6MOUSE, \ BUTTON7MOUSE)) /** Test whether the event is a mouse wheel. */ -#define ISMOUSE_WHEEL(event_type) ((event_type) >= WHEELUPMOUSE && (event_type) <= WHEELOUTMOUSE) +#define ISMOUSE_WHEEL(event_type) \ + (((event_type) >= WHEELUPMOUSE && (event_type) <= WHEELOUTMOUSE) || \ + ELEM((event_type), WHEELLEFTMOUSE, WHEELRIGHTMOUSE)) /** Test whether the event is a mouse (trackpad) gesture. */ #define ISMOUSE_GESTURE(event_type) ((event_type) >= MOUSEPAN && (event_type) <= MOUSESMARTZOOM)