Skip to content

Commit 15a37d3

Browse files
fix(macOS): correct right and middle mouse drag handling (#95)
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
1 parent 85cc60d commit 15a37d3

4 files changed

Lines changed: 77 additions & 15 deletions

File tree

src/platform/macos/macos_backend.cpp

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,14 @@ namespace lvh::detail {
531531
CGEventType up_event {}; ///< CoreGraphics up event type.
532532
};
533533

534+
/**
535+
* @brief CoreGraphics metadata for a mouse motion event.
536+
*/
537+
struct MacosMouseMotion {
538+
CGMouseButton button {}; ///< CoreGraphics button associated with the motion.
539+
CGEventType event_type {}; ///< CoreGraphics motion event type.
540+
};
541+
534542
/**
535543
* @brief Translate a portable mouse button to CoreGraphics metadata.
536544
*
@@ -555,6 +563,25 @@ namespace lvh::detail {
555563
return std::nullopt;
556564
}
557565

566+
/**
567+
* @brief Select CoreGraphics motion metadata for the currently held mouse buttons.
568+
*
569+
* @param mouse_down Local left, right, and middle button state.
570+
* @return Matching CoreGraphics button and motion event type.
571+
*/
572+
inline MacosMouseMotion macos_mouse_motion(const std::array<bool, 3> &mouse_down) {
573+
if (mouse_down[0]) {
574+
return {kCGMouseButtonLeft, kCGEventLeftMouseDragged};
575+
}
576+
if (mouse_down[1]) {
577+
return {kCGMouseButtonRight, kCGEventRightMouseDragged};
578+
}
579+
if (mouse_down[2]) {
580+
return {kCGMouseButtonCenter, kCGEventOtherMouseDragged};
581+
}
582+
return {kCGMouseButtonLeft, kCGEventMouseMoved};
583+
}
584+
558585
/**
559586
* @brief Backend mouse backed by CoreGraphics mouse and scroll events.
560587
*/
@@ -613,19 +640,6 @@ namespace lvh::detail {
613640
return current;
614641
}
615642

616-
CGEventType event_type_for_current_buttons() const {
617-
if (mouse_down_[0]) {
618-
return kCGEventLeftMouseDragged;
619-
}
620-
if (mouse_down_[1]) {
621-
return kCGEventOtherMouseDragged;
622-
}
623-
if (mouse_down_[2]) {
624-
return kCGEventRightMouseDragged;
625-
}
626-
return kCGEventMouseMoved;
627-
}
628-
629643
OperationStatus post_mouse(
630644
CGMouseButton button,
631645
CGEventType type,
@@ -660,13 +674,15 @@ namespace lvh::detail {
660674
OperationStatus submit_relative_motion(std::int32_t delta_x, std::int32_t delta_y) {
661675
const auto current = current_location();
662676
const auto location = CGPoint {current.x + delta_x, current.y + delta_y};
663-
return post_mouse(kCGMouseButtonLeft, event_type_for_current_buttons(), location, current, 0);
677+
const auto motion = macos_mouse_motion(mouse_down_);
678+
return post_mouse(motion.button, motion.event_type, location, current, 0);
664679
}
665680

666681
OperationStatus submit_absolute_motion(const MouseEvent &event) {
667682
const auto display_bounds = CGDisplayBounds(state_->display);
668683
const auto location = absolute_mouse_location(event, display_bounds);
669-
return post_mouse(kCGMouseButtonLeft, event_type_for_current_buttons(), location, current_location(), 0);
684+
const auto motion = macos_mouse_motion(mouse_down_);
685+
return post_mouse(motion.button, motion.event_type, location, current_location(), 0);
670686
}
671687

672688
OperationStatus submit_button(const MouseEvent &event) {

tests/fixtures/include/fixtures/macos_backend_test_hooks.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ namespace lvh::detail::test {
2121
double y {}; ///< Vertical coordinate.
2222
};
2323

24+
/**
25+
* @brief Portable representation of CoreGraphics mouse motion metadata for tests.
26+
*/
27+
struct MacosMouseMotionResult {
28+
std::uint32_t button {}; ///< CoreGraphics mouse button value.
29+
std::uint32_t event_type {}; ///< CoreGraphics mouse event type value.
30+
};
31+
2432
/**
2533
* @brief Result set for macOS backend lifecycle utility coverage.
2634
*/
@@ -93,6 +101,16 @@ namespace lvh::detail::test {
93101
double height
94102
);
95103

104+
/**
105+
* @brief Select CoreGraphics motion metadata for a mouse button state.
106+
*
107+
* @param left_down Whether the left button is held.
108+
* @param right_down Whether the right button is held.
109+
* @param middle_down Whether the middle button is held.
110+
* @return CoreGraphics button and motion event type values.
111+
*/
112+
MacosMouseMotionResult macos_backend_mouse_motion(bool left_down, bool right_down, bool middle_down);
113+
96114
/**
97115
* @brief Exercise macOS backend creation and unsupported-device paths.
98116
*

tests/fixtures/macos_backend_test_hooks.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ namespace lvh::detail::test {
5656
return {.x = location.x, .y = location.y};
5757
}
5858

59+
MacosMouseMotionResult macos_backend_mouse_motion(bool left_down, bool right_down, bool middle_down) {
60+
const auto motion = macos::macos_mouse_motion({left_down, right_down, middle_down});
61+
return {
62+
.button = static_cast<std::uint32_t>(motion.button),
63+
.event_type = static_cast<std::uint32_t>(motion.event_type),
64+
};
65+
}
66+
5967
MacosBackendUtilityResult macos_backend_utilities() {
6068
auto backend = create_platform_backend_for_macos_backend_test_hooks();
6169
MacosBackendUtilityResult result;

tests/unit/test_macos_backend.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,26 @@ TEST_F(MacosBackendTest, ConvertsAbsoluteMouseCoordinates) {
104104
EXPECT_DOUBLE_EQ(location.y, 170.0);
105105
}
106106

107+
TEST_F(MacosBackendTest, SelectsMouseMotionMetadataForHeldButtons) {
108+
using lvh::detail::test::macos_backend_mouse_motion;
109+
110+
auto motion = macos_backend_mouse_motion(false, false, false);
111+
EXPECT_EQ(motion.button, kCGMouseButtonLeft);
112+
EXPECT_EQ(motion.event_type, kCGEventMouseMoved);
113+
114+
motion = macos_backend_mouse_motion(true, false, false);
115+
EXPECT_EQ(motion.button, kCGMouseButtonLeft);
116+
EXPECT_EQ(motion.event_type, kCGEventLeftMouseDragged);
117+
118+
motion = macos_backend_mouse_motion(false, true, false);
119+
EXPECT_EQ(motion.button, kCGMouseButtonRight);
120+
EXPECT_EQ(motion.event_type, kCGEventRightMouseDragged);
121+
122+
motion = macos_backend_mouse_motion(false, false, true);
123+
EXPECT_EQ(motion.button, kCGMouseButtonCenter);
124+
EXPECT_EQ(motion.event_type, kCGEventOtherMouseDragged);
125+
}
126+
107127
TEST_F(MacosBackendTest, ReportsCapabilitiesAndUnsupportedDevices) {
108128
const auto result = lvh::detail::test::macos_backend_utilities();
109129

0 commit comments

Comments
 (0)