Source code

Revision control

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define INPUTSCOPE_INIT_GUID
#define TEXTATTRS_INIT_GUID
#include "TSFTextStore.h"
#include <olectl.h>
#include <algorithm>
#include "nscore.h"
#include "IMMHandler.h"
#include "KeyboardLayout.h"
#include "WinIMEHandler.h"
#include "WinUtils.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_intl.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEvents.h"
#include "mozilla/ToString.h"
#include "mozilla/WindowsVersion.h"
#include "nsWindow.h"
#include "nsPrintfCString.h"
// Workaround for mingw32
#ifndef TS_SD_INPUTPANEMANUALDISPLAYENABLE
# define TS_SD_INPUTPANEMANUALDISPLAYENABLE 0x40
#endif
namespace mozilla {
namespace widget {
static const char* kPrefNameEnableTSF = "intl.tsf.enable";
/**
* TSF related code should log its behavior even on release build especially
* in the interface methods.
*
* In interface methods, use LogLevel::Info.
* In internal methods, use LogLevel::Debug for logging normal behavior.
* For logging error, use LogLevel::Error.
*
* When an instance method is called, start with following text:
* "0x%p TSFFoo::Bar(", the 0x%p should be the "this" of the nsFoo.
* after that, start with:
* "0x%p TSFFoo::Bar("
* In an internal method, start with following text:
* "0x%p TSFFoo::Bar("
* When a static method is called, start with following text:
* "TSFFoo::Bar("
*/
LazyLogModule sTextStoreLog("nsTextStoreWidgets");
enum class TextInputProcessorID {
// Internal use only. This won't be returned by TSFStaticSink::ActiveTIP().
eNotComputed,
// Not a TIP. E.g., simple keyboard layout or IMM-IME.
eNone,
// Used for other TIPs, i.e., any TIPs which we don't support specifically.
eUnknown,
// TIP for Japanese.
eMicrosoftIMEForJapanese,
eMicrosoftOfficeIME2010ForJapanese,
eGoogleJapaneseInput,
eATOK2011,
eATOK2012,
eATOK2013,
eATOK2014,
eATOK2015,
eATOK2016,
eATOKUnknown,
eJapanist10,
// TIP for Traditional Chinese.
eMicrosoftBopomofo,
eMicrosoftChangJie,
eMicrosoftPhonetic,
eMicrosoftQuick,
eMicrosoftNewChangJie,
eMicrosoftNewPhonetic,
eMicrosoftNewQuick,
eFreeChangJie,
// TIP for Simplified Chinese.
eMicrosoftPinyin,
eMicrosoftPinyinNewExperienceInputStyle,
eMicrosoftWubi,
// TIP for Korean.
eMicrosoftIMEForKorean,
eMicrosoftOldHangul,
// Keyman Desktop, which can install various language keyboards.
eKeymanDesktop,
};
static const char* GetBoolName(bool aBool) { return aBool ? "true" : "false"; }
static void HandleSeparator(nsCString& aDesc) {
if (!aDesc.IsEmpty()) {
aDesc.AppendLiteral(" | ");
}
}
static const nsCString GetFindFlagName(DWORD aFindFlag) {
nsCString description;
if (!aFindFlag) {
description.AppendLiteral("no flags (0)");
return description;
}
if (aFindFlag & TS_ATTR_FIND_BACKWARDS) {
description.AppendLiteral("TS_ATTR_FIND_BACKWARDS");
}
if (aFindFlag & TS_ATTR_FIND_WANT_OFFSET) {
HandleSeparator(description);
description.AppendLiteral("TS_ATTR_FIND_WANT_OFFSET");
}
if (aFindFlag & TS_ATTR_FIND_UPDATESTART) {
HandleSeparator(description);
description.AppendLiteral("TS_ATTR_FIND_UPDATESTART");
}
if (aFindFlag & TS_ATTR_FIND_WANT_VALUE) {
HandleSeparator(description);
description.AppendLiteral("TS_ATTR_FIND_WANT_VALUE");
}
if (aFindFlag & TS_ATTR_FIND_WANT_END) {
HandleSeparator(description);
description.AppendLiteral("TS_ATTR_FIND_WANT_END");
}
if (aFindFlag & TS_ATTR_FIND_HIDDEN) {
HandleSeparator(description);
description.AppendLiteral("TS_ATTR_FIND_HIDDEN");
}
if (description.IsEmpty()) {
description.AppendLiteral("Unknown (");
description.AppendInt(static_cast<uint32_t>(aFindFlag));
description.Append(')');
}
return description;
}
class GetACPFromPointFlagName : public nsAutoCString {
public:
explicit GetACPFromPointFlagName(DWORD aFlags) {
if (!aFlags) {
AppendLiteral("no flags (0)");
return;
}
if (aFlags & GXFPF_ROUND_NEAREST) {
AppendLiteral("GXFPF_ROUND_NEAREST");
aFlags &= ~GXFPF_ROUND_NEAREST;
}
if (aFlags & GXFPF_NEAREST) {
HandleSeparator(*this);
AppendLiteral("GXFPF_NEAREST");
aFlags &= ~GXFPF_NEAREST;
}
if (aFlags) {
HandleSeparator(*this);
AppendLiteral("Unknown(");
AppendInt(static_cast<uint32_t>(aFlags));
Append(')');
}
}
virtual ~GetACPFromPointFlagName() {}
};
static const char* GetFocusChangeName(
InputContextAction::FocusChange aFocusChange) {
switch (aFocusChange) {
case InputContextAction::FOCUS_NOT_CHANGED:
return "FOCUS_NOT_CHANGED";
case InputContextAction::GOT_FOCUS:
return "GOT_FOCUS";
case InputContextAction::LOST_FOCUS:
return "LOST_FOCUS";
case InputContextAction::MENU_GOT_PSEUDO_FOCUS:
return "MENU_GOT_PSEUDO_FOCUS";
case InputContextAction::MENU_LOST_PSEUDO_FOCUS:
return "MENU_LOST_PSEUDO_FOCUS";
case InputContextAction::WIDGET_CREATED:
return "WIDGET_CREATED";
default:
return "Unknown";
}
}
static nsCString GetCLSIDNameStr(REFCLSID aCLSID) {
LPOLESTR str = nullptr;
HRESULT hr = ::StringFromCLSID(aCLSID, &str);
if (FAILED(hr) || !str || !str[0]) {
return ""_ns;
}
nsCString result;
result = NS_ConvertUTF16toUTF8(str);
::CoTaskMemFree(str);
return result;
}
static nsCString GetGUIDNameStr(REFGUID aGUID) {
OLECHAR str[40];
int len = ::StringFromGUID2(aGUID, str, ArrayLength(str));
if (!len || !str[0]) {
return ""_ns;
}
return NS_ConvertUTF16toUTF8(str);
}
static nsCString GetGUIDNameStrWithTable(REFGUID aGUID) {
#define RETURN_GUID_NAME(aNamedGUID) \
if (IsEqualGUID(aGUID, aNamedGUID)) { \
return nsLiteralCString(#aNamedGUID); \
}
RETURN_GUID_NAME(GUID_PROP_INPUTSCOPE)
RETURN_GUID_NAME(TSATTRID_OTHERS)
RETURN_GUID_NAME(TSATTRID_Font)
RETURN_GUID_NAME(TSATTRID_Font_FaceName)
RETURN_GUID_NAME(TSATTRID_Font_SizePts)
RETURN_GUID_NAME(TSATTRID_Font_Style)
RETURN_GUID_NAME(TSATTRID_Font_Style_Bold)
RETURN_GUID_NAME(TSATTRID_Font_Style_Italic)
RETURN_GUID_NAME(TSATTRID_Font_Style_SmallCaps)
RETURN_GUID_NAME(TSATTRID_Font_Style_Capitalize)
RETURN_GUID_NAME(TSATTRID_Font_Style_Uppercase)
RETURN_GUID_NAME(TSATTRID_Font_Style_Lowercase)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_LasVegasLights)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_BlinkingBackground)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_SparkleText)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_MarchingBlackAnts)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_MarchingRedAnts)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_Shimmer)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_WipeDown)
RETURN_GUID_NAME(TSATTRID_Font_Style_Animation_WipeRight)
RETURN_GUID_NAME(TSATTRID_Font_Style_Emboss)
RETURN_GUID_NAME(TSATTRID_Font_Style_Engrave)
RETURN_GUID_NAME(TSATTRID_Font_Style_Hidden)
RETURN_GUID_NAME(TSATTRID_Font_Style_Kerning)
RETURN_GUID_NAME(TSATTRID_Font_Style_Outlined)
RETURN_GUID_NAME(TSATTRID_Font_Style_Position)
RETURN_GUID_NAME(TSATTRID_Font_Style_Protected)
RETURN_GUID_NAME(TSATTRID_Font_Style_Shadow)
RETURN_GUID_NAME(TSATTRID_Font_Style_Spacing)
RETURN_GUID_NAME(TSATTRID_Font_Style_Weight)
RETURN_GUID_NAME(TSATTRID_Font_Style_Height)
RETURN_GUID_NAME(TSATTRID_Font_Style_Underline)
RETURN_GUID_NAME(TSATTRID_Font_Style_Underline_Single)
RETURN_GUID_NAME(TSATTRID_Font_Style_Underline_Double)
RETURN_GUID_NAME(TSATTRID_Font_Style_Strikethrough)
RETURN_GUID_NAME(TSATTRID_Font_Style_Strikethrough_Single)
RETURN_GUID_NAME(TSATTRID_Font_Style_Strikethrough_Double)
RETURN_GUID_NAME(TSATTRID_Font_Style_Overline)
RETURN_GUID_NAME(TSATTRID_Font_Style_Overline_Single)
RETURN_GUID_NAME(TSATTRID_Font_Style_Overline_Double)
RETURN_GUID_NAME(TSATTRID_Font_Style_Blink)
RETURN_GUID_NAME(TSATTRID_Font_Style_Subscript)
RETURN_GUID_NAME(TSATTRID_Font_Style_Superscript)
RETURN_GUID_NAME(TSATTRID_Font_Style_Color)
RETURN_GUID_NAME(TSATTRID_Font_Style_BackgroundColor)
RETURN_GUID_NAME(TSATTRID_Text)
RETURN_GUID_NAME(TSATTRID_Text_VerticalWriting)
RETURN_GUID_NAME(TSATTRID_Text_RightToLeft)
RETURN_GUID_NAME(TSATTRID_Text_Orientation)
RETURN_GUID_NAME(TSATTRID_Text_Language)
RETURN_GUID_NAME(TSATTRID_Text_ReadOnly)
RETURN_GUID_NAME(TSATTRID_Text_EmbeddedObject)
RETURN_GUID_NAME(TSATTRID_Text_Alignment)
RETURN_GUID_NAME(TSATTRID_Text_Alignment_Left)
RETURN_GUID_NAME(TSATTRID_Text_Alignment_Right)
RETURN_GUID_NAME(TSATTRID_Text_Alignment_Center)
RETURN_GUID_NAME(TSATTRID_Text_Alignment_Justify)
RETURN_GUID_NAME(TSATTRID_Text_Link)
RETURN_GUID_NAME(TSATTRID_Text_Hyphenation)
RETURN_GUID_NAME(TSATTRID_Text_Para)
RETURN_GUID_NAME(TSATTRID_Text_Para_FirstLineIndent)
RETURN_GUID_NAME(TSATTRID_Text_Para_LeftIndent)
RETURN_GUID_NAME(TSATTRID_Text_Para_RightIndent)
RETURN_GUID_NAME(TSATTRID_Text_Para_SpaceAfter)
RETURN_GUID_NAME(TSATTRID_Text_Para_SpaceBefore)
RETURN_GUID_NAME(TSATTRID_Text_Para_LineSpacing)
RETURN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Single)
RETURN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_OnePtFive)
RETURN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Double)
RETURN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_AtLeast)
RETURN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Exactly)
RETURN_GUID_NAME(TSATTRID_Text_Para_LineSpacing_Multiple)
RETURN_GUID_NAME(TSATTRID_List)
RETURN_GUID_NAME(TSATTRID_List_LevelIndel)
RETURN_GUID_NAME(TSATTRID_List_Type)
RETURN_GUID_NAME(TSATTRID_List_Type_Bullet)
RETURN_GUID_NAME(TSATTRID_List_Type_Arabic)
RETURN_GUID_NAME(TSATTRID_List_Type_LowerLetter)
RETURN_GUID_NAME(TSATTRID_List_Type_UpperLetter)
RETURN_GUID_NAME(TSATTRID_List_Type_LowerRoman)
RETURN_GUID_NAME(TSATTRID_List_Type_UpperRoman)
RETURN_GUID_NAME(TSATTRID_App)
RETURN_GUID_NAME(TSATTRID_App_IncorrectSpelling)
RETURN_GUID_NAME(TSATTRID_App_IncorrectGrammar)
#undef RETURN_GUID_NAME
return GetGUIDNameStr(aGUID);
}
static nsCString GetRIIDNameStr(REFIID aRIID) {
LPOLESTR str = nullptr;
HRESULT hr = ::StringFromIID(aRIID, &str);
if (FAILED(hr) || !str || !str[0]) {
return ""_ns;
}
nsAutoString key(L"Interface\\");
key += str;
nsCString result;
wchar_t buf[256];
if (WinUtils::GetRegistryKey(HKEY_CLASSES_ROOT, key.get(), nullptr, buf,
sizeof(buf))) {
result = NS_ConvertUTF16toUTF8(buf);
} else {
result = NS_ConvertUTF16toUTF8(str);
}
::CoTaskMemFree(str);
return result;
}
static const char* GetCommonReturnValueName(HRESULT aResult) {
switch (aResult) {
case S_OK:
return "S_OK";
case E_ABORT:
return "E_ABORT";
case E_ACCESSDENIED:
return "E_ACCESSDENIED";
case E_FAIL:
return "E_FAIL";
case E_HANDLE:
return "E_HANDLE";
case E_INVALIDARG:
return "E_INVALIDARG";
case E_NOINTERFACE:
return "E_NOINTERFACE";
case E_NOTIMPL:
return "E_NOTIMPL";
case E_OUTOFMEMORY:
return "E_OUTOFMEMORY";
case E_POINTER:
return "E_POINTER";
case E_UNEXPECTED:
return "E_UNEXPECTED";
default:
return SUCCEEDED(aResult) ? "Succeeded" : "Failed";
}
}
static const char* GetTextStoreReturnValueName(HRESULT aResult) {
switch (aResult) {
case TS_E_FORMAT:
return "TS_E_FORMAT";
case TS_E_INVALIDPOINT:
return "TS_E_INVALIDPOINT";
case TS_E_INVALIDPOS:
return "TS_E_INVALIDPOS";
case TS_E_NOINTERFACE:
return "TS_E_NOINTERFACE";
case TS_E_NOLAYOUT:
return "TS_E_NOLAYOUT";
case TS_E_NOLOCK:
return "TS_E_NOLOCK";
case TS_E_NOOBJECT:
return "TS_E_NOOBJECT";
case TS_E_NOSELECTION:
return "TS_E_NOSELECTION";
case TS_E_NOSERVICE:
return "TS_E_NOSERVICE";
case TS_E_READONLY:
return "TS_E_READONLY";
case TS_E_SYNCHRONOUS:
return "TS_E_SYNCHRONOUS";
case TS_S_ASYNC:
return "TS_S_ASYNC";
default:
return GetCommonReturnValueName(aResult);
}
}
static const nsCString GetSinkMaskNameStr(DWORD aSinkMask) {
nsCString description;
if (aSinkMask & TS_AS_TEXT_CHANGE) {
description.AppendLiteral("TS_AS_TEXT_CHANGE");
}
if (aSinkMask & TS_AS_SEL_CHANGE) {
HandleSeparator(description);
description.AppendLiteral("TS_AS_SEL_CHANGE");
}
if (aSinkMask & TS_AS_LAYOUT_CHANGE) {
HandleSeparator(description);
description.AppendLiteral("TS_AS_LAYOUT_CHANGE");
}
if (aSinkMask & TS_AS_ATTR_CHANGE) {
HandleSeparator(description);
description.AppendLiteral("TS_AS_ATTR_CHANGE");
}
if (aSinkMask & TS_AS_STATUS_CHANGE) {
HandleSeparator(description);
description.AppendLiteral("TS_AS_STATUS_CHANGE");
}
if (description.IsEmpty()) {
description.AppendLiteral("not-specified");
}
return description;
}
static const nsCString GetLockFlagNameStr(DWORD aLockFlags) {
nsCString description;
if ((aLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE) {
description.AppendLiteral("TS_LF_READWRITE");
} else if (aLockFlags & TS_LF_READ) {
description.AppendLiteral("TS_LF_READ");
}
if (aLockFlags & TS_LF_SYNC) {
if (!description.IsEmpty()) {
description.AppendLiteral(" | ");
}
description.AppendLiteral("TS_LF_SYNC");
}
if (description.IsEmpty()) {
description.AppendLiteral("not-specified");
}
return description;
}
static const char* GetTextRunTypeName(TsRunType aRunType) {
switch (aRunType) {
case TS_RT_PLAIN:
return "TS_RT_PLAIN";
case TS_RT_HIDDEN:
return "TS_RT_HIDDEN";
case TS_RT_OPAQUE:
return "TS_RT_OPAQUE";
default:
return "Unknown";
}
}
static nsCString GetColorName(const TF_DA_COLOR& aColor) {
switch (aColor.type) {
case TF_CT_NONE:
return "TF_CT_NONE"_ns;
case TF_CT_SYSCOLOR:
return nsPrintfCString("TF_CT_SYSCOLOR, nIndex:0x%08X",
static_cast<int32_t>(aColor.nIndex));
case TF_CT_COLORREF:
return nsPrintfCString("TF_CT_COLORREF, cr:0x%08X",
static_cast<int32_t>(aColor.cr));
break;
default:
return nsPrintfCString("Unknown(%08X)",
static_cast<int32_t>(aColor.type));
}
}
static nsCString GetLineStyleName(TF_DA_LINESTYLE aLineStyle) {
switch (aLineStyle) {
case TF_LS_NONE:
return "TF_LS_NONE"_ns;
case TF_LS_SOLID:
return "TF_LS_SOLID"_ns;
case TF_LS_DOT:
return "TF_LS_DOT"_ns;
case TF_LS_DASH:
return "TF_LS_DASH"_ns;
case TF_LS_SQUIGGLE:
return "TF_LS_SQUIGGLE"_ns;
default: {
return nsPrintfCString("Unknown(%08X)", static_cast<int32_t>(aLineStyle));
}
}
}
static nsCString GetClauseAttrName(TF_DA_ATTR_INFO aAttr) {
switch (aAttr) {
case TF_ATTR_INPUT:
return "TF_ATTR_INPUT"_ns;
case TF_ATTR_TARGET_CONVERTED:
return "TF_ATTR_TARGET_CONVERTED"_ns;
case TF_ATTR_CONVERTED:
return "TF_ATTR_CONVERTED"_ns;
case TF_ATTR_TARGET_NOTCONVERTED:
return "TF_ATTR_TARGET_NOTCONVERTED"_ns;
case TF_ATTR_INPUT_ERROR:
return "TF_ATTR_INPUT_ERROR"_ns;
case TF_ATTR_FIXEDCONVERTED:
return "TF_ATTR_FIXEDCONVERTED"_ns;
case TF_ATTR_OTHER:
return "TF_ATTR_OTHER"_ns;
default: {
return nsPrintfCString("Unknown(%08X)", static_cast<int32_t>(aAttr));
}
}
}
static nsCString GetDisplayAttrStr(const TF_DISPLAYATTRIBUTE& aDispAttr) {
nsCString str;
str = "crText:{ ";
str += GetColorName(aDispAttr.crText);
str += " }, crBk:{ ";
str += GetColorName(aDispAttr.crBk);
str += " }, lsStyle: ";
str += GetLineStyleName(aDispAttr.lsStyle);
str += ", fBoldLine: ";
str += GetBoolName(aDispAttr.fBoldLine);
str += ", crLine:{ ";
str += GetColorName(aDispAttr.crLine);
str += " }, bAttr: ";
str += GetClauseAttrName(aDispAttr.bAttr);
return str;
}
static const char* GetMouseButtonName(int16_t aButton) {
switch (aButton) {
case MouseButton::ePrimary:
return "LeftButton";
case MouseButton::eMiddle:
return "MiddleButton";
case MouseButton::eSecondary:
return "RightButton";
default:
return "UnknownButton";
}
}
#define ADD_SEPARATOR_IF_NECESSARY(aStr) \
if (!aStr.IsEmpty()) { \
aStr.AppendLiteral(", "); \
}
static nsCString GetMouseButtonsName(int16_t aButtons) {
if (!aButtons) {
return "no buttons"_ns;
}
nsCString names;
if (aButtons & MouseButtonsFlag::ePrimaryFlag) {
names = "LeftButton";
}
if (aButtons & MouseButtonsFlag::eSecondaryFlag) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += "RightButton";
}
if (aButtons & MouseButtonsFlag::eMiddleFlag) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += "MiddleButton";
}
if (aButtons & MouseButtonsFlag::e4thFlag) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += "4thButton";
}
if (aButtons & MouseButtonsFlag::e5thFlag) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += "5thButton";
}
return names;
}
static nsCString GetModifiersName(Modifiers aModifiers) {
if (aModifiers == MODIFIER_NONE) {
return "no modifiers"_ns;
}
nsCString names;
if (aModifiers & MODIFIER_ALT) {
names = NS_DOM_KEYNAME_ALT;
}
if (aModifiers & MODIFIER_ALTGRAPH) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_ALTGRAPH;
}
if (aModifiers & MODIFIER_CAPSLOCK) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_CAPSLOCK;
}
if (aModifiers & MODIFIER_CONTROL) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_CONTROL;
}
if (aModifiers & MODIFIER_FN) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_FN;
}
if (aModifiers & MODIFIER_FNLOCK) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_FNLOCK;
}
if (aModifiers & MODIFIER_META) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_META;
}
if (aModifiers & MODIFIER_NUMLOCK) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_NUMLOCK;
}
if (aModifiers & MODIFIER_SCROLLLOCK) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_SCROLLLOCK;
}
if (aModifiers & MODIFIER_SHIFT) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_SHIFT;
}
if (aModifiers & MODIFIER_SYMBOL) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_SYMBOL;
}
if (aModifiers & MODIFIER_SYMBOLLOCK) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_SYMBOLLOCK;
}
if (aModifiers & MODIFIER_OS) {
ADD_SEPARATOR_IF_NECESSARY(names);
names += NS_DOM_KEYNAME_OS;
}
return names;
}
class GetWritingModeName : public nsAutoCString {
public:
explicit GetWritingModeName(const WritingMode& aWritingMode) {
if (!aWritingMode.IsVertical()) {
AssignLiteral("Horizontal");
return;
}
if (aWritingMode.IsVerticalLR()) {
AssignLiteral("Vertical (LR)");
return;
}
AssignLiteral("Vertical (RL)");
}
virtual ~GetWritingModeName() {}
};
class GetEscapedUTF8String final : public NS_ConvertUTF16toUTF8 {
public:
explicit GetEscapedUTF8String(const nsAString& aString)
: NS_ConvertUTF16toUTF8(aString) {
Escape();
}
explicit GetEscapedUTF8String(const char16ptr_t aString)
: NS_ConvertUTF16toUTF8(aString) {
Escape();
}
GetEscapedUTF8String(const char16ptr_t aString, uint32_t aLength)
: NS_ConvertUTF16toUTF8(aString, aLength) {
Escape();
}
private:
void Escape() {
ReplaceSubstring("\r", "\\r");
ReplaceSubstring("\n", "\\n");
ReplaceSubstring("\t", "\\t");
}
};
class GetInputScopeString : public nsAutoCString {
public:
explicit GetInputScopeString(const nsTArray<InputScope>& aList) {
for (InputScope inputScope : aList) {
if (!IsEmpty()) {
AppendLiteral(", ");
}
switch (inputScope) {
case IS_DEFAULT:
AppendLiteral("IS_DEFAULT");
break;
case IS_URL:
AppendLiteral("IS_URL");
break;
case IS_FILE_FULLFILEPATH:
AppendLiteral("IS_FILE_FULLFILEPATH");
break;
case IS_FILE_FILENAME:
AppendLiteral("IS_FILE_FILENAME");
break;
case IS_EMAIL_USERNAME:
AppendLiteral("IS_EMAIL_USERNAME");
break;
case IS_EMAIL_SMTPEMAILADDRESS:
AppendLiteral("IS_EMAIL_SMTPEMAILADDRESS");
break;
case IS_LOGINNAME:
AppendLiteral("IS_LOGINNAME");
break;
case IS_PERSONALNAME_FULLNAME:
AppendLiteral("IS_PERSONALNAME_FULLNAME");
break;
case IS_PERSONALNAME_PREFIX:
AppendLiteral("IS_PERSONALNAME_PREFIX");
break;
case IS_PERSONALNAME_GIVENNAME:
AppendLiteral("IS_PERSONALNAME_GIVENNAME");
break;
case IS_PERSONALNAME_MIDDLENAME:
AppendLiteral("IS_PERSONALNAME_MIDDLENAME");
break;
case IS_PERSONALNAME_SURNAME:
AppendLiteral("IS_PERSONALNAME_SURNAME");
break;
case IS_PERSONALNAME_SUFFIX:
AppendLiteral("IS_PERSONALNAME_SUFFIX");
break;
case IS_ADDRESS_FULLPOSTALADDRESS:
AppendLiteral("IS_ADDRESS_FULLPOSTALADDRESS");
break;
case IS_ADDRESS_POSTALCODE:
AppendLiteral("IS_ADDRESS_POSTALCODE");
break;
case IS_ADDRESS_STREET:
AppendLiteral("IS_ADDRESS_STREET");
break;
case IS_ADDRESS_STATEORPROVINCE:
AppendLiteral("IS_ADDRESS_STATEORPROVINCE");
break;
case IS_ADDRESS_CITY:
AppendLiteral("IS_ADDRESS_CITY");
break;
case IS_ADDRESS_COUNTRYNAME:
AppendLiteral("IS_ADDRESS_COUNTRYNAME");
break;
case IS_ADDRESS_COUNTRYSHORTNAME:
AppendLiteral("IS_ADDRESS_COUNTRYSHORTNAME");
break;
case IS_CURRENCY_AMOUNTANDSYMBOL:
AppendLiteral("IS_CURRENCY_AMOUNTANDSYMBOL");
break;
case IS_CURRENCY_AMOUNT:
AppendLiteral("IS_CURRENCY_AMOUNT");
break;
case IS_DATE_FULLDATE:
AppendLiteral("IS_DATE_FULLDATE");
break;
case IS_DATE_MONTH:
AppendLiteral("IS_DATE_MONTH");
break;
case IS_DATE_DAY:
AppendLiteral("IS_DATE_DAY");
break;
case IS_DATE_YEAR:
AppendLiteral("IS_DATE_YEAR");
break;
case IS_DATE_MONTHNAME:
AppendLiteral("IS_DATE_MONTHNAME");
break;
case IS_DATE_DAYNAME:
AppendLiteral("IS_DATE_DAYNAME");
break;
case IS_DIGITS:
AppendLiteral("IS_DIGITS");
break;
case IS_NUMBER:
AppendLiteral("IS_NUMBER");
break;
case IS_ONECHAR:
AppendLiteral("IS_ONECHAR");
break;
case IS_PASSWORD:
AppendLiteral("IS_PASSWORD");
break;
case IS_TELEPHONE_FULLTELEPHONENUMBER:
AppendLiteral("IS_TELEPHONE_FULLTELEPHONENUMBER");
break;
case IS_TELEPHONE_COUNTRYCODE:
AppendLiteral("IS_TELEPHONE_COUNTRYCODE");
break;
case IS_TELEPHONE_AREACODE:
AppendLiteral("IS_TELEPHONE_AREACODE");
break;
case IS_TELEPHONE_LOCALNUMBER:
AppendLiteral("IS_TELEPHONE_LOCALNUMBER");
break;
case IS_TIME_FULLTIME:
AppendLiteral("IS_TIME_FULLTIME");
break;
case IS_TIME_HOUR:
AppendLiteral("IS_TIME_HOUR");
break;
case IS_TIME_MINORSEC:
AppendLiteral("IS_TIME_MINORSEC");
break;
case IS_NUMBER_FULLWIDTH:
AppendLiteral("IS_NUMBER_FULLWIDTH");
break;
case IS_ALPHANUMERIC_HALFWIDTH:
AppendLiteral("IS_ALPHANUMERIC_HALFWIDTH");
break;
case IS_ALPHANUMERIC_FULLWIDTH:
AppendLiteral("IS_ALPHANUMERIC_FULLWIDTH");
break;
case IS_CURRENCY_CHINESE:
AppendLiteral("IS_CURRENCY_CHINESE");
break;
case IS_BOPOMOFO:
AppendLiteral("IS_BOPOMOFO");
break;
case IS_HIRAGANA:
AppendLiteral("IS_HIRAGANA");
break;
case IS_KATAKANA_HALFWIDTH:
AppendLiteral("IS_KATAKANA_HALFWIDTH");
break;
case IS_KATAKANA_FULLWIDTH:
AppendLiteral("IS_KATAKANA_FULLWIDTH");
break;
case IS_HANJA:
AppendLiteral("IS_HANJA");
break;
case IS_PHRASELIST:
AppendLiteral("IS_PHRASELIST");
break;
case IS_REGULAREXPRESSION:
AppendLiteral("IS_REGULAREXPRESSION");
break;
case IS_SRGS:
AppendLiteral("IS_SRGS");
break;
case IS_XML:
AppendLiteral("IS_XML");
break;
case IS_PRIVATE:
AppendLiteral("IS_PRIVATE");
break;
default:
AppendPrintf("Unknown Value(%d)", inputScope);
break;
}
}
}
};
/******************************************************************/
/* InputScopeImpl */
/******************************************************************/
class InputScopeImpl final : public ITfInputScope {
~InputScopeImpl() {}
public:
explicit InputScopeImpl(const nsTArray<InputScope>& aList)
: mInputScopes(aList.Clone()) {
MOZ_LOG(
sTextStoreLog, LogLevel::Info,
("0x%p InputScopeImpl(%s)", this, GetInputScopeString(aList).get()));
}
NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(InputScopeImpl)
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {
*ppv = nullptr;
if ((IID_IUnknown == riid) || (IID_ITfInputScope == riid)) {
*ppv = static_cast<ITfInputScope*>(this);
}
if (*ppv) {
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP GetInputScopes(InputScope** pprgInputScopes, UINT* pcCount) {
uint32_t count = (mInputScopes.IsEmpty() ? 1 : mInputScopes.Length());
InputScope* pScope =
(InputScope*)CoTaskMemAlloc(sizeof(InputScope) * count);
NS_ENSURE_TRUE(pScope, E_OUTOFMEMORY);
if (mInputScopes.IsEmpty()) {
*pScope = IS_DEFAULT;
*pcCount = 1;
*pprgInputScopes = pScope;
return S_OK;
}
*pcCount = 0;
for (uint32_t idx = 0; idx < count; idx++) {
*(pScope + idx) = mInputScopes[idx];
(*pcCount)++;
}
*pprgInputScopes = pScope;
return S_OK;
}
STDMETHODIMP GetPhrase(BSTR** ppbstrPhrases, UINT* pcCount) {
return E_NOTIMPL;
}
STDMETHODIMP GetRegularExpression(BSTR* pbstrRegExp) { return E_NOTIMPL; }
STDMETHODIMP GetSRGS(BSTR* pbstrSRGS) { return E_NOTIMPL; }
STDMETHODIMP GetXML(BSTR* pbstrXML) { return E_NOTIMPL; }
private:
nsTArray<InputScope> mInputScopes;
};
/******************************************************************/
/* TSFStaticSink */
/******************************************************************/
class TSFStaticSink final : public ITfInputProcessorProfileActivationSink {
public:
static TSFStaticSink* GetInstance() {
if (!sInstance) {
RefPtr<ITfThreadMgr> threadMgr = TSFTextStore::GetThreadMgr();
if (NS_WARN_IF(!threadMgr)) {
MOZ_LOG(
sTextStoreLog, LogLevel::Error,
("TSFStaticSink::GetInstance() FAILED to initialize TSFStaticSink "
"instance due to no ThreadMgr instance"));
return nullptr;
}
RefPtr<ITfInputProcessorProfiles> inputProcessorProfiles =
TSFTextStore::GetInputProcessorProfiles();
if (NS_WARN_IF(!inputProcessorProfiles)) {
MOZ_LOG(
sTextStoreLog, LogLevel::Error,
("TSFStaticSink::GetInstance() FAILED to initialize TSFStaticSink "
"instance due to no InputProcessorProfiles instance"));
return nullptr;
}
RefPtr<TSFStaticSink> staticSink = new TSFStaticSink();
if (NS_WARN_IF(!staticSink->Init(threadMgr, inputProcessorProfiles))) {
staticSink->Destroy();
MOZ_LOG(
sTextStoreLog, LogLevel::Error,
("TSFStaticSink::GetInstance() FAILED to initialize TSFStaticSink "
"instance"));
return nullptr;
}
sInstance = staticSink.forget();
}
return sInstance;
}
static void Shutdown() {
if (sInstance) {
sInstance->Destroy();
sInstance = nullptr;
}
}
bool Init(ITfThreadMgr* aThreadMgr,
ITfInputProcessorProfiles* aInputProcessorProfiles);
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {
*ppv = nullptr;
if (IID_IUnknown == riid ||
IID_ITfInputProcessorProfileActivationSink == riid) {
*ppv = static_cast<ITfInputProcessorProfileActivationSink*>(this);
}
if (*ppv) {
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(TSFStaticSink)
const nsString& GetActiveTIPKeyboardDescription() const {
return mActiveTIPKeyboardDescription;
}
static bool IsIMM_IMEActive() {
// Use IMM API until TSFStaticSink starts to work.
if (!sInstance || !sInstance->EnsureInitActiveTIPKeyboard()) {
return IsIMM_IME(::GetKeyboardLayout(0));
}
return sInstance->mIsIMM_IME;
}
static bool IsIMM_IME(HKL aHKL) {
return (::ImmGetIMEFileNameW(aHKL, nullptr, 0) > 0);
}
static bool IsTraditionalChinese() {
EnsureInstance();
return sInstance && sInstance->IsTraditionalChineseInternal();
}
static bool IsSimplifiedChinese() {
EnsureInstance();
return sInstance && sInstance->IsSimplifiedChineseInternal();
}
static bool IsJapanese() {
EnsureInstance();
return sInstance && sInstance->IsJapaneseInternal();
}
static bool IsKorean() {
EnsureInstance();
return sInstance && sInstance->IsKoreanInternal();
}
/**
* ActiveTIP() returns an ID for currently active TIP.
* Please note that this method is expensive due to needs a lot of GUID
* comparations if active language ID is one of CJKT. If you need to
* check TIPs for a specific language, you should check current language
* first.
*/
static TextInputProcessorID ActiveTIP() {
EnsureInstance();
if (!sInstance || !sInstance->EnsureInitActiveTIPKeyboard()) {
return TextInputProcessorID::eUnknown;
}
sInstance->ComputeActiveTextInputProcessor();
if (NS_WARN_IF(sInstance->mActiveTIP ==
TextInputProcessorID::eNotComputed)) {
return TextInputProcessorID::eUnknown;
}
return sInstance->mActiveTIP;
}
static bool IsMSChangJieOrMSQuickActive() {
// ActiveTIP() is expensive if it hasn't computed active TIP yet.
// For avoiding unnecessary computation, we should check if the language
// for current TIP is Traditional Chinese.
if (!IsTraditionalChinese()) {
return false;
}
switch (ActiveTIP()) {
case TextInputProcessorID::eMicrosoftChangJie:
case TextInputProcessorID::eMicrosoftQuick:
return true;
default:
return false;
}
}
static bool IsMSPinyinOrMSWubiActive() {
// ActiveTIP() is expensive if it hasn't computed active TIP yet.
// For avoiding unnecessary computation, we should check if the language
// for current TIP is Simplified Chinese.
if (!IsSimplifiedChinese()) {
return false;
}
switch (ActiveTIP()) {
case TextInputProcessorID::eMicrosoftPinyin:
case TextInputProcessorID::eMicrosoftWubi:
return true;
default:
return false;
}
}
static bool IsMSJapaneseIMEActive() {
// ActiveTIP() is expensive if it hasn't computed active TIP yet.
// For avoiding unnecessary computation, we should check if the language
// for current TIP is Japanese.
if (!IsJapanese()) {
return false;
}
return ActiveTIP() == TextInputProcessorID::eMicrosoftIMEForJapanese;
}
static bool IsGoogleJapaneseInputActive() {
// ActiveTIP() is expensive if it hasn't computed active TIP yet.
// For avoiding unnecessary computation, we should check if the language
// for current TIP is Japanese.
if (!IsJapanese()) {
return false;
}
return ActiveTIP() == TextInputProcessorID::eGoogleJapaneseInput;
}
static bool IsATOKActive() {
// ActiveTIP() is expensive if it hasn't computed active TIP yet.
// For avoiding unnecessary computation, we should check if active TIP is
// ATOK first since it's cheaper.
return IsJapanese() && sInstance->IsATOKActiveInternal();
}
// Note that ATOK 2011 - 2016 refers native caret position for deciding its
// popup window position.
static bool IsATOKReferringNativeCaretActive() {
// ActiveTIP() is expensive if it hasn't computed active TIP yet.
// For avoiding unnecessary computation, we should check if active TIP is
// ATOK first since it's cheaper.
if (!IsJapanese() || !sInstance->IsATOKActiveInternal()) {
return false;
}
switch (ActiveTIP()) {
case TextInputProcessorID::eATOK2011:
case TextInputProcessorID::eATOK2012:
case TextInputProcessorID::eATOK2013:
case TextInputProcessorID::eATOK2014:
case TextInputProcessorID::eATOK2015:
return true;
default:
return false;
}
}
private:
static void EnsureInstance() {
if (!sInstance) {
RefPtr<TSFStaticSink> staticSink = GetInstance();
Unused << staticSink;
}
}
bool IsTraditionalChineseInternal() const { return mLangID == 0x0404; }
bool IsSimplifiedChineseInternal() const { return mLangID == 0x0804; }
bool IsJapaneseInternal() const { return mLangID == 0x0411; }
bool IsKoreanInternal() const { return mLangID == 0x0412; }
bool IsATOKActiveInternal() {
EnsureInitActiveTIPKeyboard();
// FYI: Name of packaged ATOK includes the release year like "ATOK 2015".
// Name of ATOK Passport (subscription) equals "ATOK".
return StringBeginsWith(mActiveTIPKeyboardDescription, u"ATOK "_ns) ||
mActiveTIPKeyboardDescription.EqualsLiteral("ATOK");
}
void ComputeActiveTextInputProcessor() {
if (mActiveTIP != TextInputProcessorID::eNotComputed) {
return;
}
if (mActiveTIPGUID == GUID_NULL) {
mActiveTIP = TextInputProcessorID::eNone;
return;
}
// Comparing GUID is slow. So, we should use language information to
// reduce the comparing cost for TIP which is not we do not support
// specifically since they are always compared with all supported TIPs.
switch (mLangID) {
case 0x0404:
mActiveTIP = ComputeActiveTIPAsTraditionalChinese();
break;
case 0x0411:
mActiveTIP = ComputeActiveTIPAsJapanese();
break;
case 0x0412:
mActiveTIP = ComputeActiveTIPAsKorean();
break;
case 0x0804:
mActiveTIP = ComputeActiveTIPAsSimplifiedChinese();
break;
default:
mActiveTIP = TextInputProcessorID::eUnknown;
break;
}
// Special case for Keyman Desktop, it is available for any languages.
// Therefore, we need to check it only if we don't know the active TIP.
if (mActiveTIP != TextInputProcessorID::eUnknown) {
return;
}
// Note that keyboard layouts for Keyman assign its GUID on install
// randomly, but CLSID is constant in any environments.
// {FE0420F1-38D1-4B4C-96BF-E7E20A74CFB7}
static constexpr CLSID kKeymanDesktop_CLSID = {
0xFE0420F1,
0x38D1,
0x4B4C,
{0x96, 0xBF, 0xE7, 0xE2, 0x0A, 0x74, 0xCF, 0xB7}};
if (mActiveTIPCLSID == kKeymanDesktop_CLSID) {
mActiveTIP = TextInputProcessorID::eKeymanDesktop;
}
}
TextInputProcessorID ComputeActiveTIPAsJapanese() {
// {A76C93D9-5523-4E90-AAFA-4DB112F9AC76} (Win7, Win8.1, Win10)
static constexpr GUID kMicrosoftIMEForJapaneseGUID = {
0xA76C93D9,
0x5523,
0x4E90,
{0xAA, 0xFA, 0x4D, 0xB1, 0x12, 0xF9, 0xAC, 0x76}};
if (mActiveTIPGUID == kMicrosoftIMEForJapaneseGUID) {
return TextInputProcessorID::eMicrosoftIMEForJapanese;
}
// {54EDCC94-1524-4BB1-9FB7-7BABE4F4CA64}
static constexpr GUID kMicrosoftOfficeIME2010ForJapaneseGUID = {
0x54EDCC94,
0x1524,
0x4BB1,
{0x9F, 0xB7, 0x7B, 0xAB, 0xE4, 0xF4, 0xCA, 0x64}};
if (mActiveTIPGUID == kMicrosoftOfficeIME2010ForJapaneseGUID) {
return TextInputProcessorID::eMicrosoftOfficeIME2010ForJapanese;
}
// {773EB24E-CA1D-4B1B-B420-FA985BB0B80D}
static constexpr GUID kGoogleJapaneseInputGUID = {
0x773EB24E,
0xCA1D,
0x4B1B,
{0xB4, 0x20, 0xFA, 0x98, 0x5B, 0xB0, 0xB8, 0x0D}};
if (mActiveTIPGUID == kGoogleJapaneseInputGUID) {
return TextInputProcessorID::eGoogleJapaneseInput;
}
// {F9C24A5C-8A53-499D-9572-93B2FF582115}
static const GUID kATOK2011GUID = {
0xF9C24A5C,
0x8A53,
0x499D,
{0x95, 0x72, 0x93, 0xB2, 0xFF, 0x58, 0x21, 0x15}};
if (mActiveTIPGUID == kATOK2011GUID) {
return TextInputProcessorID::eATOK2011;
}
// {1DE01562-F445-401B-B6C3-E5B18DB79461}
static constexpr GUID kATOK2012GUID = {
0x1DE01562,
0xF445,
0x401B,
{0xB6, 0xC3, 0xE5, 0xB1, 0x8D, 0xB7, 0x94, 0x61}};
if (mActiveTIPGUID == kATOK2012GUID) {
return TextInputProcessorID::eATOK2012;
}
// {3C4DB511-189A-4168-B6EA-BFD0B4C85615}
static constexpr GUID kATOK2013GUID = {
0x3C4DB511,
0x189A,
0x4168,
{0xB6, 0xEA, 0xBF, 0xD0, 0xB4, 0xC8, 0x56, 0x15}};
if (mActiveTIPGUID == kATOK2013GUID) {
return TextInputProcessorID::eATOK2013;
}
// {4EF33B79-6AA9-4271-B4BF-9321C279381B}
static constexpr GUID kATOK2014GUID = {
0x4EF33B79,
0x6AA9,
0x4271,
{0xB4, 0xBF, 0x93, 0x21, 0xC2, 0x79, 0x38, 0x1B}};
if (mActiveTIPGUID == kATOK2014GUID) {
return TextInputProcessorID::eATOK2014;
}
// {EAB4DC00-CE2E-483D-A86A-E6B99DA9599A}
static constexpr GUID kATOK2015GUID = {
0xEAB4DC00,
0xCE2E,
0x483D,
{0xA8, 0x6A, 0xE6, 0xB9, 0x9D, 0xA9, 0x59, 0x9A}};
if (mActiveTIPGUID == kATOK2015GUID) {
return TextInputProcessorID::eATOK2015;
}
// {0B557B4C-5740-4110-A60A-1493FA10BF2B}
static constexpr GUID kATOK2016GUID = {
0x0B557B4C,
0x5740,
0x4110,
{0xA6, 0x0A, 0x14, 0x93, 0xFA, 0x10, 0xBF, 0x2B}};
if (mActiveTIPGUID == kATOK2016GUID) {
return TextInputProcessorID::eATOK2016;
}
// * ATOK 2017
// - {6DBFD8F5-701D-11E6-920F-782BCBA6348F}
// * ATOK Passport (confirmed with version 31.1.2)
// - {A38F2FD9-7199-45E1-841C-BE0313D8052F}
if (IsATOKActiveInternal()) {
return TextInputProcessorID::eATOKUnknown;
}
// {E6D66705-1EDA-4373-8D01-1D0CB2D054C7}
static constexpr GUID kJapanist10GUID = {
0xE6D66705,
0x1EDA,
0x4373,
{0x8D, 0x01, 0x1D, 0x0C, 0xB2, 0xD0, 0x54, 0xC7}};
if (mActiveTIPGUID == kJapanist10GUID) {
return TextInputProcessorID::eJapanist10;
}
return TextInputProcessorID::eUnknown;
}
TextInputProcessorID ComputeActiveTIPAsTraditionalChinese() {
// {B2F9C502-1742-11D4-9790-0080C882687E} (Win8.1, Win10)
static constexpr GUID kMicrosoftBopomofoGUID = {
0xB2F9C502,
0x1742,
0x11D4,
{0x97, 0x90, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftBopomofoGUID) {
return TextInputProcessorID::eMicrosoftBopomofo;
}
// {4BDF9F03-C7D3-11D4-B2AB-0080C882687E} (Win7, Win8.1, Win10)
static const GUID kMicrosoftChangJieGUID = {
0x4BDF9F03,
0xC7D3,
0x11D4,
{0xB2, 0xAB, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftChangJieGUID) {
return TextInputProcessorID::eMicrosoftChangJie;
}
// {761309DE-317A-11D4-9B5D-0080C882687E} (Win7)
static constexpr GUID kMicrosoftPhoneticGUID = {
0x761309DE,
0x317A,
0x11D4,
{0x9B, 0x5D, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftPhoneticGUID) {
return TextInputProcessorID::eMicrosoftPhonetic;
}
// {6024B45F-5C54-11D4-B921-0080C882687E} (Win7, Win8.1, Win10)
static constexpr GUID kMicrosoftQuickGUID = {
0x6024B45F,
0x5C54,
0x11D4,
{0xB9, 0x21, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftQuickGUID) {
return TextInputProcessorID::eMicrosoftQuick;
}
// {F3BA907A-6C7E-11D4-97FA-0080C882687E} (Win7)
static constexpr GUID kMicrosoftNewChangJieGUID = {
0xF3BA907A,
0x6C7E,
0x11D4,
{0x97, 0xFA, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftNewChangJieGUID) {
return TextInputProcessorID::eMicrosoftNewChangJie;
}
// {B2F9C502-1742-11D4-9790-0080C882687E} (Win7)
static constexpr GUID kMicrosoftNewPhoneticGUID = {
0xB2F9C502,
0x1742,
0x11D4,
{0x97, 0x90, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftNewPhoneticGUID) {
return TextInputProcessorID::eMicrosoftNewPhonetic;
}
// {0B883BA0-C1C7-11D4-87F9-0080C882687E} (Win7)
static constexpr GUID kMicrosoftNewQuickGUID = {
0x0B883BA0,
0xC1C7,
0x11D4,
{0x87, 0xF9, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftNewQuickGUID) {
return TextInputProcessorID::eMicrosoftNewQuick;
}
// NOTE: There are some other Traditional Chinese TIPs installed in Windows:
// * Chinese Traditional Array (version 6.0)
// - {D38EFF65-AA46-4FD5-91A7-67845FB02F5B} (Win7, Win8.1)
// * Chinese Traditional DaYi (version 6.0)
// - {037B2C25-480C-4D7F-B027-D6CA6B69788A} (Win7, Win8.1)
// {B58630B5-0ED3-4335-BBC9-E77BBCB43CAD}
static const GUID kFreeChangJieGUID = {
0xB58630B5,
0x0ED3,
0x4335,
{0xBB, 0xC9, 0xE7, 0x7B, 0xBC, 0xB4, 0x3C, 0xAD}};
if (mActiveTIPGUID == kFreeChangJieGUID) {
return TextInputProcessorID::eFreeChangJie;
}
return TextInputProcessorID::eUnknown;
}
TextInputProcessorID ComputeActiveTIPAsSimplifiedChinese() {
// FYI: This matches with neither "Microsoft Pinyin ABC Input Style" nor
// "Microsoft Pinyin New Experience Input Style" on Win7.
// {FA550B04-5AD7-411F-A5AC-CA038EC515D7} (Win8.1, Win10)
static constexpr GUID kMicrosoftPinyinGUID = {
0xFA550B04,
0x5AD7,
0x411F,
{0xA5, 0xAC, 0xCA, 0x03, 0x8E, 0xC5, 0x15, 0xD7}};
if (mActiveTIPGUID == kMicrosoftPinyinGUID) {
return TextInputProcessorID::eMicrosoftPinyin;
}
// {F3BA9077-6C7E-11D4-97FA-0080C882687E} (Win7)
static constexpr GUID kMicrosoftPinyinNewExperienceInputStyleGUID = {
0xF3BA9077,
0x6C7E,
0x11D4,
{0x97, 0xFA, 0x00, 0x80, 0xC8, 0x82, 0x68, 0x7E}};
if (mActiveTIPGUID == kMicrosoftPinyinNewExperienceInputStyleGUID) {
return TextInputProcessorID::eMicrosoftPinyinNewExperienceInputStyle;
}
// {82590C13-F4DD-44F4-BA1D-8667246FDF8E} (Win8.1, Win10)
static constexpr GUID kMicrosoftWubiGUID = {
0x82590C13,
0xF4DD,
0x44F4,
{0xBA, 0x1D, 0x86, 0x67, 0x24, 0x6F, 0xDF, 0x8E}};
if (mActiveTIPGUID == kMicrosoftWubiGUID) {
return TextInputProcessorID::eMicrosoftWubi;
}
// NOTE: There are some other Simplified Chinese TIPs installed in Windows:
// * Chinese Simplified QuanPin (version 6.0)
// - {54FC610E-6ABD-4685-9DDD-A130BDF1B170} (Win8.1)
// * Chinese Simplified ZhengMa (version 6.0)
// - {733B4D81-3BC3-4132-B91A-E9CDD5E2BFC9} (Win8.1)
// * Chinese Simplified ShuangPin (version 6.0)
// - {EF63706D-31C4-490E-9DBB-BD150ADC454B} (Win8.1)
// * Microsoft Pinyin ABC Input Style
// - {FCA121D2-8C6D-41FB-B2DE-A2AD110D4820} (Win7)
return TextInputProcessorID::eUnknown;
}
TextInputProcessorID ComputeActiveTIPAsKorean() {
// {B5FE1F02-D5F2-4445-9C03-C568F23C99A1} (Win7, Win8.1, Win10)
static constexpr GUID kMicrosoftIMEForKoreanGUID = {
0xB5FE1F02,
0xD5F2,
0x4445,
{0x9C, 0x03, 0xC5, 0x68, 0xF2, 0x3C, 0x99, 0xA1}};
if (mActiveTIPGUID == kMicrosoftIMEForKoreanGUID) {
return TextInputProcessorID::eMicrosoftIMEForKorean;
}
// {B60AF051-257A-46BC-B9D3-84DAD819BAFB} (Win8.1, Win10)
static constexpr GUID kMicrosoftOldHangulGUID = {
0xB60AF051,
0x257A,
0x46BC,
{0xB9, 0xD3, 0x84, 0xDA, 0xD8, 0x19, 0xBA, 0xFB}};
if (mActiveTIPGUID == kMicrosoftOldHangulGUID) {
return TextInputProcessorID::eMicrosoftOldHangul;
}
// NOTE: There is the other Korean TIP installed in Windows:
// * Microsoft IME 2010
// - {48878C45-93F9-4aaf-A6A1-272CD863C4F5} (Win7)
return TextInputProcessorID::eUnknown;
}
public: // ITfInputProcessorProfileActivationSink
STDMETHODIMP OnActivated(DWORD, LANGID, REFCLSID, REFGUID, REFGUID, HKL,
DWORD);
private:
TSFStaticSink();
virtual ~TSFStaticSink() {}
bool EnsureInitActiveTIPKeyboard();
void Destroy();
void GetTIPDescription(REFCLSID aTextService, LANGID aLangID,
REFGUID aProfile, nsAString& aDescription);
bool IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID,
REFGUID aProfile);
TextInputProcessorID mActiveTIP;
// Cookie of installing ITfInputProcessorProfileActivationSink
DWORD mIPProfileCookie;
LANGID mLangID;
// True if current IME is implemented with IMM.
bool mIsIMM_IME;
// True if OnActivated() is already called
bool mOnActivatedCalled;
RefPtr<ITfThreadMgr> mThreadMgr;
RefPtr<ITfInputProcessorProfiles> mInputProcessorProfiles;
// Active TIP keyboard's description. If active language profile isn't TIP,
// i.e., IMM-IME or just a keyboard layout, this is empty.
nsString mActiveTIPKeyboardDescription;
// Active TIP's GUID and CLSID
GUID mActiveTIPGUID;
CLSID mActiveTIPCLSID;
static StaticRefPtr<TSFStaticSink> sInstance;
};
StaticRefPtr<TSFStaticSink> TSFStaticSink::sInstance;
TSFStaticSink::TSFStaticSink()
: mActiveTIP(TextInputProcessorID::eNotComputed),
mIPProfileCookie(TF_INVALID_COOKIE),
mLangID(0),
mIsIMM_IME(false),
mOnActivatedCalled(false),
mActiveTIPGUID(GUID_NULL) {}
bool TSFStaticSink::Init(ITfThreadMgr* aThreadMgr,
ITfInputProcessorProfiles* aInputProcessorProfiles) {
MOZ_ASSERT(!mThreadMgr && !mInputProcessorProfiles,
"TSFStaticSink::Init() must be called only once");
mThreadMgr = aThreadMgr;
mInputProcessorProfiles = aInputProcessorProfiles;
RefPtr<ITfSource> source;
HRESULT hr =
mThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source));
if (FAILED(hr)) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
("0x%p TSFStaticSink::Init() FAILED to get ITfSource "
"instance (0x%08X)",
this, hr));
return false;
}
// NOTE: On Vista or later, Windows let us know activate IME changed only
// with ITfInputProcessorProfileActivationSink.
hr = source->AdviseSink(
IID_ITfInputProcessorProfileActivationSink,
static_cast<ITfInputProcessorProfileActivationSink*>(this),
&mIPProfileCookie);
if (FAILED(hr) || mIPProfileCookie == TF_INVALID_COOKIE) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
("0x%p TSFStaticSink::Init() FAILED to install "
"ITfInputProcessorProfileActivationSink (0x%08X)",
this, hr));
return false;
}
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("0x%p TSFStaticSink::Init(), "
"mIPProfileCookie=0x%08X",
this, mIPProfileCookie));
return true;
}
void TSFStaticSink::Destroy() {
MOZ_LOG(sTextStoreLog, LogLevel::Info,
("0x%p TSFStaticSink::Shutdown() "
"mIPProfileCookie=0x%08X",
this, mIPProfileCookie));
if (mIPProfileCookie != TF_INVALID_COOKIE) {
RefPtr<ITfSource> source;
HRESULT hr =
mThreadMgr->QueryInterface(IID_ITfSource, getter_AddRefs(source));
if (FAILED(hr)) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
("0x%p TSFStaticSink::Shutdown() FAILED to get "
"ITfSource instance (0x%08X)",
this, hr));
} else {
hr = source->UnadviseSink(mIPProfileCookie);
if (FAILED(hr)) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
("0x%p TSFTextStore::Shutdown() FAILED to uninstall "
"ITfInputProcessorProfileActivationSink (0x%08X)",
this, hr));
}
}
}
mThreadMgr = nullptr;
mInputProcessorProfiles = nullptr;
}
STDMETHODIMP
TSFStaticSink::OnActivated(DWORD dwProfileType, LANGID langid, REFCLSID rclsid,
REFGUID catid, REFGUID guidProfile, HKL hkl,
DWORD dwFlags) {
if ((dwFlags & TF_IPSINK_FLAG_ACTIVE) &&
(dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT ||
catid == GUID_TFCAT_TIP_KEYBOARD)) {
mOnActivatedCalled = true;
mActiveTIP = TextInputProcessorID::eNotComputed;
mActiveTIPGUID = guidProfile;
mActiveTIPCLSID = rclsid;
mLangID = langid & 0xFFFF;
mIsIMM_IME = IsIMM_IME(hkl);
GetTIPDescription(rclsid, langid, guidProfile,