diff options
Diffstat (limited to 'chromium/ui/base/win')
-rw-r--r-- | chromium/ui/base/win/direct_manipulation.cc | 121 | ||||
-rw-r--r-- | chromium/ui/base/win/direct_manipulation.h | 88 | ||||
-rw-r--r-- | chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc | 379 | ||||
-rw-r--r-- | chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h | 60 | ||||
-rw-r--r-- | chromium/ui/base/win/shell.cc | 50 | ||||
-rw-r--r-- | chromium/ui/base/win/shell.h | 4 |
6 files changed, 666 insertions, 36 deletions
diff --git a/chromium/ui/base/win/direct_manipulation.cc b/chromium/ui/base/win/direct_manipulation.cc new file mode 100644 index 00000000000..78f19277727 --- /dev/null +++ b/chromium/ui/base/win/direct_manipulation.cc @@ -0,0 +1,121 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/win/direct_manipulation.h" + +#include <objbase.h> + +#include "base/win/windows_version.h" + +namespace ui { +namespace win { + +// static +std::unique_ptr<DirectManipulationHelper> +DirectManipulationHelper::CreateInstance() { + // TODO(dtapuska): Do not create a DirectManipulationHelper on any windows + // versions as it only causes issues. High Precision Touchpad events seem to + // always be sent to apps with recent Windows 10 versions. This class should + // eventually be removed. See https://crbug.com/647038. + return nullptr; +} + +DirectManipulationHelper::DirectManipulationHelper() {} + +DirectManipulationHelper::~DirectManipulationHelper() { + if (view_port_outer_) + view_port_outer_->Abandon(); +} + +void DirectManipulationHelper::Initialize(HWND window) { + DCHECK(::IsWindow(window)); + + // TODO(ananta) + // Remove the CHECK statements here and below and replace them with logs + // when this code stabilizes. + HRESULT hr = + ::CoCreateInstance(CLSID_DirectManipulationManager, nullptr, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&manager_)); + CHECK(SUCCEEDED(hr)); + + hr = ::CoCreateInstance(CLSID_DCompManipulationCompositor, nullptr, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&compositor_)); + CHECK(SUCCEEDED(hr)); + + hr = manager_->GetUpdateManager(IID_PPV_ARGS(update_manager_.GetAddressOf())); + CHECK(SUCCEEDED(hr)); + + hr = compositor_->SetUpdateManager(update_manager_.Get()); + CHECK(SUCCEEDED(hr)); + + hr = compositor_.CopyTo(frame_info_.GetAddressOf()); + CHECK(SUCCEEDED(hr)); + + hr = manager_->CreateViewport(frame_info_.Get(), window, + IID_PPV_ARGS(view_port_outer_.GetAddressOf())); + CHECK(SUCCEEDED(hr)); + + // + // Enable the desired configuration for each viewport. + // + DIRECTMANIPULATION_CONFIGURATION configuration = + DIRECTMANIPULATION_CONFIGURATION_INTERACTION | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA | + DIRECTMANIPULATION_CONFIGURATION_RAILS_X | + DIRECTMANIPULATION_CONFIGURATION_RAILS_Y | + DIRECTMANIPULATION_CONFIGURATION_SCALING | + DIRECTMANIPULATION_CONFIGURATION_SCALING_INERTIA; + + hr = view_port_outer_->ActivateConfiguration(configuration); + CHECK(SUCCEEDED(hr)); +} + +void DirectManipulationHelper::SetBounds(const gfx::Rect& bounds) { + Microsoft::WRL::ComPtr<IDirectManipulationPrimaryContent> + primary_content_outer; + HRESULT hr = view_port_outer_->GetPrimaryContent( + IID_PPV_ARGS(primary_content_outer.GetAddressOf())); + CHECK(SUCCEEDED(hr)); + + Microsoft::WRL::ComPtr<IDirectManipulationContent> content_outer; + hr = primary_content_outer.CopyTo(content_outer.GetAddressOf()); + CHECK(SUCCEEDED(hr)); + + RECT rect = bounds.ToRECT(); + + hr = view_port_outer_->SetViewportRect(&rect); + CHECK(SUCCEEDED(hr)); + + hr = content_outer->SetContentRect(&rect); + CHECK(SUCCEEDED(hr)); +} + +void DirectManipulationHelper::Activate(HWND window) { + DCHECK(::IsWindow(window)); + manager_->Activate(window); +} + +void DirectManipulationHelper::Deactivate(HWND window) { + DCHECK(::IsWindow(window)); + manager_->Deactivate(window); +} + +void DirectManipulationHelper::HandleMouseWheel(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param) { + MSG msg = {window, message, w_param, l_param}; + + HRESULT hr = view_port_outer_->SetContact(DIRECTMANIPULATION_MOUSEFOCUS); + if (SUCCEEDED(hr)) { + BOOL handled = FALSE; + manager_->ProcessInput(&msg, &handled); + view_port_outer_->ReleaseContact(DIRECTMANIPULATION_MOUSEFOCUS); + } +} + +} // namespace win. +} // namespace ui. diff --git a/chromium/ui/base/win/direct_manipulation.h b/chromium/ui/base/win/direct_manipulation.h new file mode 100644 index 00000000000..af7ad807f2e --- /dev/null +++ b/chromium/ui/base/win/direct_manipulation.h @@ -0,0 +1,88 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_WIN_DIRECT_MANIPULATION_H_ +#define UI_WIN_DIRECT_MANIPULATION_H_ + +#include <directmanipulation.h> +#include <wrl/client.h> + +#include <memory> + +#include "base/macros.h" +#include "ui/base/ui_base_export.h" +#include "ui/gfx/geometry/rect.h" + +namespace ui { +namespace win { + +// Windows 10 provides a new API called Direct Manipulation which generates +// smooth scroll events via WM_MOUSEWHEEL messages with predictable deltas +// on high precision touch pads. This basically requires the application window +// to register as a Direct Manipulation consumer. The way mouse wheel messages +// are dispatched is +// 1. The foreground window is checked to see if it is a Direct Manipulation +// consumer. +// 2. If it is then Direct Manipulation takes over and sends the following +// messages. WM_POINTERACTIVATE, WM_POINTERDOWN and DM_POINTERHITTEST. +// 3. It then posts WM_MOUSEWHEEL messages with precision deltas which vary +// based on the amount of the scroll. +// 4. If the foreground window is not a Direct Manipulation consumer, it +// then takes a fallback route where it posts WM_MOUSEWHEEL messages +// with precision but varying deltas to the window. There is a also +// a slight delay in receiving the first set of mouse wheel messages. +// This causes scrolling to appear janky and jumpy. +// Our approach for addressing this is to do the absolute minimum to +// register our window as a Direct Manipulation consumer. This class +// provides the necessary functionality to register the passed in HWND as a +// Direct Manipulation consumer. We don't rely on Direct manipulation +// to do the smooth scrolling in the background thread as documented on +// msdn. +class UI_BASE_EXPORT DirectManipulationHelper { + public: + // Creates an instance of this class if Direct Manipulation is enabled on + // the platform. If not returns NULL. + static std::unique_ptr<DirectManipulationHelper> CreateInstance(); + + // This function instantiates Direct Manipulation and creates a viewport for + // the passed in |window|. + // consumer. Most of the code is boiler plate and is based on the sample. + void Initialize(HWND window); + + // Sets the bounds of the fake Direct manipulation viewport to match those + // of the legacy window. + void SetBounds(const gfx::Rect& bounds); + + // Registers and activates the passed in |window| as a Direct Manipulation + // consumer. + void Activate(HWND window); + + // Deactivates Direct Manipulation processing on the passed in |window|. + void Deactivate(HWND window); + + // Passes the WM_MOUSEWHEEL messages to Direct Manipulation. This is for + // logistics purposes. + void HandleMouseWheel(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param); + + ~DirectManipulationHelper(); + + private: + DirectManipulationHelper(); + + Microsoft::WRL::ComPtr<IDirectManipulationManager2> manager_; + Microsoft::WRL::ComPtr<IDirectManipulationCompositor> compositor_; + Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> update_manager_; + Microsoft::WRL::ComPtr<IDirectManipulationFrameInfoProvider> frame_info_; + Microsoft::WRL::ComPtr<IDirectManipulationViewport2> view_port_outer_; + + DISALLOW_COPY_AND_ASSIGN(DirectManipulationHelper); +}; + +} // namespace win +} // namespace ui + +#endif // UI_WIN_DIRECT_MANIPULATION_H_ diff --git a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc new file mode 100644 index 00000000000..bbce7bda6eb --- /dev/null +++ b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc @@ -0,0 +1,379 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/win/osk_display_manager.h" + +#include <windows.h> +#include <shellapi.h> +#include <shlobj.h> +#include <shobjidl.h> // Must be before propkey. + +#include "base/bind.h" +#include "base/debug/leak_annotations.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/single_thread_task_runner.h" +#include "base/strings/string_util.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/win/registry.h" +#include "base/win/scoped_co_mem.h" +#include "base/win/win_util.h" +#include "base/win/windows_version.h" +#include "ui/base/win/hidden_window.h" +#include "ui/base/win/osk_display_observer.h" +#include "ui/display/win/dpi.h" +#include "ui/gfx/geometry/dip_util.h" + +namespace { + +constexpr int kCheckOSKDelayMs = 1000; +constexpr int kDismissKeyboardRetryTimeoutMs = 100; +constexpr int kDismissKeyboardMaxRetries = 5; + +constexpr wchar_t kOSKClassName[] = L"IPTip_Main_Window"; + +constexpr wchar_t kWindows8OSKRegPath[] = + L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}" + L"\\LocalServer32"; + +} // namespace + +namespace ui { + +// This class provides functionality to detect when the on screen keyboard +// is displayed and move the main window up if it is obscured by the keyboard. +class OnScreenKeyboardDetector { + public: + OnScreenKeyboardDetector(); + ~OnScreenKeyboardDetector(); + + // Schedules a delayed task which detects if the on screen keyboard was + // displayed. + void DetectKeyboard(HWND main_window); + + // Dismisses the on screen keyboard. If a call to display the keyboard was + // made, this function waits for the keyboard to become visible by retrying + // upto a maximum of kDismissKeyboardMaxRetries. + bool DismissKeyboard(); + + // Add/Remove keyboard observers. + // Please note that this class does not track the |observer| destruction. It + // is upto the classes which set up these observers to remove them when they + // are destroyed. + void AddObserver(OnScreenKeyboardObserver* observer); + void RemoveObserver(OnScreenKeyboardObserver* observer); + + // Returns true if the osk is visible. Sets osk bounding rect if non-null + static bool IsKeyboardVisible(gfx::Rect* osk_bounding_rect); + + private: + // Executes as a task and detects if the on screen keyboard is displayed. + // Once the keyboard is displayed it schedules the HideIfNecessary() task to + // detect when the keyboard is or should be hidden. + void CheckIfKeyboardVisible(); + + // Executes as a task and detects if the keyboard was hidden or should be + // hidden. + void HideIfNecessary(); + + // Notifies observers that the keyboard was displayed. + // A recurring task HideIfNecessary() is started to detect when the OSK + // disappears. + void HandleKeyboardVisible(); + + // Notifies observers that the keyboard was hidden. + // The observer list is cleared out after this notification. + void HandleKeyboardHidden(); + + // Removes all observers from the list. + void ClearObservers(); + + // The main window which displays the on screen keyboard. + HWND main_window_ = nullptr; + + // Tracks if the keyboard was displayed. + bool osk_visible_notification_received_ = false; + + // The keyboard dimensions in pixels. + gfx::Rect osk_rect_pixels_; + + // Set to true if a call to DetectKeyboard() was made. + bool keyboard_detect_requested_ = false; + + // Contains the number of attempts made to dismiss the keyboard. Please refer + // to the DismissKeyboard() function for more information. + int keyboard_dismiss_retry_count_ = 0; + + base::ObserverList<OnScreenKeyboardObserver, false> observers_; + + // Should be the last member in the class. Helps ensure that tasks spawned + // by this class instance are canceled when it is destroyed. + base::WeakPtrFactory<OnScreenKeyboardDetector> keyboard_detector_factory_; + + DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDetector); +}; + +// OnScreenKeyboardDetector member definitions. +OnScreenKeyboardDetector::OnScreenKeyboardDetector() + : keyboard_detector_factory_(this) {} + +OnScreenKeyboardDetector::~OnScreenKeyboardDetector() { + ClearObservers(); +} + +void OnScreenKeyboardDetector::DetectKeyboard(HWND main_window) { + main_window_ = main_window; + keyboard_detect_requested_ = true; + // The keyboard is displayed by TabTip.exe which is launched via a + // ShellExecute call in the + // OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard() function. We use + // a delayed task to check if the keyboard is visible because of the possible + // delay between the ShellExecute call and the keyboard becoming visible. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&OnScreenKeyboardDetector::CheckIfKeyboardVisible, + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); +} + +bool OnScreenKeyboardDetector::DismissKeyboard() { + // We dismiss the virtual keyboard by generating the ESC keystroke + // programmatically. + HWND osk = ::FindWindow(kOSKClassName, nullptr); + if (::IsWindow(osk) && ::IsWindowEnabled(osk)) { + keyboard_detect_requested_ = false; + keyboard_dismiss_retry_count_ = 0; + HandleKeyboardHidden(); + PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0); + return true; + } else if (keyboard_detect_requested_) { + if (keyboard_dismiss_retry_count_ < kDismissKeyboardMaxRetries) { + keyboard_dismiss_retry_count_++; + // Please refer to the comments in the DetectKeyboard() function for more + // information as to why we need a delayed task here. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(base::IgnoreResult( + &OnScreenKeyboardDetector::DismissKeyboard), + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kDismissKeyboardRetryTimeoutMs)); + } else { + keyboard_dismiss_retry_count_ = 0; + } + } + return false; +} + +void OnScreenKeyboardDetector::AddObserver(OnScreenKeyboardObserver* observer) { + observers_.AddObserver(observer); +} + +void OnScreenKeyboardDetector::RemoveObserver( + OnScreenKeyboardObserver* observer) { + observers_.RemoveObserver(observer); +} + +// static +bool OnScreenKeyboardDetector::IsKeyboardVisible(gfx::Rect* osk_bounding_rect) { + HWND osk = ::FindWindow(kOSKClassName, nullptr); + if (!::IsWindow(osk)) + return false; + if (osk_bounding_rect) { + RECT osk_rect = {}; + ::GetWindowRect(osk, &osk_rect); + *osk_bounding_rect = gfx::Rect(osk_rect); + } + return ::IsWindowVisible(osk) && ::IsWindowEnabled(osk); +} + +void OnScreenKeyboardDetector::CheckIfKeyboardVisible() { + if (IsKeyboardVisible(&osk_rect_pixels_)) { + if (!osk_visible_notification_received_) + HandleKeyboardVisible(); + } else { + DVLOG(1) << "OSK did not come up in 1 second. Something wrong."; + } +} + +void OnScreenKeyboardDetector::HideIfNecessary() { + HWND osk = ::FindWindow(kOSKClassName, nullptr); + if (!::IsWindow(osk)) + return; + + // Three cases here. + // 1. OSK was hidden because the user dismissed it. + // 2. We are no longer in the foreground. + // 3. The OSK is still visible. + // In the first case we just have to notify the observers that the OSK was + // hidden. + // In the second case we need to dismiss the OSK which internally will + // notify the observers about the OSK being hidden. + if (!::IsWindowEnabled(osk)) { + if (osk_visible_notification_received_) { + if (main_window_ == ::GetForegroundWindow()) { + DVLOG(1) << "OSK window hidden while we are in the foreground."; + HandleKeyboardHidden(); + } + } + } else if (main_window_ != ::GetForegroundWindow()) { + if (osk_visible_notification_received_) { + DVLOG(1) << "We are no longer in the foreground. Dismising OSK."; + DismissKeyboard(); + } + } else { + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary, + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); + } +} + +void OnScreenKeyboardDetector::HandleKeyboardVisible() { + DCHECK(!osk_visible_notification_received_); + osk_visible_notification_received_ = true; + + for (OnScreenKeyboardObserver& observer : observers_) + observer.OnKeyboardVisible(osk_rect_pixels_); + + // Now that the keyboard is visible, run the task to detect if it was hidden. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary, + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); +} + +void OnScreenKeyboardDetector::HandleKeyboardHidden() { + osk_visible_notification_received_ = false; + for (OnScreenKeyboardObserver& observer : observers_) + observer.OnKeyboardHidden(osk_rect_pixels_); + ClearObservers(); +} + +void OnScreenKeyboardDetector::ClearObservers() { + for (auto& observer : observers_) + RemoveObserver(&observer); +} + +// OnScreenKeyboardDisplayManager member definitions. +OnScreenKeyboardDisplayManager::OnScreenKeyboardDisplayManager() {} + +OnScreenKeyboardDisplayManager::~OnScreenKeyboardDisplayManager() {} + +OnScreenKeyboardDisplayManager* OnScreenKeyboardDisplayManager::GetInstance() { + static OnScreenKeyboardDisplayManager* instance = nullptr; + if (!instance) { + instance = new OnScreenKeyboardDisplayManager; + ANNOTATE_LEAKING_OBJECT_PTR(instance); + } + return instance; +} + +bool OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard( + OnScreenKeyboardObserver* observer) { + if (base::win::GetVersion() < base::win::VERSION_WIN8) + return false; + + if (base::win::IsKeyboardPresentOnSlate(nullptr, ui::GetHiddenWindow())) + return false; + + if (osk_path_.empty() && !GetOSKPath(&osk_path_)) { + DLOG(WARNING) << "Failed to get on screen keyboard path from registry"; + return false; + } + + HINSTANCE ret = ::ShellExecuteW(nullptr, L"", osk_path_.c_str(), nullptr, + nullptr, SW_SHOW); + + bool success = reinterpret_cast<intptr_t>(ret) > 32; + if (success) { + // If multiple calls to DisplayVirtualKeyboard occur one after the other, + // the last observer would be the one to get notifications. + keyboard_detector_.reset(new OnScreenKeyboardDetector); + if (observer) + keyboard_detector_->AddObserver(observer); + keyboard_detector_->DetectKeyboard(::GetForegroundWindow()); + } + return success; +} + +bool OnScreenKeyboardDisplayManager::DismissVirtualKeyboard() { + if (base::win::GetVersion() < base::win::VERSION_WIN8) + return false; + + return keyboard_detector_ ? keyboard_detector_->DismissKeyboard() : false; +} + +void OnScreenKeyboardDisplayManager::RemoveObserver( + OnScreenKeyboardObserver* observer) { + if (keyboard_detector_) + keyboard_detector_->RemoveObserver(observer); +} + +bool OnScreenKeyboardDisplayManager::GetOSKPath(base::string16* osk_path) { + DCHECK(osk_path); + + // We need to launch TabTip.exe from the location specified under the + // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}} + // CLSID. + // TabTip.exe is typically found at + // c:\program files\common files\microsoft shared\ink on English Windows. + // We don't want to launch TabTip.exe from + // c:\program files (x86)\common files\microsoft shared\ink. This path is + // normally found on 64 bit Windows. + base::win::RegKey key(HKEY_LOCAL_MACHINE, kWindows8OSKRegPath, + KEY_READ | KEY_WOW64_64KEY); + DWORD osk_path_length = 1024; + if (key.ReadValue(nullptr, base::WriteInto(osk_path, osk_path_length), + &osk_path_length, nullptr) != ERROR_SUCCESS) { + return false; + } + + osk_path->resize(base::string16::traits_type::length(osk_path->c_str())); + + *osk_path = base::ToLowerASCII(*osk_path); + + size_t common_program_files_offset = osk_path->find(L"%commonprogramfiles%"); + // Typically the path to TabTip.exe read from the registry will start with + // %CommonProgramFiles% which needs to be replaced with the corrsponding + // expanded string. + // If the path does not begin with %CommonProgramFiles% we use it as is. + if (common_program_files_offset != base::string16::npos) { + // Preserve the beginning quote in the path. + osk_path->erase(common_program_files_offset, + wcslen(L"%commonprogramfiles%")); + // The path read from the registry contains the %CommonProgramFiles% + // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath + // function returns the common program files path with the X86 suffix for + // the FOLDERID_ProgramFilesCommon value. + // To get the correct path to TabTip.exe we first read the environment + // variable CommonProgramW6432 which points to the desired common + // files path. Failing that we fallback to the SHGetKnownFolderPath API. + + // We then replace the %CommonProgramFiles% value with the actual common + // files path found in the process. + base::string16 common_program_files_path; + DWORD buffer_size = + GetEnvironmentVariable(L"CommonProgramW6432", nullptr, 0); + if (buffer_size) { + GetEnvironmentVariable( + L"CommonProgramW6432", + base::WriteInto(&common_program_files_path, buffer_size), + buffer_size); + DCHECK(!common_program_files_path.empty()); + } else { + base::win::ScopedCoMem<wchar_t> common_program_files; + if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, nullptr, + &common_program_files))) { + return false; + } + common_program_files_path = common_program_files; + } + osk_path->insert(common_program_files_offset, common_program_files_path); + } + return !osk_path->empty(); +} + +bool OnScreenKeyboardDisplayManager::IsKeyboardVisible() const { + return OnScreenKeyboardDetector::IsKeyboardVisible(nullptr); +} + +} // namespace ui diff --git a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h new file mode 100644 index 00000000000..b5392c4b686 --- /dev/null +++ b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_ +#define UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_ + +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/strings/string16.h" +#include "ui/base/ui_base_export.h" +#include "ui/gfx/geometry/rect.h" + +namespace ui { + +class OnScreenKeyboardDetector; +class OnScreenKeyboardObserver; + +// This class provides functionality to display the on screen keyboard on +// Windows 8+. It optionally notifies observers that the OSK is displayed, +// hidden, etc. +class UI_BASE_EXPORT OnScreenKeyboardDisplayManager { + public: + static OnScreenKeyboardDisplayManager* GetInstance(); + + ~OnScreenKeyboardDisplayManager(); + + // Functions to display and dismiss the keyboard. + // The optional |observer| parameter allows callers to be notified when the + // keyboard is displayed, dismissed, etc. + bool DisplayVirtualKeyboard(OnScreenKeyboardObserver* observer); + // When the keyboard is dismissed, the registered observer if any is removed + // after notifying it. + bool DismissVirtualKeyboard(); + + // Removes a registered observer. + void RemoveObserver(OnScreenKeyboardObserver* observer); + + // Returns the path of the on screen keyboard exe (TabTip.exe) in the + // |osk_path| parameter. + // Returns true on success. + bool GetOSKPath(base::string16* osk_path); + + // Returns true if the virtual keyboard is currently visible. + bool IsKeyboardVisible() const; + + private: + OnScreenKeyboardDisplayManager(); + + std::unique_ptr<OnScreenKeyboardDetector> keyboard_detector_; + + // The location of TabTip.exe. + base::string16 osk_path_; + + DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManager); +}; + +} // namespace ui + +#endif // UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_ diff --git a/chromium/ui/base/win/shell.cc b/chromium/ui/base/win/shell.cc index ebd6c65d481..b5afdead174 100644 --- a/chromium/ui/base/win/shell.cc +++ b/chromium/ui/base/win/shell.cc @@ -27,29 +27,21 @@ namespace win { namespace { -// Default ShellExecuteEx flags used with the "openas" verb. +// Default ShellExecuteEx flags used with "openas", "explore", and default +// verbs. // // SEE_MASK_NOASYNC is specified so that ShellExecuteEx can be invoked from a // thread whose message loop may not wait around long enough for the // asynchronous tasks initiated by ShellExecuteEx to complete. Using this flag // causes ShellExecuteEx() to block until these tasks complete. -const DWORD kDefaultOpenAsFlags = SEE_MASK_NOASYNC; - -// Default ShellExecuteEx flags used with the "explore", "open" or default verb. -// -// See kDefaultOpenFlags for description SEE_MASK_NOASYNC flag. -// SEE_MASK_FLAG_NO_UI is used to suppress any error message boxes that might be -// displayed if there is an error in opening the file. Failure in invoking the -// "open" actions result in invocation of the "saveas" verb, making the error -// dialog superfluous. -const DWORD kDefaultOpenFlags = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; +const DWORD kDefaultShellExecuteFlags = SEE_MASK_NOASYNC; // Invokes ShellExecuteExW() with the given parameters. -DWORD InvokeShellExecute(const base::string16 path, - const base::string16 working_directory, - const base::string16 args, - const base::string16 verb, - DWORD mask) { +bool InvokeShellExecute(const base::string16 path, + const base::string16 working_directory, + const base::string16 args, + const base::string16 verb, + DWORD mask) { base::AssertBlockingAllowed(); SHELLEXECUTEINFO sei = {sizeof(sei)}; sei.fMask = mask; @@ -59,7 +51,7 @@ DWORD InvokeShellExecute(const base::string16 path, sei.lpDirectory = (working_directory.empty() ? nullptr : working_directory.c_str()); sei.lpParameters = (args.empty() ? nullptr : args.c_str()); - return ::ShellExecuteExW(&sei) ? ERROR_SUCCESS : ::GetLastError(); + return ::ShellExecuteExW(&sei); } } // namespace @@ -68,32 +60,22 @@ bool OpenAnyViaShell(const base::string16& full_path, const base::string16& directory, const base::string16& args, DWORD mask) { - DWORD open_result = - InvokeShellExecute(full_path, directory, args, base::string16(), mask); - if (open_result == ERROR_SUCCESS) - return true; - // Show the Windows "Open With" dialog box to ask the user to pick an app to - // open the file with. Note that we are not forwarding |args| for the "openas" - // call since the target application is nolonger known at this point. - if (open_result == ERROR_NO_ASSOCIATION) - return InvokeShellExecute(full_path, directory, base::string16(), L"openas", - kDefaultOpenAsFlags) == ERROR_SUCCESS; - return false; + return InvokeShellExecute(full_path, directory, args, base::string16(), mask); } bool OpenFileViaShell(const base::FilePath& full_path) { - return OpenAnyViaShell(full_path.value(), full_path.DirName().value(), - base::string16(), kDefaultOpenFlags); + // Invoke the default verb on the file with no arguments. + return InvokeShellExecute(full_path.value(), full_path.DirName().value(), + base::string16(), base::string16(), + kDefaultShellExecuteFlags); } bool OpenFolderViaShell(const base::FilePath& full_path) { // The "explore" verb causes the folder at |full_path| to be displayed in a - // file browser. This will fail if |full_path| is not a directory. The - // resulting error does not cause UI due to the SEE_MASK_FLAG_NO_UI flag in - // kDefaultOpenFlags. + // file browser. This will fail if |full_path| is not a directory. return InvokeShellExecute(full_path.value(), full_path.value(), base::string16(), L"explore", - kDefaultOpenFlags) == ERROR_SUCCESS; + kDefaultShellExecuteFlags); } bool PreventWindowFromPinning(HWND hwnd) { diff --git a/chromium/ui/base/win/shell.h b/chromium/ui/base/win/shell.h index df784a6e13b..c47e5ce3f47 100644 --- a/chromium/ui/base/win/shell.h +++ b/chromium/ui/base/win/shell.h @@ -17,8 +17,8 @@ class FilePath; namespace ui { namespace win { -// Open the folder at |full_path| via the Windows shell. Does nothing if -// |full_path| is not a folder. +// Open the folder at |full_path| via the Windows shell. It is an error if +// |full_path| does not refer to a folder. // // Note: Must be called on a thread that allows blocking. UI_BASE_EXPORT bool OpenFolderViaShell(const base::FilePath& full_path); |