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 |