diff options
author | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-07 22:06:34 +0000 |
---|---|---|
committer | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-07 22:06:34 +0000 |
commit | 562b8d289eb1db9b1253691c83b7c5fcc7138602 (patch) | |
tree | 164e60c061d4baa7f60fc808f85fb3d259dda864 /ui | |
parent | eea61f21716ce9dca63a4a8693514e07f8bbf230 (diff) | |
download | chromium_src-562b8d289eb1db9b1253691c83b7c5fcc7138602.zip chromium_src-562b8d289eb1db9b1253691c83b7c5fcc7138602.tar.gz chromium_src-562b8d289eb1db9b1253691c83b7c5fcc7138602.tar.bz2 |
X11: Avoid treating scrollwheel events as button presses.
This fixes a few scrollwheel-related problems in events_x.c:
- GetEventFlagsForButton() was getting called for
scrollwheel events and DLOG-ing a warning. This change
makes us avoid calling it for core scrollwheel events and
removes the warning (since it can still get called for
buttons other 1-3 when inspecting the button mask for
XInput events).
- EventTypeFromNative() was classifying button 6 and 7 (left
and right scrollwheel) events as button presses and
releases instead of as scrolls. As a result, doing a
two-finger left or right scroll on a Chrome OS device
would trigger a failed assertion in WebKit.
I'm also adding some basic unit tests.
BUG=102675
TEST=added, also manually checked that the warning and crash are gone
Review URL: http://codereview.chromium.org/8423065
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108920 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/base/x/events_x.cc | 92 | ||||
-rw-r--r-- | ui/base/x/events_x_unittest.cc | 118 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 5 |
3 files changed, 175 insertions, 40 deletions
diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc index 39404a5..329acbe 100644 --- a/ui/base/x/events_x.cc +++ b/ui/base/x/events_x.cc @@ -14,7 +14,15 @@ namespace { // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. -static int kWheelScrollAmount = 53; +static const int kWheelScrollAmount = 53; + +static const int kMinWheelButton = 4; +#if defined(OS_CHROMEOS) +// Chrome OS also uses buttons 8 and 9 for scrolling. +static const int kMaxWheelButton = 9; +#else +static const int kMaxWheelButton = 7; +#endif int GetEventFlagsFromXState(unsigned int state) { int flags = 0; @@ -51,9 +59,9 @@ int GetEventFlagsForButton(int button) { return ui::EF_MIDDLE_BUTTON_DOWN; case 3: return ui::EF_RIGHT_BUTTON_DOWN; + default: + return 0; } - DLOG(WARNING) << "Unexpected button (" << button << ") received."; - return 0; } int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { @@ -145,24 +153,14 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) { case KeyRelease: return ET_KEY_RELEASED; case ButtonPress: - if (native_event->xbutton.button == 4 || - native_event->xbutton.button == 5) + if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && + static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) return ET_MOUSEWHEEL; -#if defined (OS_CHROMEOS) - if (native_event->xbutton.button == 8 || - native_event->xbutton.button == 9) - return ET_MOUSEWHEEL; -#endif return ET_MOUSE_PRESSED; case ButtonRelease: - if (native_event->xbutton.button == 4 || - native_event->xbutton.button == 5) - return ET_MOUSEWHEEL; -#if defined (OS_CHROMEOS) - if (native_event->xbutton.button == 8 || - native_event->xbutton.button == 9) + if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && + static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) return ET_MOUSEWHEEL; -#endif return ET_MOUSE_RELEASED; case MotionNotify: if (native_event->xmotion.state & @@ -180,19 +178,15 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) { return GetTouchEventType(native_event); switch (xievent->evtype) { case XI_ButtonPress: -#if defined (OS_CHROMEOS) - if (xievent->detail == 8 || xievent->detail == 9) + if (xievent->detail >= kMinWheelButton && + xievent->detail <= kMaxWheelButton) return ET_MOUSEWHEEL; -#endif - return (xievent->detail == 4 || xievent->detail == 5) ? - ET_MOUSEWHEEL : ET_MOUSE_PRESSED; + return ET_MOUSE_PRESSED; case XI_ButtonRelease: -#if defined (OS_CHROMEOS) - if (xievent->detail == 8 || xievent->detail == 9) + if (xievent->detail >= kMinWheelButton && + xievent->detail <= kMaxWheelButton) return ET_MOUSEWHEEL; -#endif - return (xievent->detail == 4 || xievent->detail == 5) ? - ET_MOUSEWHEEL : ET_MOUSE_RELEASED; + return ET_MOUSE_RELEASED; case XI_Motion: return GetButtonMaskForX2Event(xievent) ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED; @@ -210,22 +204,30 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) { case KeyRelease: return GetEventFlagsFromXState(native_event->xbutton.state); case ButtonPress: - case ButtonRelease: - return GetEventFlagsFromXState(native_event->xbutton.state) | - GetEventFlagsForButton(native_event->xbutton.button); + case ButtonRelease: { + int flags = GetEventFlagsFromXState(native_event->xbutton.state); + const EventType type = EventTypeFromNative(native_event); + if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) + flags |= GetEventFlagsForButton(native_event->xbutton.button); + return flags; + } case MotionNotify: return GetEventFlagsFromXState(native_event->xmotion.state); case GenericEvent: { XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(native_event->xcookie.data); - bool touch = + const bool touch = TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid); switch (xievent->evtype) { case XI_ButtonPress: - case XI_ButtonRelease: - return GetButtonMaskForX2Event(xievent) | - GetEventFlagsFromXState(xievent->mods.effective) | - (touch ? 0 : GetEventFlagsForButton(xievent->detail)); + case XI_ButtonRelease: { + int flags = GetButtonMaskForX2Event(xievent) | + GetEventFlagsFromXState(xievent->mods.effective); + const EventType type = EventTypeFromNative(native_event); + if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch) + flags |= GetEventFlagsForButton(xievent->detail); + return flags; + } case XI_Motion: return GetButtonMaskForX2Event(xievent) | GetEventFlagsFromXState(xievent->mods.effective); @@ -280,13 +282,23 @@ int GetMouseWheelOffset(const base::NativeEvent& native_event) { } else { button = native_event->xbutton.button; } + switch (button) { + case 4: #if defined(OS_CHROMEOS) - if (button == 8) - return kWheelScrollAmount; - else if (button == 9) - return -kWheelScrollAmount; + case 8: #endif - return button == 4 ? kWheelScrollAmount : -kWheelScrollAmount; + return kWheelScrollAmount; + + case 5: +#if defined(OS_CHROMEOS) + case 9: +#endif + return -kWheelScrollAmount; + + default: + // TODO(derat): Do something for horizontal scrolls (buttons 6 and 7)? + return 0; + } } int GetTouchId(const base::NativeEvent& xev) { diff --git a/ui/base/x/events_x_unittest.cc b/ui/base/x/events_x_unittest.cc new file mode 100644 index 0000000..2419ff6 --- /dev/null +++ b/ui/base/x/events_x_unittest.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <cstring> + +#include <X11/Xlib.h> + +// Generically-named #defines from Xlib that conflict with symbols in GTest. +#undef Bool +#undef None + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/events.h" +#include "ui/gfx/point.h" + +namespace ui { + +namespace { + +// Initializes the passed-in Xlib event. +void InitButtonEvent(XEvent* event, + bool is_press, + const gfx::Point& location, + int button, + int state) { + memset(event, 0, sizeof(*event)); + + // We don't bother setting fields that the event code doesn't use, such as + // x_root/y_root and window/root/subwindow. + XButtonEvent* button_event = &(event->xbutton); + button_event->type = is_press ? ButtonPress : ButtonRelease; + button_event->x = location.x(); + button_event->y = location.y(); + button_event->button = button; + button_event->state = state; +} + +} // namespace + +TEST(EventsXTest, ButtonEvents) { + XEvent event; + gfx::Point location(5, 10); + + InitButtonEvent(&event, true, location, 1, 0); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event)); + EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + + InitButtonEvent(&event, true, location, 2, Button1Mask | ShiftMask); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event)); + EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_MIDDLE_BUTTON_DOWN | + ui::EF_SHIFT_DOWN, + ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + + InitButtonEvent(&event, false, location, 3, 0); + EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(&event)); + EXPECT_EQ(ui::EF_RIGHT_BUTTON_DOWN, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + + // Scroll up. + InitButtonEvent(&event, true, location, 4, 0); + EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event)); + EXPECT_EQ(0, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + EXPECT_GT(ui::GetMouseWheelOffset(&event), 0); + + // Scroll down. + InitButtonEvent(&event, true, location, 5, 0); + EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event)); + EXPECT_EQ(0, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + EXPECT_LT(ui::GetMouseWheelOffset(&event), 0); + + // Scroll left, typically. + InitButtonEvent(&event, true, location, 6, 0); + EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event)); + EXPECT_EQ(0, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + EXPECT_EQ(0, ui::GetMouseWheelOffset(&event)); + + // Scroll right, typically. + InitButtonEvent(&event, true, location, 7, 0); + EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event)); + EXPECT_EQ(0, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + EXPECT_EQ(0, ui::GetMouseWheelOffset(&event)); + +#if defined(OS_CHROMEOS) + // Scroll up. + InitButtonEvent(&event, true, location, 8, 0); + EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event)); + EXPECT_EQ(0, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + EXPECT_GT(ui::GetMouseWheelOffset(&event), 0); + + // Scroll down. + InitButtonEvent(&event, true, location, 9, 0); + EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event)); + EXPECT_EQ(0, ui::EventFlagsFromNative(&event)); + EXPECT_EQ(location, ui::EventLocationFromNative(&event)); + EXPECT_TRUE(ui::IsMouseEvent(&event)); + EXPECT_LT(ui::GetMouseWheelOffset(&event), 0); +#endif + + // TODO(derat): Test XInput code. +} + +} // namespace ui diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index 5dc86a6..82d5200 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -120,6 +120,11 @@ ], }, }], + ['OS == "linux"', { + 'sources': [ + 'base/x/events_x_unittest.cc', + ], + }], ['OS != "mac"', { 'sources': [ 'gfx/transform_unittest.cc', |