summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2023-02-15 12:23:03 +0800
committerPo Lu <luangruo@yahoo.com>2023-02-15 12:23:03 +0800
commita158c1d5b964fda36f752998cef076d581dc4df4 (patch)
treeb9c7a22a7259dbd876be0e047304a338ef05e334 /java
parent5a7855e84abd56e55b456aef4a43ae7623e76899 (diff)
Update Android port
* configure.ac (HAVE_TEXT_CONVERSION): Define on Android. * doc/emacs/input.texi (On-Screen Keyboards): Document ``text conversion'' slightly. * doc/lispref/commands.texi (Misc Events): Document new `text-conversion' event. * java/org/gnu/emacs/EmacsContextMenu.java (display): Use `syncRunnable'. * java/org/gnu/emacs/EmacsDialog.java (display): Likewise. * java/org/gnu/emacs/EmacsEditable.java: Delete file. * java/org/gnu/emacs/EmacsInputConnection.java (EmacsInputConnection): Reimplement from scratch. * java/org/gnu/emacs/EmacsNative.java (EmacsNative): Add new functions. * java/org/gnu/emacs/EmacsService.java (EmacsService, getEmacsView) (getLocationOnScreen, sync, getClipboardManager, restartEmacs): Use syncRunnable. (syncRunnable): New function. (updateIC, resetIC): New functions. * java/org/gnu/emacs/EmacsView.java (EmacsView): New field `inputConnection' and `icMode'. (onCreateInputConnection): Update accordingly. (setICMode, getICMode): New functions. * lisp/bindings.el (global-map): Ignore text conversion events. * src/alloc.c (mark_frame): Mark text conversion data. * src/android.c (struct android_emacs_service): New fields `update_ic' and `reset_ic'. (event_serial): Export. (android_query_sem): New function. (android_init_events): Initialize new semaphore. (android_write_event): Export. (android_select): Check for UI thread code. (setEmacsParams, android_init_emacs_service): Initialize new methods. (android_check_query, android_begin_query, android_end_query) (android_run_in_emacs_thread): (android_update_ic, android_reset_ic): New functions for managing synchronous queries from one thread to another. * src/android.h: Export new functions. * src/androidgui.h (enum android_event_type): Add input method events. (enum android_ime_operation, struct android_ime_event) (union android_event, enum android_ic_mode): New structs and enums. * src/androidterm.c (android_window_to_frame): Allow DPYINFO to be NULL. (android_decode_utf16, android_handle_ime_event) (handle_one_android_event, android_sync_edit) (android_copy_java_string, beginBatchEdit, endBatchEdit) (commitCompletion, deleteSurroundingText, finishComposingText) (getSelectedtext, getTextAfterCursor, getTextBeforeCursor) (setComposingText, setComposingRegion, setSelection, getSelection) (performEditorAction, getExtractedText): New functions. (struct android_conversion_query_context): (android_perform_conversion_query): (android_text_to_string): (struct android_get_selection_context): (android_get_selection): (struct android_get_extracted_text_context): (android_get_extracted_text): (struct android_extracted_text_request_class): (struct android_extracted_text_class): (android_update_selection): (android_reset_conversion): (android_set_point): (android_compose_region_changed): (android_notify_conversion): (text_conversion_interface): New functions and structures. (android_term_init): Initialize text conversion. * src/coding.c (syms_of_coding): Define Qutf_16le on Android. * src/frame.c (make_frame): Clear conversion data. (delete_frame): Reset conversion state. * src/frame.h (enum text_conversion_operation) (struct text_conversion_action, struct text_conversion_state) (GCALIGNED_STRUCT): Update structures. * src/keyboard.c (read_char, readable_events, kbd_buffer_get_event) (syms_of_keyboard): Handle text conversion events. * src/lisp.h: * src/process.c: Fix includes. * src/textconv.c (enum textconv_batch_edit_flags, textconv_query) (reset_frame_state, detect_conversion_events) (restore_selected_window, really_commit_text) (really_finish_composing_text, really_set_composing_text) (really_set_composing_region, really_delete_surrounding_text) (really_set_point, complete_edit) (handle_pending_conversion_events_1) (handle_pending_conversion_events, start_batch_edit) (end_batch_edit, commit_text, finish_composing_text) (set_composing_text, set_composing_region, textconv_set_point) (delete_surrounding_text, get_extracted_text) (report_selected_window_change, report_point_change) (register_texconv_interface): New functions. * src/textconv.h (struct textconv_interface) (TEXTCONV_SKIP_CONVERSION_REGION): Update prototype. * src/xdisp.c (mark_window_display_accurate_1): * src/xfns.c (xic_string_conversion_callback): * src/xterm.c (init_xterm): Adjust accordingly.
Diffstat (limited to 'java')
-rw-r--r--java/org/gnu/emacs/EmacsContextMenu.java15
-rw-r--r--java/org/gnu/emacs/EmacsDialog.java15
-rw-r--r--java/org/gnu/emacs/EmacsEditable.java300
-rw-r--r--java/org/gnu/emacs/EmacsInputConnection.java181
-rw-r--r--java/org/gnu/emacs/EmacsNative.java46
-rw-r--r--java/org/gnu/emacs/EmacsService.java117
-rw-r--r--java/org/gnu/emacs/EmacsView.java55
7 files changed, 264 insertions, 465 deletions
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java
index 92429410d03..184c611bf9d 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -279,20 +279,7 @@ public class EmacsContextMenu
}
};
- synchronized (runnable)
- {
- EmacsService.SERVICE.runOnUiThread (runnable);
-
- try
- {
- runnable.wait ();
- }
- catch (InterruptedException e)
- {
- EmacsNative.emacsAbort ();
- }
- }
-
+ EmacsService.syncRunnable (runnable);
return rc.thing;
}
diff --git a/java/org/gnu/emacs/EmacsDialog.java b/java/org/gnu/emacs/EmacsDialog.java
index bd5e9ba8ee7..bc0333e99b9 100644
--- a/java/org/gnu/emacs/EmacsDialog.java
+++ b/java/org/gnu/emacs/EmacsDialog.java
@@ -317,20 +317,7 @@ public class EmacsDialog implements DialogInterface.OnDismissListener
}
};
- synchronized (runnable)
- {
- EmacsService.SERVICE.runOnUiThread (runnable);
-
- try
- {
- runnable.wait ();
- }
- catch (InterruptedException e)
- {
- EmacsNative.emacsAbort ();
- }
- }
-
+ EmacsService.syncRunnable (runnable);
return rc.thing;
}
diff --git a/java/org/gnu/emacs/EmacsEditable.java b/java/org/gnu/emacs/EmacsEditable.java
deleted file mode 100644
index 79af65a6ccd..00000000000
--- a/java/org/gnu/emacs/EmacsEditable.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
-
-Copyright (C) 2023 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-package org.gnu.emacs;
-
-import android.text.InputFilter;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.SpanWatcher;
-import android.text.Selection;
-
-import android.content.Context;
-
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-
-import android.text.Spannable;
-
-import android.util.Log;
-
-import android.os.Build;
-
-/* Android input methods insist on having access to buffer contents.
- Since Emacs is not designed like ``any other Android text editor'',
- that is not possible.
-
- This file provides a fake editing buffer that is designed to weasel
- as much information as possible out of an input method, without
- actually providing buffer contents to Emacs.
-
- The basic idea is to have the fake editing buffer be initially
- empty.
-
- When the input method inserts composed text, it sets a flag.
- Updates to the buffer while the flag is set are sent to Emacs to be
- displayed as ``preedit text''.
-
- Once some heuristics decide that composition has been completed,
- the composed text is sent to Emacs, and the text that was inserted
- in this editing buffer is erased. */
-
-public class EmacsEditable extends SpannableStringBuilder
- implements SpanWatcher
-{
- private static final String TAG = "EmacsEditable";
-
- /* Whether or not composition is currently in progress. */
- private boolean isComposing;
-
- /* The associated input connection. */
- private EmacsInputConnection connection;
-
- /* The associated IM manager. */
- private InputMethodManager imManager;
-
- /* Any extracted text an input method may be monitoring. */
- private ExtractedText extractedText;
-
- /* The corresponding text request. */
- private ExtractedTextRequest extractRequest;
-
- /* The number of nested batch edits. */
- private int batchEditCount;
-
- /* Whether or not invalidateInput should be called upon batch edits
- ending. */
- private boolean pendingInvalidate;
-
- /* The ``composing span'' indicating the bounds of an ongoing
- character composition. */
- private Object composingSpan;
-
- public
- EmacsEditable (EmacsInputConnection connection)
- {
- /* Initialize the editable with one initial space, so backspace
- always works. */
- super ();
-
- Object tem;
- Context context;
-
- this.connection = connection;
-
- context = connection.view.getContext ();
- tem = context.getSystemService (Context.INPUT_METHOD_SERVICE);
- imManager = (InputMethodManager) tem;
-
- /* To watch for changes to text properties on Android, you
- add... a text property. */
- setSpan (this, 0, 0, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- public void
- endBatchEdit ()
- {
- if (batchEditCount < 1)
- return;
-
- if (--batchEditCount == 0 && pendingInvalidate)
- invalidateInput ();
- }
-
- public void
- beginBatchEdit ()
- {
- ++batchEditCount;
- }
-
- public void
- setExtractedTextAndRequest (ExtractedText text,
- ExtractedTextRequest request,
- boolean monitor)
- {
- /* Extract the text. If monitor is set, also record it as the
- text that is currently being extracted. */
-
- text.startOffset = 0;
- text.selectionStart = Selection.getSelectionStart (this);
- text.selectionEnd = Selection.getSelectionStart (this);
- text.text = this;
-
- if (monitor)
- {
- extractedText = text;
- extractRequest = request;
- }
- }
-
- public void
- compositionStart ()
- {
- isComposing = true;
- }
-
- public void
- compositionEnd ()
- {
- isComposing = false;
- sendComposingText (null);
- }
-
- private void
- sendComposingText (String string)
- {
- EmacsWindow window;
- long time, serial;
-
- window = connection.view.window;
-
- if (window.isDestroyed ())
- return;
-
- time = System.currentTimeMillis ();
-
- /* A composition event is simply a special key event with a
- keycode of -1. */
-
- synchronized (window.eventStrings)
- {
- serial
- = EmacsNative.sendKeyPress (window.handle, time, 0, -1, -1);
-
- /* Save the string so that android_lookup_string can find
- it. */
- if (string != null)
- window.saveUnicodeString ((int) serial, string);
- }
- }
-
- private void
- invalidateInput ()
- {
- int start, end, composingSpanStart, composingSpanEnd;
-
- if (batchEditCount > 0)
- {
- Log.d (TAG, "invalidateInput: deferring for batch edit");
- pendingInvalidate = true;
- return;
- }
-
- pendingInvalidate = false;
-
- start = Selection.getSelectionStart (this);
- end = Selection.getSelectionEnd (this);
-
- if (composingSpan != null)
- {
- composingSpanStart = getSpanStart (composingSpan);
- composingSpanEnd = getSpanEnd (composingSpan);
- }
- else
- {
- composingSpanStart = -1;
- composingSpanEnd = -1;
- }
-
- Log.d (TAG, "invalidateInput: now " + start + ", " + end);
-
- /* Tell the input method that the cursor changed. */
- imManager.updateSelection (connection.view, start, end,
- composingSpanStart,
- composingSpanEnd);
-
- /* If there is any extracted text, tell the IME that it has
- changed. */
- if (extractedText != null)
- imManager.updateExtractedText (connection.view,
- extractRequest.token,
- extractedText);
- }
-
- public SpannableStringBuilder
- replace (int start, int end, CharSequence tb, int tbstart,
- int tbend)
- {
- super.replace (start, end, tb, tbstart, tbend);
-
- /* If a change happens during composition, perform the change and
- then send the text being composed. */
-
- if (isComposing)
- sendComposingText (toString ());
-
- return this;
- }
-
- private boolean
- isSelectionSpan (Object span)
- {
- return ((Selection.SELECTION_START == span
- || Selection.SELECTION_END == span)
- && (getSpanFlags (span)
- & Spanned.SPAN_INTERMEDIATE) == 0);
- }
-
- @Override
- public void
- onSpanAdded (Spannable text, Object what, int start, int end)
- {
- Log.d (TAG, "onSpanAdded: " + text + " " + what + " "
- + start + " " + end);
-
- /* Try to find the composing span. This isn't a public API. */
-
- if (what.getClass ().getName ().contains ("ComposingText"))
- composingSpan = what;
-
- if (isSelectionSpan (what))
- invalidateInput ();
- }
-
- @Override
- public void
- onSpanChanged (Spannable text, Object what, int ostart,
- int oend, int nstart, int nend)
- {
- Log.d (TAG, "onSpanChanged: " + text + " " + what + " "
- + nstart + " " + nend);
-
- if (isSelectionSpan (what))
- invalidateInput ();
- }
-
- @Override
- public void
- onSpanRemoved (Spannable text, Object what,
- int start, int end)
- {
- Log.d (TAG, "onSpanRemoved: " + text + " " + what + " "
- + start + " " + end);
-
- if (isSelectionSpan (what))
- invalidateInput ();
- }
-
- public boolean
- isInBatchEdit ()
- {
- return batchEditCount > 0;
- }
-}
diff --git a/java/org/gnu/emacs/EmacsInputConnection.java b/java/org/gnu/emacs/EmacsInputConnection.java
index 897a393b984..3cf4419838b 100644
--- a/java/org/gnu/emacs/EmacsInputConnection.java
+++ b/java/org/gnu/emacs/EmacsInputConnection.java
@@ -25,6 +25,7 @@ import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.SurroundingText;
+import android.view.inputmethod.TextSnapshot;
import android.view.KeyEvent;
import android.text.Editable;
@@ -38,138 +39,156 @@ import android.util.Log;
public class EmacsInputConnection extends BaseInputConnection
{
private static final String TAG = "EmacsInputConnection";
- public EmacsView view;
- private EmacsEditable editable;
-
- /* The length of the last string to be committed. */
- private int lastCommitLength;
-
- int currentLargeOffset;
+ private EmacsView view;
+ private short windowHandle;
public
EmacsInputConnection (EmacsView view)
{
- super (view, false);
+ super (view, true);
+
this.view = view;
- this.editable = new EmacsEditable (this);
+ this.windowHandle = view.window.handle;
}
@Override
- public Editable
- getEditable ()
+ public boolean
+ beginBatchEdit ()
{
- return editable;
+ Log.d (TAG, "beginBatchEdit");
+ EmacsNative.beginBatchEdit (windowHandle);
+ return true;
}
@Override
public boolean
- setComposingText (CharSequence text, int newCursorPosition)
+ endBatchEdit ()
{
- editable.compositionStart ();
- super.setComposingText (text, newCursorPosition);
+ Log.d (TAG, "endBatchEdit");
+ EmacsNative.endBatchEdit (windowHandle);
return true;
}
@Override
public boolean
- setComposingRegion (int start, int end)
+ commitCompletion (CompletionInfo info)
{
- int i;
-
- if (lastCommitLength != 0)
- {
- Log.d (TAG, "Restarting composition for: " + lastCommitLength);
-
- for (i = 0; i < lastCommitLength; ++i)
- sendKeyEvent (new KeyEvent (KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_DEL));
+ Log.d (TAG, "commitCompletion: " + info);
+ EmacsNative.commitCompletion (windowHandle,
+ info.getText ().toString (),
+ info.getPosition ());
+ return true;
+ }
- lastCommitLength = 0;
- }
+ @Override
+ public boolean
+ commitText (CharSequence text, int newCursorPosition)
+ {
+ Log.d (TAG, "commitText: " + text + " " + newCursorPosition);
+ EmacsNative.commitText (windowHandle, text.toString (),
+ newCursorPosition);
+ return true;
+ }
- editable.compositionStart ();
- super.setComposingRegion (start, end);
+ @Override
+ public boolean
+ deleteSurroundingText (int leftLength, int rightLength)
+ {
+ Log.d (TAG, ("deleteSurroundingText: "
+ + leftLength + " " + rightLength));
+ EmacsNative.deleteSurroundingText (windowHandle, leftLength,
+ rightLength);
return true;
}
-
+
@Override
public boolean
finishComposingText ()
{
- editable.compositionEnd ();
- return super.finishComposingText ();
+ Log.d (TAG, "finishComposingText");
+
+ EmacsNative.finishComposingText (windowHandle);
+ return true;
}
@Override
- public boolean
- beginBatchEdit ()
+ public String
+ getSelectedText (int flags)
{
- editable.beginBatchEdit ();
- return super.beginBatchEdit ();
+ Log.d (TAG, "getSelectedText: " + flags);
+
+ return EmacsNative.getSelectedText (windowHandle, flags);
}
@Override
- public boolean
- endBatchEdit ()
+ public String
+ getTextAfterCursor (int length, int flags)
{
- editable.endBatchEdit ();
- return super.endBatchEdit ();
+ Log.d (TAG, "getTextAfterCursor: " + length + " " + flags);
+
+ return EmacsNative.getTextAfterCursor (windowHandle, length,
+ flags);
}
-
+
@Override
- public boolean
- commitText (CharSequence text, int newCursorPosition)
+ public String
+ getTextBeforeCursor (int length, int flags)
{
- editable.compositionEnd ();
- super.commitText (text, newCursorPosition);
+ Log.d (TAG, "getTextBeforeCursor: " + length + " " + flags);
- /* An observation is that input methods rarely recompose trailing
- spaces. Avoid re-setting the commit length in that case. */
+ return EmacsNative.getTextBeforeCursor (windowHandle, length,
+ flags);
+ }
- if (text.toString ().equals (" "))
- lastCommitLength += 1;
- else
- /* At this point, the editable is now empty.
-
- The input method may try to cancel the edit upon a subsequent
- backspace by calling setComposingRegion with a region that is
- the length of TEXT.
-
- Record this length in order to be able to send backspace
- events to ``delete'' the text in that case. */
- lastCommitLength = text.length ();
+ @Override
+ public boolean
+ setComposingText (CharSequence text, int newCursorPosition)
+ {
+ Log.d (TAG, "setComposingText: " + newCursorPosition);
- Log.d (TAG, "commitText: \"" + text + "\"");
+ EmacsNative.setComposingText (windowHandle, text.toString (),
+ newCursorPosition);
+ return true;
+ }
+ @Override
+ public boolean
+ setComposingRegion (int start, int end)
+ {
+ Log.d (TAG, "setComposingRegion: " + start + " " + end);
+
+ EmacsNative.setComposingRegion (windowHandle, start, end);
return true;
}
- /* Return a large offset, cycling through 100000, 30000, 0.
- The offset is typically used to force the input method to update
- its notion of ``surrounding text'', bypassing any caching that
- it might have in progress.
+ @Override
+ public boolean
+ performEditorAction (int editorAction)
+ {
+ Log.d (TAG, "performEditorAction: " + editorAction);
- There must be another way to do this, but I can't find it. */
+ EmacsNative.performEditorAction (windowHandle, editorAction);
+ return true;
+ }
- public int
- largeSelectionOffset ()
+ @Override
+ public ExtractedText
+ getExtractedText (ExtractedTextRequest request, int flags)
{
- switch (currentLargeOffset)
- {
- case 0:
- currentLargeOffset = 100000;
- return 100000;
+ Log.d (TAG, "getExtractedText: " + request + " " + flags);
- case 100000:
- currentLargeOffset = 30000;
- return 30000;
+ return EmacsNative.getExtractedText (windowHandle, request,
+ flags);
+ }
- case 30000:
- currentLargeOffset = 0;
- return 0;
- }
+
+ /* Override functions which are not implemented. */
- currentLargeOffset = 0;
- return -1;
+ @Override
+ public TextSnapshot
+ takeSnapshot ()
+ {
+ Log.d (TAG, "takeSnapshot");
+ return null;
}
}
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
index f0219843d35..aaac9446510 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -22,6 +22,8 @@ package org.gnu.emacs;
import java.lang.System;
import android.content.res.AssetManager;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
public class EmacsNative
{
@@ -161,6 +163,50 @@ public class EmacsNative
descriptor, or NULL if there is none. */
public static native byte[] getProcName (int fd);
+ /* Notice that the Emacs thread will now start waiting for the main
+ thread's looper to respond. */
+ public static native void beginSynchronous ();
+
+ /* Notice that the Emacs thread will has finished waiting for the
+ main thread's looper to respond. */
+ public static native void endSynchronous ();
+
+
+
+ /* Input connection functions. These mostly correspond to their
+ counterparts in Android's InputConnection. */
+
+ public static native void beginBatchEdit (short window);
+ public static native void endBatchEdit (short window);
+ public static native void commitCompletion (short window, String text,
+ int position);
+ public static native void commitText (short window, String text,
+ int position);
+ public static native void deleteSurroundingText (short window,
+ int leftLength,
+ int rightLength);
+ public static native void finishComposingText (short window);
+ public static native String getSelectedText (short window, int flags);
+ public static native String getTextAfterCursor (short window, int length,
+ int flags);
+ public static native String getTextBeforeCursor (short window, int length,
+ int flags);
+ public static native void setComposingText (short window, String text,
+ int newCursorPosition);
+ public static native void setComposingRegion (short window, int start,
+ int end);
+ public static native void setSelection (short window, int start, int end);
+ public static native void performEditorAction (short window,
+ int editorAction);
+ public static native ExtractedText getExtractedText (short window,
+ ExtractedTextRequest req,
+ int flags);
+
+
+ /* Return the current value of the selection, or -1 upon
+ failure. */
+ public static native int getSelection (short window);
+
static
{
/* Older versions of Android cannot link correctly with shared
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index 2ec2ddf9bda..855a738a30f 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -80,6 +80,11 @@ public class EmacsService extends Service
private EmacsThread thread;
private Handler handler;
+ /* Keep this in synch with androidgui.h. */
+ public static final int IC_MODE_NULL = 0;
+ public static final int IC_MODE_ACTION = 1;
+ public static final int IC_MODE_TEXT = 2;
+
/* Display metrics used by font backends. */
public DisplayMetrics metrics;
@@ -258,20 +263,7 @@ public class EmacsService extends Service
}
};
- synchronized (runnable)
- {
- runOnUiThread (runnable);
-
- try
- {
- runnable.wait ();
- }
- catch (InterruptedException e)
- {
- EmacsNative.emacsAbort ();
- }
- }
-
+ syncRunnable (runnable);
return view.thing;
}
@@ -292,19 +284,7 @@ public class EmacsService extends Service
}
};
- synchronized (runnable)
- {
- runOnUiThread (runnable);
-
- try
- {
- runnable.wait ();
- }
- catch (InterruptedException e)
- {
- EmacsNative.emacsAbort ();
- }
- }
+ syncRunnable (runnable);
}
public void
@@ -502,19 +482,7 @@ public class EmacsService extends Service
}
};
- synchronized (runnable)
- {
- runOnUiThread (runnable);
-
- try
- {
- runnable.wait ();
- }
- catch (InterruptedException e)
- {
- EmacsNative.emacsAbort ();
- }
- }
+ syncRunnable (runnable);
}
@@ -594,20 +562,7 @@ public class EmacsService extends Service
}
};
- synchronized (runnable)
- {
- runOnUiThread (runnable);
-
- try
- {
- runnable.wait ();
- }
- catch (InterruptedException e)
- {
- EmacsNative.emacsAbort ();
- }
- }
-
+ syncRunnable (runnable);
return manager.thing;
}
@@ -622,4 +577,58 @@ public class EmacsService extends Service
startActivity (intent);
System.exit (0);
}
+
+ /* Wait synchronously for the specified RUNNABLE to complete in the
+ UI thread. Must be called from the Emacs thread. */
+
+ public static void
+ syncRunnable (Runnable runnable)
+ {
+ EmacsNative.beginSynchronous ();
+
+ synchronized (runnable)
+ {
+ SERVICE.runOnUiThread (runnable);
+
+ while (true)
+ {
+ try
+ {
+ runnable.wait ();
+ break;
+ }
+ catch (InterruptedException e)
+ {
+ continue;
+ }
+ }
+ }
+
+ EmacsNative.endSynchronous ();
+ }
+
+ public void
+ updateIC (EmacsWindow window, int newSelectionStart,
+ int newSelectionEnd, int composingRegionStart,
+ int composingRegionEnd)
+ {
+ Log.d (TAG, ("updateIC: " + window + " " + newSelectionStart
+ + " " + newSelectionEnd + " "
+ + composingRegionStart + " "
+ + composingRegionEnd));
+ window.view.imManager.updateSelection (window.view,
+ newSelectionStart,
+ newSelectionEnd,
+ composingRegionStart,
+ composingRegionEnd);
+ }
+
+ public void
+ resetIC (EmacsWindow window, int icMode)
+ {
+ Log.d (TAG, "resetIC: " + window);
+
+ window.view.setICMode (icMode);
+ window.view.imManager.restartInput (window.view);
+ }
};
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index bc3716f6da8..52da6d41f7d 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -103,6 +103,13 @@ public class EmacsView extends ViewGroup
displayed whenever possible. */
public boolean isCurrentlyTextEditor;
+ /* The associated input connection. */
+ private EmacsInputConnection inputConnection;
+
+ /* The current IC mode. See `android_reset_ic' for more
+ details. */
+ private int icMode;
+
public
EmacsView (EmacsWindow window)
{
@@ -554,14 +561,46 @@ public class EmacsView extends ViewGroup
public InputConnection
onCreateInputConnection (EditorInfo info)
{
+ int selection, mode;
+
+ /* Figure out what kind of IME behavior Emacs wants. */
+ mode = getICMode ();
+
/* Make sure the input method never displays a full screen input
box that obscures Emacs. */
info.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
/* Set a reasonable inputType. */
- info.inputType = InputType.TYPE_NULL;
+ info.inputType = InputType.TYPE_CLASS_TEXT;
+
+ /* Obtain the current position of point and set it as the
+ selection. */
+ selection = EmacsNative.getSelection (window.handle);
+
+ Log.d (TAG, "onCreateInputConnection: current selection is: " + selection);
+
+ /* If this fails or ANDROID_IC_MODE_NULL was requested, then don't
+ initialize the input connection. */
+ if (selection == -1 || mode == EmacsService.IC_MODE_NULL)
+ {
+ info.inputType = InputType.TYPE_NULL;
+ return null;
+ }
+
+ if (mode == EmacsService.IC_MODE_ACTION)
+ info.imeOptions |= EditorInfo.IME_ACTION_DONE;
- return null;
+ /* Set the initial selection fields. */
+ info.initialSelStart = selection;
+ info.initialSelEnd = selection;
+
+ /* Create the input connection if necessary. */
+
+ if (inputConnection == null)
+ inputConnection = new EmacsInputConnection (this);
+
+ /* Return the input connection. */
+ return inputConnection;
}
@Override
@@ -572,4 +611,16 @@ public class EmacsView extends ViewGroup
keyboard. */
return isCurrentlyTextEditor;
}
+
+ public synchronized void
+ setICMode (int icMode)
+ {
+ this.icMode = icMode;
+ }
+
+ public synchronized int
+ getICMode ()
+ {
+ return icMode;
+ }
};