diff options
Diffstat (limited to 'chromium/win8/metro_driver/chrome_app_view_ash.cc')
-rw-r--r-- | chromium/win8/metro_driver/chrome_app_view_ash.cc | 498 |
1 files changed, 319 insertions, 179 deletions
diff --git a/chromium/win8/metro_driver/chrome_app_view_ash.cc b/chromium/win8/metro_driver/chrome_app_view_ash.cc index c1a8f4cd573..fd193853d3c 100644 --- a/chromium/win8/metro_driver/chrome_app_view_ash.cc +++ b/chromium/win8/metro_driver/chrome_app_view_ash.cc @@ -17,11 +17,14 @@ #include "base/threading/thread.h" #include "base/win/metro.h" #include "base/win/win_util.h" +#include "base/win/windows_version.h" #include "chrome/common/chrome_switches.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_channel_proxy.h" #include "ipc/ipc_sender.h" #include "ui/events/gestures/gesture_sequence.h" +#include "ui/gfx/geometry/point_conversions.h" +#include "ui/gfx/win/dpi.h" #include "ui/metro_viewer/metro_viewer_messages.h" #include "win8/metro_driver/file_picker_ash.h" #include "win8/metro_driver/ime/ime_popup_monitor.h" @@ -73,6 +76,8 @@ struct Globals { BreakpadExceptionHandler breakpad_exception_handler; } globals; +extern float GetModernUIScale(); + namespace { enum KeyModifier { @@ -85,7 +90,7 @@ enum KeyModifier { // Helper function to send keystrokes via the SendInput function. // mnemonic_char: The keystroke to be sent. // modifiers: Combination with Alt, Ctrl, Shift, etc. -void SendMnemonic( +void SendKeySequence( WORD mnemonic_char, KeyModifier modifiers) { INPUT keys[4] = {0}; // Keyboard events int key_count = 0; // Number of generated events @@ -134,19 +139,6 @@ void SendMnemonic( } } -// Helper function to Exit metro chrome cleanly. If we are in the foreground -// then we try and exit by sending an Alt+F4 key combination to the core -// window which ensures that the chrome application tile does not show up in -// the running metro apps list on the top left corner. -void MetroExit(HWND core_window) { - if ((core_window != NULL) && (core_window == ::GetForegroundWindow())) { - DVLOG(1) << "We are in the foreground. Exiting via Alt F4"; - SendMnemonic(VK_F4, ALT); - } else { - globals.app_exit->Exit(); - } -} - class ChromeChannelListener : public IPC::Listener { public: ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view) @@ -179,11 +171,15 @@ class ChromeChannelListener : public IPC::Listener { virtual void OnChannelError() OVERRIDE { DVLOG(1) << "Channel error. Exiting."; - MetroExit(app_view_->core_window_hwnd()); + ui_proxy_->PostTask(FROM_HERE, + base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_), + TERMINATE_USING_KEY_SEQUENCE)); + // In early Windows 8 versions the code above sometimes fails so we call // it a second time with a NULL window which just calls Exit(). ui_proxy_->PostDelayedTask(FROM_HERE, - base::Bind(&MetroExit, HWND(NULL)), + base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_), + TERMINATE_USING_PROCESS_EXIT), base::TimeDelta::FromMilliseconds(100)); } @@ -196,11 +192,13 @@ class ChromeChannelListener : public IPC::Listener { } void OnMetroExit() { - MetroExit(app_view_->core_window_hwnd()); + ui_proxy_->PostTask(FROM_HERE, + base::Bind(&ChromeAppViewAsh::OnMetroExit, + base::Unretained(app_view_), TERMINATE_USING_KEY_SEQUENCE)); } void OnOpenURLOnDesktop(const base::FilePath& shortcut, - const string16& url) { + const base::string16& url) { ui_proxy_->PostTask(FROM_HERE, base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop, base::Unretained(app_view_), @@ -214,8 +212,8 @@ class ChromeChannelListener : public IPC::Listener { reinterpret_cast<HCURSOR>(cursor))); } - void OnDisplayFileOpenDialog(const string16& title, - const string16& filter, + void OnDisplayFileOpenDialog(const base::string16& title, + const base::string16& filter, const base::FilePath& default_path, bool allow_multiple_files) { ui_proxy_->PostTask(FROM_HERE, @@ -236,7 +234,7 @@ class ChromeChannelListener : public IPC::Listener { params)); } - void OnDisplayFolderPicker(const string16& title) { + void OnDisplayFolderPicker(const base::string16& title) { ui_proxy_->PostTask( FROM_HERE, base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker, @@ -279,22 +277,104 @@ bool WaitForChromeIPCConnection(const std::string& channel_name) { int ms_elapsed = 0; while (!IPC::Channel::IsNamedServerInitialized(channel_name) && ms_elapsed < 10000) { - ms_elapsed += 500; - Sleep(500); + ms_elapsed += 100; + Sleep(100); } return IPC::Channel::IsNamedServerInitialized(channel_name); } +void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) { + // We're entering a nested message loop, let's allow dispatching + // tasks while we're in there. + base::MessageLoop::current()->SetNestableTasksAllowed(true); + + // Enter main core message loop. There are several ways to exit it + // Nicely: + // 1 - User action like ALT-F4. + // 2 - Calling ICoreApplicationExit::Exit(). + // 3- Posting WM_CLOSE to the core window. + HRESULT hr = dispatcher->ProcessEvents( + winui::Core::CoreProcessEventsOption + ::CoreProcessEventsOption_ProcessUntilQuit); + + // Wind down the thread's chrome message loop. + base::MessageLoop::current()->Quit(); +} + +// Helper to return the state of the shift/control/alt keys. +uint32 GetKeyboardEventFlags() { + uint32 flags = 0; + if (base::win::IsShiftPressed()) + flags |= ui::EF_SHIFT_DOWN; + if (base::win::IsCtrlPressed()) + flags |= ui::EF_CONTROL_DOWN; + if (base::win::IsAltPressed()) + flags |= ui::EF_ALT_DOWN; + return flags; +} + +bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters, + winapp::Activation::IActivatedEventArgs* args) { + if (args) { + DVLOG(1) << __FUNCTION__ << ":" << ::GetCommandLineW(); + winapp::Activation::ActivationKind activation_kind; + CheckHR(args->get_Kind(&activation_kind)); + + DVLOG(1) << __FUNCTION__ << ", activation_kind=" << activation_kind; + + if (activation_kind == winapp::Activation::ActivationKind_Launch) { + mswr::ComPtr<winapp::Activation::ILaunchActivatedEventArgs> launch_args; + if (args->QueryInterface( + winapp::Activation::IID_ILaunchActivatedEventArgs, + &launch_args) == S_OK) { + DVLOG(1) << "Activate: ActivationKind_Launch"; + mswrw::HString launch_args_str; + launch_args->get_Arguments(launch_args_str.GetAddressOf()); + base::string16 actual_launch_args( + MakeStdWString(launch_args_str.Get())); + if (actual_launch_args == win8::kMetroViewerConnectVerb) { + DVLOG(1) << __FUNCTION__ << "Not launching chrome server"; + return true; + } + } + } + } + + DVLOG(1) << "Launching chrome server"; + base::FilePath chrome_exe_path; + + if (!PathService::Get(base::FILE_EXE, &chrome_exe_path)) + return false; + + base::string16 parameters = L"--silent-launch --viewer-connect "; + if (additional_parameters) + parameters += additional_parameters; + + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.nShow = SW_SHOWNORMAL; + sei.lpFile = chrome_exe_path.value().c_str(); + sei.lpDirectory = L""; + sei.lpParameters = parameters.c_str(); + ::ShellExecuteEx(&sei); + return true; +} + +} // namespace + // This class helps decoding the pointer properties of an event. -class PointerInfoHandler { +class ChromeAppViewAsh::PointerInfoHandler { public: - PointerInfoHandler() + PointerInfoHandler(float metro_dpi_scale, float win32_dpi_scale) : x_(0), y_(0), wheel_delta_(0), update_kind_(winui::Input::PointerUpdateKind_Other), timestamp_(0), - pointer_id_(0) {} + pointer_id_(0), + mouse_down_flags_(0), + is_horizontal_wheel_(0), + metro_dpi_scale_(metro_dpi_scale), + win32_dpi_scale_(win32_dpi_scale) {} HRESULT Init(winui::Core::IPointerEventArgs* args) { HRESULT hr = args->get_CurrentPoint(&pointer_point_); @@ -318,13 +398,50 @@ class PointerInfoHandler { hr = properties->get_MouseWheelDelta(&wheel_delta_); if (FAILED(hr)) return hr; - x_ = point.X; - y_ = point.Y; + + is_horizontal_wheel_ = 0; + properties->get_IsHorizontalMouseWheel(&is_horizontal_wheel_); + + // The input coordinates are in DIP based on the metro scale factor. + // We want to convert it to DIP based on the win32 scale factor. + // We scale the point by the metro scale factor and then scale down + // via the win32 scale factor which achieves the needful. + gfx::Point dip_point_metro(point.X, point.Y); + gfx::Point scaled_point_metro = + gfx::ToCeiledPoint(gfx::ScalePoint(dip_point_metro, metro_dpi_scale_)); + gfx::Point dip_point_win32 = + gfx::ToCeiledPoint(gfx::ScalePoint(scaled_point_metro, + 1.0 / win32_dpi_scale_)); + x_ = dip_point_win32.x(); + y_ = dip_point_win32.y(); + pointer_point_->get_Timestamp(×tamp_); pointer_point_->get_PointerId(&pointer_id_); // Map the OS touch event id to a range allowed by the gesture recognizer. if (IsTouch()) pointer_id_ %= ui::GestureSequence::kMaxGesturePoints; + + boolean left_button_state; + hr = properties->get_IsLeftButtonPressed(&left_button_state); + if (FAILED(hr)) + return hr; + if (left_button_state) + mouse_down_flags_ |= ui::EF_LEFT_MOUSE_BUTTON; + + boolean right_button_state; + hr = properties->get_IsRightButtonPressed(&right_button_state); + if (FAILED(hr)) + return hr; + if (right_button_state) + mouse_down_flags_ |= ui::EF_RIGHT_MOUSE_BUTTON; + + boolean middle_button_state; + hr = properties->get_IsMiddleButtonPressed(&middle_button_state); + if (FAILED(hr)) + return hr; + if (middle_button_state) + mouse_down_flags_ |= ui::EF_MIDDLE_MOUSE_BUTTON; + return S_OK; } @@ -348,7 +465,8 @@ class PointerInfoHandler { return wheel_delta_; } - ui::EventFlags flags() { + // Identifies the button that changed. + ui::EventFlags changed_button() const { switch (update_kind_) { case winui::Input::PointerUpdateKind_LeftButtonPressed: return ui::EF_LEFT_MOUSE_BUTTON; @@ -364,9 +482,11 @@ class PointerInfoHandler { return ui::EF_MIDDLE_MOUSE_BUTTON; default: return ui::EF_NONE; - }; + } } + uint32 mouse_down_flags() const { return mouse_down_flags_; } + int x() const { return x_; } int y() const { return y_; } @@ -376,6 +496,10 @@ class PointerInfoHandler { uint64 timestamp() const { return timestamp_; } + winui::Input::PointerUpdateKind update_kind() const { return update_kind_; } + + bool is_horizontal_wheel() const { return !!is_horizontal_wheel_; } + private: int x_; int y_; @@ -384,90 +508,29 @@ class PointerInfoHandler { winui::Input::PointerUpdateKind update_kind_; mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_; uint64 timestamp_; -}; -void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) { - // We're entering a nested message loop, let's allow dispatching - // tasks while we're in there. - base::MessageLoop::current()->SetNestableTasksAllowed(true); - - // Enter main core message loop. There are several ways to exit it - // Nicely: - // 1 - User action like ALT-F4. - // 2 - Calling ICoreApplicationExit::Exit(). - // 3- Posting WM_CLOSE to the core window. - HRESULT hr = dispatcher->ProcessEvents( - winui::Core::CoreProcessEventsOption - ::CoreProcessEventsOption_ProcessUntilQuit); + // Bitmask of ui::EventFlags corresponding to the buttons that are currently + // down. + uint32 mouse_down_flags_; - // Wind down the thread's chrome message loop. - base::MessageLoop::current()->Quit(); -} + // Set to true for a horizontal wheel message. + boolean is_horizontal_wheel_; -// Helper to return the state of the shift/control/alt keys. -uint32 GetKeyboardEventFlags() { - uint32 flags = 0; - if (base::win::IsShiftPressed()) - flags |= ui::EF_SHIFT_DOWN; - if (base::win::IsCtrlPressed()) - flags |= ui::EF_CONTROL_DOWN; - if (base::win::IsAltPressed()) - flags |= ui::EF_ALT_DOWN; - return flags; -} - -bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters, - winapp::Activation::IActivatedEventArgs* args) { - if (args) { - DVLOG(1) << __FUNCTION__ << ":" << ::GetCommandLineW(); - winapp::Activation::ActivationKind activation_kind; - CheckHR(args->get_Kind(&activation_kind)); - - DVLOG(1) << __FUNCTION__ << ", activation_kind=" << activation_kind; - - if (activation_kind == winapp::Activation::ActivationKind_Launch) { - mswr::ComPtr<winapp::Activation::ILaunchActivatedEventArgs> launch_args; - if (args->QueryInterface( - winapp::Activation::IID_ILaunchActivatedEventArgs, - &launch_args) == S_OK) { - DVLOG(1) << "Activate: ActivationKind_Launch"; - mswrw::HString launch_args_str; - launch_args->get_Arguments(launch_args_str.GetAddressOf()); - string16 actual_launch_args(MakeStdWString(launch_args_str.Get())); - if (actual_launch_args == win8::kMetroViewerConnectVerb) { - DVLOG(1) << __FUNCTION__ << "Not launching chrome server"; - return true; - } - } - } - } - - DVLOG(1) << "Launching chrome server"; - base::FilePath chrome_exe_path; + // The metro device scale factor as reported by the winrt interfaces. + float metro_dpi_scale_; + // The win32 dpi scale which is queried via GetDeviceCaps. Please refer to + // ui/gfx/win/dpi.cc for more information. + float win32_dpi_scale_; - if (!PathService::Get(base::FILE_EXE, &chrome_exe_path)) - return false; - - string16 parameters = L"--silent-launch --viewer-connect "; - if (additional_parameters) - parameters += additional_parameters; - - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.nShow = SW_SHOWNORMAL; - sei.lpFile = chrome_exe_path.value().c_str(); - sei.lpDirectory = L""; - sei.lpParameters = parameters.c_str(); - ::ShellExecuteEx(&sei); - return true; -} - -} // namespace + DISALLOW_COPY_AND_ASSIGN(PointerInfoHandler); +}; ChromeAppViewAsh::ChromeAppViewAsh() : mouse_down_flags_(ui::EF_NONE), ui_channel_(nullptr), core_window_hwnd_(NULL), - ui_loop_(base::MessageLoop::TYPE_UI) { + metro_dpi_scale_(0), + win32_dpi_scale_(0) { DVLOG(1) << __FUNCTION__; globals.previous_state = winapp::Activation::ApplicationExecutionState_NotRunning; @@ -535,7 +598,7 @@ ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) { CheckHR(hr); mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; - hr = window_->get_Dispatcher(&dispatcher); + hr = window_->get_Dispatcher(dispatcher.GetAddressOf()); CheckHR(hr, "Get Dispatcher failed."); mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys; @@ -564,31 +627,44 @@ ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) { &window_activated_token_); CheckHR(hr); - // Register for edge gesture notifications. - mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics; - hr = winrt_utils::CreateActivationFactory( - RuntimeClass_Windows_UI_Input_EdgeGesture, - edge_gesture_statics.GetAddressOf()); - CheckHR(hr); - - mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture; - hr = edge_gesture_statics->GetForCurrentView(&edge_gesture); - CheckHR(hr); - - hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>( - this, &ChromeAppViewAsh::OnEdgeGestureCompleted).Get(), - &edgeevent_token_); - CheckHR(hr); + if (base::win::GetVersion() >= base::win::VERSION_WIN8) { + // Register for edge gesture notifications only for Windows 8 and above. + mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics; + hr = winrt_utils::CreateActivationFactory( + RuntimeClass_Windows_UI_Input_EdgeGesture, + edge_gesture_statics.GetAddressOf()); + CheckHR(hr); + + mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture; + hr = edge_gesture_statics->GetForCurrentView(&edge_gesture); + CheckHR(hr); + + hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>( + this, &ChromeAppViewAsh::OnEdgeGestureCompleted).Get(), + &edgeevent_token_); + CheckHR(hr); + } // By initializing the direct 3D swap chain with the corewindow // we can now directly blit to it from the browser process. direct3d_helper_.Initialize(window); DVLOG(1) << "Initialized Direct3D."; + + // On Windows 8+ the WinRT interface IDisplayProperties which we use to get + // device scale factor does not return the correct values in metro mode. + // To workaround this we retrieve the device scale factor via the win32 way + // and scale input coordinates accordingly to pass them in DIP to chrome. + // TODO(ananta). Investigate and fix. + metro_dpi_scale_ = GetModernUIScale(); + win32_dpi_scale_ = gfx::GetDPIScale(); + DVLOG(1) << "Metro Scale is " << metro_dpi_scale_; + DVLOG(1) << "Win32 Scale is " << win32_dpi_scale_; return S_OK; } IFACEMETHODIMP ChromeAppViewAsh::Load(HSTRING entryPoint) { + // On Win7 |entryPoint| is NULL. DVLOG(1) << __FUNCTION__; return S_OK; } @@ -597,7 +673,7 @@ IFACEMETHODIMP ChromeAppViewAsh::Run() { DVLOG(1) << __FUNCTION__; mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; - HRESULT hr = window_->get_Dispatcher(&dispatcher); + HRESULT hr = window_->get_Dispatcher(dispatcher.GetAddressOf()); CheckHR(hr, "Dispatcher failed."); hr = window_->Activate(); @@ -618,16 +694,17 @@ ChromeAppViewAsh::Run() { // In Aura mode we create an IPC channel to the browser, then ask it to // connect to us. ChromeChannelListener ui_channel_listener(&ui_loop_, this); - IPC::ChannelProxy ui_channel(win8::kMetroViewerIPCChannelName, - IPC::Channel::MODE_NAMED_CLIENT, - &ui_channel_listener, - io_thread.message_loop_proxy()); - ui_channel_ = &ui_channel; + scoped_ptr<IPC::ChannelProxy> channel = + IPC::ChannelProxy::Create(win8::kMetroViewerIPCChannelName, + IPC::Channel::MODE_NAMED_CLIENT, + &ui_channel_listener, + io_thread.message_loop_proxy()); + ui_channel_ = channel.get(); // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the // browser will use D3D from the browser process to present to our Window. ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface( - gfx::NativeViewId(core_window_hwnd_))); + gfx::NativeViewId(core_window_hwnd_), win32_dpi_scale_)); DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_; // Send an initial size message so that the Ash root window host gets sized @@ -701,7 +778,7 @@ void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path, if (ash_exit) { // As we are the top level window, the exiting is done async so we manage // to execute the entire function including the final Send(). - MetroExit(core_window_hwnd()); + OnMetroExit(TERMINATE_USING_KEY_SEQUENCE); } // We are just executing delegate_execute here without parameters. Assumption @@ -726,7 +803,7 @@ void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path, } void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath& shortcut, - const string16& url) { + const base::string16& url) { base::FilePath::StringType file = shortcut.value(); SHELLEXECUTEINFO sei = { sizeof(sei) }; sei.fMask = SEE_MASK_FLAG_LOG_USAGE; @@ -742,8 +819,8 @@ void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) { } void ChromeAppViewAsh::OnDisplayFileOpenDialog( - const string16& title, - const string16& filter, + const base::string16& title, + const base::string16& filter, const base::FilePath& default_path, bool allow_multiple_files) { DVLOG(1) << __FUNCTION__; @@ -772,7 +849,7 @@ void ChromeAppViewAsh::OnDisplayFileSaveAsDialog( file_picker_->Run(); } -void ChromeAppViewAsh::OnDisplayFolderPicker(const string16& title) { +void ChromeAppViewAsh::OnDisplayFolderPicker(const base::string16& title) { DVLOG(1) << __FUNCTION__; // The FolderPickerSession instance is deleted when we receive a // callback from the FolderPickerSession class about the completion of the @@ -872,6 +949,30 @@ void ChromeAppViewAsh::OnImePopupChanged(ImePopupObserver::EventType event) { } } +// Function to Exit metro chrome cleanly. If we are in the foreground +// then we try and exit by sending an Alt+F4 key combination to the core +// window which ensures that the chrome application tile does not show up in +// the running metro apps list on the top left corner. +void ChromeAppViewAsh::OnMetroExit(MetroTerminateMethod method) { + if (base::win::GetVersion() >= base::win::VERSION_WIN8) { + HWND core_window = core_window_hwnd(); + if (method == TERMINATE_USING_KEY_SEQUENCE && core_window != NULL && + core_window == ::GetForegroundWindow()) { + DVLOG(1) << "We are in the foreground. Exiting via Alt F4"; + SendKeySequence(VK_F4, ALT); + if (ui_channel_) + ui_channel_->Close(); + } else { + globals.app_exit->Exit(); + } + } else { + if (ui_channel_) + ui_channel_->Close(); + + globals.app_exit->Exit(); + } +} + void ChromeAppViewAsh::OnInputSourceChanged() { if (!input_source_) return; @@ -887,7 +988,7 @@ void ChromeAppViewAsh::OnInputSourceChanged() { } void ChromeAppViewAsh::OnCompositionChanged( - const string16& text, + const base::string16& text, int32 selection_start, int32 selection_end, const std::vector<metro_viewer::UnderlineInfo>& underlines) { @@ -895,10 +996,54 @@ void ChromeAppViewAsh::OnCompositionChanged( text, selection_start, selection_end, underlines)); } -void ChromeAppViewAsh::OnTextCommitted(const string16& text) { +void ChromeAppViewAsh::OnTextCommitted(const base::string16& text) { ui_channel_->Send(new MetroViewerHostMsg_ImeTextCommitted(text)); } +void ChromeAppViewAsh::SendMouseButton(int x, + int y, + int extra, + ui::EventType event_type, + uint32 flags, + ui::EventFlags changed_button, + bool is_horizontal_wheel) { + MetroViewerHostMsg_MouseButtonParams params; + params.x = static_cast<int32>(x); + params.y = static_cast<int32>(y); + params.extra = static_cast<int32>(extra); + params.event_type = event_type; + params.flags = static_cast<int32>(flags); + params.changed_button = changed_button; + params.is_horizontal_wheel = is_horizontal_wheel; + ui_channel_->Send(new MetroViewerHostMsg_MouseButton(params)); +} + +void ChromeAppViewAsh::GenerateMouseEventFromMoveIfNecessary( + const PointerInfoHandler& pointer) { + ui::EventType event_type; + // For aura we want the flags to include the button that was released, thus + // we or the old and new. + uint32 mouse_down_flags = pointer.mouse_down_flags() | mouse_down_flags_; + mouse_down_flags_ = pointer.mouse_down_flags(); + switch (pointer.update_kind()) { + case winui::Input::PointerUpdateKind_LeftButtonPressed: + case winui::Input::PointerUpdateKind_RightButtonPressed: + case winui::Input::PointerUpdateKind_MiddleButtonPressed: + event_type = ui::ET_MOUSE_PRESSED; + break; + case winui::Input::PointerUpdateKind_LeftButtonReleased: + case winui::Input::PointerUpdateKind_RightButtonReleased: + case winui::Input::PointerUpdateKind_MiddleButtonReleased: + event_type = ui::ET_MOUSE_RELEASED; + break; + default: + return; + } + SendMouseButton(pointer.x(), pointer.y(), 0, event_type, + mouse_down_flags | GetKeyboardEventFlags(), + pointer.changed_button(), pointer.is_horizontal_wheel()); +} + HRESULT ChromeAppViewAsh::OnActivate( winapp::Core::ICoreApplicationView*, winapp::Activation::IActivatedEventArgs* args) { @@ -931,12 +1076,13 @@ HRESULT ChromeAppViewAsh::OnActivate( HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender, winui::Core::IPointerEventArgs* args) { - PointerInfoHandler pointer; + PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); HRESULT hr = pointer.Init(args); if (FAILED(hr)) return hr; if (pointer.IsMouse()) { + GenerateMouseEventFromMoveIfNecessary(pointer); ui_channel_->Send(new MetroViewerHostMsg_MouseMoved( pointer.x(), pointer.y(), @@ -955,25 +1101,21 @@ HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender, // event for the first button pressed and the last button released in a sequence // of mouse events. // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results -// only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. +// only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. Intermediary +// presses and releases are tracked in OnPointMoved(). HRESULT ChromeAppViewAsh::OnPointerPressed( winui::Core::ICoreWindow* sender, winui::Core::IPointerEventArgs* args) { - PointerInfoHandler pointer; + PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); HRESULT hr = pointer.Init(args); if (FAILED(hr)) return hr; if (pointer.IsMouse()) { - // TODO: this is wrong, more than one pointer may be down at a time. - mouse_down_flags_ = pointer.flags(); - ui_channel_->Send(new MetroViewerHostMsg_MouseButton( - pointer.x(), - pointer.y(), - 0, - ui::ET_MOUSE_PRESSED, - static_cast<ui::EventFlags>( - mouse_down_flags_ | GetKeyboardEventFlags()))); + mouse_down_flags_ = pointer.mouse_down_flags(); + SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_PRESSED, + mouse_down_flags_ | GetKeyboardEventFlags(), + pointer.changed_button(), pointer.is_horizontal_wheel()); } else { DCHECK(pointer.IsTouch()); ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(), @@ -987,21 +1129,18 @@ HRESULT ChromeAppViewAsh::OnPointerPressed( HRESULT ChromeAppViewAsh::OnPointerReleased( winui::Core::ICoreWindow* sender, winui::Core::IPointerEventArgs* args) { - PointerInfoHandler pointer; + PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); HRESULT hr = pointer.Init(args); if (FAILED(hr)) return hr; if (pointer.IsMouse()) { - // TODO: this is wrong, more than one pointer may be down at a time. mouse_down_flags_ = ui::EF_NONE; - ui_channel_->Send(new MetroViewerHostMsg_MouseButton( - pointer.x(), - pointer.y(), - 0, - ui::ET_MOUSE_RELEASED, - static_cast<ui::EventFlags>( - pointer.flags() | GetKeyboardEventFlags()))); + SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_RELEASED, + static_cast<uint32>(pointer.changed_button()) | + GetKeyboardEventFlags(), + pointer.changed_button(), + pointer.is_horizontal_wheel()); } else { DCHECK(pointer.IsTouch()); ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(), @@ -1015,15 +1154,14 @@ HRESULT ChromeAppViewAsh::OnPointerReleased( HRESULT ChromeAppViewAsh::OnWheel( winui::Core::ICoreWindow* sender, winui::Core::IPointerEventArgs* args) { - PointerInfoHandler pointer; + PointerInfoHandler pointer(metro_dpi_scale_, win32_dpi_scale_); HRESULT hr = pointer.Init(args); if (FAILED(hr)) return hr; DCHECK(pointer.IsMouse()); - ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), pointer.y(), - pointer.wheel_delta(), - ui::ET_MOUSEWHEEL, - ui::EF_NONE)); + SendMouseButton(pointer.x(), pointer.y(), pointer.wheel_delta(), + ui::ET_MOUSEWHEEL, ui::EF_NONE, ui::EF_NONE, + pointer.is_horizontal_wheel()); return S_OK; } @@ -1093,6 +1231,13 @@ HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown( break; case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown: + // Don't send the Alt + F4 combination to Chrome as this is intended to + // shut the metro environment down. Reason we check for Control here is + // Windows does not shutdown metro if Ctrl is pressed along with Alt F4. + // Other key combinations with Alt F4 shutdown metro. + if ((virtual_key == VK_F4) && ((keyboard_flags & ui::EF_ALT_DOWN) && + !(keyboard_flags & ui::EF_CONTROL_DOWN))) + return S_OK; ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key, status.RepeatCount, status.ScanCode, @@ -1165,7 +1310,7 @@ HRESULT ChromeAppViewAsh::HandleSearchRequest( mswrw::HString search_string; CheckHR(search_args->get_QueryText(search_string.GetAddressOf())); - string16 search_text(MakeStdWString(search_string.Get())); + base::string16 search_text(MakeStdWString(search_string.Get())); ui_loop_.PostTask(FROM_HERE, base::Bind(&ChromeAppViewAsh::OnSearchRequest, @@ -1190,7 +1335,7 @@ HRESULT ChromeAppViewAsh::HandleProtocolRequest( protocol_args->get_Uri(&uri); mswrw::HString url; uri->get_AbsoluteUri(url.GetAddressOf()); - string16 actual_url(MakeStdWString(url.Get())); + base::string16 actual_url(MakeStdWString(url.Get())); DVLOG(1) << "Received url request: " << actual_url; ui_loop_.PostTask(FROM_HERE, @@ -1203,20 +1348,16 @@ HRESULT ChromeAppViewAsh::HandleProtocolRequest( HRESULT ChromeAppViewAsh::OnEdgeGestureCompleted( winui::Input::IEdgeGesture* gesture, winui::Input::IEdgeGestureEventArgs* args) { - // Swipe from edge gesture (and win+z) is equivalent to pressing F11. - // TODO(cpu): Make this cleaner for m33. - ui_channel_->Send(new MetroViewerHostMsg_KeyDown(VK_F11, 1, 0, 0)); - ::Sleep(15); - ui_channel_->Send(new MetroViewerHostMsg_KeyUp(VK_F11, 1, 0, 0)); + ui_channel_->Send(new MetroViewerHostMsg_EdgeGesture()); return S_OK; } -void ChromeAppViewAsh::OnSearchRequest(const string16& search_string) { +void ChromeAppViewAsh::OnSearchRequest(const base::string16& search_string) { DCHECK(ui_channel_); ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string)); } -void ChromeAppViewAsh::OnNavigateToUrl(const string16& url) { +void ChromeAppViewAsh::OnNavigateToUrl(const base::string16& url) { DCHECK(ui_channel_); ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url)); } @@ -1227,13 +1368,14 @@ HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender, return S_OK; } - winfoundtn::Size size; - HRESULT hr = args->get_Size(&size); - if (FAILED(hr)) - return hr; + // winui::Core::IWindowSizeChangedEventArgs args->Size appears to return + // scaled values under HiDPI. We will instead use GetWindowRect() which + // should always return values in Pixels. + RECT rect = {0}; + ::GetWindowRect(core_window_hwnd_, &rect); - uint32 cx = static_cast<uint32>(size.Width); - uint32 cy = static_cast<uint32>(size.Height); + uint32 cx = static_cast<uint32>(rect.right - rect.left); + uint32 cy = static_cast<uint32>(rect.bottom - rect.top); DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy; ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy)); @@ -1243,9 +1385,7 @@ HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender, /////////////////////////////////////////////////////////////////////////////// ChromeAppViewFactory::ChromeAppViewFactory( - winapp::Core::ICoreApplication* icore_app, - LPTHREAD_START_ROUTINE host_main, - void* host_context) { + winapp::Core::ICoreApplication* icore_app) { mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app); mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; CheckHR(core_app.As(&app_exit)); |