[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 123b77436e1: Introduce an input method callback required by Andro
From: |
Po Lu |
Subject: |
master 123b77436e1: Introduce an input method callback required by Android 34 |
Date: |
Thu, 5 Oct 2023 02:38:20 -0400 (EDT) |
branch: master
commit 123b77436e187c6254d4585d08135a44077528d1
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Introduce an input method callback required by Android 34
* java/org/gnu/emacs/EmacsInputConnection.java (replaceText):
New function.
* java/org/gnu/emacs/EmacsNative.java (replaceText): Declare
native function.
* src/androidgui.h (enum android_ime_operation): New operation
ANDROID_IME_REPLACE_TEXT.
* src/androidterm.c (android_handle_ime_event): Decode text when
encountering an ANDROID_IME_REPLACE_TEXT operation. Return if
decoding overflowed rather than presenting Qnil to textconv
functions.
(replaceText): New JNI function.
* src/frame.h (enum text_conversion_operation): New operation
TEXTCONV_REPLACE_TEXT.
* src/textconv.c (really_commit_text): Move point to start if
the composing region is set.
(really_replace_text): New function.
(handle_pending_conversion_events_1) <TEXTCONV_REPLACE_TEXT>:
New case.
(replace_text): New function.
* src/textconv.h: Update prototypes.
---
java/org/gnu/emacs/EmacsInputConnection.java | 15 +++
java/org/gnu/emacs/EmacsNative.java | 4 +
src/androidgui.h | 1 +
src/androidterm.c | 47 ++++++++
src/frame.h | 1 +
src/textconv.c | 168 ++++++++++++++++++++++++++-
src/textconv.h | 3 +
7 files changed, 238 insertions(+), 1 deletion(-)
diff --git a/java/org/gnu/emacs/EmacsInputConnection.java
b/java/org/gnu/emacs/EmacsInputConnection.java
index c3764a7b29f..7f6331205cb 100644
--- a/java/org/gnu/emacs/EmacsInputConnection.java
+++ b/java/org/gnu/emacs/EmacsInputConnection.java
@@ -628,6 +628,21 @@ public final class EmacsInputConnection implements
InputConnection
batchEditCount = 0;
}
+ @Override
+ public boolean
+ replaceText (int start, int end, CharSequence text,
+ int newCursorPosition, TextAttribute attributes)
+ {
+ if (EmacsService.DEBUG_IC)
+ Log.d (TAG, ("replaceText: " + text + ":: " + start + ","
+ + end + "," + newCursorPosition));
+
+ EmacsNative.replaceText (windowHandle, start, end,
+ text.toString (), newCursorPosition,
+ attributes);
+ return true;
+ }
+
public void
diff --git a/java/org/gnu/emacs/EmacsNative.java
b/java/org/gnu/emacs/EmacsNative.java
index a4b45aafbc1..d8524d92130 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -26,6 +26,7 @@ import android.graphics.Bitmap;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.SurroundingText;
+import android.view.inputmethod.TextAttribute;
import android.view.inputmethod.TextSnapshot;
public final class EmacsNative
@@ -219,6 +220,9 @@ public final class EmacsNative
int leftLength,
int rightLength);
public static native void finishComposingText (short window);
+ public static native void replaceText (short window, int start, int end,
+ String text, int newCursorPosition,
+ TextAttribute attributes);
public static native String getSelectedText (short window, int flags);
public static native String getTextAfterCursor (short window, int length,
int flags);
diff --git a/src/androidgui.h b/src/androidgui.h
index 14225f7bf80..936706b092e 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -463,6 +463,7 @@ enum android_ime_operation
ANDROID_IME_END_BATCH_EDIT,
ANDROID_IME_REQUEST_SELECTION_UPDATE,
ANDROID_IME_REQUEST_CURSOR_UPDATES,
+ ANDROID_IME_REPLACE_TEXT,
};
enum
diff --git a/src/androidterm.c b/src/androidterm.c
index 438f8ce1fbb..9b00ad85642 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -687,9 +687,17 @@ android_handle_ime_event (union android_event *event,
struct frame *f)
{
case ANDROID_IME_COMMIT_TEXT:
case ANDROID_IME_SET_COMPOSING_TEXT:
+ case ANDROID_IME_REPLACE_TEXT:
text = android_decode_utf16 (event->ime.text,
event->ime.length);
xfree (event->ime.text);
+
+ /* Return should text be long enough that it overflows ptrdiff_t.
+ Such circumstances are detected within android_decode_utf16. */
+
+ if (NILP (text))
+ return;
+
break;
default:
@@ -773,6 +781,12 @@ android_handle_ime_event (union android_event *event,
struct frame *f)
case ANDROID_IME_REQUEST_CURSOR_UPDATES:
android_request_cursor_updates (f, event->ime.length);
break;
+
+ case ANDROID_IME_REPLACE_TEXT:
+ replace_text (f, event->ime.start, event->ime.end,
+ text, event->ime.position,
+ event->ime.counter);
+ break;
}
}
@@ -4856,6 +4870,39 @@ NATIVE_NAME (finishComposingText) (JNIEnv *env, jobject
object,
android_write_event (&event);
}
+JNIEXPORT void JNICALL
+NATIVE_NAME (replaceText) (JNIEnv *env, jobject object, jshort window,
+ jint start, jint end, jobject text,
+ int new_cursor_position, jobject attribute)
+{
+ JNI_STACK_ALIGNMENT_PROLOGUE;
+
+ union android_event event;
+ size_t length;
+
+ /* First, obtain a copy of the Java string. */
+ text = android_copy_java_string (env, text, &length);
+
+ if (!text)
+ return;
+
+ /* Next, populate the event with the information in this function's
+ arguments. */
+
+ event.ime.type = ANDROID_INPUT_METHOD;
+ event.ime.serial = ++event_serial;
+ event.ime.window = window;
+ event.ime.operation = ANDROID_IME_REPLACE_TEXT;
+ event.ime.start = start + 1;
+ event.ime.end = end + 1;
+ event.ime.length = length;
+ event.ime.position = new_cursor_position;
+ event.ime.text = text;
+ event.ime.counter = ++edit_counter;
+
+ android_write_event (&event);
+}
+
/* Structure describing the context used for a text query. */
struct android_conversion_query_context
diff --git a/src/frame.h b/src/frame.h
index f4726f1c0e5..d826ae56e8b 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -90,6 +90,7 @@ enum text_conversion_operation
TEXTCONV_DELETE_SURROUNDING_TEXT,
TEXTCONV_REQUEST_POINT_UPDATE,
TEXTCONV_BARRIER,
+ TEXTCONV_REPLACE_TEXT,
};
/* Structure describing a single edit being performed by the input
diff --git a/src/textconv.c b/src/textconv.c
index 57daa7e53b6..bd72562317f 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -616,6 +616,12 @@ really_commit_text (struct frame *f, EMACS_INT position,
end = max (mark, PT);
}
+ /* If it transpires that the start of the compose region is not
+ point, move point there. */
+
+ if (start != PT)
+ set_point (start);
+
/* Now delete whatever needs to go. */
del_range_1 (start, end, true, false);
@@ -635,7 +641,7 @@ really_commit_text (struct frame *f, EMACS_INT position,
record_buffer_change (start, PT, text);
}
- /* Move to a the position specified in POSITION. */
+ /* Move to the position specified in POSITION. */
if (position <= 0)
{
@@ -1154,6 +1160,135 @@ really_set_point_and_mark (struct frame *f, ptrdiff_t
point,
unbind_to (count, Qnil);
}
+/* Remove the composing region. Replace the text between START and
+ END in F's selected window with TEXT, then set point to POSITION
+ relative to it. If the mark is active, deactivate it. */
+
+static void
+really_replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end,
+ Lisp_Object text, ptrdiff_t position)
+{
+ specpdl_ref count;
+ ptrdiff_t new_start, new_end, wanted;
+ struct window *w;
+
+ /* If F's old selected window is no longer alive, fail. */
+
+ if (!WINDOW_LIVE_P (f->old_selected_window))
+ return;
+
+ count = SPECPDL_INDEX ();
+ record_unwind_protect (restore_selected_window,
+ selected_window);
+
+ /* Make the composition region markers point elsewhere. */
+
+ if (!NILP (f->conversion.compose_region_start))
+ {
+ Fset_marker (f->conversion.compose_region_start, Qnil, Qnil);
+ Fset_marker (f->conversion.compose_region_end, Qnil, Qnil);
+ f->conversion.compose_region_start = Qnil;
+ f->conversion.compose_region_end = Qnil;
+
+ /* Notify the IME of an update to the composition region,
+ inasmuch as the point might not change if START and END are
+ identical and TEXT is empty, among other circumstances. */
+
+ if (text_interface
+ && text_interface->compose_region_changed)
+ (*text_interface->compose_region_changed) (f);
+ }
+
+ /* Delete the composition region overlay. */
+
+ if (!NILP (f->conversion.compose_region_overlay))
+ Fdelete_overlay (f->conversion.compose_region_overlay);
+
+ /* Temporarily switch to F's selected window at the time of the last
+ redisplay. */
+ select_window (f->old_selected_window, Qt);
+
+ /* Sort START and END by magnitude. */
+ new_start = min (start, end);
+ new_end = max (start, end);
+
+ /* Now constrain both to the accessible region. */
+
+ if (new_start < BEGV)
+ new_start = BEGV;
+ else if (new_start > ZV)
+ new_start = ZV;
+
+ if (new_end < BEGV)
+ new_end = BEGV;
+ else if (new_end > ZV)
+ new_end = ZV;
+
+ start = new_start;
+ end = new_end;
+
+ /* This should deactivate the mark. */
+ call0 (Qdeactivate_mark);
+
+ /* Go to start. */
+ set_point (start);
+
+ /* Now delete the text in between, and save PT before TEXT is
+ inserted. */
+ del_range_1 (start, end, true, false);
+ record_buffer_change (start, start, Qt);
+ wanted = PT;
+
+ /* So long as TEXT isn't empty, insert it now. */
+
+ if (SCHARS (text))
+ {
+ /* Insert the new text. Make sure to inherit text properties
+ from the surroundings: if this doesn't happen, CC Mode
+ fontification might grow confused and become very slow. */
+
+ insert_from_string (text, 0, 0, SCHARS (text),
+ SBYTES (text), true);
+ record_buffer_change (start, PT, text);
+ }
+
+ /* Now, move point to the position designated by POSITION. */
+
+ if (position <= 0)
+ {
+ if (INT_ADD_WRAPV (wanted, position, &wanted)
+ || wanted < BEGV)
+ wanted = BEGV;
+
+ if (wanted > ZV)
+ wanted = ZV;
+
+ set_point (wanted);
+ }
+ else
+ {
+ wanted = PT;
+
+ if (INT_ADD_WRAPV (wanted, position - 1, &wanted)
+ || wanted > ZV)
+ wanted = ZV;
+
+ if (wanted < BEGV)
+ wanted = BEGV;
+
+ set_point (wanted);
+ }
+
+ /* Print some debugging information. */
+ TEXTCONV_DEBUG ("text inserted: %s, point now: %zd",
+ SSDATA (text), PT);
+
+ /* Update the ephemeral last point. */
+ w = XWINDOW (selected_window);
+ w->ephemeral_last_point = PT;
+ unbind_to (count, Qnil);
+}
+
/* Complete the edit specified by the counter value inside *TOKEN. */
static void
@@ -1325,6 +1460,13 @@ handle_pending_conversion_events_1 (struct frame *f,
if (w)
w->ephemeral_last_point = window_point (w);
break;
+
+ case TEXTCONV_REPLACE_TEXT:
+ really_replace_text (f, XFIXNUM (XCAR (data)),
+ XFIXNUM (XCAR (XCDR (data))),
+ XCAR (XCDR (XCDR (data))),
+ XFIXNUM (XCAR (XCDR (XCDR (XCDR (data))))));
+ break;
}
/* Signal success. */
@@ -1679,6 +1821,30 @@ textconv_barrier (struct frame *f, unsigned long counter)
input_pending = true;
}
+/* Remove the composing region. Replace the text between START and
+ END within F's selected window with TEXT; deactivate the mark if it
+ is active. Subsequently, set point to POSITION relative to TEXT,
+ much as `commit_text' would. */
+
+void
+replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end,
+ Lisp_Object text, ptrdiff_t position,
+ unsigned long counter)
+{
+ struct text_conversion_action *action, **last;
+
+ action = xmalloc (sizeof *action);
+ action->operation = TEXTCONV_REPLACE_TEXT;
+ action->data = list4 (make_fixnum (start), make_fixnum (end),
+ text, make_fixnum (position));
+ action->next = NULL;
+ action->counter = counter;
+ for (last = &f->conversion.actions; *last; last = &(*last)->next)
+ ;;
+ *last = action;
+ input_pending = true;
+}
+
/* Return N characters of text around point in frame F's old selected
window.
diff --git a/src/textconv.h b/src/textconv.h
index feac5b805af..c677c07e9aa 100644
--- a/src/textconv.h
+++ b/src/textconv.h
@@ -142,6 +142,9 @@ extern void delete_surrounding_text (struct frame *,
ptrdiff_t,
ptrdiff_t, unsigned long);
extern void request_point_update (struct frame *, unsigned long);
extern void textconv_barrier (struct frame *, unsigned long);
+extern void replace_text (struct frame *, ptrdiff_t, ptrdiff_t,
+ Lisp_Object, ptrdiff_t, unsigned long);
+
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
ptrdiff_t *, ptrdiff_t *, ptrdiff_t *,
ptrdiff_t *, bool *);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 123b77436e1: Introduce an input method callback required by Android 34,
Po Lu <=