Bug 1215818 - part 2: Add telemetry probe to collect IME usage on macOS r?m_kato
This patch adds a telemetry probe to collect Input Source ID or Bundle ID of
IME when an IME open mode is selected by user. Input Source ID includes
input mode of IME, but Bundle ID does not so. In most languages, we need
to collect the former, but only for Japanese IME, we need to collect the
latter because non-Japanese IME's input mode is "how to input characters".
So, the input mode is important. However, Japanese IME's input mode is
"to input which type of characters". So, Japanese IME user may use multiple
input modes but we need only the IME mode. If we'd collect number of
each input mode users of Japanese language, it'd be difficult to count
how many users actually used typical Japanese IME since somebody may use
only a mode, some others may use only different modes.
So, this patch collects Input Source ID when non-Japanese IME is open and
Bundle ID when Japanese IME is open.
MozReview-Commit-ID: CltLrWVGyRk
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -1746,16 +1746,33 @@ widget:
expires: never
kind: boolean
notification_emails:
- mnakano@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- 'main'
+ ime_name_on_mac:
+ bug_numbers:
+ - 1215818
+ description: >
+ Name of IME which was selected by users on macOS. The value is Input
+ Source ID if non-Japanese IME was open. Otherwise, if Japanese IME was
+ open, the value is Bundle ID. Input Source ID includes input mode, but
+ Bundle ID does not include input mode.
+ keyed: true
+ expires: never
+ kind: boolean
+ notification_emails:
+ - mnakano@mozilla.com
+ release_channel_collection: opt-out
+ record_in_processes:
+ - 'main'
+
# The following section contains memory reporter counters.
memoryreporter:
max_ghost_windows:
bug_numbers:
- 1454724
description: >
The maximum number of leaked ghost windows seen.
expires: "66"
--- a/widget/cocoa/TextInputHandler.h
+++ b/widget/cocoa/TextInputHandler.h
@@ -219,16 +219,17 @@ public:
bool GetInputSourceType(nsAString &aType)
{
NS_ENSURE_TRUE(mInputSource, false);
return GetStringProperty(kTISPropertyInputSourceType, aType);
}
bool IsForRTLLanguage();
+ bool IsForJapaneseLanguage();
bool IsInitializedByCurrentInputSource();
enum {
// 40 is an actual result of the ::LMGetKbdType() when we connect an
// unknown keyboard and set the keyboard type to ANSI manually on the
// set up dialog.
eKbdType_ANSI = 40
};
--- a/widget/cocoa/TextInputHandler.mm
+++ b/widget/cocoa/TextInputHandler.mm
@@ -7,16 +7,17 @@
#include "TextInputHandler.h"
#include "mozilla/Logging.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/MiscEvents.h"
#include "mozilla/MouseEvents.h"
+#include "mozilla/Telemetry.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEvents.h"
#include "nsChildView.h"
#include "nsObjCExceptions.h"
#include "nsBidiUtils.h"
#include "nsToolkit.h"
#include "nsCocoaUtils.h"
@@ -828,16 +829,24 @@ TISInputSourceWrapper::IsForRTLLanguage(
NS_ENSURE_TRUE(ret, ret);
char16_t ch = str.IsEmpty() ? char16_t(0) : str.CharAt(0);
mIsRTL = UTF16_CODE_UNIT_IS_BIDI(ch);
}
return mIsRTL != 0;
}
bool
+TISInputSourceWrapper::IsForJapaneseLanguage()
+{
+ nsAutoString lang;
+ GetPrimaryLanguage(lang);
+ return lang.EqualsLiteral("ja");
+}
+
+bool
TISInputSourceWrapper::IsInitializedByCurrentInputSource()
{
return mInputSource == ::TISCopyCurrentKeyboardInputSource();
}
void
TISInputSourceWrapper::Select()
{
@@ -3045,16 +3054,45 @@ IMEInputHandler::OnCurrentTextInputSourc
const void* aObject,
CFDictionaryRef aUserInfo)
{
// Cache the latest IME opened mode to sLatestIMEOpenedModeInputSourceID.
TISInputSourceWrapper tis;
tis.InitByCurrentInputSource();
if (tis.IsOpenedIMEMode()) {
tis.GetInputSourceID(sLatestIMEOpenedModeInputSourceID);
+ // Collect Input Source ID which includes input mode in most cases.
+ // However, if it's Japanese IME, collecting input mode (e.g.,
+ // "HiraganaKotei") does not make sense because in most languages,
+ // input mode changes "how to input", but Japanese IME changes
+ // "which type of characters to input". I.e., only Japanese IME
+ // users may use multiple input modes. If we'd collect each type of
+ // input mode of Japanese IMEs, it'd be difficult to count actual
+ // users of each IME from the result. So, only when active IME is
+ // a Japanese IME, we should use Bundle ID which does not contain
+ // input mode instead.
+ nsAutoString key;
+ if (tis.IsForJapaneseLanguage()) {
+ tis.GetBundleID(key);
+ } else {
+ tis.GetInputSourceID(key);
+ }
+ // 72 is kMaximumKeyStringLength in TelemetryScalar.cpp
+ if (key.Length() > 72) {
+ if (NS_IS_LOW_SURROGATE(key[72 - 1]) &&
+ NS_IS_HIGH_SURROGATE(key[72 - 2])) {
+ key.Truncate(72 - 2);
+ } else {
+ key.Truncate(72 - 1);
+ }
+ // U+2026 is "..."
+ key.Append(char16_t(0x2026));
+ }
+ Telemetry::ScalarSet(Telemetry::ScalarID::WIDGET_IME_NAME_ON_MAC,
+ key, true);
}
if (MOZ_LOG_TEST(gLog, LogLevel::Info)) {
static CFStringRef sLastTIS = nullptr;
CFStringRef newTIS;
tis.GetInputSourceID(newTIS);
if (!sLastTIS ||
::CFStringCompare(sLastTIS, newTIS, 0) != kCFCompareEqualTo) {
@@ -3140,25 +3178,28 @@ IMEInputHandler::DebugPrintAllIMEModes()
CFArrayRef list = CreateAllIMEModeList();
MOZ_LOG(gLog, LogLevel::Info, ("IME mode configuration:"));
CFIndex idx = ::CFArrayGetCount(list);
TISInputSourceWrapper tis;
for (CFIndex i = 0; i < idx; ++i) {
TISInputSourceRef inputSource = static_cast<TISInputSourceRef>(
const_cast<void *>(::CFArrayGetValueAtIndex(list, i)));
tis.InitByTISInputSourceRef(inputSource);
- nsAutoString name, isid;
+ nsAutoString name, isid, bundleID;
tis.GetLocalizedName(name);
tis.GetInputSourceID(isid);
+ tis.GetBundleID(bundleID);
MOZ_LOG(gLog, LogLevel::Info,
- (" %s\t<%s>%s%s\n",
+ (" %s\t<%s>%s%s\n"
+ " bundled in <%s>\n",
NS_ConvertUTF16toUTF8(name).get(),
NS_ConvertUTF16toUTF8(isid).get(),
tis.IsASCIICapable() ? "" : "\t(Isn't ASCII capable)",
- tis.IsEnabled() ? "" : "\t(Isn't Enabled)"));
+ tis.IsEnabled() ? "" : "\t(Isn't Enabled)",
+ NS_ConvertUTF16toUTF8(bundleID).get()));
}
::CFRelease(list);
}
}
//static
TSMDocumentID
IMEInputHandler::GetCurrentTSMDocumentID()