blob: b21ea2aeaaf7a92c7cb124b7f0754d074881a11f [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "win32/tip/tip_input_mode_manager.h"
#include "testing/base/public/googletest.h"
#include "testing/base/public/gunit.h"
namespace mozc {
namespace win32 {
namespace tsf {
namespace {
typedef TipInputModeManagerImpl::StatePair StatePair;
class TestableTipInputModeManagerImpl : public TipInputModeManagerImpl {
public:
using TipInputModeManagerImpl::GetOverriddenState;
};
TipInputModeManager::Config GetGlobalMode() {
TipInputModeManager::Config config;
config.use_global_mode = true;
return config;
}
TipInputModeManager::Config GetThreadLocalMode() {
TipInputModeManager::Config config;
config.use_global_mode = false;
return config;
}
const DWORD kNativeHiragana =
IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN;
const DWORD kNativeHalfAlpha = IME_CMODE_ROMAN;
TEST(TipInputModeManagerImplTest, GetOverriddenState) {
// Check if input scopes for turning off IME temporarily.
{
vector<InputScope> input_scope_off;
input_scope_off.push_back(IS_NUMBER);
input_scope_off.push_back(IS_EMAIL_SMTPEMAILADDRESS);
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(false, TipInputModeManagerImpl::kHiragana),
input_scope_off);
EXPECT_FALSE(state.open_close);
EXPECT_EQ(TipInputModeManagerImpl::kHiragana, state.conversion_mode);
}
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(true, TipInputModeManagerImpl::kHiragana),
input_scope_off);
EXPECT_FALSE(state.open_close) << "Should be temporarily off.";
EXPECT_EQ(TipInputModeManagerImpl::kHiragana, state.conversion_mode);
}
}
// Check if input scopes for turning on IME temporarily.
{
vector<InputScope> input_scope_full_hiragana;
input_scope_full_hiragana.push_back(IS_HIRAGANA);
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(false, TipInputModeManagerImpl::kHiragana),
input_scope_full_hiragana);
EXPECT_TRUE(state.open_close) << "Should be temporarily on.";
EXPECT_EQ(TipInputModeManagerImpl::kHiragana, state.conversion_mode);
}
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(true, TipInputModeManagerImpl::kHiragana),
input_scope_full_hiragana);
EXPECT_TRUE(state.open_close) << "Should be temporarily on.";
EXPECT_EQ(TipInputModeManagerImpl::kHiragana, state.conversion_mode);
}
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(true, TipInputModeManagerImpl::kFullAscii),
input_scope_full_hiragana);
EXPECT_TRUE(state.open_close) << "Should be temporarily on.";
EXPECT_EQ(TipInputModeManagerImpl::kHiragana, state.conversion_mode)
<< "Should be temporarily Hiragana";
}
}
// If there are multiple input scopes and they are not aggregatable, use the
// original state as is.
{
vector<InputScope> input_scope_invalid;
input_scope_invalid.push_back(IS_HIRAGANA);
input_scope_invalid.push_back(IS_KATAKANA_FULLWIDTH);
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(false, TipInputModeManagerImpl::kHiragana),
input_scope_invalid);
EXPECT_FALSE(state.open_close);
EXPECT_EQ(TipInputModeManagerImpl::kHiragana, state.conversion_mode);
}
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(true, TipInputModeManagerImpl::kHiragana),
input_scope_invalid);
EXPECT_TRUE(state.open_close);
EXPECT_EQ(TipInputModeManagerImpl::kHiragana, state.conversion_mode);
}
{
const StatePair state =
TestableTipInputModeManagerImpl::GetOverriddenState(
StatePair(true, TipInputModeManagerImpl::kFullAscii),
input_scope_invalid);
EXPECT_TRUE(state.open_close);
EXPECT_EQ(TipInputModeManagerImpl::kFullAscii, state.conversion_mode);
}
}
}
TEST(TipInputModeManagerTest, IgnoreConversionModeByGlobalConfig_Issue8583505) {
// When per-session input mode is enabled, mode change notification from the
// application should be ignored.
TipInputModeManager input_mode_manager(GetGlobalMode());
// Initialize (Off + Hiragana)
input_mode_manager.OnInitialize(false, kNativeHiragana);
// SetFocus (Off + Hiragana)
vector<InputScope> input_scope_empty;
auto action = input_mode_manager.OnSetFocus(
false, kNativeHiragana, input_scope_empty);
EXPECT_EQ(TipInputModeManager::kDoNothing, action);
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
EXPECT_FALSE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_EQ(TipInputModeManager::kHiragana,
input_mode_manager.GetEffectiveConversionMode());
// On
input_mode_manager.OnReceiveCommand(
true, TipInputModeManager::kHiragana, TipInputModeManager::kHiragana);
EXPECT_TRUE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_TRUE(input_mode_manager.IsIndicatorVisible());
// Key
action = input_mode_manager.OnKey(VirtualKey(), true, true);
EXPECT_TRUE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
// Hiragana -> HalfAlpha (ignored)
action = input_mode_manager.OnChangeConversionMode(kNativeHalfAlpha);
EXPECT_EQ(TipInputModeManager::kDoNothing, action);
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
EXPECT_EQ(TipInputModeManager::kHiragana,
input_mode_manager.GetEffectiveConversionMode());
}
TEST(TipInputModeManagerTest, HonorConversionMode_Issue8583505) {
// When thread local input mode is enabled, mode change notification from the
// application should be honored.
TipInputModeManager input_mode_manager(GetThreadLocalMode());
// Initialize (Off + Hiragana)
input_mode_manager.OnInitialize(false, kNativeHiragana);
// SetFocus (Off + Hiragana)
vector<InputScope> input_scope_empty;
auto action = input_mode_manager.OnSetFocus(
false, kNativeHiragana, input_scope_empty);
EXPECT_EQ(TipInputModeManager::kDoNothing, action);
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
EXPECT_FALSE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_EQ(TipInputModeManager::kHiragana,
input_mode_manager.GetEffectiveConversionMode());
// On
input_mode_manager.OnReceiveCommand(
true, TipInputModeManager::kHiragana, TipInputModeManager::kHiragana);
EXPECT_TRUE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_TRUE(input_mode_manager.IsIndicatorVisible());
// Key
action = input_mode_manager.OnKey(VirtualKey(), true, true);
EXPECT_TRUE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
// Hiragana -> HalfAlpha (honored)
action = input_mode_manager.OnChangeConversionMode(kNativeHalfAlpha);
EXPECT_EQ(TipInputModeManager::kUpdateUI, action);
EXPECT_TRUE(input_mode_manager.IsIndicatorVisible());
EXPECT_EQ(TipInputModeManager::kHalfAscii,
input_mode_manager.GetEffectiveConversionMode());
}
TEST(TipInputModeManagerTest, ChangeInputScope) {
TipInputModeManager input_mode_manager(GetThreadLocalMode());
// Initialize (Off + Hiragana)
input_mode_manager.OnInitialize(false, kNativeHiragana);
// SetFocus (Off + Hiragana)
vector<InputScope> input_scope_empty;
auto action = input_mode_manager.OnSetFocus(
false, kNativeHiragana, input_scope_empty);
EXPECT_EQ(TipInputModeManager::kDoNothing, action);
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
EXPECT_FALSE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_EQ(TipInputModeManager::kHiragana,
input_mode_manager.GetEffectiveConversionMode());
vector<InputScope> input_scope_full_katakana;
input_scope_full_katakana.push_back(IS_KATAKANA_FULLWIDTH);
// InputScope: IS_KATAKANA_FULLWIDTH
// This should change the mode and make indicator visible.
action = input_mode_manager.OnChangeInputScope(input_scope_full_katakana);
EXPECT_EQ(TipInputModeManager::kUpdateUI, action);
EXPECT_TRUE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_EQ(TipInputModeManager::kFullKatakana,
input_mode_manager.GetEffectiveConversionMode());
EXPECT_TRUE(input_mode_manager.IsIndicatorVisible());
action = input_mode_manager.OnKey(VirtualKey(), true, true);
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
// InputScope: IS_EMAIL_SMTPEMAILADDRESS
// This should change the mode and make indicator visible.
vector<InputScope> input_scope_email;
input_scope_email.push_back(IS_EMAIL_SMTPEMAILADDRESS);
action = input_mode_manager.OnChangeInputScope(input_scope_email);
EXPECT_EQ(TipInputModeManager::kUpdateUI, action);
EXPECT_FALSE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_EQ(TipInputModeManager::kHiragana,
input_mode_manager.GetEffectiveConversionMode());
EXPECT_TRUE(input_mode_manager.IsIndicatorVisible());
// OnKey
// This should make indicator invisible.
action = input_mode_manager.OnKey(VirtualKey(), true, true);
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
// InputScope: IS_NUMBER
// This should not change the mode and keep indicator invisible.
vector<InputScope> input_scope_number;
input_scope_number.push_back(IS_NUMBER);
action = input_mode_manager.OnChangeInputScope(input_scope_number);
EXPECT_EQ(TipInputModeManager::kDoNothing, action);
EXPECT_FALSE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_EQ(TipInputModeManager::kHiragana,
input_mode_manager.GetEffectiveConversionMode());
EXPECT_FALSE(input_mode_manager.IsIndicatorVisible());
}
TEST(TipInputModeManagerTest, HonorOpenCloseModeFromApps_Issue8661096) {
TipInputModeManager input_mode_manager(GetGlobalMode());
// Initialize (Off + Hiragana)
input_mode_manager.OnInitialize(false, kNativeHiragana);
// An application calls ImmSetOpenStatus(himc, TRUE)
auto action = input_mode_manager.OnChangeOpenClose(true);
EXPECT_EQ(TipInputModeManager::kUpdateUI, action);
EXPECT_TRUE(input_mode_manager.IsIndicatorVisible());
EXPECT_TRUE(input_mode_manager.GetEffectiveOpenClose());
EXPECT_TRUE(input_mode_manager.GetTsfOpenClose());
}
} // namespace
} // namespace tsf
} // namespace win32
} // namespace mozc