Bug 1239744 - no longer automatically show an on-screen keyboard for programmatic focus changes, tidy up osk logic in IMEHandler, r=masayuki

--HG--
extra : rebase_source : 013c2759f4faca65ed3de79ca1d7f0b97e6375cb
This commit is contained in:
Gijs Kruitbosch 2016-02-09 19:39:55 +00:00
parent 8532605cf4
commit b499a37faf
3 changed files with 55 additions and 20 deletions

View File

@ -393,6 +393,18 @@ struct InputContextAction final
(mCause == CAUSE_MOUSE || mCause == CAUSE_TOUCH));
}
static bool IsUserAction(Cause aCause)
{
switch (aCause) {
case CAUSE_KEY:
case CAUSE_MOUSE:
case CAUSE_TOUCH:
return true;
default:
return false;
}
}
InputContextAction()
: mCause(CAUSE_UNKNOWN)
, mFocusChange(FOCUS_NOT_CHANGED)

View File

@ -606,7 +606,7 @@ IMEHandler::MaybeShowOnScreenKeyboard()
!IsWin8OrLater() ||
!Preferences::GetBool(kOskEnabled, true) ||
GetOnScreenKeyboardWindow() ||
IMEHandler::IsKeyboardPresentOnSlate()) {
!IMEHandler::NeedOnScreenKeyboard()) {
return;
}
@ -653,24 +653,31 @@ IMEHandler::WStringStartsWithCaseInsensitive(const std::wstring& aHaystack,
lowerCaseNeedle.c_str()) == lowerCaseHaystack.c_str();
}
// Returns true if a physical keyboard is detected on Windows 8 and up.
// Uses the Setup APIs to enumerate the attached keyboards and returns true
// if the keyboard count is 1 or more. While this will work in most cases
// it won't work if there are devices which expose keyboard interfaces which
// are attached to the machine.
// Based on IsKeyboardPresentOnSlate() in Chromium's base/win/win_util.cc.
// Returns false if a physical keyboard is detected on Windows 8 and up,
// or there is some other reason why an onscreen keyboard is not necessary.
// Returns true if no keyboard is found and this device looks like it needs
// an on-screen keyboard for text input.
// static
bool
IMEHandler::IsKeyboardPresentOnSlate()
IMEHandler::NeedOnScreenKeyboard()
{
// This function is only supported for Windows 8 and up.
if (!IsWin8OrLater()) {
Preferences::SetString(kOskDebugReason, L"IKPOS: Requires Win8+.");
return true;
return false;
}
if (!Preferences::GetBool(kOskDetectPhysicalKeyboard, true)) {
Preferences::SetString(kOskDebugReason, L"IKPOS: Detection disabled.");
return true;
}
// If the last focus cause was not user-initiated (ie a result of code
// setting focus to an element) then don't auto-show a keyboard. This
// avoids cases where the keyboard would pop up "just" because e.g. a
// web page chooses to focus a search field on the page, even when that
// really isn't what the user is trying to do at that moment.
if (!InputContextAction::IsUserAction(sLastContextActionCause)) {
return false;
}
@ -679,13 +686,13 @@ IMEHandler::IsKeyboardPresentOnSlate()
!= NID_INTEGRATED_TOUCH) {
Preferences::SetString(kOskDebugReason,
L"IKPOS: Touch screen not found.");
return true;
return false;
}
// If the device is docked, the user is treating the device as a PC.
if (::GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
Preferences::SetString(kOskDebugReason, L"IKPOS: System docked.");
return true;
return false;
}
// To determine whether a keyboard is present on the device, we do the
@ -697,11 +704,15 @@ IMEHandler::IsKeyboardPresentOnSlate()
// 2. If the device supports auto rotation, then we get its platform role
// and check the system metric SM_CONVERTIBLESLATEMODE to see if it is
// being used in slate mode. If yes then we return false here to ensure
// that the OSK is displayed.
// being used in slate mode. If not then we return false here to ensure
// that the OSK is not displayed.
// 3. If step 1 and 2 fail then we check attached keyboards and return true
// if we find ACPI\*, HID\VID* or bluetooth keyboards.
// 3. If step 1 and 2 both confirm this *could* be a device with no usable
// keyboard, we check whether the last input was touch-based. If so,
// we return true immediately to get an on-screen keyboard.
// 4. If this was a mouse or (on-screen) keyboard event, we check if
// this device has keyboards attached to it.
typedef BOOL (WINAPI* GetAutoRotationState)(PAR_STATE state);
GetAutoRotationState get_rotation_state =
@ -717,11 +728,11 @@ IMEHandler::IsKeyboardPresentOnSlate()
if (auto_rotation_state & AR_NOSENSOR) {
Preferences::SetString(kOskDebugReason,
L"IKPOS: Rotation sensor not found.");
return true;
return false;
} else if (auto_rotation_state & AR_NOT_SUPPORTED) {
Preferences::SetString(kOskDebugReason,
L"IKPOS: Auto-rotation not supported.");
return true;
return false;
}
}
@ -747,13 +758,13 @@ IMEHandler::IsKeyboardPresentOnSlate()
if (sPowerPlatformRole != PlatformRoleMobile &&
sPowerPlatformRole != PlatformRoleSlate) {
Preferences::SetString(kOskDebugReason, L"IKPOS: PlatformRole is neither Mobile nor Slate.");
return true;
return false;
}
// Likewise, if the tablet/mobile isn't in "slate" mode, we should bail:
if (::GetSystemMetrics(SM_CONVERTIBLESLATEMODE) != 0) {
Preferences::SetString(kOskDebugReason, L"IKPOS: ConvertibleSlateMode is non-zero");
return true;
return false;
}
// Before we check for a keyboard, we should check if the last input was touch,
@ -761,9 +772,20 @@ IMEHandler::IsKeyboardPresentOnSlate()
if (sLastContextActionCause == InputContextAction::CAUSE_TOUCH) {
Preferences::SetString(kOskDebugReason,
L"IKPOS: Used touch to focus control, ignoring keyboard presence");
return false;
return true;
}
return !IMEHandler::IsKeyboardPresentOnSlate();
}
// Uses the Setup APIs to enumerate the attached keyboards and returns true
// if the keyboard count is 1 or more. While this will work in most cases
// it won't work if there are devices which expose keyboard interfaces which
// are attached to the machine.
// Based on IsKeyboardPresentOnSlate() in Chromium's base/win/win_util.cc.
// static
bool
IMEHandler::IsKeyboardPresentOnSlate()
{
const GUID KEYBOARD_CLASS_GUID =
{ 0x4D36E96B, 0xE325, 0x11CE,
{ 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };

View File

@ -145,6 +145,7 @@ private:
static void MaybeDismissOnScreenKeyboard(nsWindow* aWindow);
static bool WStringStartsWithCaseInsensitive(const std::wstring& aHaystack,
const std::wstring& aNeedle);
static bool NeedOnScreenKeyboard();
static bool IsKeyboardPresentOnSlate();
static bool IsInTabletMode();
static bool AutoInvokeOnScreenKeyboardInDesktopMode();