1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-01 08:17:38 +00:00

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'.
This commit is contained in:
Po Lu 2023-05-07 11:09:56 +08:00
parent c0a52c6cef
commit 889b61b999
8 changed files with 213 additions and 1 deletions

View File

@ -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. */

View File

@ -209,6 +209,7 @@ public static native ExtractedText getExtractedText (short window,
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

View File

@ -25,10 +25,12 @@
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 @@ invocation of app_process (through android-emacs) can
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.

View File

@ -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. */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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. */