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