mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-20 18:17:20 +00:00
Update Android port
* java/org/gnu/emacs/EmacsInputConnection.java (EmacsInputConnection, beginBatchEdit, reset, endBatchEdit): Keep track of the number of batch edits and return an appropriate value. (takeSnapshot): Implement function. * java/org/gnu/emacs/EmacsNative.java (takeSnapshot): New function. * java/org/gnu/emacs/EmacsService.java (resetIC): Improve debugging output. * java/org/gnu/emacs/EmacsView.java (onCreateInputConnection): Call `reset' to clear the UI side batch edit count. * src/androidterm.c (struct android_get_surrounding_text_context): New fields `conversion_start' and `conversion_end'. (android_get_surrounding_text): Return the conversion region. (android_get_surrounding_text_internal, NATIVE_NAME): Factor out `getSurroundingText'. (takeSnapshot): New function.
This commit is contained in:
parent
ca120044ac
commit
363e293cc9
@ -50,6 +50,11 @@ public final class EmacsInputConnection implements InputConnection
|
||||
/* The handle ID associated with that view's window. */
|
||||
private short windowHandle;
|
||||
|
||||
/* Number of batch edits currently underway. Used to avoid
|
||||
synchronizing with the Emacs thread after each
|
||||
`endBatchEdit'. */
|
||||
private int batchEditCount;
|
||||
|
||||
/* Whether or not to synchronize and call `updateIC' with the
|
||||
selection position after committing text.
|
||||
|
||||
@ -110,6 +115,10 @@ public final class EmacsInputConnection implements InputConnection
|
||||
Log.d (TAG, "beginBatchEdit");
|
||||
|
||||
EmacsNative.beginBatchEdit (windowHandle);
|
||||
|
||||
/* Keep a record of the number of outstanding batch edits here as
|
||||
well. */
|
||||
batchEditCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -125,7 +134,14 @@ public final class EmacsInputConnection implements InputConnection
|
||||
Log.d (TAG, "endBatchEdit");
|
||||
|
||||
EmacsNative.endBatchEdit (windowHandle);
|
||||
return true;
|
||||
|
||||
/* Subtract one from the UI thread record of the number of batch
|
||||
edits currently under way. */
|
||||
|
||||
if (batchEditCount > 0)
|
||||
batchEditCount -= 1;
|
||||
|
||||
return batchEditCount > 0;
|
||||
}
|
||||
|
||||
public boolean
|
||||
@ -584,6 +600,42 @@ public final class EmacsInputConnection implements InputConnection
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextSnapshot
|
||||
takeSnapshot ()
|
||||
{
|
||||
TextSnapshot snapshot;
|
||||
|
||||
/* Return if the input connection is out of date. */
|
||||
if (view.icSerial < view.icGeneration)
|
||||
return null;
|
||||
|
||||
snapshot = EmacsNative.takeSnapshot (windowHandle);
|
||||
|
||||
if (EmacsService.DEBUG_IC)
|
||||
Log.d (TAG, ("takeSnapshot: "
|
||||
+ snapshot.getSurroundingText ().getText ()
|
||||
+ " @ " + snapshot.getCompositionEnd ()
|
||||
+ ", " + snapshot.getCompositionStart ()));
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
closeConnection ()
|
||||
{
|
||||
batchEditCount = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void
|
||||
reset ()
|
||||
{
|
||||
batchEditCount = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Override functions which are not implemented. */
|
||||
|
||||
@ -594,13 +646,6 @@ public final class EmacsInputConnection implements InputConnection
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
closeConnection ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean
|
||||
commitContent (InputContentInfo inputContentInfo, int flags,
|
||||
@ -616,13 +661,6 @@ public final class EmacsInputConnection implements InputConnection
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextSnapshot
|
||||
takeSnapshot ()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean
|
||||
clearMetaKeyStates (int states)
|
||||
|
@ -26,6 +26,7 @@
|
||||
import android.view.inputmethod.ExtractedText;
|
||||
import android.view.inputmethod.ExtractedTextRequest;
|
||||
import android.view.inputmethod.SurroundingText;
|
||||
import android.view.inputmethod.TextSnapshot;
|
||||
|
||||
public final class EmacsNative
|
||||
{
|
||||
@ -230,6 +231,7 @@ public static native ExtractedText getExtractedText (short window,
|
||||
public static native SurroundingText getSurroundingText (short window,
|
||||
int left, int right,
|
||||
int flags);
|
||||
public static native TextSnapshot takeSnapshot (short window);
|
||||
|
||||
|
||||
/* Return the current value of the selection, or -1 upon
|
||||
|
@ -767,8 +767,31 @@ invocation of app_process (through android-emacs) can
|
||||
public void
|
||||
resetIC (EmacsWindow window, int icMode)
|
||||
{
|
||||
int oldMode;
|
||||
|
||||
if (DEBUG_IC)
|
||||
Log.d (TAG, "resetIC: " + window);
|
||||
Log.d (TAG, "resetIC: " + window + ", " + icMode);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
|
||||
&& (oldMode = window.view.getICMode ()) == icMode
|
||||
/* Don't do this if there is currently no input
|
||||
connection. */
|
||||
&& oldMode != IC_MODE_NULL)
|
||||
{
|
||||
if (DEBUG_IC)
|
||||
Log.d (TAG, "resetIC: calling invalidateInput");
|
||||
|
||||
/* Android 33 and later allow the IM reset to be optimized out
|
||||
and replaced by a call to `invalidateInput', which is much
|
||||
faster, as it does not involve resetting the input
|
||||
connection. */
|
||||
|
||||
icBeginSynchronous ();
|
||||
window.view.imManager.invalidateInput (window.view);
|
||||
icEndSynchronous ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.view.setICMode (icMode);
|
||||
|
||||
|
@ -681,6 +681,9 @@ else if (child.getVisibility () != GONE)
|
||||
|
||||
if (inputConnection == null)
|
||||
inputConnection = new EmacsInputConnection (this);
|
||||
else
|
||||
/* Clear several pieces of state in the input connection. */
|
||||
inputConnection.reset ();
|
||||
|
||||
/* Return the input connection. */
|
||||
return inputConnection;
|
||||
|
@ -5668,6 +5668,10 @@ struct android_get_surrounding_text_context
|
||||
/* Offsets into that text. */
|
||||
ptrdiff_t offset, start, end;
|
||||
|
||||
/* The start and end indices of the conversion region.
|
||||
-1 if it does not exist. */
|
||||
ptrdiff_t conversion_start, conversion_end;
|
||||
|
||||
/* The window. */
|
||||
android_window window;
|
||||
};
|
||||
@ -5706,22 +5710,47 @@ android_get_surrounding_text (void *data)
|
||||
request->start = request->end;
|
||||
request->end = temp;
|
||||
}
|
||||
|
||||
/* Retrieve the conversion region. */
|
||||
|
||||
request->conversion_start = -1;
|
||||
request->conversion_end = -1;
|
||||
|
||||
if (MARKERP (f->conversion.compose_region_start))
|
||||
{
|
||||
request->conversion_start
|
||||
= marker_position (f->conversion.compose_region_start) - 1;
|
||||
request->conversion_end
|
||||
= marker_position (f->conversion.compose_region_end) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
NATIVE_NAME (getSurroundingText) (JNIEnv *env, jobject ignored_object,
|
||||
jshort window, jint before_length,
|
||||
jint after_length, jint flags)
|
||||
/* Return a local reference to a `SurroundingText' object describing
|
||||
WINDOW's surrounding text. ENV should be a valid JNI environment
|
||||
for the current thread.
|
||||
|
||||
BEFORE_LENGTH and AFTER_LENGTH specify the number of characters
|
||||
around point and mark to return.
|
||||
|
||||
Return the conversion region (or -1) in *CONVERSION_START and
|
||||
*CONVERSION_END if non-NULL.
|
||||
|
||||
Value is the object upon success, else NULL. */
|
||||
|
||||
static jobject
|
||||
android_get_surrounding_text_internal (JNIEnv *env, jshort window,
|
||||
jint before_length,
|
||||
jint after_length,
|
||||
ptrdiff_t *conversion_start,
|
||||
ptrdiff_t *conversion_end)
|
||||
{
|
||||
JNI_STACK_ALIGNMENT_PROLOGUE;
|
||||
|
||||
static jclass class;
|
||||
static jmethodID constructor;
|
||||
|
||||
struct android_get_surrounding_text_context context;
|
||||
jstring string;
|
||||
jobject object;
|
||||
|
||||
static jclass class;
|
||||
static jmethodID constructor;
|
||||
|
||||
/* Initialize CLASS if it has not yet been initialized. */
|
||||
|
||||
if (!class)
|
||||
@ -5745,7 +5774,9 @@ NATIVE_NAME (getSurroundingText) (JNIEnv *env, jobject ignored_object,
|
||||
|
||||
class = (*env)->NewGlobalRef (env, class);
|
||||
if (!class)
|
||||
return NULL;
|
||||
/* Clear class to prevent a local reference from remaining in
|
||||
`class'. */
|
||||
return (class = NULL);
|
||||
|
||||
/* Now look for its constructor. */
|
||||
constructor = (*env)->GetMethodID (env, class, "<init>",
|
||||
@ -5787,6 +5818,86 @@ NATIVE_NAME (getSurroundingText) (JNIEnv *env, jobject ignored_object,
|
||||
if (!object)
|
||||
return NULL;
|
||||
|
||||
/* Now return the conversion region if that was requested. */
|
||||
|
||||
if (conversion_start)
|
||||
{
|
||||
*conversion_start = context.conversion_start;
|
||||
*conversion_end = context.conversion_start;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
NATIVE_NAME (getSurroundingText) (JNIEnv *env, jobject object,
|
||||
jshort window, jint before_length,
|
||||
jint after_length, jint flags)
|
||||
{
|
||||
JNI_STACK_ALIGNMENT_PROLOGUE;
|
||||
|
||||
return android_get_surrounding_text_internal (env, window, before_length,
|
||||
after_length, NULL, NULL);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
NATIVE_NAME (takeSnapshot) (JNIEnv *env, jobject object, jshort window)
|
||||
{
|
||||
JNI_STACK_ALIGNMENT_PROLOGUE;
|
||||
|
||||
jobject text;
|
||||
ptrdiff_t start, end;
|
||||
|
||||
static jclass class;
|
||||
static jmethodID constructor;
|
||||
|
||||
/* First, obtain the surrounding text and conversion region. */
|
||||
text = android_get_surrounding_text_internal (env, window, 600, 600,
|
||||
&start, &end);
|
||||
|
||||
/* If that fails, return NULL. */
|
||||
|
||||
if (!text)
|
||||
return NULL;
|
||||
|
||||
/* Next, initialize the TextSnapshot class. */
|
||||
|
||||
if (!class)
|
||||
{
|
||||
class
|
||||
= (*env)->FindClass (env, ("android/view/inputmethod"
|
||||
"/TextSnapshot"));
|
||||
#if __ANDROID_API__ < 33
|
||||
/* If CLASS cannot be found, the version of Android currently
|
||||
running is too old. */
|
||||
|
||||
if (!class)
|
||||
{
|
||||
(*env)->ExceptionClear (env);
|
||||
return NULL;
|
||||
}
|
||||
#else /* __ANDROID_API__ >= 33 */
|
||||
assert (class);
|
||||
#endif /* __ANDROID_API__ < 33 */
|
||||
|
||||
class = (*env)->NewGlobalRef (env, class);
|
||||
if (!class)
|
||||
/* Clear class to prevent a local reference from remaining in
|
||||
`class'. */
|
||||
return (class = NULL);
|
||||
|
||||
constructor = (*env)->GetMethodID (env, class, "<init>",
|
||||
"(Landroid/view/inputmethod"
|
||||
"/SurroundingText;III)V");
|
||||
assert (constructor);
|
||||
}
|
||||
|
||||
/* Try to create a TextSnapshot object. */
|
||||
eassert (start <= end);
|
||||
object = (*env)->NewObject (env, class, constructor, text,
|
||||
(jint) min (start, TYPE_MAXIMUM (jint)),
|
||||
(jint) min (end, TYPE_MAXIMUM (jint)),
|
||||
(jint) 0);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user