Bug 1343451 - part 5: Make GeckoEditableSupport dispatch dummy eKeyDown and eKeyUp event during composition always r?jchen
On Android, GeckoEditableSupport has already dispatched eKeyDown event and
eKeyUp event even during composition. I.e., the pref which will be enabled
by
bug 354358 has already been set to true only on Android.
On the other hand, GeckoEditableSupport does not dispatch them if content
listens to "input", "compositionstart", "compositionupdate" or
"compositionend". So, different from the other platforms, we need additional
pref to make the new behavior behind pref.
Therefore, this patch adds a new pref,
"intl.ime.hack.on_any_apps.fire_key_events_for_composition", to override
existing "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition"
pref. And sets mKeyCode and mKeyNameIndex of the dummy KeyboardEvents to
NS_VK_PROCESSKEY and KEY_NAME_INDEX_Process.
MozReview-Commit-ID: Fuy0Ir2xiO5
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
@@ -32,17 +32,17 @@ public class testInputConnection extends
GeckoHelper.blockForReady();
// Spatial navigation interferes with design-mode key event tests.
mActions.setPref("snav.enabled", false, /* flush */ false);
// Enable "selectionchange" events for input/textarea.
mActions.setPref("dom.select_events.enabled", true, /* flush */ false);
mActions.setPref("dom.select_events.textcontrols.enabled", true, /* flush */ false);
// Enable dummy key synthesis.
- mActions.setPref("intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
+ mActions.setPref("intl.ime.hack.on_any_apps.fire_key_events_for_composition",
true, /* flush */ false);
final String url = mStringHelper.ROBOCOP_INPUT_URL;
NavigationHelper.enterAndLoadUrl(url);
mToolbar.assertTitle(url);
// First run tests inside the normal input field.
getJS().syncCall("focus_input", INITIAL_TEXT);
@@ -207,28 +207,21 @@ public class testInputConnection extends
ic.finishComposingText(); // Does not synthesize key.
assertTextAndSelectionAt("Can finish F key", ic, "f", 1);
ic.commitText("o", 1); // Synthesizes O key.
assertTextAndSelectionAt("Can commit O key", ic, "fo", 2);
ic.commitText("of", 1); // Synthesizes dummy key.
assertTextAndSelectionAt("Can commit non-key string", ic, "foof", 4);
getJS().syncCall("end_key_log");
- if (mType.equals("designMode")) {
- // designMode doesn't support dummy key synthesis.
- fAssertEquals("Can synthesize keys",
- "keydown:o,casm;keypress:o,casm;keyup:o,casm;", // O key
- getKeyLog());
- } else {
- fAssertEquals("Can synthesize keys",
- "keydown:Unidentified,casm;keyup:Unidentified,casm;" + // Dummy
- "keydown:o,casm;keypress:o,casm;keyup:o,casm;" + // O key
- "keydown:Unidentified,casm;keyup:Unidentified,casm;", // Dummy
- getKeyLog());
- }
+ fAssertEquals("Can synthesize keys",
+ "keydown:Process,casm;keyup:Process,casm;" + // Dummy
+ "keydown:o,casm;keypress:o,casm;keyup:o,casm;" + // O key
+ "keydown:Process,casm;keyup:Process,casm;", // Dummy
+ getKeyLog());
ic.deleteSurroundingText(4, 0);
assertTextAndSelectionAt("Can clear text", ic, "", 0);
// Bug 1133802, duplication when setting the same composing text more than once.
ic.setComposingText("foo", 1);
assertTextAndSelectionAt("Can set the composing text", ic, "foo", 3);
ic.setComposingText("foo", 1);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2387,22 +2387,36 @@ pref("intl.ellipsis",
// OS locale set instead of the app locale set.
pref("intl.regional_prefs.use_os_locales", false);
// fallback charset list for Unicode conversion (converting from Unicode)
// currently used for mail send only to handle symbol characters (e.g Euro, trademark, smartquotes)
// for ISO-8859-1
pref("intl.fallbackCharsetList.ISO-8859-1", "windows-1252");
pref("font.language.group", "chrome://global/locale/intl.properties");
-// Android-specific pref to use key-events-only mode for IME-unaware webapps.
+// Android-specific pref to control if keydown and keyup events are fired even
+// in during composition. Note that those prefs are ignored if
+// "dom.keyboardevent.dispatch_during_composition" is false.
#ifdef MOZ_WIDGET_ANDROID
+// If true, dispatch the keydown and keyup events on any web apps even during
+// composition.
+#ifdef EARLY_BETA_OR_EARLIER
+pref("intl.ime.hack.on_any_apps.fire_key_events_for_composition", true);
+#else // #ifdef EARLY_BETA_OR_EARLIER
+pref("intl.ime.hack.on_any_apps.fire_key_events_for_composition", false);
+#endif // #ifdef EARLY_BETA_OR_EARLIER #else
+// If true and the above pref is false, dispatch the keydown and keyup events
+// only on IME-unaware web apps. So, this supports web apps which listen to
+// only keydown or keyup event to get a change to do something at every text
+// input.
pref("intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", true);
-#else
+#else // #ifdef MOZ_WIDGET_ANDROID
+pref("intl.ime.hack.on_any_apps.fire_key_events_for_composition", false);
pref("intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", false);
-#endif
+#endif // #ifdef MOZ_WIDGET_ANDROID #else
// If you use legacy Chinese IME which puts an ideographic space to composition
// string as placeholder, this pref might be useful. If this is true and when
// web contents forcibly commits composition (e.g., moving focus), the
// ideographic space will be ignored (i.e., commits with empty string).
pref("intl.ime.remove_placeholder_character_at_commit", false);
pref("intl.uidirection", -1); // -1 to set from locale; 0 for LTR; 1 for RTL
--- a/widget/android/GeckoEditableSupport.cpp
+++ b/widget/android/GeckoEditableSupport.cpp
@@ -8,16 +8,17 @@
#include "AndroidRect.h"
#include "KeyEvent.h"
#include "PuppetWidget.h"
#include "nsIContent.h"
#include "nsISelection.h"
#include "mozilla/IMEStateManager.h"
+#include "mozilla/Preferences.h"
#include "mozilla/TextComposition.h"
#include "mozilla/TextEventDispatcherListener.h"
#include "mozilla/TextEvents.h"
#include <android/api-level.h>
#include <android/input.h>
#include <android/log.h>
@@ -553,20 +554,36 @@ ConvertRectArrayToJavaRectFArray(const n
rects->SetElement(i, rect);
}
return rects;
}
namespace mozilla {
namespace widget {
+bool GeckoEditableSupport::sDispatchKeyEventsInCompositionForAnyApps = false;
+
NS_IMPL_ISUPPORTS(GeckoEditableSupport,
TextEventDispatcherListener,
nsISupportsWeakReference)
+void
+GeckoEditableSupport::ObservePrefs()
+{
+ static bool sIsObservingPref = false;
+ if (sIsObservingPref) {
+ return;
+ }
+ sIsObservingPref = true;
+ Preferences::AddBoolVarCache(
+ &sDispatchKeyEventsInCompositionForAnyApps,
+ "intl.ime.hack.on_any_apps.fire_key_events_for_composition",
+ false);
+}
+
RefPtr<TextComposition>
GeckoEditableSupport::GetComposition() const
{
nsCOMPtr<nsIWidget> widget = GetWidget();
return widget ? IMEStateManager::GetTextCompositionFor(widget) : nullptr;
}
void
@@ -663,27 +680,31 @@ GeckoEditableSupport::OnKeyEvent(int32_t
} else {
dispatcher->MaybeDispatchKeypressEvents(pressEvent, status);
}
}
/*
* Send dummy key events for pages that are unaware of input events,
* to provide web compatibility for pages that depend on key events.
- * Our dummy key events have 0 as the keycode.
*/
void
GeckoEditableSupport::SendIMEDummyKeyEvent(nsIWidget* aWidget, EventMessage msg)
{
nsEventStatus status = nsEventStatus_eIgnore;
MOZ_ASSERT(mDispatcher);
WidgetKeyboardEvent event(true, msg, aWidget);
event.mTime = PR_Now() / 1000;
- MOZ_ASSERT(event.mKeyCode == 0);
+ // TODO: If we can know scan code of the key event which caused replacing
+ // composition string, we should set mCodeNameIndex here. Then,
+ // we should rename this method because it becomes not a "dummy"
+ // keyboard event.
+ event.mKeyCode = NS_VK_PROCESSKEY;
+ event.mKeyNameIndex = KEY_NAME_INDEX_Process;
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
mDispatcher->DispatchKeyboardEvent(msg, event, status);
}
void
GeckoEditableSupport::AddIMETextChange(const IMETextChange& aChange)
{
mIMETextChanges.AppendElement(aChange);
@@ -1022,17 +1043,18 @@ GeckoEditableSupport::OnImeReplaceText(i
* change notification. However, the Java side still expects
* one, so we manually generate a notification. */
IMETextChange dummyChange;
dummyChange.mStart = aStart;
dummyChange.mOldEnd = dummyChange.mNewEnd = aEnd;
AddIMETextChange(dummyChange);
}
- if (mInputContext.mMayBeIMEUnaware) {
+ if (sDispatchKeyEventsInCompositionForAnyApps ||
+ mInputContext.mMayBeIMEUnaware) {
SendIMEDummyKeyEvent(widget, eKeyDown);
if (!mDispatcher || widget->Destroyed()) {
return;
}
}
if (composing) {
mDispatcher->SetPendingComposition(string, mIMERanges);
@@ -1041,17 +1063,18 @@ GeckoEditableSupport::OnImeReplaceText(i
mIMERanges->Clear();
} else if (!string.IsEmpty() || mDispatcher->IsComposing()) {
mDispatcher->CommitComposition(status, &string);
}
if (!mDispatcher || widget->Destroyed()) {
return;
}
- if (mInputContext.mMayBeIMEUnaware) {
+ if (sDispatchKeyEventsInCompositionForAnyApps ||
+ mInputContext.mMayBeIMEUnaware) {
SendIMEDummyKeyEvent(widget, eKeyUp);
// Widget may be destroyed after dispatching the above event.
}
}
void
GeckoEditableSupport::OnImeAddCompositionRange(
int32_t aStart, int32_t aEnd, int32_t aRangeType, int32_t aRangeStyle,
--- a/widget/android/GeckoEditableSupport.h
+++ b/widget/android/GeckoEditableSupport.h
@@ -101,16 +101,20 @@ class GeckoEditableSupport final
AutoTArray<IMETextChange, 4> mIMETextChanges;
RefPtr<TextRangeArray> mIMERanges;
int32_t mIMEMaskEventsCount; // Mask events when > 0.
bool mIMEUpdatingContext;
bool mIMESelectionChanged;
bool mIMETextChangedDuringFlush;
bool mIMEMonitorCursor;
+ static bool sDispatchKeyEventsInCompositionForAnyApps;
+
+ void ObservePrefs();
+
nsIWidget* GetWidget() const
{
return mDispatcher ? mDispatcher->GetWidget() : mWindow;
}
nsresult BeginInputTransaction(TextEventDispatcher* aDispatcher)
{
if (mIsRemote) {
@@ -175,22 +179,25 @@ public:
, mEditable(aEditableChild)
, mEditableAttached(!mIsRemote)
, mIMERanges(new TextRangeArray())
, mIMEMaskEventsCount(1) // Mask IME events since there's no focus yet
, mIMEUpdatingContext(false)
, mIMESelectionChanged(false)
, mIMETextChangedDuringFlush(false)
, mIMEMonitorCursor(false)
- {}
+ {
+ ObservePrefs();
+ }
// Constructor for content process GeckoEditableChild.
GeckoEditableSupport(java::GeckoEditableChild::Param aEditableChild)
: GeckoEditableSupport(nullptr, nullptr, aEditableChild)
- {}
+ {
+ }
NS_DECL_ISUPPORTS
// TextEventDispatcherListener methods
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) override;
NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override;