| 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 |