Update Android port

* java/org/gnu/emacs/EmacsInputConnection.java
(EmacsInputConnection): Apply workarounds on Vivo devices as
well.
* src/android.c (sendKeyPress, sendKeyRelease): Clear counter.
* src/androidgui.h (struct android_key_event): New field
`counter'.
* src/androidterm.c (handle_one_android_event): Generate
barriers as appropriate.
(JNICALL): Set `counter'.
* src/frame.h (enum text_conversion_operation):
* src/textconv.c (detect_conversion_events)
(really_set_composing_text, handle_pending_conversion_events_1)
(handle_pending_conversion_events, textconv_barrier):
* src/textconv.h: Implement text conversion barriers and fix
various typos.
This commit is contained in:
Po Lu 2023-06-02 13:31:40 +08:00
parent c3c2289b29
commit 189a91bfb6
7 changed files with 79 additions and 12 deletions

View file

@ -66,11 +66,12 @@ public final class EmacsInputConnection extends BaseInputConnection
|| Build.MANUFACTURER.equalsIgnoreCase ("Honor"))
extractAbsoluteOffsets = syncAfterCommit = true;
/* The Samsung keyboard takes `selectionStart' at face value if
some text is returned, and also searches for words solely
within that text. However, when no text is returned, it falls
back to getTextAfterCursor and getTextBeforeCursor. */
if (Build.MANUFACTURER.equalsIgnoreCase ("Samsung"))
/* The Samsung and Vivo keyboards take `selectionStart' at face
value if some text is returned, and also searches for words
solely within that text. However, when no text is returned, it
falls back to getTextAfterCursor and getTextBeforeCursor. */
if (Build.MANUFACTURER.equalsIgnoreCase ("Samsung")
|| Build.MANUFACTURER.equalsIgnoreCase ("Vivo"))
extractAbsoluteOffsets = true;
};

View file

@ -2543,6 +2543,7 @@ NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object,
event.xkey.state = state;
event.xkey.keycode = keycode;
event.xkey.unicode_char = unicode_char;
event.xkey.counter = 0;
android_write_event (&event);
return event_serial;
@ -2565,6 +2566,7 @@ NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object,
event.xkey.state = state;
event.xkey.keycode = keycode;
event.xkey.unicode_char = unicode_char;
event.xkey.counter = 0;
android_write_event (&event);
return event_serial;

View file

@ -277,6 +277,10 @@ struct android_key_event
/* If this field is -1, then android_lookup_string should be called
to retrieve the associated individual characters. */
unsigned int unicode_char;
/* If this field is non-zero, a text conversion barrier should be
generated with its value as the counter. */
unsigned long counter;
};
typedef struct android_key_event android_key_pressed_event;

View file

@ -885,6 +885,11 @@ handle_one_android_event (struct android_display_info *dpyinfo,
if (!f)
goto OTHER;
if (event->xkey.counter)
/* This event was generated by `performEditorAction'. Make
sure it is processed before any subsequent edits. */
textconv_barrier (f, event->xkey.counter);
wchar_t copy_buffer[129];
wchar_t *copy_bufptr = copy_buffer;
int copy_bufsiz = 128 * sizeof (wchar_t);
@ -5178,7 +5183,10 @@ NATIVE_NAME (performEditorAction) (JNIEnv *env, jobject object,
android_write_event (&event);
/* Finally, send the return key press. */
/* Finally, send the return key press. `counter' is set; this means
that a text conversion barrier will be generated once the event
is read, which will cause subsequent edits to wait until the
edits associated with this key press complete. */
event.xkey.type = ANDROID_KEY_PRESS;
event.xkey.serial = ++event_serial;
@ -5187,6 +5195,7 @@ NATIVE_NAME (performEditorAction) (JNIEnv *env, jobject object,
event.xkey.state = 0;
event.xkey.keycode = 66;
event.xkey.unicode_char = 0;
event.xkey.counter = ++edit_counter;
android_write_event (&event);
}
@ -5234,6 +5243,7 @@ NATIVE_NAME (performContextMenuAction) (JNIEnv *env, jobject object,
event.xkey.state = 0;
event.xkey.keycode = 66;
event.xkey.unicode_char = 0;
event.xkey.counter = ++edit_counter;
android_write_event (&event);
}

View file

@ -89,6 +89,7 @@ enum text_conversion_operation
TEXTCONV_SET_POINT_AND_MARK,
TEXTCONV_DELETE_SURROUNDING_TEXT,
TEXTCONV_REQUEST_POINT_UPDATE,
TEXTCONV_BARRIER,
};
/* Structure describing a single edit being performed by the input

View file

@ -36,6 +36,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "buffer.h"
#include "syntax.h"
#include "blockinput.h"
#include "keyboard.h"
@ -522,7 +523,11 @@ detect_conversion_events (void)
FOR_EACH_FRAME (tail, frame)
{
if (XFRAME (frame)->conversion.actions)
/* See if there's a pending edit on this frame. */
if (XFRAME (frame)->conversion.actions
&& ((XFRAME (frame)->conversion.actions->operation
!= TEXTCONV_BARRIER)
|| (kbd_fetch_ptr == kbd_store_ptr)))
return true;
}
@ -740,7 +745,7 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
Fset_marker_insertion_type (f->conversion.compose_region_end,
Qt);
start = position;
start = PT;
}
else
{
@ -762,7 +767,7 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
record_buffer_change (start, PT, Qnil);
/* Now move point to an appropriate location. */
if (position < 0)
if (position <= 0)
{
wanted = start;
@ -1198,6 +1203,19 @@ handle_pending_conversion_events_1 (struct frame *f,
case TEXTCONV_REQUEST_POINT_UPDATE:
really_request_point_update (f);
break;
case TEXTCONV_BARRIER:
if (kbd_fetch_ptr != kbd_store_ptr)
emacs_abort ();
/* Once a barrier is hit, synchronize F's selected window's
`ephemeral_last_point' with its current point. The reason
for this is because otherwise a previous keyboard event may
have taken place without redisplay happening in between. */
if (w)
w->ephemeral_last_point = window_point (w);
break;
}
/* Signal success. */
@ -1231,7 +1249,7 @@ handle_pending_conversion_events (void)
static int inside;
specpdl_ref count;
ptrdiff_t last_point;
struct window *w;
struct window *w, *w1;
handled = false;
@ -1242,8 +1260,6 @@ handle_pending_conversion_events (void)
Vtext_conversion_edits = Qnil;
inside++;
last_point = -1;
w = NULL;
count = SPECPDL_INDEX ();
record_unwind_protect_ptr (decrement_inside, &inside);
@ -1251,6 +1267,8 @@ handle_pending_conversion_events (void)
FOR_EACH_FRAME (tail, frame)
{
f = XFRAME (frame);
last_point = -1;
w = NULL;
/* Test if F has any outstanding conversion events. Then
process them in bottom to up order. */
@ -1283,6 +1301,13 @@ handle_pending_conversion_events (void)
if (!action)
break;
/* If action is a barrier event and the keyboard buffer is
not yet empty, break out of the loop. */
if (action->operation == TEXTCONV_BARRIER
&& kbd_store_ptr != kbd_fetch_ptr)
break;
/* Unlink this action. */
next = action->next;
f->conversion.actions = next;
@ -1515,6 +1540,29 @@ request_point_update (struct frame *f, unsigned long counter)
input_pending = true;
}
/* Request that text conversion on F pause until the keyboard buffer
becomes empty.
Use this function to ensure that edits associated with a keyboard
event complete before the text conversion edits after the barrier
take place. */
void
textconv_barrier (struct frame *f, unsigned long counter)
{
struct text_conversion_action *action, **last;
action = xmalloc (sizeof *action);
action->operation = TEXTCONV_BARRIER;
action->data = Qnil;
action->next = NULL;
action->counter = counter;
for (last = &f->conversion.actions; *last; last = &(*last)->next)
;;
*last = action;
input_pending = true;
}
/* Return N characters of text around point in F's old selected
window.

View file

@ -139,6 +139,7 @@ extern void textconv_set_point_and_mark (struct frame *, ptrdiff_t,
extern void delete_surrounding_text (struct frame *, ptrdiff_t,
ptrdiff_t, unsigned long);
extern void request_point_update (struct frame *, unsigned long);
extern void textconv_barrier (struct frame *, unsigned long);
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
ptrdiff_t *, ptrdiff_t *, ptrdiff_t *,
ptrdiff_t *);