| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "views/events/event.h" | 5 #include "views/events/event.h" |
| 6 | 6 |
| 7 #include <windows.h> | |
| 8 | |
| 9 #include "base/logging.h" | 7 #include "base/logging.h" |
| 10 #include "ui/base/keycodes/keyboard_code_conversion_win.h" | |
| 11 | 8 |
| 12 namespace views { | 9 namespace views { |
| 13 | 10 |
| 14 namespace { | |
| 15 | |
| 16 // Returns a mask corresponding to the set of modifier keys that are currently | |
| 17 // pressed. Windows key messages don't come with control key state as parameters | |
| 18 // as with mouse messages, so we need to explicitly ask for these states. | |
| 19 int GetKeyStateFlags() { | |
| 20 int flags = 0; | |
| 21 flags |= (GetKeyState(VK_MENU) & 0x80)? ui::EF_ALT_DOWN : 0; | |
| 22 flags |= (GetKeyState(VK_SHIFT) & 0x80)? ui::EF_SHIFT_DOWN : 0; | |
| 23 flags |= (GetKeyState(VK_CONTROL) & 0x80)? ui::EF_CONTROL_DOWN : 0; | |
| 24 return flags; | |
| 25 } | |
| 26 | |
| 27 bool IsButtonDown(NativeEvent native_event) { | |
| 28 return (native_event.wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | | |
| 29 MK_XBUTTON1 | MK_XBUTTON2)) != 0; | |
| 30 } | |
| 31 | |
| 32 // Convert windows message identifiers to Event types. | |
| 33 ui::EventType EventTypeFromNative(NativeEvent native_event) { | |
| 34 switch (native_event.message) { | |
| 35 case WM_KEYDOWN: | |
| 36 case WM_SYSKEYDOWN: | |
| 37 case WM_CHAR: | |
| 38 return ui::ET_KEY_PRESSED; | |
| 39 case WM_KEYUP: | |
| 40 case WM_SYSKEYUP: | |
| 41 return ui::ET_KEY_RELEASED; | |
| 42 case WM_LBUTTONDBLCLK: | |
| 43 case WM_LBUTTONDOWN: | |
| 44 case WM_MBUTTONDBLCLK: | |
| 45 case WM_MBUTTONDOWN: | |
| 46 case WM_NCLBUTTONDBLCLK: | |
| 47 case WM_NCLBUTTONDOWN: | |
| 48 case WM_NCMBUTTONDBLCLK: | |
| 49 case WM_NCMBUTTONDOWN: | |
| 50 case WM_NCRBUTTONDBLCLK: | |
| 51 case WM_NCRBUTTONDOWN: | |
| 52 case WM_NCXBUTTONDBLCLK: | |
| 53 case WM_NCXBUTTONDOWN: | |
| 54 case WM_RBUTTONDBLCLK: | |
| 55 case WM_RBUTTONDOWN: | |
| 56 case WM_XBUTTONDBLCLK: | |
| 57 case WM_XBUTTONDOWN: | |
| 58 return ui::ET_MOUSE_PRESSED; | |
| 59 case WM_LBUTTONUP: | |
| 60 case WM_MBUTTONUP: | |
| 61 case WM_NCLBUTTONUP: | |
| 62 case WM_NCMBUTTONUP: | |
| 63 case WM_NCRBUTTONUP: | |
| 64 case WM_NCXBUTTONUP: | |
| 65 case WM_RBUTTONUP: | |
| 66 case WM_XBUTTONUP: | |
| 67 return ui::ET_MOUSE_RELEASED; | |
| 68 case WM_MOUSEMOVE: | |
| 69 return IsButtonDown(native_event) ? ui::ET_MOUSE_DRAGGED : | |
| 70 ui::ET_MOUSE_MOVED; | |
| 71 case WM_NCMOUSEMOVE: | |
| 72 return ui::ET_MOUSE_MOVED; | |
| 73 case WM_MOUSEWHEEL: | |
| 74 return ui::ET_MOUSEWHEEL; | |
| 75 case WM_MOUSELEAVE: | |
| 76 case WM_NCMOUSELEAVE: | |
| 77 return ui::ET_MOUSE_EXITED; | |
| 78 default: | |
| 79 NOTREACHED(); | |
| 80 } | |
| 81 return ui::ET_UNKNOWN; | |
| 82 } | |
| 83 | |
| 84 // Get views::Event flags from a native Windows message | |
| 85 int EventFlagsFromNative(NativeEvent native_event) { | |
| 86 int flags = 0; | |
| 87 | |
| 88 // TODO(msw): ORing the pressed/released button into the flags is _wrong_. | |
| 89 // It makes it impossible to tell which button was modified when multiple | |
| 90 // buttons are/were held down. We need to instead put the modified button into | |
| 91 // a separate member on the MouseEvent, then audit all consumers of | |
| 92 // MouseEvents to fix them to use the resulting values correctly. | |
| 93 switch (native_event.message) { | |
| 94 case WM_LBUTTONDBLCLK: | |
| 95 case WM_LBUTTONDOWN: | |
| 96 case WM_LBUTTONUP: | |
| 97 case WM_NCLBUTTONDBLCLK: | |
| 98 case WM_NCLBUTTONDOWN: | |
| 99 case WM_NCLBUTTONUP: | |
| 100 native_event.wParam |= MK_LBUTTON; | |
| 101 break; | |
| 102 case WM_MBUTTONDBLCLK: | |
| 103 case WM_MBUTTONDOWN: | |
| 104 case WM_MBUTTONUP: | |
| 105 case WM_NCMBUTTONDBLCLK: | |
| 106 case WM_NCMBUTTONDOWN: | |
| 107 case WM_NCMBUTTONUP: | |
| 108 native_event.wParam |= MK_MBUTTON; | |
| 109 break; | |
| 110 case WM_RBUTTONDBLCLK: | |
| 111 case WM_RBUTTONDOWN: | |
| 112 case WM_RBUTTONUP: | |
| 113 case WM_NCRBUTTONDBLCLK: | |
| 114 case WM_NCRBUTTONDOWN: | |
| 115 case WM_NCRBUTTONUP: | |
| 116 native_event.wParam |= MK_RBUTTON; | |
| 117 break; | |
| 118 case WM_NCXBUTTONDBLCLK: | |
| 119 case WM_NCXBUTTONDOWN: | |
| 120 case WM_NCXBUTTONUP: | |
| 121 case WM_XBUTTONDBLCLK: | |
| 122 case WM_XBUTTONDOWN: | |
| 123 case WM_XBUTTONUP: | |
| 124 native_event.wParam |= MK_XBUTTON1; | |
| 125 break; | |
| 126 } | |
| 127 | |
| 128 // Check if the event occurred in the non-client area. | |
| 129 if (IsNonClientMouseEvent(native_event)) | |
| 130 flags |= ui::EF_IS_NON_CLIENT; | |
| 131 | |
| 132 // Check for double click events. | |
| 133 switch (native_event.message) { | |
| 134 case WM_NCLBUTTONDBLCLK: | |
| 135 case WM_NCMBUTTONDBLCLK: | |
| 136 case WM_NCRBUTTONDBLCLK: | |
| 137 case WM_NCXBUTTONDBLCLK: | |
| 138 case WM_LBUTTONDBLCLK: | |
| 139 case WM_MBUTTONDBLCLK: | |
| 140 case WM_RBUTTONDBLCLK: | |
| 141 case WM_XBUTTONDBLCLK: | |
| 142 flags |= ui::EF_IS_DOUBLE_CLICK; | |
| 143 break; | |
| 144 } | |
| 145 | |
| 146 // For non-client mouse message, the WPARAM value represents the hit test | |
| 147 // result, instead of the key state. | |
| 148 switch (native_event.message) { | |
| 149 case WM_NCLBUTTONDOWN: | |
| 150 case WM_NCLBUTTONUP: | |
| 151 flags |= ui::EF_LEFT_BUTTON_DOWN; | |
| 152 break; | |
| 153 case WM_NCMBUTTONDOWN: | |
| 154 case WM_NCMBUTTONUP: | |
| 155 flags |= ui::EF_MIDDLE_BUTTON_DOWN; | |
| 156 break; | |
| 157 case WM_NCRBUTTONDOWN: | |
| 158 case WM_NCRBUTTONUP: | |
| 159 flags |= ui::EF_RIGHT_BUTTON_DOWN; | |
| 160 break; | |
| 161 default: { | |
| 162 UINT win_flags = GET_KEYSTATE_WPARAM(native_event.wParam); | |
| 163 flags |= (win_flags & MK_CONTROL) ? ui::EF_CONTROL_DOWN : 0; | |
| 164 flags |= (win_flags & MK_SHIFT) ? ui::EF_SHIFT_DOWN : 0; | |
| 165 flags |= (GetKeyState(VK_MENU) < 0) ? ui::EF_ALT_DOWN : 0; | |
| 166 flags |= (win_flags & MK_LBUTTON) ? ui::EF_LEFT_BUTTON_DOWN : 0; | |
| 167 flags |= (win_flags & MK_MBUTTON) ? ui::EF_MIDDLE_BUTTON_DOWN : 0; | |
| 168 flags |= (win_flags & MK_RBUTTON) ? ui::EF_RIGHT_BUTTON_DOWN : 0; | |
| 169 break; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 return flags; | |
| 174 } | |
| 175 | |
| 176 } // namespace | |
| 177 | |
| 178 bool IsClientMouseEvent(const views::NativeEvent& native_event) { | |
| 179 return native_event.message == WM_MOUSELEAVE || | |
| 180 native_event.message == WM_MOUSEHOVER || | |
| 181 (native_event.message >= WM_MOUSEFIRST && | |
| 182 native_event.message <= WM_MOUSELAST); | |
| 183 } | |
| 184 | |
| 185 bool IsNonClientMouseEvent(const views::NativeEvent& native_event) { | |
| 186 return native_event.message == WM_NCMOUSELEAVE || | |
| 187 native_event.message == WM_NCMOUSEHOVER || | |
| 188 (native_event.message >= WM_NCMOUSEMOVE && | |
| 189 native_event.message <= WM_NCXBUTTONDBLCLK); | |
| 190 } | |
| 191 | |
| 192 //////////////////////////////////////////////////////////////////////////////// | |
| 193 // Event, public: | |
| 194 | |
| 195 int Event::GetWindowsFlags() const { | |
| 196 // TODO: need support for x1/x2. | |
| 197 int result = 0; | |
| 198 result |= (flags_ & ui::EF_SHIFT_DOWN) ? MK_SHIFT : 0; | |
| 199 result |= (flags_ & ui::EF_CONTROL_DOWN) ? MK_CONTROL : 0; | |
| 200 result |= (flags_ & ui::EF_LEFT_BUTTON_DOWN) ? MK_LBUTTON : 0; | |
| 201 result |= (flags_ & ui::EF_MIDDLE_BUTTON_DOWN) ? MK_MBUTTON : 0; | |
| 202 result |= (flags_ & ui::EF_RIGHT_BUTTON_DOWN) ? MK_RBUTTON : 0; | |
| 203 return result; | |
| 204 } | |
| 205 | |
| 206 //////////////////////////////////////////////////////////////////////////////// | |
| 207 // Event, private: | |
| 208 | |
| 209 void Event::Init() { | |
| 210 ZeroMemory(&native_event_, sizeof(native_event_)); | |
| 211 native_event_2_ = NULL; | |
| 212 } | |
| 213 | |
| 214 void Event::InitWithNativeEvent(NativeEvent native_event) { | |
| 215 native_event_ = native_event; | |
| 216 // TODO(beng): remove once we rid views of Gtk/Gdk. | |
| 217 native_event_2_ = NULL; | |
| 218 } | |
| 219 | |
| 220 void Event::InitWithNativeEvent2(NativeEvent2 native_event_2, | |
| 221 FromNativeEvent2) { | |
| 222 // No one should ever call this on Windows. | |
| 223 // TODO(beng): remove once we rid views of Gtk/Gdk. | |
| 224 NOTREACHED(); | |
| 225 native_event_2_ = NULL; | |
| 226 } | |
| 227 | |
| 228 //////////////////////////////////////////////////////////////////////////////// | |
| 229 // LocatedEvent, protected: | |
| 230 | |
| 231 LocatedEvent::LocatedEvent(NativeEvent native_event) | |
| 232 : Event(native_event, EventTypeFromNative(native_event), | |
| 233 EventFlagsFromNative(native_event)), | |
| 234 location_(native_event.pt.x, native_event.pt.y) { | |
| 235 } | |
| 236 | |
| 237 LocatedEvent::LocatedEvent(NativeEvent2 native_event_2, | |
| 238 FromNativeEvent2 from_native) | |
| 239 : Event(native_event_2, ui::ET_UNKNOWN, 0, from_native) { | |
| 240 // No one should ever call this on Windows. | |
| 241 // TODO(msw): remove once we rid views of Gtk/Gdk. | |
| 242 NOTREACHED(); | |
| 243 } | |
| 244 | |
| 245 //////////////////////////////////////////////////////////////////////////////// | 11 //////////////////////////////////////////////////////////////////////////////// |
| 246 // KeyEvent, public: | 12 // KeyEvent, public: |
| 247 | 13 |
| 248 KeyEvent::KeyEvent(NativeEvent native_event) | |
| 249 : Event(native_event, | |
| 250 EventTypeFromNative(native_event), | |
| 251 GetKeyStateFlags()), | |
| 252 key_code_(ui::KeyboardCodeForWindowsKeyCode(native_event.wParam)), | |
| 253 character_(0), | |
| 254 unmodified_character_(0) { | |
| 255 } | |
| 256 | |
| 257 KeyEvent::KeyEvent(NativeEvent2 native_event_2, FromNativeEvent2 from_native) | |
| 258 : Event(native_event_2, ui::ET_UNKNOWN, 0, from_native) { | |
| 259 // No one should ever call this on Windows. | |
| 260 // TODO(beng): remove once we rid views of Gtk/Gdk. | |
| 261 NOTREACHED(); | |
| 262 } | |
| 263 | |
| 264 uint16 KeyEvent::GetCharacter() const { | 14 uint16 KeyEvent::GetCharacter() const { |
| 265 if (character_) | 15 if (character_) |
| 266 return character_; | 16 return character_; |
| 267 return (native_event().message == WM_CHAR) ? key_code_ : | 17 return (native_event().message == WM_CHAR) ? key_code_ : |
| 268 GetCharacterFromKeyCode(key_code_, flags()); | 18 GetCharacterFromKeyCode(key_code_, flags()); |
| 269 } | 19 } |
| 270 | 20 |
| 271 uint16 KeyEvent::GetUnmodifiedCharacter() const { | 21 uint16 KeyEvent::GetUnmodifiedCharacter() const { |
| 272 if (unmodified_character_) | 22 if (unmodified_character_) |
| 273 return unmodified_character_; | 23 return unmodified_character_; |
| 274 // Looks like there is no way to get unmodified character on Windows. | 24 // Looks like there is no way to get unmodified character on Windows. |
| 275 return (native_event().message == WM_CHAR) ? key_code_ : | 25 return (native_event().message == WM_CHAR) ? key_code_ : |
| 276 GetCharacterFromKeyCode(key_code_, flags() & ui::EF_SHIFT_DOWN); | 26 GetCharacterFromKeyCode(key_code_, flags() & ui::EF_SHIFT_DOWN); |
| 277 } | 27 } |
| 278 | 28 |
| 279 //////////////////////////////////////////////////////////////////////////////// | |
| 280 // MouseEvent, public: | |
| 281 | |
| 282 MouseEvent::MouseEvent(NativeEvent native_event) | |
| 283 : LocatedEvent(native_event) { | |
| 284 if (IsNonClientMouseEvent(native_event)) { | |
| 285 // Non-client message. The position is contained in a POINTS structure in | |
| 286 // LPARAM, and is in screen coordinates so we have to convert to client. | |
| 287 POINT native_point = location_.ToPOINT(); | |
| 288 ScreenToClient(native_event.hwnd, &native_point); | |
| 289 location_ = gfx::Point(native_point); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 MouseEvent::MouseEvent(NativeEvent2 native_event_2, | |
| 294 FromNativeEvent2 from_native) | |
| 295 : LocatedEvent(native_event_2, from_native) { | |
| 296 // No one should ever call this on Windows. | |
| 297 // TODO(msw): remove once we rid views of Gtk/Gdk. | |
| 298 NOTREACHED(); | |
| 299 } | |
| 300 | |
| 301 //////////////////////////////////////////////////////////////////////////////// | |
| 302 // MouseWheelEvent, public: | |
| 303 | |
| 304 MouseWheelEvent::MouseWheelEvent(NativeEvent native_event) | |
| 305 : MouseEvent(native_event), | |
| 306 offset_(GET_WHEEL_DELTA_WPARAM(native_event.wParam)) { | |
| 307 } | |
| 308 | |
| 309 MouseWheelEvent::MouseWheelEvent(NativeEvent2 native_event_2, | |
| 310 FromNativeEvent2 from_native) | |
| 311 : MouseEvent(native_event_2, from_native) { | |
| 312 // No one should ever call this on Windows. | |
| 313 // TODO(msw): remove once we rid views of Gtk/Gdk. | |
| 314 NOTREACHED(); | |
| 315 } | |
| 316 | |
| 317 } // namespace views | 29 } // namespace views |
| OLD | NEW |