[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android 63339a9577f: Update Android port
From: |
Po Lu |
Subject: |
feature/android 63339a9577f: Update Android port |
Date: |
Tue, 6 Jun 2023 23:04:41 -0400 (EDT) |
branch: feature/android
commit 63339a9577f085074d16fa8c56ddd56864c94dda
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Update Android port
* java/org/gnu/emacs/EmacsInputConnection.java (beginBatchEdit)
(endBatchEdit, commitCompletion, commitText, deleteSurroundingText)
(finishComposingText, getSelectedText, getTextAfterCursor)
(getTextBeforeCursor, setComposingText, setComposingRegion)
(performEditorAction, performContextMenuAction, getExtractedText)
(setSelection, sendKeyEvent, deleteSurroundingTextInCodePoints)
(requestCursorUpdates): Ensure that the input connection is up
to date.
(getSurroundingText): New function.
* java/org/gnu/emacs/EmacsNative.java (getSurroundingText):
Export new C function.
* java/org/gnu/emacs/EmacsService.java (resetIC): Invalidate
previously created input connections.
* java/org/gnu/emacs/EmacsView.java (EmacsView)
(onCreateInputConnection): Signify that input connections are
now up to date.
* src/androidterm.c (struct
android_get_surrounding_text_context): New structure.
(android_get_surrounding_text, NATIVE_NAME):
* src/textconv.c (get_surrounding_text):
* src/textconv.h: New functions.
---
java/org/gnu/emacs/EmacsInputConnection.java | 105 ++++++++++++++++++++
java/org/gnu/emacs/EmacsNative.java | 4 +
java/org/gnu/emacs/EmacsService.java | 1 +
java/org/gnu/emacs/EmacsView.java | 13 +++
src/androidterm.c | 143 +++++++++++++++++++++++++++
src/textconv.c | 100 +++++++++++++++++++
src/textconv.h | 4 +
7 files changed, 370 insertions(+)
diff --git a/java/org/gnu/emacs/EmacsInputConnection.java
b/java/org/gnu/emacs/EmacsInputConnection.java
index 9ced7cb7aaf..73c93c67ac7 100644
--- a/java/org/gnu/emacs/EmacsInputConnection.java
+++ b/java/org/gnu/emacs/EmacsInputConnection.java
@@ -23,7 +23,9 @@ import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.SurroundingText;
import android.view.inputmethod.TextSnapshot;
+
import android.view.KeyEvent;
import android.os.Build;
@@ -88,6 +90,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
beginBatchEdit ()
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "beginBatchEdit");
@@ -99,6 +105,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
endBatchEdit ()
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "endBatchEdit");
@@ -110,6 +120,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
commitCompletion (CompletionInfo info)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "commitCompletion: " + info);
@@ -125,6 +139,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
{
int[] selection;
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "commitText: " + text + " " + newCursorPosition);
@@ -156,6 +174,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
deleteSurroundingText (int leftLength, int rightLength)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, ("deleteSurroundingText: "
+ leftLength + " " + rightLength));
@@ -169,6 +191,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
finishComposingText ()
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "finishComposingText");
@@ -180,6 +206,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public String
getSelectedText (int flags)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return null;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "getSelectedText: " + flags);
@@ -192,6 +222,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
{
String string;
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return null;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "getTextAfterCursor: " + length + " " + flags);
@@ -210,6 +244,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
{
String string;
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return null;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "getTextBeforeCursor: " + length + " " + flags);
@@ -226,6 +264,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
setComposingText (CharSequence text, int newCursorPosition)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, ("setComposingText: "
+ text + " ## " + newCursorPosition));
@@ -239,6 +281,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
setComposingRegion (int start, int end)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "setComposingRegion: " + start + " " + end);
@@ -250,6 +296,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
performEditorAction (int editorAction)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "performEditorAction: " + editorAction);
@@ -263,6 +313,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
{
int action;
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "performContextMenuAction: " + contextMenuAction);
@@ -310,6 +364,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
ExtractedText text;
int[] selection;
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return null;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "getExtractedText: " + request.hintMaxChars + ", "
+ request.hintMaxLines + " " + flags);
@@ -360,6 +418,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
setSelection (int start, int end)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "setSelection: " + start + " " + end);
@@ -371,6 +433,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
sendKeyEvent (KeyEvent key)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "sendKeyEvent: " + key);
@@ -381,6 +447,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
deleteSurroundingTextInCodePoints (int beforeLength, int afterLength)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
/* This can be implemented the same way as
deleteSurroundingText. */
return this.deleteSurroundingText (beforeLength, afterLength);
@@ -390,6 +460,10 @@ public final class EmacsInputConnection extends
BaseInputConnection
public boolean
requestCursorUpdates (int cursorUpdateMode)
{
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return false;
+
if (EmacsService.DEBUG_IC)
Log.d (TAG, "requestCursorUpdates: " + cursorUpdateMode);
@@ -397,6 +471,37 @@ public final class EmacsInputConnection extends
BaseInputConnection
return true;
}
+ @Override
+ public SurroundingText
+ getSurroundingText (int beforeLength, int afterLength,
+ int flags)
+ {
+ SurroundingText text;
+
+ /* Return if the input connection is out of date. */
+ if (view.icSerial < view.icGeneration)
+ return null;
+
+ if (EmacsService.DEBUG_IC)
+ Log.d (TAG, ("getSurroundingText: " + beforeLength + ", "
+ + afterLength));
+
+ text = EmacsNative.getSurroundingText (windowHandle, beforeLength,
+ afterLength, flags);
+
+ if (text != null)
+ Log.d (TAG, ("getSurroundingText: "
+ + text.getSelectionStart ()
+ + ","
+ + text.getSelectionEnd ()
+ + "+"
+ + text.getOffset ()
+ + ": "
+ + text.getText ()));
+
+ return text;
+ }
+
/* Override functions which are not implemented. */
diff --git a/java/org/gnu/emacs/EmacsNative.java
b/java/org/gnu/emacs/EmacsNative.java
index cb1c6caa79a..cb89cf6808a 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -25,6 +25,7 @@ import android.graphics.Bitmap;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.SurroundingText;
public final class EmacsNative
{
@@ -222,6 +223,9 @@ public final class EmacsNative
public static native void requestSelectionUpdate (short window);
public static native void requestCursorUpdates (short window, int mode);
public static native void clearInputFlags (short window);
+ public static native SurroundingText getSurroundingText (short window,
+ int left, int right,
+ int flags);
/* Return the current value of the selection, or -1 upon
diff --git a/java/org/gnu/emacs/EmacsService.java
b/java/org/gnu/emacs/EmacsService.java
index 2074a5b7c2b..48e39f8b355 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -748,6 +748,7 @@ public final class EmacsService extends Service
window.view.setICMode (icMode);
icBeginSynchronous ();
+ window.view.icGeneration++;
window.view.imManager.restartInput (window.view);
icEndSynchronous ();
}
diff --git a/java/org/gnu/emacs/EmacsView.java
b/java/org/gnu/emacs/EmacsView.java
index a78dec08839..d432162132d 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -111,6 +111,13 @@ public final class EmacsView extends ViewGroup
details. */
private int icMode;
+ /* The number of calls to `resetIC' to have taken place the last
+ time an InputConnection was created. */
+ public long icSerial;
+
+ /* The number of calls to `recetIC' that have taken place. */
+ public volatile long icGeneration;
+
public
EmacsView (EmacsWindow window)
{
@@ -627,6 +634,12 @@ public final class EmacsView extends ViewGroup
return null;
}
+ /* Set icSerial. If icSerial < icGeneration, the input connection
+ has been reset, and future input should be ignored until a new
+ connection is created. */
+
+ icSerial = icGeneration;
+
/* Reset flags set by the previous input method. */
EmacsNative.clearInputFlags (window.handle);
diff --git a/src/androidterm.c b/src/androidterm.c
index 2a054715d6a..77f2bd1c7a0 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -5636,6 +5636,149 @@ NATIVE_NAME (clearInputFlags) (JNIEnv *env, jobject
object,
android_write_event (&event);
}
+
+
+/* Context for a call to `getSurroundingText'. */
+
+struct android_get_surrounding_text_context
+{
+ /* Number of characters before the region to return. */
+ int before_length;
+
+ /* Number of characters after the region to return. */
+ int after_length;
+
+ /* The returned text, or NULL. */
+ char *text;
+
+ /* The size of that text in characters and bytes. */
+ ptrdiff_t length, bytes;
+
+ /* Offsets into that text. */
+ ptrdiff_t offset, start, end;
+
+ /* The window. */
+ android_window window;
+};
+
+/* Return the surrounding text in the surrounding text context
+ specified by DATA. */
+
+static void
+android_get_surrounding_text (void *data)
+{
+ struct android_get_surrounding_text_context *request;
+ struct frame *f;
+ ptrdiff_t temp;
+
+ request = data;
+
+ /* Find the frame associated with the window. */
+ f = android_window_to_frame (NULL, request->window);
+
+ if (!f)
+ return;
+
+ /* Now get the surrounding text. */
+ request->text
+ = get_surrounding_text (f, request->before_length,
+ request->after_length, &request->length,
+ &request->bytes, &request->offset,
+ &request->start, &request->end);
+
+ /* Sort request->start and request->end for compatibility with some
+ bad input methods. */
+
+ if (request->end < request->start)
+ {
+ temp = request->start;
+ request->start = request->end;
+ request->end = temp;
+ }
+}
+
+JNIEXPORT jobject JNICALL
+NATIVE_NAME (getSurroundingText) (JNIEnv *env, jobject ignored_object,
+ jshort window, jint before_length,
+ jint after_length, jint flags)
+{
+ JNI_STACK_ALIGNMENT_PROLOGUE;
+
+ static jclass class;
+ static jmethodID constructor;
+
+ struct android_get_surrounding_text_context context;
+ jstring string;
+ jobject object;
+
+ /* Initialize CLASS if it has not yet been initialized. */
+
+ if (!class)
+ {
+ class
+ = (*env)->FindClass (env, ("android/view/inputmethod"
+ "/SurroundingText"));
+
+#if __ANDROID_API__ < 31
+ /* If CLASS cannot be found, the version of Android currently
+ running is too old. */
+
+ if (!class)
+ {
+ (*env)->ExceptionClear (env);
+ return NULL;
+ }
+#else /* __ANDROID_API__ >= 31 */
+ assert (class);
+#endif /* __ANDROID_API__ < 31 */
+
+ class = (*env)->NewGlobalRef (env, class);
+ if (!class)
+ return NULL;
+
+ /* Now look for its constructor. */
+ constructor = (*env)->GetMethodID (env, class, "<init>",
+ "(Ljava/lang/CharSequence;III)V");
+ assert (constructor);
+ }
+
+ context.before_length = before_length;
+ context.after_length = after_length;
+ context.window = window;
+ context.text = NULL;
+
+ android_sync_edit ();
+ if (android_run_in_emacs_thread (android_get_surrounding_text,
+ &context))
+ return NULL;
+
+ if (!context.text)
+ return NULL;
+
+ /* Encode the returned text. */
+ string = android_text_to_string (env, context.text, context.length,
+ context.bytes);
+ free (context.text);
+
+ if (!string)
+ return NULL;
+
+ /* Create an SurroundingText object containing this information. */
+ object = (*env)->NewObject (env, class, constructor, string,
+ (jint) min (context.start,
+ TYPE_MAXIMUM (jint)),
+ (jint) min (context.end,
+ TYPE_MAXIMUM (jint)),
+ /* Adjust point offsets to fit into
+ Android's 0-based indexing. */
+ (jint) min (context.offset - 1,
+ TYPE_MAXIMUM (jint)));
+ if (!object)
+ return NULL;
+
+ return object;
+}
+
#ifdef __clang__
#pragma clang diagnostic pop
#else
diff --git a/src/textconv.c b/src/textconv.c
index 0dcf5bdcea8..1161b781b6a 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -1732,6 +1732,106 @@ get_extracted_text (struct frame *f, ptrdiff_t n,
return buffer;
}
+/* Return the text between the positions PT - LEFT and PT + RIGHT. If
+ the mark is active, return the range of text relative to the bounds
+ of the region instead.
+
+ Set *LENGTH to the number of characters returned, *BYTES to the
+ number of bytes returned, *OFFSET to the character position of the
+ returned text, and *START_RETURN and *END_RETURN to the mark and
+ point relative to that position. */
+
+char *
+get_surrounding_text (struct frame *f, ptrdiff_t left,
+ ptrdiff_t right, ptrdiff_t *length,
+ ptrdiff_t *bytes, ptrdiff_t *offset,
+ ptrdiff_t *start_return,
+ ptrdiff_t *end_return)
+{
+ specpdl_ref count;
+ ptrdiff_t start, end, start_byte, end_byte, mark, temp;
+ char *buffer;
+
+ if (!WINDOW_LIVE_P (f->old_selected_window))
+ return NULL;
+
+ /* Save the excursion, as there will be extensive changes to the
+ selected window. */
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_excursion ();
+
+ /* Inhibit quitting. */
+ specbind (Qinhibit_quit, Qt);
+
+ /* Temporarily switch to F's selected window at the time of the last
+ redisplay. */
+ select_window (f->old_selected_window, Qt);
+ buffer = NULL;
+
+ /* Figure out the bounds of the text to return. */
+
+ /* First, obtain start and end. */
+ end = get_mark ();
+ start = PT;
+
+ /* If the mark is not active, make it start and end. */
+
+ if (end == -1)
+ end = start;
+
+ /* Now sort start and end. */
+
+ if (end < start)
+ {
+ temp = start;
+ start = end;
+ end = temp;
+ }
+
+ /* And subtract left and right. */
+
+ if (INT_SUBTRACT_WRAPV (start, left, &start)
+ || INT_ADD_WRAPV (end, right, &end))
+ goto finish;
+
+ start = max (start, BEGV);
+ end = min (end, ZV);
+
+ /* Detect overflow. */
+
+ if (!(start <= PT && PT <= end))
+ goto finish;
+
+ /* Convert the character positions to byte positions. */
+ start_byte = CHAR_TO_BYTE (start);
+ end_byte = CHAR_TO_BYTE (end);
+
+ /* Extract the text from the buffer. */
+ buffer = xmalloc (end_byte - start_byte);
+ copy_buffer (start, start_byte, end, end_byte,
+ buffer);
+
+ /* Get the mark. If it's not active, use PT. */
+
+ mark = get_mark ();
+
+ if (mark == -1)
+ mark = PT;
+
+ /* Return the offsets. Unlike `get_extracted_text', this need not
+ sort mark and point. */
+
+ *offset = start;
+ *start_return = mark - start;
+ *end_return = PT - start;
+ *length = end - start;
+ *bytes = end_byte - start_byte;
+
+ finish:
+ unbind_to (count, Qnil);
+ return buffer;
+}
+
/* Return whether or not text conversion is temporarily disabled.
`reset' should always call this to determine whether or not to
disable the input method. */
diff --git a/src/textconv.h b/src/textconv.h
index 339cefdba92..7550388a723 100644
--- a/src/textconv.h
+++ b/src/textconv.h
@@ -143,6 +143,10 @@ extern void textconv_barrier (struct frame *, unsigned
long);
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
ptrdiff_t *, ptrdiff_t *, ptrdiff_t *,
ptrdiff_t *, bool *);
+extern char *get_surrounding_text (struct frame *, ptrdiff_t,
+ ptrdiff_t, ptrdiff_t *,
+ ptrdiff_t *, ptrdiff_t *,
+ ptrdiff_t *, ptrdiff_t *);
extern bool conversion_disabled_p (void);
extern void register_textconv_interface (struct textconv_interface *);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- feature/android 63339a9577f: Update Android port,
Po Lu <=