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:
parent
c0a52c6cef
commit
889b61b999
@ -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. */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user