diff options
| author | Po Lu | 2023-06-14 15:37:47 +0800 |
|---|---|---|
| committer | Po Lu | 2023-06-14 15:37:47 +0800 |
| commit | 90ae3cc387530229e5aca32c00d35495ab680e21 (patch) | |
| tree | f35e1da961f97a04a9b35ff6e62536587a6164b6 /java | |
| parent | 87b8f8769e6cd4563f82747c279c858617ce1b2b (diff) | |
| download | emacs-90ae3cc387530229e5aca32c00d35495ab680e21.tar.gz emacs-90ae3cc387530229e5aca32c00d35495ab680e21.zip | |
Improve IM synchronization on Android
* java/org/gnu/emacs/EmacsInputConnection.java
(EmacsInputConnection): Reimplement as an InputConnection, not
BaseInputConnection.
* src/androidterm.c (performEditorAction): Sync prior to sending
keyboard events.
Diffstat (limited to 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsInputConnection.java | 189 |
1 files changed, 167 insertions, 22 deletions
diff --git a/java/org/gnu/emacs/EmacsInputConnection.java b/java/org/gnu/emacs/EmacsInputConnection.java index 73c93c67ac7..1bcc9a62a81 100644 --- a/java/org/gnu/emacs/EmacsInputConnection.java +++ b/java/org/gnu/emacs/EmacsInputConnection.java | |||
| @@ -19,26 +19,35 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 19 | 19 | ||
| 20 | package org.gnu.emacs; | 20 | package org.gnu.emacs; |
| 21 | 21 | ||
| 22 | import android.view.inputmethod.BaseInputConnection; | 22 | import android.os.Build; |
| 23 | import android.os.Bundle; | ||
| 24 | import android.os.Handler; | ||
| 25 | |||
| 26 | import android.view.KeyEvent; | ||
| 27 | |||
| 23 | import android.view.inputmethod.CompletionInfo; | 28 | import android.view.inputmethod.CompletionInfo; |
| 29 | import android.view.inputmethod.CorrectionInfo; | ||
| 24 | import android.view.inputmethod.ExtractedText; | 30 | import android.view.inputmethod.ExtractedText; |
| 25 | import android.view.inputmethod.ExtractedTextRequest; | 31 | import android.view.inputmethod.ExtractedTextRequest; |
| 32 | import android.view.inputmethod.InputConnection; | ||
| 33 | import android.view.inputmethod.InputContentInfo; | ||
| 26 | import android.view.inputmethod.SurroundingText; | 34 | import android.view.inputmethod.SurroundingText; |
| 35 | import android.view.inputmethod.TextAttribute; | ||
| 27 | import android.view.inputmethod.TextSnapshot; | 36 | import android.view.inputmethod.TextSnapshot; |
| 28 | 37 | ||
| 29 | import android.view.KeyEvent; | ||
| 30 | |||
| 31 | import android.os.Build; | ||
| 32 | |||
| 33 | import android.util.Log; | 38 | import android.util.Log; |
| 34 | 39 | ||
| 35 | /* Android input methods, take number six. See textconv.c for more | 40 | /* Android input methods, take number six. See textconv.c for more |
| 36 | details; this is more-or-less a thin wrapper around that file. */ | 41 | details; this is more-or-less a thin wrapper around that file. */ |
| 37 | 42 | ||
| 38 | public final class EmacsInputConnection extends BaseInputConnection | 43 | public final class EmacsInputConnection implements InputConnection |
| 39 | { | 44 | { |
| 40 | private static final String TAG = "EmacsInputConnection"; | 45 | private static final String TAG = "EmacsInputConnection"; |
| 46 | |||
| 47 | /* View associated with this input connection. */ | ||
| 41 | private EmacsView view; | 48 | private EmacsView view; |
| 49 | |||
| 50 | /* The handle ID associated with that view's window. */ | ||
| 42 | private short windowHandle; | 51 | private short windowHandle; |
| 43 | 52 | ||
| 44 | /* Whether or not to synchronize and call `updateIC' with the | 53 | /* Whether or not to synchronize and call `updateIC' with the |
| @@ -77,15 +86,18 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 77 | extractAbsoluteOffsets = true; | 86 | extractAbsoluteOffsets = true; |
| 78 | }; | 87 | }; |
| 79 | 88 | ||
| 89 | |||
| 80 | public | 90 | public |
| 81 | EmacsInputConnection (EmacsView view) | 91 | EmacsInputConnection (EmacsView view) |
| 82 | { | 92 | { |
| 83 | super (view, true); | ||
| 84 | |||
| 85 | this.view = view; | 93 | this.view = view; |
| 86 | this.windowHandle = view.window.handle; | 94 | this.windowHandle = view.window.handle; |
| 87 | } | 95 | } |
| 88 | 96 | ||
| 97 | |||
| 98 | /* The functions below are called by input methods whenever they | ||
| 99 | need to perform an edit. */ | ||
| 100 | |||
| 89 | @Override | 101 | @Override |
| 90 | public boolean | 102 | public boolean |
| 91 | beginBatchEdit () | 103 | beginBatchEdit () |
| @@ -116,7 +128,6 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 116 | return true; | 128 | return true; |
| 117 | } | 129 | } |
| 118 | 130 | ||
| 119 | @Override | ||
| 120 | public boolean | 131 | public boolean |
| 121 | commitCompletion (CompletionInfo info) | 132 | commitCompletion (CompletionInfo info) |
| 122 | { | 133 | { |
| @@ -135,6 +146,19 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 135 | 146 | ||
| 136 | @Override | 147 | @Override |
| 137 | public boolean | 148 | public boolean |
| 149 | commitCorrection (CorrectionInfo info) | ||
| 150 | { | ||
| 151 | /* The input method calls this function not to commit text, but to | ||
| 152 | indicate that a subsequent edit will consist of a correction. | ||
| 153 | Emacs has no use for this information. | ||
| 154 | |||
| 155 | Of course this completely contradicts the provided | ||
| 156 | documentation, but this is how Android actually behaves. */ | ||
| 157 | return false; | ||
| 158 | } | ||
| 159 | |||
| 160 | @Override | ||
| 161 | public boolean | ||
| 138 | commitText (CharSequence text, int newCursorPosition) | 162 | commitText (CharSequence text, int newCursorPosition) |
| 139 | { | 163 | { |
| 140 | int[] selection; | 164 | int[] selection; |
| @@ -172,6 +196,14 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 172 | 196 | ||
| 173 | @Override | 197 | @Override |
| 174 | public boolean | 198 | public boolean |
| 199 | commitText (CharSequence text, int newCursorPosition, | ||
| 200 | TextAttribute textAttribute) | ||
| 201 | { | ||
| 202 | return commitText (text, newCursorPosition); | ||
| 203 | } | ||
| 204 | |||
| 205 | @Override | ||
| 206 | public boolean | ||
| 175 | deleteSurroundingText (int leftLength, int rightLength) | 207 | deleteSurroundingText (int leftLength, int rightLength) |
| 176 | { | 208 | { |
| 177 | /* Return if the input connection is out of date. */ | 209 | /* Return if the input connection is out of date. */ |
| @@ -189,6 +221,16 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 189 | 221 | ||
| 190 | @Override | 222 | @Override |
| 191 | public boolean | 223 | public boolean |
| 224 | deleteSurroundingTextInCodePoints (int leftLength, int rightLength) | ||
| 225 | { | ||
| 226 | /* Emacs returns characters which cannot be represented in a Java | ||
| 227 | `char' as NULL characters, so code points always reflect | ||
| 228 | characters themselves. */ | ||
| 229 | return deleteSurroundingText (leftLength, rightLength); | ||
| 230 | } | ||
| 231 | |||
| 232 | @Override | ||
| 233 | public boolean | ||
| 192 | finishComposingText () | 234 | finishComposingText () |
| 193 | { | 235 | { |
| 194 | /* Return if the input connection is out of date. */ | 236 | /* Return if the input connection is out of date. */ |
| @@ -279,6 +321,14 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 279 | 321 | ||
| 280 | @Override | 322 | @Override |
| 281 | public boolean | 323 | public boolean |
| 324 | setComposingText (CharSequence text, int newCursorPosition, | ||
| 325 | TextAttribute textAttribute) | ||
| 326 | { | ||
| 327 | return setComposingText (text, newCursorPosition); | ||
| 328 | } | ||
| 329 | |||
| 330 | @Override | ||
| 331 | public boolean | ||
| 282 | setComposingRegion (int start, int end) | 332 | setComposingRegion (int start, int end) |
| 283 | { | 333 | { |
| 284 | /* Return if the input connection is out of date. */ | 334 | /* Return if the input connection is out of date. */ |
| @@ -294,6 +344,13 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 294 | 344 | ||
| 295 | @Override | 345 | @Override |
| 296 | public boolean | 346 | public boolean |
| 347 | setComposingRegion (int start, int end, TextAttribute textAttribute) | ||
| 348 | { | ||
| 349 | return setComposingRegion (start, end); | ||
| 350 | } | ||
| 351 | |||
| 352 | @Override | ||
| 353 | public boolean | ||
| 297 | performEditorAction (int editorAction) | 354 | performEditorAction (int editorAction) |
| 298 | { | 355 | { |
| 299 | /* Return if the input connection is out of date. */ | 356 | /* Return if the input connection is out of date. */ |
| @@ -430,6 +487,8 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 430 | } | 487 | } |
| 431 | 488 | ||
| 432 | @Override | 489 | @Override |
| 490 | /* ACTION_MULTIPLE is apparently obsolete. */ | ||
| 491 | @SuppressWarnings ("deprecation") | ||
| 433 | public boolean | 492 | public boolean |
| 434 | sendKeyEvent (KeyEvent key) | 493 | sendKeyEvent (KeyEvent key) |
| 435 | { | 494 | { |
| @@ -440,20 +499,33 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 440 | if (EmacsService.DEBUG_IC) | 499 | if (EmacsService.DEBUG_IC) |
| 441 | Log.d (TAG, "sendKeyEvent: " + key); | 500 | Log.d (TAG, "sendKeyEvent: " + key); |
| 442 | 501 | ||
| 443 | return super.sendKeyEvent (key); | 502 | /* Use the standard API if possible. */ |
| 444 | } | ||
| 445 | 503 | ||
| 446 | @Override | 504 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) |
| 447 | public boolean | 505 | view.imManager.dispatchKeyEventFromInputMethod (view, key); |
| 448 | deleteSurroundingTextInCodePoints (int beforeLength, int afterLength) | 506 | else |
| 449 | { | 507 | { |
| 450 | /* Return if the input connection is out of date. */ | 508 | /* Fall back to dispatching the event manually if not. */ |
| 451 | if (view.icSerial < view.icGeneration) | 509 | |
| 452 | return false; | 510 | switch (key.getAction ()) |
| 511 | { | ||
| 512 | case KeyEvent.ACTION_DOWN: | ||
| 513 | view.onKeyDown (key.getKeyCode (), key); | ||
| 514 | break; | ||
| 515 | |||
| 516 | case KeyEvent.ACTION_UP: | ||
| 517 | view.onKeyUp (key.getKeyCode (), key); | ||
| 518 | break; | ||
| 519 | |||
| 520 | case KeyEvent.ACTION_MULTIPLE: | ||
| 521 | view.onKeyMultiple (key.getKeyCode (), | ||
| 522 | key.getRepeatCount (), | ||
| 523 | key); | ||
| 524 | break; | ||
| 525 | } | ||
| 526 | } | ||
| 453 | 527 | ||
| 454 | /* This can be implemented the same way as | 528 | return true; |
| 455 | deleteSurroundingText. */ | ||
| 456 | return this.deleteSurroundingText (beforeLength, afterLength); | ||
| 457 | } | 529 | } |
| 458 | 530 | ||
| 459 | @Override | 531 | @Override |
| @@ -472,6 +544,16 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 472 | } | 544 | } |
| 473 | 545 | ||
| 474 | @Override | 546 | @Override |
| 547 | public boolean | ||
| 548 | requestCursorUpdates (int cursorUpdateMode, int filter) | ||
| 549 | { | ||
| 550 | if (filter != 0) | ||
| 551 | return false; | ||
| 552 | |||
| 553 | return requestCursorUpdates (cursorUpdateMode); | ||
| 554 | } | ||
| 555 | |||
| 556 | @Override | ||
| 475 | public SurroundingText | 557 | public SurroundingText |
| 476 | getSurroundingText (int beforeLength, int afterLength, | 558 | getSurroundingText (int beforeLength, int afterLength, |
| 477 | int flags) | 559 | int flags) |
| @@ -506,10 +588,73 @@ public final class EmacsInputConnection extends BaseInputConnection | |||
| 506 | /* Override functions which are not implemented. */ | 588 | /* Override functions which are not implemented. */ |
| 507 | 589 | ||
| 508 | @Override | 590 | @Override |
| 591 | public Handler | ||
| 592 | getHandler () | ||
| 593 | { | ||
| 594 | return null; | ||
| 595 | } | ||
| 596 | |||
| 597 | @Override | ||
| 598 | public void | ||
| 599 | closeConnection () | ||
| 600 | { | ||
| 601 | |||
| 602 | } | ||
| 603 | |||
| 604 | @Override | ||
| 605 | public boolean | ||
| 606 | commitContent (InputContentInfo inputContentInfo, int flags, | ||
| 607 | Bundle opts) | ||
| 608 | { | ||
| 609 | return false; | ||
| 610 | } | ||
| 611 | |||
| 612 | @Override | ||
| 613 | public boolean | ||
| 614 | setImeConsumesInput (boolean imeConsumesInput) | ||
| 615 | { | ||
| 616 | return false; | ||
| 617 | } | ||
| 618 | |||
| 619 | @Override | ||
| 509 | public TextSnapshot | 620 | public TextSnapshot |
| 510 | takeSnapshot () | 621 | takeSnapshot () |
| 511 | { | 622 | { |
| 512 | Log.d (TAG, "takeSnapshot"); | ||
| 513 | return null; | 623 | return null; |
| 514 | } | 624 | } |
| 625 | |||
| 626 | @Override | ||
| 627 | public boolean | ||
| 628 | clearMetaKeyStates (int states) | ||
| 629 | { | ||
| 630 | return false; | ||
| 631 | } | ||
| 632 | |||
| 633 | @Override | ||
| 634 | public boolean | ||
| 635 | reportFullscreenMode (boolean enabled) | ||
| 636 | { | ||
| 637 | return false; | ||
| 638 | } | ||
| 639 | |||
| 640 | @Override | ||
| 641 | public boolean | ||
| 642 | performSpellCheck () | ||
| 643 | { | ||
| 644 | return false; | ||
| 645 | } | ||
| 646 | |||
| 647 | @Override | ||
| 648 | public boolean | ||
| 649 | performPrivateCommand (String action, Bundle data) | ||
| 650 | { | ||
| 651 | return false; | ||
| 652 | } | ||
| 653 | |||
| 654 | @Override | ||
| 655 | public int | ||
| 656 | getCursorCapsMode (int reqModes) | ||
| 657 | { | ||
| 658 | return 0; | ||
| 659 | } | ||
| 515 | } | 660 | } |