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;
+ }
+
\f
/* Override functions which are not implemented. */
ExtractedTextRequest req,
int flags);
public static native void requestSelectionUpdate (short window);
+ public static native void requestCursorUpdates (short window, int mode);
\f
/* Return the current value of the selection, or -1 upon
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;
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.
jmethodID query_battery;
jmethodID display_toast;
jmethodID update_extracted_text;
+ jmethodID update_cursor_anchor_info;
};
struct android_emacs_pixmap
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
}
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 ();
+}
+
\f
/* Window decoration management functions. */
make_fixnum (state.temperature));
}
+\f
+
+/* 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
\f
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
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
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
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.
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;
}
}
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
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;
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:
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;
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);
}
}
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
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;
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. */