emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android 90ae3cc3875 2/2: Improve IM synchronization on Android


From: Po Lu
Subject: feature/android 90ae3cc3875 2/2: Improve IM synchronization on Android
Date: Wed, 14 Jun 2023 03:38:44 -0400 (EDT)

branch: feature/android
commit 90ae3cc387530229e5aca32c00d35495ab680e21
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Improve IM synchronization on Android
    
    * java/org/gnu/emacs/EmacsInputConnection.java
    (EmacsInputConnection): Reimplement as an InputConnection, not
    BaseInputConnection.
    * src/androidterm.c (performEditorAction): Sync prior to sending
    keyboard events.
---
 java/org/gnu/emacs/EmacsInputConnection.java | 189 +++++++++++++++++++++++----
 src/androidterm.c                            |   7 +
 2 files changed, 174 insertions(+), 22 deletions(-)

diff --git a/java/org/gnu/emacs/EmacsInputConnection.java 
b/java/org/gnu/emacs/EmacsInputConnection.java
index 73c93c67ac7..1bcc9a62a81 100644
--- a/java/org/gnu/emacs/EmacsInputConnection.java
+++ b/java/org/gnu/emacs/EmacsInputConnection.java
@@ -19,26 +19,35 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 package org.gnu.emacs;
 
-import android.view.inputmethod.BaseInputConnection;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.view.KeyEvent;
+
 import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.SurroundingText;
+import android.view.inputmethod.TextAttribute;
 import android.view.inputmethod.TextSnapshot;
 
-import android.view.KeyEvent;
-
-import android.os.Build;
-
 import android.util.Log;
 
 /* Android input methods, take number six.  See textconv.c for more
    details; this is more-or-less a thin wrapper around that file.  */
 
-public final class EmacsInputConnection extends BaseInputConnection
+public final class EmacsInputConnection implements InputConnection
 {
   private static final String TAG = "EmacsInputConnection";
+
+  /* View associated with this input connection.  */
   private EmacsView view;
+
+  /* The handle ID associated with that view's window.  */
   private short windowHandle;
 
   /* Whether or not to synchronize and call `updateIC' with the
@@ -77,15 +86,18 @@ public final class EmacsInputConnection extends 
BaseInputConnection
       extractAbsoluteOffsets = true;
   };
 
+
   public
   EmacsInputConnection (EmacsView view)
   {
-    super (view, true);
-
     this.view = view;
     this.windowHandle = view.window.handle;
   }
 
+
+  /* The functions below are called by input methods whenever they
+     need to perform an edit.  */
+
   @Override
   public boolean
   beginBatchEdit ()
@@ -116,7 +128,6 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     return true;
   }
 
-  @Override
   public boolean
   commitCompletion (CompletionInfo info)
   {
@@ -133,6 +144,19 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     return true;
   }
 
+  @Override
+  public boolean
+  commitCorrection (CorrectionInfo info)
+  {
+    /* The input method calls this function not to commit text, but to
+       indicate that a subsequent edit will consist of a correction.
+       Emacs has no use for this information.
+
+       Of course this completely contradicts the provided
+       documentation, but this is how Android actually behaves.  */
+    return false;
+  }
+
   @Override
   public boolean
   commitText (CharSequence text, int newCursorPosition)
@@ -170,6 +194,14 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     return true;
   }
 
+  @Override
+  public boolean
+  commitText (CharSequence text, int newCursorPosition,
+             TextAttribute textAttribute)
+  {
+    return commitText (text, newCursorPosition);
+  }
+
   @Override
   public boolean
   deleteSurroundingText (int leftLength, int rightLength)
@@ -187,6 +219,16 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     return true;
   }
 
+  @Override
+  public boolean
+  deleteSurroundingTextInCodePoints (int leftLength, int rightLength)
+  {
+    /* Emacs returns characters which cannot be represented in a Java
+       `char' as NULL characters, so code points always reflect
+       characters themselves.  */
+    return deleteSurroundingText (leftLength, rightLength);
+  }
+
   @Override
   public boolean
   finishComposingText ()
@@ -277,6 +319,14 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     return true;
   }
 
+  @Override
+  public boolean
+  setComposingText (CharSequence text, int newCursorPosition,
+                   TextAttribute textAttribute)
+  {
+    return setComposingText (text, newCursorPosition);
+  }
+
   @Override
   public boolean
   setComposingRegion (int start, int end)
@@ -292,6 +342,13 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     return true;
   }
 
+  @Override
+  public boolean
+  setComposingRegion (int start, int end, TextAttribute textAttribute)
+  {
+    return setComposingRegion (start, end);
+  }
+
   @Override
   public boolean
   performEditorAction (int editorAction)
@@ -430,6 +487,8 @@ public final class EmacsInputConnection extends 
BaseInputConnection
   }
 
   @Override
+  /* ACTION_MULTIPLE is apparently obsolete.  */
+  @SuppressWarnings ("deprecation")
   public boolean
   sendKeyEvent (KeyEvent key)
   {
@@ -440,20 +499,33 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     if (EmacsService.DEBUG_IC)
       Log.d (TAG, "sendKeyEvent: " + key);
 
-    return super.sendKeyEvent (key);
-  }
+    /* Use the standard API if possible.  */
 
-  @Override
-  public boolean
-  deleteSurroundingTextInCodePoints (int beforeLength, int afterLength)
-  {
-    /* Return if the input connection is out of date.  */
-    if (view.icSerial < view.icGeneration)
-      return false;
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+      view.imManager.dispatchKeyEventFromInputMethod (view, key);
+    else
+      {
+       /* Fall back to dispatching the event manually if not.  */
+
+       switch (key.getAction ())
+         {
+         case KeyEvent.ACTION_DOWN:
+           view.onKeyDown (key.getKeyCode (), key);
+           break;
+
+         case KeyEvent.ACTION_UP:
+           view.onKeyUp (key.getKeyCode (), key);
+           break;
+
+         case KeyEvent.ACTION_MULTIPLE:
+           view.onKeyMultiple (key.getKeyCode (),
+                               key.getRepeatCount (),
+                               key);
+           break;
+         }
+      }
 
-    /* This can be implemented the same way as
-       deleteSurroundingText.  */
-    return this.deleteSurroundingText (beforeLength, afterLength);
+    return true;
   }
 
   @Override
@@ -471,6 +543,16 @@ public final class EmacsInputConnection extends 
BaseInputConnection
     return true;
   }
 
+  @Override
+  public boolean
+  requestCursorUpdates (int cursorUpdateMode, int filter)
+  {
+    if (filter != 0)
+      return false;
+
+    return requestCursorUpdates (cursorUpdateMode);
+  }
+
   @Override
   public SurroundingText
   getSurroundingText (int beforeLength, int afterLength,
@@ -505,11 +587,74 @@ public final class EmacsInputConnection extends 
BaseInputConnection
 
   /* Override functions which are not implemented.  */
 
+  @Override
+  public Handler
+  getHandler ()
+  {
+    return null;
+  }
+
+  @Override
+  public void
+  closeConnection ()
+  {
+
+  }
+
+  @Override
+  public boolean
+  commitContent (InputContentInfo inputContentInfo, int flags,
+                Bundle opts)
+  {
+    return false;
+  }
+
+  @Override
+  public boolean
+  setImeConsumesInput (boolean imeConsumesInput)
+  {
+    return false;
+  }
+
   @Override
   public TextSnapshot
   takeSnapshot ()
   {
-    Log.d (TAG, "takeSnapshot");
     return null;
   }
+
+  @Override
+  public boolean
+  clearMetaKeyStates (int states)
+  {
+    return false;
+  }
+
+  @Override
+  public boolean
+  reportFullscreenMode (boolean enabled)
+  {
+    return false;
+  }
+
+  @Override
+  public boolean
+  performSpellCheck ()
+  {
+    return false;
+  }
+
+  @Override
+  public boolean
+  performPrivateCommand (String action, Bundle data)
+  {
+    return false;
+  }
+
+  @Override
+  public int
+  getCursorCapsMode (int reqModes)
+  {
+    return 0;
+  }
 }
diff --git a/src/androidterm.c b/src/androidterm.c
index f08536c02ab..191ff65199b 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -5193,6 +5193,13 @@ NATIVE_NAME (performEditorAction) (JNIEnv *env, jobject 
object,
 
   union android_event event;
 
+  /* It's a good idea to call `android_sync_edit' before sending the
+     key event.  Otherwise, if RET causes the current window to be
+     changed, any text previously committed might end up in the newly
+     selected window.  */
+
+  android_sync_edit ();
+
   /* Undocumented behavior: performEditorAction is apparently expected
      to finish composing any text.  */
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]