diff options
| author | Po Lu | 2023-02-12 20:32:25 +0800 |
|---|---|---|
| committer | Po Lu | 2023-02-12 20:32:25 +0800 |
| commit | 0198b8cffd82893412c738dae8e50c45a99286f1 (patch) | |
| tree | 5dd87dc03d1c1ee08205c988f2c287f714f1cfa3 /java/org/gnu | |
| parent | ab48881a2fb72df016f2a00bc107e5a35a411a9d (diff) | |
| download | emacs-0198b8cffd82893412c738dae8e50c45a99286f1.tar.gz emacs-0198b8cffd82893412c738dae8e50c45a99286f1.zip | |
Update Android port
* doc/emacs/android.texi (Android Environment): Document
notifications permission.
* java/org/gnu/emacs/EmacsEditable.java (EmacsEditable):
* java/org/gnu/emacs/EmacsInputConnection.java
(EmacsInputConnection): New files.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): Load
library dependencies in a less verbose fashion.
* java/org/gnu/emacs/EmacsView.java (EmacsView): Make imManager
public.
(onCreateInputConnection): Set InputType to TYPE_NULL for now.
* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow, onKeyDown)
(onKeyUp, getEventUnicodeChar): Correctly handle key events with
strings.
* lisp/term/android-win.el (android-clear-preedit-text)
(android-preedit-text): New special event handlers.
* src/android.c (struct android_emacs_window): Add function
lookup_string.
(android_init_emacs_window): Adjust accordingly.
(android_wc_lookup_string): New function.
* src/androidgui.h (struct android_key_event): Improve
commentary.
(enum android_lookup_status): New enum.
* src/androidterm.c (handle_one_android_event): Synchronize IM
lookup code with X.
* src/coding.c (from_unicode_buffer): Implement on Android.
* src/coding.h:
* src/sfnt.c: Fix commentary.
Diffstat (limited to 'java/org/gnu')
| -rw-r--r-- | java/org/gnu/emacs/EmacsEditable.java | 300 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsInputConnection.java | 175 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsNative.java | 166 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsView.java | 7 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsWindow.java | 96 |
5 files changed, 588 insertions, 156 deletions
diff --git a/java/org/gnu/emacs/EmacsEditable.java b/java/org/gnu/emacs/EmacsEditable.java new file mode 100644 index 00000000000..79af65a6ccd --- /dev/null +++ b/java/org/gnu/emacs/EmacsEditable.java | |||
| @@ -0,0 +1,300 @@ | |||
| 1 | /* Communication module for Android terminals. -*- c-file-style: "GNU" -*- | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.text.InputFilter; | ||
| 23 | import android.text.SpannableStringBuilder; | ||
| 24 | import android.text.Spanned; | ||
| 25 | import android.text.SpanWatcher; | ||
| 26 | import android.text.Selection; | ||
| 27 | |||
| 28 | import android.content.Context; | ||
| 29 | |||
| 30 | import android.view.inputmethod.InputMethodManager; | ||
| 31 | import android.view.inputmethod.ExtractedText; | ||
| 32 | import android.view.inputmethod.ExtractedTextRequest; | ||
| 33 | |||
| 34 | import android.text.Spannable; | ||
| 35 | |||
| 36 | import android.util.Log; | ||
| 37 | |||
| 38 | import android.os.Build; | ||
| 39 | |||
| 40 | /* Android input methods insist on having access to buffer contents. | ||
| 41 | Since Emacs is not designed like ``any other Android text editor'', | ||
| 42 | that is not possible. | ||
| 43 | |||
| 44 | This file provides a fake editing buffer that is designed to weasel | ||
| 45 | as much information as possible out of an input method, without | ||
| 46 | actually providing buffer contents to Emacs. | ||
| 47 | |||
| 48 | The basic idea is to have the fake editing buffer be initially | ||
| 49 | empty. | ||
| 50 | |||
| 51 | When the input method inserts composed text, it sets a flag. | ||
| 52 | Updates to the buffer while the flag is set are sent to Emacs to be | ||
| 53 | displayed as ``preedit text''. | ||
| 54 | |||
| 55 | Once some heuristics decide that composition has been completed, | ||
| 56 | the composed text is sent to Emacs, and the text that was inserted | ||
| 57 | in this editing buffer is erased. */ | ||
| 58 | |||
| 59 | public class EmacsEditable extends SpannableStringBuilder | ||
| 60 | implements SpanWatcher | ||
| 61 | { | ||
| 62 | private static final String TAG = "EmacsEditable"; | ||
| 63 | |||
| 64 | /* Whether or not composition is currently in progress. */ | ||
| 65 | private boolean isComposing; | ||
| 66 | |||
| 67 | /* The associated input connection. */ | ||
| 68 | private EmacsInputConnection connection; | ||
| 69 | |||
| 70 | /* The associated IM manager. */ | ||
| 71 | private InputMethodManager imManager; | ||
| 72 | |||
| 73 | /* Any extracted text an input method may be monitoring. */ | ||
| 74 | private ExtractedText extractedText; | ||
| 75 | |||
| 76 | /* The corresponding text request. */ | ||
| 77 | private ExtractedTextRequest extractRequest; | ||
| 78 | |||
| 79 | /* The number of nested batch edits. */ | ||
| 80 | private int batchEditCount; | ||
| 81 | |||
| 82 | /* Whether or not invalidateInput should be called upon batch edits | ||
| 83 | ending. */ | ||
| 84 | private boolean pendingInvalidate; | ||
| 85 | |||
| 86 | /* The ``composing span'' indicating the bounds of an ongoing | ||
| 87 | character composition. */ | ||
| 88 | private Object composingSpan; | ||
| 89 | |||
| 90 | public | ||
| 91 | EmacsEditable (EmacsInputConnection connection) | ||
| 92 | { | ||
| 93 | /* Initialize the editable with one initial space, so backspace | ||
| 94 | always works. */ | ||
| 95 | super (); | ||
| 96 | |||
| 97 | Object tem; | ||
| 98 | Context context; | ||
| 99 | |||
| 100 | this.connection = connection; | ||
| 101 | |||
| 102 | context = connection.view.getContext (); | ||
| 103 | tem = context.getSystemService (Context.INPUT_METHOD_SERVICE); | ||
| 104 | imManager = (InputMethodManager) tem; | ||
| 105 | |||
| 106 | /* To watch for changes to text properties on Android, you | ||
| 107 | add... a text property. */ | ||
| 108 | setSpan (this, 0, 0, Spanned.SPAN_INCLUSIVE_INCLUSIVE); | ||
| 109 | } | ||
| 110 | |||
| 111 | public void | ||
| 112 | endBatchEdit () | ||
| 113 | { | ||
| 114 | if (batchEditCount < 1) | ||
| 115 | return; | ||
| 116 | |||
| 117 | if (--batchEditCount == 0 && pendingInvalidate) | ||
| 118 | invalidateInput (); | ||
| 119 | } | ||
| 120 | |||
| 121 | public void | ||
| 122 | beginBatchEdit () | ||
| 123 | { | ||
| 124 | ++batchEditCount; | ||
| 125 | } | ||
| 126 | |||
| 127 | public void | ||
| 128 | setExtractedTextAndRequest (ExtractedText text, | ||
| 129 | ExtractedTextRequest request, | ||
| 130 | boolean monitor) | ||
| 131 | { | ||
| 132 | /* Extract the text. If monitor is set, also record it as the | ||
| 133 | text that is currently being extracted. */ | ||
| 134 | |||
| 135 | text.startOffset = 0; | ||
| 136 | text.selectionStart = Selection.getSelectionStart (this); | ||
| 137 | text.selectionEnd = Selection.getSelectionStart (this); | ||
| 138 | text.text = this; | ||
| 139 | |||
| 140 | if (monitor) | ||
| 141 | { | ||
| 142 | extractedText = text; | ||
| 143 | extractRequest = request; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | public void | ||
| 148 | compositionStart () | ||
| 149 | { | ||
| 150 | isComposing = true; | ||
| 151 | } | ||
| 152 | |||
| 153 | public void | ||
| 154 | compositionEnd () | ||
| 155 | { | ||
| 156 | isComposing = false; | ||
| 157 | sendComposingText (null); | ||
| 158 | } | ||
| 159 | |||
| 160 | private void | ||
| 161 | sendComposingText (String string) | ||
| 162 | { | ||
| 163 | EmacsWindow window; | ||
| 164 | long time, serial; | ||
| 165 | |||
| 166 | window = connection.view.window; | ||
| 167 | |||
| 168 | if (window.isDestroyed ()) | ||
| 169 | return; | ||
| 170 | |||
| 171 | time = System.currentTimeMillis (); | ||
| 172 | |||
| 173 | /* A composition event is simply a special key event with a | ||
| 174 | keycode of -1. */ | ||
| 175 | |||
| 176 | synchronized (window.eventStrings) | ||
| 177 | { | ||
| 178 | serial | ||
| 179 | = EmacsNative.sendKeyPress (window.handle, time, 0, -1, -1); | ||
| 180 | |||
| 181 | /* Save the string so that android_lookup_string can find | ||
| 182 | it. */ | ||
| 183 | if (string != null) | ||
| 184 | window.saveUnicodeString ((int) serial, string); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | private void | ||
| 189 | invalidateInput () | ||
| 190 | { | ||
| 191 | int start, end, composingSpanStart, composingSpanEnd; | ||
| 192 | |||
| 193 | if (batchEditCount > 0) | ||
| 194 | { | ||
| 195 | Log.d (TAG, "invalidateInput: deferring for batch edit"); | ||
| 196 | pendingInvalidate = true; | ||
| 197 | return; | ||
| 198 | } | ||
| 199 | |||
| 200 | pendingInvalidate = false; | ||
| 201 | |||
| 202 | start = Selection.getSelectionStart (this); | ||
| 203 | end = Selection.getSelectionEnd (this); | ||
| 204 | |||
| 205 | if (composingSpan != null) | ||
| 206 | { | ||
| 207 | composingSpanStart = getSpanStart (composingSpan); | ||
| 208 | composingSpanEnd = getSpanEnd (composingSpan); | ||
| 209 | } | ||
| 210 | else | ||
| 211 | { | ||
| 212 | composingSpanStart = -1; | ||
| 213 | composingSpanEnd = -1; | ||
| 214 | } | ||
| 215 | |||
| 216 | Log.d (TAG, "invalidateInput: now " + start + ", " + end); | ||
| 217 | |||
| 218 | /* Tell the input method that the cursor changed. */ | ||
| 219 | imManager.updateSelection (connection.view, start, end, | ||
| 220 | composingSpanStart, | ||
| 221 | composingSpanEnd); | ||
| 222 | |||
| 223 | /* If there is any extracted text, tell the IME that it has | ||
| 224 | changed. */ | ||
| 225 | if (extractedText != null) | ||
| 226 | imManager.updateExtractedText (connection.view, | ||
| 227 | extractRequest.token, | ||
| 228 | extractedText); | ||
| 229 | } | ||
| 230 | |||
| 231 | public SpannableStringBuilder | ||
| 232 | replace (int start, int end, CharSequence tb, int tbstart, | ||
| 233 | int tbend) | ||
| 234 | { | ||
| 235 | super.replace (start, end, tb, tbstart, tbend); | ||
| 236 | |||
| 237 | /* If a change happens during composition, perform the change and | ||
| 238 | then send the text being composed. */ | ||
| 239 | |||
| 240 | if (isComposing) | ||
| 241 | sendComposingText (toString ()); | ||
| 242 | |||
| 243 | return this; | ||
| 244 | } | ||
| 245 | |||
| 246 | private boolean | ||
| 247 | isSelectionSpan (Object span) | ||
| 248 | { | ||
| 249 | return ((Selection.SELECTION_START == span | ||
| 250 | || Selection.SELECTION_END == span) | ||
| 251 | && (getSpanFlags (span) | ||
| 252 | & Spanned.SPAN_INTERMEDIATE) == 0); | ||
| 253 | } | ||
| 254 | |||
| 255 | @Override | ||
| 256 | public void | ||
| 257 | onSpanAdded (Spannable text, Object what, int start, int end) | ||
| 258 | { | ||
| 259 | Log.d (TAG, "onSpanAdded: " + text + " " + what + " " | ||
| 260 | + start + " " + end); | ||
| 261 | |||
| 262 | /* Try to find the composing span. This isn't a public API. */ | ||
| 263 | |||
| 264 | if (what.getClass ().getName ().contains ("ComposingText")) | ||
| 265 | composingSpan = what; | ||
| 266 | |||
| 267 | if (isSelectionSpan (what)) | ||
| 268 | invalidateInput (); | ||
| 269 | } | ||
| 270 | |||
| 271 | @Override | ||
| 272 | public void | ||
| 273 | onSpanChanged (Spannable text, Object what, int ostart, | ||
| 274 | int oend, int nstart, int nend) | ||
| 275 | { | ||
| 276 | Log.d (TAG, "onSpanChanged: " + text + " " + what + " " | ||
| 277 | + nstart + " " + nend); | ||
| 278 | |||
| 279 | if (isSelectionSpan (what)) | ||
| 280 | invalidateInput (); | ||
| 281 | } | ||
| 282 | |||
| 283 | @Override | ||
| 284 | public void | ||
| 285 | onSpanRemoved (Spannable text, Object what, | ||
| 286 | int start, int end) | ||
| 287 | { | ||
| 288 | Log.d (TAG, "onSpanRemoved: " + text + " " + what + " " | ||
| 289 | + start + " " + end); | ||
| 290 | |||
| 291 | if (isSelectionSpan (what)) | ||
| 292 | invalidateInput (); | ||
| 293 | } | ||
| 294 | |||
| 295 | public boolean | ||
| 296 | isInBatchEdit () | ||
| 297 | { | ||
| 298 | return batchEditCount > 0; | ||
| 299 | } | ||
| 300 | } | ||
diff --git a/java/org/gnu/emacs/EmacsInputConnection.java b/java/org/gnu/emacs/EmacsInputConnection.java new file mode 100644 index 00000000000..897a393b984 --- /dev/null +++ b/java/org/gnu/emacs/EmacsInputConnection.java | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | /* Communication module for Android terminals. -*- c-file-style: "GNU" -*- | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.view.inputmethod.BaseInputConnection; | ||
| 23 | import android.view.inputmethod.CompletionInfo; | ||
| 24 | import android.view.inputmethod.ExtractedText; | ||
| 25 | import android.view.inputmethod.ExtractedTextRequest; | ||
| 26 | import android.view.inputmethod.InputMethodManager; | ||
| 27 | import android.view.inputmethod.SurroundingText; | ||
| 28 | import android.view.KeyEvent; | ||
| 29 | |||
| 30 | import android.text.Editable; | ||
| 31 | |||
| 32 | import android.util.Log; | ||
| 33 | |||
| 34 | /* Android input methods, take number six. | ||
| 35 | |||
| 36 | See EmacsEditable for more details. */ | ||
| 37 | |||
| 38 | public class EmacsInputConnection extends BaseInputConnection | ||
| 39 | { | ||
| 40 | private static final String TAG = "EmacsInputConnection"; | ||
| 41 | public EmacsView view; | ||
| 42 | private EmacsEditable editable; | ||
| 43 | |||
| 44 | /* The length of the last string to be committed. */ | ||
| 45 | private int lastCommitLength; | ||
| 46 | |||
| 47 | int currentLargeOffset; | ||
| 48 | |||
| 49 | public | ||
| 50 | EmacsInputConnection (EmacsView view) | ||
| 51 | { | ||
| 52 | super (view, false); | ||
| 53 | this.view = view; | ||
| 54 | this.editable = new EmacsEditable (this); | ||
| 55 | } | ||
| 56 | |||
| 57 | @Override | ||
| 58 | public Editable | ||
| 59 | getEditable () | ||
| 60 | { | ||
| 61 | return editable; | ||
| 62 | } | ||
| 63 | |||
| 64 | @Override | ||
| 65 | public boolean | ||
| 66 | setComposingText (CharSequence text, int newCursorPosition) | ||
| 67 | { | ||
| 68 | editable.compositionStart (); | ||
| 69 | super.setComposingText (text, newCursorPosition); | ||
| 70 | return true; | ||
| 71 | } | ||
| 72 | |||
| 73 | @Override | ||
| 74 | public boolean | ||
| 75 | setComposingRegion (int start, int end) | ||
| 76 | { | ||
| 77 | int i; | ||
| 78 | |||
| 79 | if (lastCommitLength != 0) | ||
| 80 | { | ||
| 81 | Log.d (TAG, "Restarting composition for: " + lastCommitLength); | ||
| 82 | |||
| 83 | for (i = 0; i < lastCommitLength; ++i) | ||
| 84 | sendKeyEvent (new KeyEvent (KeyEvent.ACTION_DOWN, | ||
| 85 | KeyEvent.KEYCODE_DEL)); | ||
| 86 | |||
| 87 | lastCommitLength = 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | editable.compositionStart (); | ||
| 91 | super.setComposingRegion (start, end); | ||
| 92 | return true; | ||
| 93 | } | ||
| 94 | |||
| 95 | @Override | ||
| 96 | public boolean | ||
| 97 | finishComposingText () | ||
| 98 | { | ||
| 99 | editable.compositionEnd (); | ||
| 100 | return super.finishComposingText (); | ||
| 101 | } | ||
| 102 | |||
| 103 | @Override | ||
| 104 | public boolean | ||
| 105 | beginBatchEdit () | ||
| 106 | { | ||
| 107 | editable.beginBatchEdit (); | ||
| 108 | return super.beginBatchEdit (); | ||
| 109 | } | ||
| 110 | |||
| 111 | @Override | ||
| 112 | public boolean | ||
| 113 | endBatchEdit () | ||
| 114 | { | ||
| 115 | editable.endBatchEdit (); | ||
| 116 | return super.endBatchEdit (); | ||
| 117 | } | ||
| 118 | |||
| 119 | @Override | ||
| 120 | public boolean | ||
| 121 | commitText (CharSequence text, int newCursorPosition) | ||
| 122 | { | ||
| 123 | editable.compositionEnd (); | ||
| 124 | super.commitText (text, newCursorPosition); | ||
| 125 | |||
| 126 | /* An observation is that input methods rarely recompose trailing | ||
| 127 | spaces. Avoid re-setting the commit length in that case. */ | ||
| 128 | |||
| 129 | if (text.toString ().equals (" ")) | ||
| 130 | lastCommitLength += 1; | ||
| 131 | else | ||
| 132 | /* At this point, the editable is now empty. | ||
| 133 | |||
| 134 | The input method may try to cancel the edit upon a subsequent | ||
| 135 | backspace by calling setComposingRegion with a region that is | ||
| 136 | the length of TEXT. | ||
| 137 | |||
| 138 | Record this length in order to be able to send backspace | ||
| 139 | events to ``delete'' the text in that case. */ | ||
| 140 | lastCommitLength = text.length (); | ||
| 141 | |||
| 142 | Log.d (TAG, "commitText: \"" + text + "\""); | ||
| 143 | |||
| 144 | return true; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* Return a large offset, cycling through 100000, 30000, 0. | ||
| 148 | The offset is typically used to force the input method to update | ||
| 149 | its notion of ``surrounding text'', bypassing any caching that | ||
| 150 | it might have in progress. | ||
| 151 | |||
| 152 | There must be another way to do this, but I can't find it. */ | ||
| 153 | |||
| 154 | public int | ||
| 155 | largeSelectionOffset () | ||
| 156 | { | ||
| 157 | switch (currentLargeOffset) | ||
| 158 | { | ||
| 159 | case 0: | ||
| 160 | currentLargeOffset = 100000; | ||
| 161 | return 100000; | ||
| 162 | |||
| 163 | case 100000: | ||
| 164 | currentLargeOffset = 30000; | ||
| 165 | return 30000; | ||
| 166 | |||
| 167 | case 30000: | ||
| 168 | currentLargeOffset = 0; | ||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | currentLargeOffset = 0; | ||
| 173 | return -1; | ||
| 174 | } | ||
| 175 | } | ||
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index 939348ba420..f0219843d35 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java | |||
| @@ -25,6 +25,10 @@ import android.content.res.AssetManager; | |||
| 25 | 25 | ||
| 26 | public class EmacsNative | 26 | public class EmacsNative |
| 27 | { | 27 | { |
| 28 | /* List of native libraries that must be loaded during class | ||
| 29 | initialization. */ | ||
| 30 | private static final String[] libraryDeps; | ||
| 31 | |||
| 28 | /* Obtain the fingerprint of this build of Emacs. The fingerprint | 32 | /* Obtain the fingerprint of this build of Emacs. The fingerprint |
| 29 | can be used to determine the dump file name. */ | 33 | can be used to determine the dump file name. */ |
| 30 | public static native String getFingerprint (); | 34 | public static native String getFingerprint (); |
| @@ -167,148 +171,26 @@ public class EmacsNative | |||
| 167 | Every time you add a new shared library dependency to Emacs, | 171 | Every time you add a new shared library dependency to Emacs, |
| 168 | please add it here as well. */ | 172 | please add it here as well. */ |
| 169 | 173 | ||
| 170 | try | 174 | libraryDeps = new String[] { "png_emacs", "selinux_emacs", |
| 171 | { | 175 | "crypto_emacs", "pcre_emacs", |
| 172 | System.loadLibrary ("png_emacs"); | 176 | "packagelistparser_emacs", |
| 173 | } | 177 | "gnutls_emacs", "gmp_emacs", |
| 174 | catch (UnsatisfiedLinkError exception) | 178 | "nettle_emacs", "p11-kit_emacs", |
| 175 | { | 179 | "tasn1_emacs", "hogweed_emacs", |
| 176 | /* Ignore this exception. */ | 180 | "jansson_emacs", "jpeg_emacs", |
| 177 | } | 181 | "tiff_emacs", "xml2_emacs", |
| 178 | 182 | "icuuc_emacs", }; | |
| 179 | try | 183 | |
| 180 | { | 184 | for (String dependency : libraryDeps) |
| 181 | System.loadLibrary ("selinux_emacs"); | 185 | { |
| 182 | } | 186 | try |
| 183 | catch (UnsatisfiedLinkError exception) | 187 | { |
| 184 | { | 188 | System.loadLibrary (dependency); |
| 185 | /* Ignore this exception. */ | 189 | } |
| 186 | } | 190 | catch (UnsatisfiedLinkError exception) |
| 187 | 191 | { | |
| 188 | try | 192 | /* Ignore this exception. */ |
| 189 | { | 193 | } |
| 190 | System.loadLibrary ("crypto_emacs"); | ||
| 191 | } | ||
| 192 | catch (UnsatisfiedLinkError exception) | ||
| 193 | { | ||
| 194 | /* Ignore this exception. */ | ||
| 195 | } | ||
| 196 | |||
| 197 | try | ||
| 198 | { | ||
| 199 | System.loadLibrary ("pcre_emacs"); | ||
| 200 | } | ||
| 201 | catch (UnsatisfiedLinkError exception) | ||
| 202 | { | ||
| 203 | /* Ignore this exception. */ | ||
| 204 | } | ||
| 205 | |||
| 206 | try | ||
| 207 | { | ||
| 208 | System.loadLibrary ("packagelistparser_emacs"); | ||
| 209 | } | ||
| 210 | catch (UnsatisfiedLinkError exception) | ||
| 211 | { | ||
| 212 | /* Ignore this exception. */ | ||
| 213 | } | ||
| 214 | |||
| 215 | try | ||
| 216 | { | ||
| 217 | System.loadLibrary ("gnutls_emacs"); | ||
| 218 | } | ||
| 219 | catch (UnsatisfiedLinkError exception) | ||
| 220 | { | ||
| 221 | /* Ignore this exception. */ | ||
| 222 | } | ||
| 223 | |||
| 224 | try | ||
| 225 | { | ||
| 226 | System.loadLibrary ("gmp_emacs"); | ||
| 227 | } | ||
| 228 | catch (UnsatisfiedLinkError exception) | ||
| 229 | { | ||
| 230 | /* Ignore this exception. */ | ||
| 231 | } | ||
| 232 | |||
| 233 | try | ||
| 234 | { | ||
| 235 | System.loadLibrary ("nettle_emacs"); | ||
| 236 | } | ||
| 237 | catch (UnsatisfiedLinkError exception) | ||
| 238 | { | ||
| 239 | /* Ignore this exception. */ | ||
| 240 | } | ||
| 241 | |||
| 242 | try | ||
| 243 | { | ||
| 244 | System.loadLibrary ("p11-kit_emacs"); | ||
| 245 | } | ||
| 246 | catch (UnsatisfiedLinkError exception) | ||
| 247 | { | ||
| 248 | /* Ignore this exception. */ | ||
| 249 | } | ||
| 250 | |||
| 251 | try | ||
| 252 | { | ||
| 253 | System.loadLibrary ("tasn1_emacs"); | ||
| 254 | } | ||
| 255 | catch (UnsatisfiedLinkError exception) | ||
| 256 | { | ||
| 257 | /* Ignore this exception. */ | ||
| 258 | } | ||
| 259 | |||
| 260 | try | ||
| 261 | { | ||
| 262 | System.loadLibrary ("hogweed_emacs"); | ||
| 263 | } | ||
| 264 | catch (UnsatisfiedLinkError exception) | ||
| 265 | { | ||
| 266 | /* Ignore this exception. */ | ||
| 267 | } | ||
| 268 | |||
| 269 | try | ||
| 270 | { | ||
| 271 | System.loadLibrary ("jansson_emacs"); | ||
| 272 | } | ||
| 273 | catch (UnsatisfiedLinkError exception) | ||
| 274 | { | ||
| 275 | /* Ignore this exception. */ | ||
| 276 | } | ||
| 277 | |||
| 278 | try | ||
| 279 | { | ||
| 280 | System.loadLibrary ("jpeg_emacs"); | ||
| 281 | } | ||
| 282 | catch (UnsatisfiedLinkError exception) | ||
| 283 | { | ||
| 284 | /* Ignore this exception. */ | ||
| 285 | } | ||
| 286 | |||
| 287 | try | ||
| 288 | { | ||
| 289 | System.loadLibrary ("tiff_emacs"); | ||
| 290 | } | ||
| 291 | catch (UnsatisfiedLinkError exception) | ||
| 292 | { | ||
| 293 | /* Ignore this exception. */ | ||
| 294 | } | ||
| 295 | |||
| 296 | try | ||
| 297 | { | ||
| 298 | System.loadLibrary ("xml2_emacs"); | ||
| 299 | } | ||
| 300 | catch (UnsatisfiedLinkError exception) | ||
| 301 | { | ||
| 302 | /* Ignore this exception. */ | ||
| 303 | } | ||
| 304 | |||
| 305 | try | ||
| 306 | { | ||
| 307 | System.loadLibrary ("icuuc_emacs"); | ||
| 308 | } | ||
| 309 | catch (UnsatisfiedLinkError exception) | ||
| 310 | { | ||
| 311 | /* Ignore this exception. */ | ||
| 312 | } | 194 | } |
| 313 | 195 | ||
| 314 | System.loadLibrary ("emacs"); | 196 | System.loadLibrary ("emacs"); |
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 4fc8104e31f..bc3716f6da8 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java | |||
| @@ -94,7 +94,7 @@ public class EmacsView extends ViewGroup | |||
| 94 | private long lastClipSerial; | 94 | private long lastClipSerial; |
| 95 | 95 | ||
| 96 | /* The InputMethodManager for this view's context. */ | 96 | /* The InputMethodManager for this view's context. */ |
| 97 | private InputMethodManager imManager; | 97 | public InputMethodManager imManager; |
| 98 | 98 | ||
| 99 | /* Whether or not this view is attached to a window. */ | 99 | /* Whether or not this view is attached to a window. */ |
| 100 | public boolean isAttachedToWindow; | 100 | public boolean isAttachedToWindow; |
| @@ -558,8 +558,9 @@ public class EmacsView extends ViewGroup | |||
| 558 | box that obscures Emacs. */ | 558 | box that obscures Emacs. */ |
| 559 | info.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN; | 559 | info.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN; |
| 560 | 560 | ||
| 561 | /* But don't return an InputConnection, in order to force the on | 561 | /* Set a reasonable inputType. */ |
| 562 | screen keyboard to work correctly. */ | 562 | info.inputType = InputType.TYPE_NULL; |
| 563 | |||
| 563 | return null; | 564 | return null; |
| 564 | } | 565 | } |
| 565 | 566 | ||
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java index 9e2f2f53270..0eca35cec61 100644 --- a/java/org/gnu/emacs/EmacsWindow.java +++ b/java/org/gnu/emacs/EmacsWindow.java | |||
| @@ -23,6 +23,8 @@ import java.lang.IllegalStateException; | |||
| 23 | import java.util.ArrayList; | 23 | import java.util.ArrayList; |
| 24 | import java.util.List; | 24 | import java.util.List; |
| 25 | import java.util.HashMap; | 25 | import java.util.HashMap; |
| 26 | import java.util.LinkedHashMap; | ||
| 27 | import java.util.Map; | ||
| 26 | 28 | ||
| 27 | import android.content.Context; | 29 | import android.content.Context; |
| 28 | 30 | ||
| @@ -100,7 +102,7 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 100 | 102 | ||
| 101 | /* The button state and keyboard modifier mask at the time of the | 103 | /* The button state and keyboard modifier mask at the time of the |
| 102 | last button press or release event. */ | 104 | last button press or release event. */ |
| 103 | private int lastButtonState, lastModifiers; | 105 | public int lastButtonState, lastModifiers; |
| 104 | 106 | ||
| 105 | /* Whether or not the window is mapped, and whether or not it is | 107 | /* Whether or not the window is mapped, and whether or not it is |
| 106 | deiconified. */ | 108 | deiconified. */ |
| @@ -122,6 +124,10 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 122 | to quit Emacs. */ | 124 | to quit Emacs. */ |
| 123 | private long lastVolumeButtonRelease; | 125 | private long lastVolumeButtonRelease; |
| 124 | 126 | ||
| 127 | /* Linked list of character strings which were recently sent as | ||
| 128 | events. */ | ||
| 129 | public LinkedHashMap<Integer, String> eventStrings; | ||
| 130 | |||
| 125 | public | 131 | public |
| 126 | EmacsWindow (short handle, final EmacsWindow parent, int x, int y, | 132 | EmacsWindow (short handle, final EmacsWindow parent, int x, int y, |
| 127 | int width, int height, boolean overrideRedirect) | 133 | int width, int height, boolean overrideRedirect) |
| @@ -155,6 +161,19 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 155 | } | 161 | } |
| 156 | 162 | ||
| 157 | scratchGC = new EmacsGC ((short) 0); | 163 | scratchGC = new EmacsGC ((short) 0); |
| 164 | |||
| 165 | /* Create the map of input method-committed strings. Keep at most | ||
| 166 | ten strings in the map. */ | ||
| 167 | |||
| 168 | eventStrings | ||
| 169 | = new LinkedHashMap<Integer, String> () { | ||
| 170 | @Override | ||
| 171 | protected boolean | ||
| 172 | removeEldestEntry (Map.Entry<Integer, String> entry) | ||
| 173 | { | ||
| 174 | return size () > 10; | ||
| 175 | } | ||
| 176 | }; | ||
| 158 | } | 177 | } |
| 159 | 178 | ||
| 160 | public void | 179 | public void |
| @@ -507,10 +526,40 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 507 | return view.getBitmap (); | 526 | return view.getBitmap (); |
| 508 | } | 527 | } |
| 509 | 528 | ||
| 529 | /* event.getCharacters is used because older input methods still | ||
| 530 | require it. */ | ||
| 531 | @SuppressWarnings ("deprecation") | ||
| 532 | public int | ||
| 533 | getEventUnicodeChar (KeyEvent event, int state) | ||
| 534 | { | ||
| 535 | String characters; | ||
| 536 | |||
| 537 | if (event.getUnicodeChar (state) != 0) | ||
| 538 | return event.getUnicodeChar (state); | ||
| 539 | |||
| 540 | characters = event.getCharacters (); | ||
| 541 | |||
| 542 | if (characters != null && characters.length () == 1) | ||
| 543 | return characters.charAt (0); | ||
| 544 | |||
| 545 | return characters == null ? 0 : -1; | ||
| 546 | } | ||
| 547 | |||
| 548 | public void | ||
| 549 | saveUnicodeString (int serial, String string) | ||
| 550 | { | ||
| 551 | eventStrings.put (serial, string); | ||
| 552 | } | ||
| 553 | |||
| 554 | /* event.getCharacters is used because older input methods still | ||
| 555 | require it. */ | ||
| 556 | @SuppressWarnings ("deprecation") | ||
| 510 | public void | 557 | public void |
| 511 | onKeyDown (int keyCode, KeyEvent event) | 558 | onKeyDown (int keyCode, KeyEvent event) |
| 512 | { | 559 | { |
| 513 | int state, state_1; | 560 | int state, state_1; |
| 561 | long serial; | ||
| 562 | String characters; | ||
| 514 | 563 | ||
| 515 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) | 564 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) |
| 516 | state = event.getModifiers (); | 565 | state = event.getModifiers (); |
| @@ -537,18 +586,28 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 537 | state_1 | 586 | state_1 |
| 538 | = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); | 587 | = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); |
| 539 | 588 | ||
| 540 | EmacsNative.sendKeyPress (this.handle, | 589 | synchronized (eventStrings) |
| 541 | event.getEventTime (), | 590 | { |
| 542 | state, keyCode, | 591 | serial |
| 543 | event.getUnicodeChar (state_1)); | 592 | = EmacsNative.sendKeyPress (this.handle, |
| 544 | lastModifiers = state; | 593 | event.getEventTime (), |
| 594 | state, keyCode, | ||
| 595 | getEventUnicodeChar (event, | ||
| 596 | state_1)); | ||
| 597 | lastModifiers = state; | ||
| 598 | |||
| 599 | characters = event.getCharacters (); | ||
| 600 | |||
| 601 | if (characters != null && characters.length () > 1) | ||
| 602 | saveUnicodeString ((int) serial, characters); | ||
| 603 | } | ||
| 545 | } | 604 | } |
| 546 | 605 | ||
| 547 | public void | 606 | public void |
| 548 | onKeyUp (int keyCode, KeyEvent event) | 607 | onKeyUp (int keyCode, KeyEvent event) |
| 549 | { | 608 | { |
| 550 | int state, state_1; | 609 | int state, state_1; |
| 551 | long time; | 610 | long time, serial; |
| 552 | 611 | ||
| 553 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) | 612 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) |
| 554 | state = event.getModifiers (); | 613 | state = event.getModifiers (); |
| @@ -575,10 +634,12 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 575 | state_1 | 634 | state_1 |
| 576 | = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); | 635 | = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); |
| 577 | 636 | ||
| 578 | EmacsNative.sendKeyRelease (this.handle, | 637 | serial |
| 579 | event.getEventTime (), | 638 | = EmacsNative.sendKeyRelease (this.handle, |
| 580 | state, keyCode, | 639 | event.getEventTime (), |
| 581 | event.getUnicodeChar (state_1)); | 640 | state, keyCode, |
| 641 | getEventUnicodeChar (event, | ||
| 642 | state_1)); | ||
| 582 | lastModifiers = state; | 643 | lastModifiers = state; |
| 583 | 644 | ||
| 584 | if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) | 645 | if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) |
| @@ -1105,4 +1166,17 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 1105 | } | 1166 | } |
| 1106 | }); | 1167 | }); |
| 1107 | } | 1168 | } |
| 1169 | |||
| 1170 | public String | ||
| 1171 | lookupString (int eventSerial) | ||
| 1172 | { | ||
| 1173 | String any; | ||
| 1174 | |||
| 1175 | synchronized (eventStrings) | ||
| 1176 | { | ||
| 1177 | any = eventStrings.remove (eventSerial); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | return any; | ||
| 1181 | } | ||
| 1108 | }; | 1182 | }; |