OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/views/win/hwnd_message_handler.h" | 5 #include "ui/views/win/hwnd_message_handler.h" |
6 | 6 |
7 #include <dwmapi.h> | 7 #include <dwmapi.h> |
8 #include <oleacc.h> | 8 #include <oleacc.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/logging.h" | |
14 #include "base/profiler/scoped_tracker.h" | 13 #include "base/profiler/scoped_tracker.h" |
15 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
16 #include "base/tracked_objects.h" | 15 #include "base/tracked_objects.h" |
17 #include "base/win/scoped_gdi_object.h" | 16 #include "base/win/scoped_gdi_object.h" |
18 #include "base/win/win_util.h" | 17 #include "base/win/win_util.h" |
19 #include "base/win/windows_version.h" | 18 #include "base/win/windows_version.h" |
20 #include "ui/base/touch/touch_enabled.h" | 19 #include "ui/base/touch/touch_enabled.h" |
21 #include "ui/base/view_prop.h" | 20 #include "ui/base/view_prop.h" |
22 #include "ui/base/win/internal_constants.h" | 21 #include "ui/base/win/internal_constants.h" |
23 #include "ui/base/win/lock_state.h" | 22 #include "ui/base/win/lock_state.h" |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 last_monitor_(NULL), | 321 last_monitor_(NULL), |
323 is_first_nccalc_(true), | 322 is_first_nccalc_(true), |
324 menu_depth_(0), | 323 menu_depth_(0), |
325 id_generator_(0), | 324 id_generator_(0), |
326 needs_scroll_styles_(false), | 325 needs_scroll_styles_(false), |
327 in_size_loop_(false), | 326 in_size_loop_(false), |
328 touch_down_contexts_(0), | 327 touch_down_contexts_(0), |
329 last_mouse_hwheel_time_(0), | 328 last_mouse_hwheel_time_(0), |
330 msg_handled_(FALSE), | 329 msg_handled_(FALSE), |
331 dwm_transition_desired_(false), | 330 dwm_transition_desired_(false), |
332 active_touch_point_count_(0), | |
333 autohide_factory_(this), | 331 autohide_factory_(this), |
334 weak_factory_(this) { | 332 weak_factory_(this) { |
335 } | 333 } |
336 | 334 |
337 HWNDMessageHandler::~HWNDMessageHandler() { | 335 HWNDMessageHandler::~HWNDMessageHandler() { |
338 delegate_ = NULL; | 336 delegate_ = NULL; |
339 // Prevent calls back into this class via WNDPROC now that we've been | 337 // Prevent calls back into this class via WNDPROC now that we've been |
340 // destroyed. | 338 // destroyed. |
341 ClearUserData(); | 339 ClearUserData(); |
342 } | 340 } |
(...skipping 1949 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2292 tracked_objects::ScopedTracker tracking_profile( | 2290 tracked_objects::ScopedTracker tracking_profile( |
2293 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 2291 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
2294 "440919 HWNDMessageHandler::OnTouchEvent")); | 2292 "440919 HWNDMessageHandler::OnTouchEvent")); |
2295 | 2293 |
2296 // Handle touch events only on Aura for now. | 2294 // Handle touch events only on Aura for now. |
2297 int num_points = LOWORD(w_param); | 2295 int num_points = LOWORD(w_param); |
2298 scoped_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]); | 2296 scoped_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]); |
2299 if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), | 2297 if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), |
2300 num_points, input.get(), | 2298 num_points, input.get(), |
2301 sizeof(TOUCHINPUT))) { | 2299 sizeof(TOUCHINPUT))) { |
| 2300 int flags = ui::GetModifiersFromKeyState(); |
| 2301 TouchEvents touch_events; |
2302 for (int i = 0; i < num_points; ++i) { | 2302 for (int i = 0; i < num_points; ++i) { |
2303 POINT point; | 2303 POINT point; |
2304 point.x = TOUCH_COORD_TO_PIXEL(input[i].x); | 2304 point.x = TOUCH_COORD_TO_PIXEL(input[i].x); |
2305 point.y = TOUCH_COORD_TO_PIXEL(input[i].y); | 2305 point.y = TOUCH_COORD_TO_PIXEL(input[i].y); |
2306 | 2306 |
2307 if (base::win::GetVersion() == base::win::VERSION_WIN7) { | 2307 if (base::win::GetVersion() == base::win::VERSION_WIN7) { |
2308 // Windows 7 sends touch events for touches in the non-client area, | 2308 // Windows 7 sends touch events for touches in the non-client area, |
2309 // whereas Windows 8 does not. In order to unify the behaviour, always | 2309 // whereas Windows 8 does not. In order to unify the behaviour, always |
2310 // ignore touch events in the non-client area. | 2310 // ignore touch events in the non-client area. |
2311 LPARAM l_param_ht = MAKELPARAM(point.x, point.y); | 2311 LPARAM l_param_ht = MAKELPARAM(point.x, point.y); |
2312 LRESULT hittest = SendMessage(hwnd(), WM_NCHITTEST, 0, l_param_ht); | 2312 LRESULT hittest = SendMessage(hwnd(), WM_NCHITTEST, 0, l_param_ht); |
2313 | 2313 |
2314 if (hittest != HTCLIENT) | 2314 if (hittest != HTCLIENT) |
2315 return 0; | 2315 return 0; |
2316 } | 2316 } |
| 2317 |
| 2318 ScreenToClient(hwnd(), &point); |
| 2319 |
| 2320 last_touch_message_time_ = ::GetMessageTime(); |
| 2321 |
| 2322 ui::EventType touch_event_type = ui::ET_UNKNOWN; |
| 2323 |
| 2324 if (input[i].dwFlags & TOUCHEVENTF_DOWN) { |
| 2325 touch_ids_.insert(input[i].dwID); |
| 2326 touch_event_type = ui::ET_TOUCH_PRESSED; |
| 2327 touch_down_contexts_++; |
| 2328 base::MessageLoop::current()->PostDelayedTask( |
| 2329 FROM_HERE, |
| 2330 base::Bind(&HWNDMessageHandler::ResetTouchDownContext, |
| 2331 weak_factory_.GetWeakPtr()), |
| 2332 base::TimeDelta::FromMilliseconds(kTouchDownContextResetTimeout)); |
| 2333 } else if (input[i].dwFlags & TOUCHEVENTF_UP) { |
| 2334 touch_ids_.erase(input[i].dwID); |
| 2335 touch_event_type = ui::ET_TOUCH_RELEASED; |
| 2336 } else if (input[i].dwFlags & TOUCHEVENTF_MOVE) { |
| 2337 touch_event_type = ui::ET_TOUCH_MOVED; |
| 2338 } |
| 2339 if (touch_event_type != ui::ET_UNKNOWN) { |
| 2340 // input[i].dwTime doesn't necessarily relate to the system time at all, |
| 2341 // so use base::TimeTicks::Now() |
| 2342 const base::TimeTicks now = base::TimeTicks::Now(); |
| 2343 ui::TouchEvent event(touch_event_type, |
| 2344 gfx::Point(point.x, point.y), |
| 2345 id_generator_.GetGeneratedID(input[i].dwID), |
| 2346 now - base::TimeTicks()); |
| 2347 event.set_flags(flags); |
| 2348 event.latency()->AddLatencyNumberWithTimestamp( |
| 2349 ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, |
| 2350 0, |
| 2351 0, |
| 2352 base::TimeTicks::FromInternalValue( |
| 2353 event.time_stamp().ToInternalValue()), |
| 2354 1); |
| 2355 |
| 2356 touch_events.push_back(event); |
| 2357 if (touch_event_type == ui::ET_TOUCH_RELEASED) |
| 2358 id_generator_.ReleaseNumber(input[i].dwID); |
| 2359 } |
2317 } | 2360 } |
2318 TouchEvents touch_events; | |
2319 int old_touch_down_contexts = touch_down_contexts_; | |
2320 PrepareTouchEventList(input.get(), num_points, &touch_events); | |
2321 int new_touch_presses = touch_down_contexts_ - old_touch_down_contexts; | |
2322 if (new_touch_presses > 0) { | |
2323 base::MessageLoop::current()->PostDelayedTask( | |
2324 FROM_HERE, base::Bind(&HWNDMessageHandler::DecrementTouchDownContext, | |
2325 weak_factory_.GetWeakPtr(), new_touch_presses), | |
2326 base::TimeDelta::FromMilliseconds(kTouchDownContextResetTimeout)); | |
2327 } | |
2328 | |
2329 // Handle the touch events asynchronously. We need this because touch | 2361 // Handle the touch events asynchronously. We need this because touch |
2330 // events on windows don't fire if we enter a modal loop in the context of | 2362 // events on windows don't fire if we enter a modal loop in the context of |
2331 // a touch event. | 2363 // a touch event. |
2332 base::MessageLoop::current()->PostTask( | 2364 base::MessageLoop::current()->PostTask( |
2333 FROM_HERE, | 2365 FROM_HERE, |
2334 base::Bind(&HWNDMessageHandler::HandleTouchEvents, | 2366 base::Bind(&HWNDMessageHandler::HandleTouchEvents, |
2335 weak_factory_.GetWeakPtr(), touch_events)); | 2367 weak_factory_.GetWeakPtr(), touch_events)); |
2336 } | 2368 } |
2337 CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(l_param)); | 2369 CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(l_param)); |
2338 SetMsgHandled(FALSE); | 2370 SetMsgHandled(FALSE); |
2339 return 0; | 2371 return 0; |
2340 } | 2372 } |
2341 | 2373 |
2342 void HWNDMessageHandler::PrepareTouchEventList(TOUCHINPUT input[], | |
2343 int num_points, | |
2344 TouchEvents* touch_events) { | |
2345 for (int i = 0; i < num_points; ++i) { | |
2346 POINT point; | |
2347 point.x = TOUCH_COORD_TO_PIXEL(input[i].x); | |
2348 point.y = TOUCH_COORD_TO_PIXEL(input[i].y); | |
2349 gfx::Point point_location(point.x, point.y); | |
2350 | |
2351 ScreenToClient(hwnd(), &point); | |
2352 | |
2353 // TOUCHEVENTF_DOWN cannot be combined with TOUCHEVENTF_MOVE or | |
2354 // TOUCHEVENTF_UP, but TOUCHEVENTF_MOVE and TOUCHEVENTF_UP can be combined | |
2355 // in one input. | |
2356 if (input[i].dwFlags & TOUCHEVENTF_DOWN) { | |
2357 touch_down_contexts_++; | |
2358 active_touch_point_count_++; | |
2359 GenerateTouchEvent(input[i].dwID, point_location, ui::ET_TOUCH_PRESSED, | |
2360 touch_events); | |
2361 } else { | |
2362 if (input[i].dwFlags & TOUCHEVENTF_MOVE) { | |
2363 GenerateTouchEvent(input[i].dwID, point_location, ui::ET_TOUCH_MOVED, | |
2364 touch_events); | |
2365 } | |
2366 if (input[i].dwFlags & TOUCHEVENTF_UP) { | |
2367 active_touch_point_count_--; | |
2368 GenerateTouchEvent(input[i].dwID, point_location, ui::ET_TOUCH_RELEASED, | |
2369 touch_events); | |
2370 } | |
2371 } | |
2372 } | |
2373 last_touch_message_time_ = ::GetMessageTime(); | |
2374 | |
2375 UpdateTouchPointStates(touch_events); | |
2376 } | |
2377 | |
2378 void HWNDMessageHandler::GenerateTouchEvent(DWORD input_dwID, | |
2379 const gfx::Point& point_location, | |
2380 ui::EventType touch_event_type, | |
2381 TouchEvents* touch_events) { | |
2382 int touch_id = static_cast<int>(id_generator_.GetGeneratedID(input_dwID)); | |
2383 if (touch_id < 0 || touch_id >= static_cast<int>(touch_id_list_.size())) { | |
2384 return; | |
2385 } | |
2386 | |
2387 TouchPoint& touch_point = touch_id_list_[touch_id]; | |
2388 int flags = ui::GetModifiersFromKeyState(); | |
2389 | |
2390 // The dwTime of every input in the WM_TOUCH message doesn't necessarily | |
2391 // relate to the system time at all, so use base::TimeTicks::Now() for | |
2392 // touchevent time. | |
2393 base::TimeDelta now = ui::EventTimeForNow(); | |
2394 | |
2395 // We set a check to assert that we do not have missing touch presses in | |
2396 // every message. | |
2397 bool has_missing_touch_press = touch_event_type != ui::ET_TOUCH_PRESSED && | |
2398 touch_point.in_touch_list == InTouchList::NotPresent; | |
2399 CHECK(!has_missing_touch_press) << "There are missing touch presses"; | |
2400 | |
2401 ui::TouchEvent event(touch_event_type, point_location, touch_id, now); | |
2402 event.set_flags(flags); | |
2403 event.latency()->AddLatencyNumberWithTimestamp( | |
2404 ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, base::TimeTicks::Now(), | |
2405 1); | |
2406 touch_events->push_back(event); | |
2407 | |
2408 // Mark the active touch pointers in the touch_id_list_ to be | |
2409 // InCurrentMessage, so we can track the ones which are missed in the | |
2410 // current message and release them. | |
2411 if (touch_event_type == ui::ET_TOUCH_RELEASED) { | |
2412 id_generator_.ReleaseNumber(input_dwID); | |
2413 touch_point.in_touch_list = InTouchList::NotPresent; | |
2414 } else { | |
2415 touch_point.in_touch_list = InTouchList::InCurrentMessage; | |
2416 touch_point.location = point_location; | |
2417 } | |
2418 } | |
2419 | |
2420 void HWNDMessageHandler::UpdateTouchPointStates(TouchEvents* touch_events) { | |
2421 for (size_t i = 0; i != touch_id_list_.size(); ++i) { | |
2422 // Loop through the touch pointers list, if we see any which is only in | |
2423 // the previous message, we will send a touch release event for this ID. | |
2424 TouchPoint& touch_point = touch_id_list_[i]; | |
2425 if (touch_point.in_touch_list == InTouchList::InPreviousMessage) { | |
2426 base::TimeDelta now = base::TimeTicks::Now() - base::TimeTicks(); | |
2427 ui::TouchEvent event(ui::ET_TOUCH_RELEASED, touch_point.location, | |
2428 static_cast<int>(i), now); | |
2429 touch_events->push_back(event); | |
2430 touch_point.in_touch_list = InTouchList::NotPresent; | |
2431 id_generator_.ReleaseGeneratedID(i); | |
2432 active_touch_point_count_--; | |
2433 } else if (touch_point.in_touch_list == InTouchList::InCurrentMessage) { | |
2434 touch_point.in_touch_list = InTouchList::InPreviousMessage; | |
2435 } | |
2436 } | |
2437 } | |
2438 | |
2439 void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) { | 2374 void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) { |
2440 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | 2375 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
2441 tracked_objects::ScopedTracker tracking_profile( | 2376 tracked_objects::ScopedTracker tracking_profile( |
2442 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 2377 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
2443 "440919 HWNDMessageHandler::OnWindowPosChanging")); | 2378 "440919 HWNDMessageHandler::OnWindowPosChanging")); |
2444 | 2379 |
2445 if (ignore_window_pos_changes_) { | 2380 if (ignore_window_pos_changes_) { |
2446 // If somebody's trying to toggle our visibility, change the nonclient area, | 2381 // If somebody's trying to toggle our visibility, change the nonclient area, |
2447 // change our Z-order, or activate us, we should probably let it go through. | 2382 // change our Z-order, or activate us, we should probably let it go through. |
2448 if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) | | 2383 if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) | |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2563 if (status_code == WTS_SESSION_UNLOCK) | 2498 if (status_code == WTS_SESSION_UNLOCK) |
2564 ForceRedrawWindow(10); | 2499 ForceRedrawWindow(10); |
2565 } | 2500 } |
2566 | 2501 |
2567 void HWNDMessageHandler::HandleTouchEvents(const TouchEvents& touch_events) { | 2502 void HWNDMessageHandler::HandleTouchEvents(const TouchEvents& touch_events) { |
2568 base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr()); | 2503 base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr()); |
2569 for (size_t i = 0; i < touch_events.size() && ref; ++i) | 2504 for (size_t i = 0; i < touch_events.size() && ref; ++i) |
2570 delegate_->HandleTouchEvent(touch_events[i]); | 2505 delegate_->HandleTouchEvent(touch_events[i]); |
2571 } | 2506 } |
2572 | 2507 |
2573 void HWNDMessageHandler::DecrementTouchDownContext(int decrement) { | 2508 void HWNDMessageHandler::ResetTouchDownContext() { |
2574 touch_down_contexts_ -= decrement; | 2509 touch_down_contexts_--; |
2575 } | 2510 } |
2576 | 2511 |
2577 LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, | 2512 LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, |
2578 WPARAM w_param, | 2513 WPARAM w_param, |
2579 LPARAM l_param, | 2514 LPARAM l_param, |
2580 bool track_mouse) { | 2515 bool track_mouse) { |
2581 if (active_touch_point_count_) | 2516 if (!touch_ids_.empty()) |
2582 return 0; | 2517 return 0; |
2583 | 2518 |
2584 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | 2519 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
2585 tracked_objects::ScopedTracker tracking_profile1( | 2520 tracked_objects::ScopedTracker tracking_profile1( |
2586 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 2521 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
2587 "440919 HWNDMessageHandler::HandleMouseEventInternal1")); | 2522 "440919 HWNDMessageHandler::HandleMouseEventInternal1")); |
2588 | 2523 |
2589 // We handle touch events on Windows Aura. Windows generates synthesized | 2524 // We handle touch events on Windows Aura. Windows generates synthesized |
2590 // mouse messages in response to touch which we should ignore. However touch | 2525 // mouse messages in response to touch which we should ignore. However touch |
2591 // messages are only received for the client area. We need to ignore the | 2526 // messages are only received for the client area. We need to ignore the |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2797 SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_HIDEWINDOW); | 2732 SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_HIDEWINDOW); |
2798 SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_SHOWWINDOW); | 2733 SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_SHOWWINDOW); |
2799 } | 2734 } |
2800 // WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want | 2735 // WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want |
2801 // to notify our children too, since we can have MDI child windows who need to | 2736 // to notify our children too, since we can have MDI child windows who need to |
2802 // update their appearance. | 2737 // update their appearance. |
2803 EnumChildWindows(hwnd(), &SendDwmCompositionChanged, NULL); | 2738 EnumChildWindows(hwnd(), &SendDwmCompositionChanged, NULL); |
2804 } | 2739 } |
2805 | 2740 |
2806 } // namespace views | 2741 } // namespace views |
OLD | NEW |