[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android 889b61b9991: Update Android port
From: |
Po Lu |
Subject: |
feature/android 889b61b9991: Update Android port |
Date: |
Sat, 6 May 2023 23:10:46 -0400 (EDT) |
branch: feature/android
commit 889b61b99918d1c6313d4f884de2e2cb3ab466c9
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Update Android port
* java/org/gnu/emacs/EmacsInputConnection.java
(requestCursorUpdates):
* java/org/gnu/emacs/EmacsNative.java (requestCursorUpdates):
* java/org/gnu/emacs/EmacsService.java (updateCursorAnchorInfo):
New functions.
* src/android.c (struct android_emacs_service)
(android_init_emacs_service): Add new method.
(android_update_cursor_anchor_info): New function.
* src/androidfns.c (android_set_preeditarea): New function.
* src/androidgui.h (enum android_ime_operation): New operation
`REQUEST_CURSOR_UPDATES'.
(struct android_ime_event): Document new meaning of `length'.
* src/androidterm.c (android_request_cursor_updates): New
function.
(android_handle_ime_event): Handle new operations.
(handle_one_android_event, android_draw_window_cursor): Update
the preedit area if needed, like on X.
(requestCursorUpdates): New function.
* src/androidterm.h (struct android_output): New field
`need_cursor_updates'.
---
java/org/gnu/emacs/EmacsInputConnection.java | 11 ++++
java/org/gnu/emacs/EmacsNative.java | 1 +
java/org/gnu/emacs/EmacsService.java | 32 ++++++++++
src/android.c | 34 +++++++++++
src/androidfns.c | 28 +++++++++
src/androidgui.h | 15 ++++-
src/androidterm.c | 88 ++++++++++++++++++++++++++++
src/androidterm.h | 5 ++
8 files changed, 213 insertions(+), 1 deletion(-)
diff --git a/java/org/gnu/emacs/EmacsInputConnection.java
b/java/org/gnu/emacs/EmacsInputConnection.java
index d13b48288ce..21bbaca5d07 100644
--- a/java/org/gnu/emacs/EmacsInputConnection.java
+++ b/java/org/gnu/emacs/EmacsInputConnection.java
@@ -324,6 +324,17 @@ public final class EmacsInputConnection extends
BaseInputConnection
return this.deleteSurroundingText (beforeLength, afterLength);
}
+ @Override
+ public boolean
+ requestCursorUpdates (int cursorUpdateMode)
+ {
+ if (EmacsService.DEBUG_IC)
+ Log.d (TAG, "requestCursorUpdates: " + cursorUpdateMode);
+
+ EmacsNative.requestCursorUpdates (windowHandle, cursorUpdateMode);
+ return true;
+ }
+
/* Override functions which are not implemented. */
diff --git a/java/org/gnu/emacs/EmacsNative.java
b/java/org/gnu/emacs/EmacsNative.java
index 7d13ff99abb..e699dda9ad4 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -209,6 +209,7 @@ public final class EmacsNative
ExtractedTextRequest req,
int flags);
public static native void requestSelectionUpdate (short window);
+ public static native void requestCursorUpdates (short window, int mode);
/* 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 33436892caa..30ef71540a9 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -25,10 +25,12 @@ import java.io.UnsupportedEncodingException;
import java.util.List;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.view.InputDevice;
import android.view.KeyEvent;
+import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.ExtractedText;
import android.app.Notification;
@@ -635,6 +637,36 @@ public final class EmacsService extends Service
window.view.imManager.restartInput (window.view);
}
+ public void
+ updateCursorAnchorInfo (EmacsWindow window, float x,
+ float y, float yBaseline,
+ float yBottom)
+ {
+ CursorAnchorInfo info;
+ CursorAnchorInfo.Builder builder;
+ Matrix matrix;
+ int[] offsets;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
+ return;
+
+ offsets = new int[2];
+ builder = new CursorAnchorInfo.Builder ();
+ matrix = new Matrix (window.view.getMatrix ());
+ window.view.getLocationOnScreen (offsets);
+ matrix.postTranslate (offsets[0], offsets[1]);
+ builder.setMatrix (matrix);
+ builder.setInsertionMarkerLocation (x, y, yBaseline, yBottom,
+ 0);
+ info = builder.build ();
+
+ if (DEBUG_IC)
+ Log.d (TAG, ("updateCursorAnchorInfo: " + x + " " + y
+ + " " + yBaseline + "-" + yBottom));
+
+ window.view.imManager.updateCursorAnchorInfo (window.view, info);
+ }
+
/* Open a content URI described by the bytes BYTES, a non-terminated
string; make it writable if WRITABLE, and readable if READABLE.
Truncate the file if TRUNCATE.
diff --git a/src/android.c b/src/android.c
index 129ad6b5767..8a41a7cdec5 100644
--- a/src/android.c
+++ b/src/android.c
@@ -113,6 +113,7 @@ struct android_emacs_service
jmethodID query_battery;
jmethodID display_toast;
jmethodID update_extracted_text;
+ jmethodID update_cursor_anchor_info;
};
struct android_emacs_pixmap
@@ -2209,6 +2210,8 @@ android_init_emacs_service (void)
FIND_METHOD (update_extracted_text, "updateExtractedText",
"(Lorg/gnu/emacs/EmacsWindow;"
"Landroid/view/inputmethod/ExtractedText;I)V");
+ FIND_METHOD (update_cursor_anchor_info, "updateCursorAnchorInfo",
+ "(Lorg/gnu/emacs/EmacsWindow;FFFF)V");
#undef FIND_METHOD
}
@@ -6277,6 +6280,37 @@ android_update_extracted_text (android_window window,
void *text,
android_exception_check_1 (text);
}
+/* Report the position of the cursor to the input method connection on
+ WINDOW.
+
+ X is the horizontal position of the end of the insertion marker. Y
+ is the top of the insertion marker. Y_BASELINE is the baseline of
+ the row containing the insertion marker, and Y_BOTTOM is the bottom
+ of the insertion marker. */
+
+void
+android_update_cursor_anchor_info (android_window window, float x,
+ float y, float y_baseline,
+ float y_bottom)
+{
+ jobject object;
+ jmethodID method;
+
+ object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
+ method = service_class.update_cursor_anchor_info;
+
+ (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
+ emacs_service,
+ service_class.class,
+ method,
+ object,
+ (jfloat) x,
+ (jfloat) y,
+ (jfloat) y_baseline,
+ (jfloat) y_bottom);
+ android_exception_check ();
+}
+
/* Window decoration management functions. */
diff --git a/src/androidfns.c b/src/androidfns.c
index 3bd34edd5b9..60b0549e7d1 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -3000,6 +3000,34 @@ for more details about these values. */)
make_fixnum (state.temperature));
}
+
+
+/* Miscellaneous input method related stuff. */
+
+/* Report X, Y, by the phys cursor width and height as the cursor
+ anchor rectangle for W's frame. */
+
+void
+android_set_preeditarea (struct window *w, int x, int y)
+{
+ struct frame *f;
+
+ f = WINDOW_XFRAME (w);
+
+ /* Convert the window coordinates to the frame's coordinate
+ space. */
+ x = (WINDOW_TO_FRAME_PIXEL_X (w, x)
+ + WINDOW_LEFT_FRINGE_WIDTH (w)
+ + WINDOW_LEFT_MARGIN_WIDTH (w));
+ y = WINDOW_TO_FRAME_PIXEL_Y (w, y);
+
+ /* Note that calculating the baseline is too hard, so the bottom of
+ the cursor is used instead. */
+ android_update_cursor_anchor_info (FRAME_ANDROID_WINDOW (f), x,
+ y, y + w->phys_cursor_height,
+ y + w->phys_cursor_height);
+}
+
#endif
diff --git a/src/androidgui.h b/src/androidgui.h
index ddd8e9fcf72..6db25098398 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -432,6 +432,13 @@ enum android_ime_operation
ANDROID_IME_START_BATCH_EDIT,
ANDROID_IME_END_BATCH_EDIT,
ANDROID_IME_REQUEST_SELECTION_UPDATE,
+ ANDROID_IME_REQUEST_CURSOR_UPDATES,
+ };
+
+enum
+ {
+ ANDROID_CURSOR_UPDATE_IMMEDIATE = 1,
+ ANDROID_CURSOR_UPDATE_MONITOR = (1 << 1),
};
struct android_ime_event
@@ -452,7 +459,11 @@ struct android_ime_event
indices, and may actually mean ``left'' and ``right''. */
ptrdiff_t start, end, position;
- /* The number of characters in TEXT. */
+ /* The number of characters in TEXT.
+
+ If OPERATION is ANDROID_IME_REQUEST_CURSOR_UPDATES, then this is
+ actually the cursor update mode associated with that
+ operation. */
size_t length;
/* TEXT is either NULL, or a pointer to LENGTH bytes of malloced
@@ -620,6 +631,8 @@ extern void android_update_ic (android_window, ptrdiff_t,
ptrdiff_t,
extern void android_reset_ic (android_window, enum android_ic_mode);
extern void android_update_extracted_text (android_window, void *,
int);
+extern void android_update_cursor_anchor_info (android_window, float,
+ float, float, float);
extern int android_set_fullscreen (android_window, bool);
enum android_cursor_shape
diff --git a/src/androidterm.c b/src/androidterm.c
index 8ba7fb6a798..6f7c06875ca 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -632,6 +632,40 @@ android_decode_utf16 (unsigned short *utf16, size_t n)
return coding.dst_object;
}
+/* Handle a cursor update request for F from the input method.
+ MODE specifies whether or not an update should be sent immediately,
+ and whether or not they are needed in the future.
+
+ If MODE & ANDROID_CURSOR_UPDATE_IMMEDIATE, report the position of
+ F's old selected window's phys cursor now.
+
+ If MODE & ANDROID_CURSOR_UPDATE_MONITOR, set
+ `need_cursor_updates'. */
+
+static void
+android_request_cursor_updates (struct frame *f, int mode)
+{
+ struct window *w;
+
+ if (mode & ANDROID_CURSOR_UPDATE_IMMEDIATE
+ && WINDOWP (WINDOW_LIVE_P (f->old_selected_window)
+ ? f->old_selected_window
+ : f->selected_window))
+ {
+ /* Prefer the old selected window, as its selection is what was
+ reported to the IME previously. */
+
+ w = XWINDOW (WINDOW_LIVE_P (f->old_selected_window)
+ ? f->old_selected_window
+ : f->selected_window);
+ android_set_preeditarea (w, w->cursor.x, w->cursor.y);
+ }
+
+ /* Now say whether or not updates are needed in the future. */
+ FRAME_OUTPUT_DATA (f)->need_cursor_updates
+ = (mode & ANDROID_CURSOR_UPDATE_MONITOR);
+}
+
/* Handle a single input method event EVENT, delivered to the frame
F.
@@ -705,6 +739,10 @@ android_handle_ime_event (union android_event *event,
struct frame *f)
case ANDROID_IME_REQUEST_SELECTION_UPDATE:
request_point_update (f, event->ime.counter);
break;
+
+ case ANDROID_IME_REQUEST_CURSOR_UPDATES:
+ android_request_cursor_updates (f, event->ime.length);
+ break;
}
}
@@ -724,6 +762,7 @@ handle_one_android_event (struct android_display_info
*dpyinfo,
double scroll_unit;
int keysym;
ptrdiff_t nchars, i;
+ struct window *w;
/* It is okay for this to not resemble handle_one_xevent so much.
Differences in event handling code are much less nasty than
@@ -812,6 +851,12 @@ handle_one_android_event (struct android_display_info
*dpyinfo,
inev.ie.kind = MOVE_FRAME_EVENT;
XSETFRAME (inev.ie.frame_or_window, f);
}
+
+ if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates)
+ {
+ w = XWINDOW (f->selected_window);
+ android_set_preeditarea (w, w->cursor.x, w->cursor.y);
+ }
}
goto OTHER;
@@ -954,6 +999,16 @@ handle_one_android_event (struct android_display_info
*dpyinfo,
goto done_keysym;
done_keysym:
+
+ /* Now proceed to tell the input method the current position of
+ the cursor, if required. */
+
+ if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates)
+ {
+ w = XWINDOW (f->selected_window);
+ android_set_preeditarea (w, w->cursor.x, w->cursor.y);
+ }
+
goto OTHER;
case ANDROID_FOCUS_IN:
@@ -4321,6 +4376,10 @@ android_draw_window_cursor (struct window *w, struct
glyph_row *glyph_row,
int x, int y, enum text_cursor_kinds cursor_type,
int cursor_width, bool on_p, bool active_p)
{
+ struct frame *f;
+
+ f = WINDOW_XFRAME (w);
+
if (on_p)
{
w->phys_cursor_type = cursor_type;
@@ -4362,6 +4421,13 @@ android_draw_window_cursor (struct window *w, struct
glyph_row *glyph_row,
emacs_abort ();
}
}
+
+ /* Now proceed to tell the input method the current position of
+ the cursor, if required. */
+
+ if (FRAME_OUTPUT_DATA (f)->need_cursor_updates
+ && w == XWINDOW (f->selected_window))
+ android_set_preeditarea (w, x, y);
}
}
@@ -5404,6 +5470,28 @@ NATIVE_NAME (requestSelectionUpdate) (JNIEnv *env,
jobject object,
android_write_event (&event);
}
+JNIEXPORT void JNICALL
+NATIVE_NAME (requestCursorUpdates) (JNIEnv *env, jobject object,
+ jshort window, jint mode)
+{
+ JNI_STACK_ALIGNMENT_PROLOGUE;
+
+ union android_event event;
+
+ event.ime.type = ANDROID_INPUT_METHOD;
+ event.ime.serial = ++event_serial;
+ event.ime.window = window;
+ event.ime.operation = ANDROID_IME_REQUEST_CURSOR_UPDATES;
+ event.ime.start = 0;
+ event.ime.end = 0;
+ event.ime.length = mode;
+ event.ime.position = 0;
+ event.ime.text = NULL;
+ event.ime.counter = ++edit_counter;
+
+ android_write_event (&event);
+}
+
#ifdef __clang__
#pragma clang diagnostic pop
#else
diff --git a/src/androidterm.h b/src/androidterm.h
index 9396d5fe315..e3738fb2192 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -231,6 +231,10 @@ struct android_output
because the frame contents have been dirtied. */
bool_bf need_buffer_flip : 1;
+ /* Whether or not the input method should be notified every time the
+ position of this frame's selected window changes. */
+ bool_bf need_cursor_updates : 1;
+
/* Relief GCs, colors etc. */
struct relief {
struct android_gc *gc;
@@ -383,6 +387,7 @@ extern struct android_display_info *x_display_list;
extern void android_free_gcs (struct frame *);
extern void android_default_font_parameter (struct frame *, Lisp_Object);
+extern void android_set_preeditarea (struct window *, int, int);
/* Defined in androidterm.c. */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- feature/android 889b61b9991: Update Android port,
Po Lu <=