Bug 927882 - Standardize TextSelection caret positioning logic for soft keyboards, r=jchen, wesj, f=margaret

This commit is contained in:
Mark Capella 2014-02-19 22:19:43 -05:00
parent 583fc0629c
commit 214013c253
2 changed files with 51 additions and 15 deletions

View File

@ -58,7 +58,9 @@ var SelectionHandler = {
Services.obs.addObserver(this, "TextSelection:Position", false);
Services.obs.addObserver(this, "TextSelection:End", false);
Services.obs.addObserver(this, "TextSelection:Action", false);
BrowserApp.deck.addEventListener("compositionend", this, false);
BrowserApp.deck.addEventListener("pagehide", this, false);
BrowserApp.deck.addEventListener("blur", this, true);
},
_removeObservers: function sh_removeObservers() {
@ -69,11 +71,19 @@ var SelectionHandler = {
Services.obs.removeObserver(this, "TextSelection:Position");
Services.obs.removeObserver(this, "TextSelection:End");
Services.obs.removeObserver(this, "TextSelection:Action");
BrowserApp.deck.removeEventListener("compositionend", this);
BrowserApp.deck.removeEventListener("pagehide", this);
BrowserApp.deck.removeEventListener("blur", this);
},
observe: function sh_observe(aSubject, aTopic, aData) {
switch (aTopic) {
// Update caret position on keyboard activity
case "TextSelection:UpdateCaretPos":
// Generated by IME close, autoCorrection / styling
this._positionHandles();
break;
case "Gesture:SingleTap": {
if (this._activeType == this.TYPE_SELECTION) {
let data = JSON.parse(aData);
@ -175,16 +185,18 @@ var SelectionHandler = {
handleEvent: function sh_handleEvent(aEvent) {
switch (aEvent.type) {
case "pagehide":
// We only add keydown and blur listeners for TYPE_CURSOR
case "keydown":
case "blur":
this._closeSelection();
break;
// Update caret position on keyboard activity
case "keyup":
// Not generated by Swiftkeyboard
case "compositionupdate":
case "compositionend":
// compositionend messages normally terminate caret display
if (this._activeType == this.TYPE_CURSOR && !this._ignoreCompositionChanges) {
this._deactivate();
// Generated by SwiftKeyboard, et. al.
if (!this._ignoreCompositionChanges) {
this._positionHandles();
}
break;
}
@ -497,10 +509,14 @@ var SelectionHandler = {
!((aElement instanceof HTMLInputElement && aElement.mozIsTextField(false)) ||
(aElement instanceof HTMLTextAreaElement)))
return;
this._initTargetInfo(aElement);
this._contentWindow.addEventListener("keydown", this, false);
this._contentWindow.addEventListener("blur", this, true);
// Caret-specific observer/listeners
Services.obs.addObserver(this, "TextSelection:UpdateCaretPos", false);
BrowserApp.deck.addEventListener("keyup", this, false);
BrowserApp.deck.addEventListener("compositionupdate", this, false);
BrowserApp.deck.addEventListener("compositionend", this, false);
this._activeType = this.TYPE_CURSOR;
this._positionHandles();
@ -508,6 +524,7 @@ var SelectionHandler = {
this._sendMessage("TextSelection:ShowHandles", [this.HANDLE_TYPE_MIDDLE]);
},
// Target initialization for both TYPE_CURSOR and TYPE_SELECTION
_initTargetInfo: function sh_initTargetInfo(aElement) {
this._targetElement = aElement;
if (aElement instanceof Ci.nsIDOMNSEditableElement) {
@ -518,7 +535,6 @@ var SelectionHandler = {
this._isRTL = (this._contentWindow.getComputedStyle(aElement, "").direction == "rtl");
this._addObservers();
this._contentWindow.addEventListener("pagehide", this, false);
},
_getSelection: function sh_getSelection() {
@ -749,20 +765,26 @@ var SelectionHandler = {
},
_deactivate: function sh_deactivate() {
this._activeType = this.TYPE_NONE;
sendMessageToJava({ type: "TextSelection:HideHandles" });
this._removeObservers();
this._contentWindow.removeEventListener("pagehide", this, false);
this._contentWindow.removeEventListener("keydown", this, false);
this._contentWindow.removeEventListener("blur", this, true);
// Only observed for caret positioning
if (this._activeType == this.TYPE_CURSOR) {
Services.obs.removeObserver(this, "TextSelection:UpdateCaretPos");
BrowserApp.deck.removeEventListener("keyup", this);
BrowserApp.deck.removeEventListener("compositionupdate", this);
BrowserApp.deck.removeEventListener("compositionend", this);
}
this._contentWindow = null;
this._targetElement = null;
this._isRTL = false;
this._cache = null;
this._ignoreSelectionChanges = false;
this._ignoreCompositionChanges = false;
this._activeType = this.TYPE_NONE;
},
_getViewOffset: function sh_getViewOffset() {

View File

@ -1960,6 +1960,13 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
selEvent.mExpandToClusterBoundary = false;
DispatchEvent(&selEvent);
// Notify SelectionHandler of final caret position
// Required after IME hide via 'Back' button
AndroidGeckoEvent* broadcastEvent = AndroidGeckoEvent::MakeBroadcastEvent(
NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"),
NS_LITERAL_CSTRING(""));
nsAppShell::gAppShell->PostEvent(broadcastEvent);
}
break;
case AndroidGeckoEvent::IME_ADD_COMPOSITION_RANGE:
@ -2047,6 +2054,13 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
DispatchEvent(&event);
mIMERanges.Clear();
// Notify SelectionHandler of final caret position
// Required in cases of keyboards providing autoCorrections
AndroidGeckoEvent* broadcastEvent = AndroidGeckoEvent::MakeBroadcastEvent(
NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"),
NS_LITERAL_CSTRING(""));
nsAppShell::gAppShell->PostEvent(broadcastEvent);
}
break;
case AndroidGeckoEvent::IME_REMOVE_COMPOSITION: