diff options
| author | Po Lu | 2024-03-02 14:04:56 +0800 |
|---|---|---|
| committer | Po Lu | 2024-03-02 14:04:56 +0800 |
| commit | 5e20b114ef32d504f4429fd35ecd0d5dcf3bd8db (patch) | |
| tree | 83215f4df69308e61c490172f4a68ff0fea63452 /src/android.c | |
| parent | 8b96503b6e8514f1f9f92895a0707c78b1bbd1fd (diff) | |
| download | emacs-5e20b114ef32d504f4429fd35ecd0d5dcf3bd8db.tar.gz emacs-5e20b114ef32d504f4429fd35ecd0d5dcf3bd8db.zip | |
Implement dead key combination on Android
* src/android.c (android_init_key_character_map)
(android_get_dead_char): New functions.
(android_wc_lookup_string): New argument COMPOSE_STATE. Ignore
key events with the COMBINING_ACCENT flag set while recording
their character values there, and combine such characters with
the key event when processing a subsequent key event.
* src/androidgui.h (struct android_compose_status): New
structure.
* src/androidterm.c (handle_one_android_event): Port dead key
combination code from X. (bug#69321)
Diffstat (limited to 'src/android.c')
| -rw-r--r-- | src/android.c | 122 |
1 files changed, 119 insertions, 3 deletions
diff --git a/src/android.c b/src/android.c index 41481afa475..eb6981093be 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -123,6 +123,12 @@ struct android_emacs_cursor | |||
| 123 | jmethodID constructor; | 123 | jmethodID constructor; |
| 124 | }; | 124 | }; |
| 125 | 125 | ||
| 126 | struct android_key_character_map | ||
| 127 | { | ||
| 128 | jclass class; | ||
| 129 | jmethodID get_dead_char; | ||
| 130 | }; | ||
| 131 | |||
| 126 | /* The API level of the current device. */ | 132 | /* The API level of the current device. */ |
| 127 | static int android_api_level; | 133 | static int android_api_level; |
| 128 | 134 | ||
| @@ -203,6 +209,9 @@ static struct android_emacs_window window_class; | |||
| 203 | /* Various methods associated with the EmacsCursor class. */ | 209 | /* Various methods associated with the EmacsCursor class. */ |
| 204 | static struct android_emacs_cursor cursor_class; | 210 | static struct android_emacs_cursor cursor_class; |
| 205 | 211 | ||
| 212 | /* Various methods associated with the KeyCharacterMap class. */ | ||
| 213 | static struct android_key_character_map key_character_map_class; | ||
| 214 | |||
| 206 | /* The time at which Emacs was installed, which also supplies the | 215 | /* The time at which Emacs was installed, which also supplies the |
| 207 | mtime of asset files. */ | 216 | mtime of asset files. */ |
| 208 | struct timespec emacs_installation_time; | 217 | struct timespec emacs_installation_time; |
| @@ -1865,6 +1874,32 @@ android_init_emacs_cursor (void) | |||
| 1865 | #undef FIND_METHOD | 1874 | #undef FIND_METHOD |
| 1866 | } | 1875 | } |
| 1867 | 1876 | ||
| 1877 | static void | ||
| 1878 | android_init_key_character_map (void) | ||
| 1879 | { | ||
| 1880 | jclass old; | ||
| 1881 | |||
| 1882 | key_character_map_class.class | ||
| 1883 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1884 | "android/view/KeyCharacterMap"); | ||
| 1885 | eassert (key_character_map_class.class); | ||
| 1886 | |||
| 1887 | old = key_character_map_class.class; | ||
| 1888 | key_character_map_class.class | ||
| 1889 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1890 | (jobject) old); | ||
| 1891 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1892 | |||
| 1893 | if (!key_character_map_class.class) | ||
| 1894 | emacs_abort (); | ||
| 1895 | |||
| 1896 | key_character_map_class.get_dead_char | ||
| 1897 | = (*android_java_env)->GetStaticMethodID (android_java_env, | ||
| 1898 | key_character_map_class.class, | ||
| 1899 | "getDeadChar", "(II)I"); | ||
| 1900 | eassert (key_character_map_class.get_dead_char); | ||
| 1901 | } | ||
| 1902 | |||
| 1868 | JNIEXPORT void JNICALL | 1903 | JNIEXPORT void JNICALL |
| 1869 | NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, | 1904 | NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, |
| 1870 | jobject dump_file_object) | 1905 | jobject dump_file_object) |
| @@ -1913,6 +1948,7 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, | |||
| 1913 | android_init_emacs_drawable (); | 1948 | android_init_emacs_drawable (); |
| 1914 | android_init_emacs_window (); | 1949 | android_init_emacs_window (); |
| 1915 | android_init_emacs_cursor (); | 1950 | android_init_emacs_cursor (); |
| 1951 | android_init_key_character_map (); | ||
| 1916 | 1952 | ||
| 1917 | /* Set HOME to the app data directory. */ | 1953 | /* Set HOME to the app data directory. */ |
| 1918 | setenv ("HOME", android_files_dir, 1); | 1954 | setenv ("HOME", android_files_dir, 1); |
| @@ -5376,11 +5412,51 @@ android_translate_coordinates (android_window src, int x, | |||
| 5376 | ANDROID_DELETE_LOCAL_REF (coordinates); | 5412 | ANDROID_DELETE_LOCAL_REF (coordinates); |
| 5377 | } | 5413 | } |
| 5378 | 5414 | ||
| 5415 | /* Return the character produced by combining the diacritic character | ||
| 5416 | DCHAR with the key-producing character C in *VALUE. Value is 1 if | ||
| 5417 | there is no character for this combination, 0 otherwise. */ | ||
| 5418 | |||
| 5419 | static int | ||
| 5420 | android_get_dead_char (unsigned int dchar, unsigned int c, | ||
| 5421 | unsigned int *value) | ||
| 5422 | { | ||
| 5423 | jmethodID method; | ||
| 5424 | jclass class; | ||
| 5425 | jint result; | ||
| 5426 | |||
| 5427 | /* Call getDeadChar. */ | ||
| 5428 | class = key_character_map_class.class; | ||
| 5429 | method = key_character_map_class.get_dead_char; | ||
| 5430 | result = (*android_java_env)->CallStaticIntMethod (android_java_env, | ||
| 5431 | class, method, | ||
| 5432 | (jint) dchar, | ||
| 5433 | (jint) c); | ||
| 5434 | |||
| 5435 | if (result) | ||
| 5436 | { | ||
| 5437 | *value = result; | ||
| 5438 | return 0; | ||
| 5439 | } | ||
| 5440 | |||
| 5441 | return 1; | ||
| 5442 | } | ||
| 5443 | |||
| 5444 | /* Return a Unicode string in BUFFER_RETURN, a buffer of size | ||
| 5445 | WCHARS_BUFFER, from the key press event EVENT, much like | ||
| 5446 | XmbLookupString. If EVENT represents a key press without a | ||
| 5447 | corresponding Unicode character, return its keysym in *KEYSYM_RETURN. | ||
| 5448 | Return the action taken in *STATUS_RETURN. | ||
| 5449 | |||
| 5450 | COMPOSE_STATUS, if non-NULL, should point to a structure for | ||
| 5451 | temporary information to be stored in during dead key | ||
| 5452 | composition. */ | ||
| 5453 | |||
| 5379 | int | 5454 | int |
| 5380 | android_wc_lookup_string (android_key_pressed_event *event, | 5455 | android_wc_lookup_string (android_key_pressed_event *event, |
| 5381 | wchar_t *buffer_return, int wchars_buffer, | 5456 | wchar_t *buffer_return, int wchars_buffer, |
| 5382 | int *keysym_return, | 5457 | int *keysym_return, |
| 5383 | enum android_lookup_status *status_return) | 5458 | enum android_lookup_status *status_return, |
| 5459 | struct android_compose_status *compose_status) | ||
| 5384 | { | 5460 | { |
| 5385 | enum android_lookup_status status; | 5461 | enum android_lookup_status status; |
| 5386 | int rc; | 5462 | int rc; |
| @@ -5389,6 +5465,7 @@ android_wc_lookup_string (android_key_pressed_event *event, | |||
| 5389 | jsize size; | 5465 | jsize size; |
| 5390 | size_t i; | 5466 | size_t i; |
| 5391 | JNIEnv *env; | 5467 | JNIEnv *env; |
| 5468 | unsigned int unicode_char; | ||
| 5392 | 5469 | ||
| 5393 | env = android_java_env; | 5470 | env = android_java_env; |
| 5394 | status = ANDROID_LOOKUP_NONE; | 5471 | status = ANDROID_LOOKUP_NONE; |
| @@ -5402,6 +5479,13 @@ android_wc_lookup_string (android_key_pressed_event *event, | |||
| 5402 | { | 5479 | { |
| 5403 | if (event->unicode_char) | 5480 | if (event->unicode_char) |
| 5404 | { | 5481 | { |
| 5482 | /* KeyCharacterMap.COMBINING_ACCENT. */ | ||
| 5483 | if ((event->unicode_char & 0x80000000) && compose_status) | ||
| 5484 | goto dead_key; | ||
| 5485 | |||
| 5486 | /* Remove combining accent bits. */ | ||
| 5487 | unicode_char = event->unicode_char & ~0x80000000; | ||
| 5488 | |||
| 5405 | if (wchars_buffer < 1) | 5489 | if (wchars_buffer < 1) |
| 5406 | { | 5490 | { |
| 5407 | *status_return = ANDROID_BUFFER_OVERFLOW; | 5491 | *status_return = ANDROID_BUFFER_OVERFLOW; |
| @@ -5409,7 +5493,31 @@ android_wc_lookup_string (android_key_pressed_event *event, | |||
| 5409 | } | 5493 | } |
| 5410 | else | 5494 | else |
| 5411 | { | 5495 | { |
| 5412 | buffer_return[0] = event->unicode_char; | 5496 | /* If COMPOSE_STATUS holds a diacritic mark unicode_char |
| 5497 | ought to be combined with, and this combination is | ||
| 5498 | valid, return the result alone with no keysym. */ | ||
| 5499 | |||
| 5500 | if (compose_status | ||
| 5501 | && compose_status->chars_matched | ||
| 5502 | && !android_get_dead_char (compose_status->accent, | ||
| 5503 | unicode_char, | ||
| 5504 | &unicode_char)) | ||
| 5505 | { | ||
| 5506 | buffer_return[0] = unicode_char; | ||
| 5507 | *status_return = ANDROID_LOOKUP_CHARS; | ||
| 5508 | compose_status->chars_matched = 0; | ||
| 5509 | return 1; | ||
| 5510 | } | ||
| 5511 | else if (compose_status && compose_status->chars_matched) | ||
| 5512 | { | ||
| 5513 | /* If the combination is valid the compose status must | ||
| 5514 | be reset and no character returned. */ | ||
| 5515 | compose_status->chars_matched = 0; | ||
| 5516 | status = ANDROID_LOOKUP_NONE; | ||
| 5517 | return 0; | ||
| 5518 | } | ||
| 5519 | |||
| 5520 | buffer_return[0] = unicode_char; | ||
| 5413 | status = ANDROID_LOOKUP_CHARS; | 5521 | status = ANDROID_LOOKUP_CHARS; |
| 5414 | rc = 1; | 5522 | rc = 1; |
| 5415 | } | 5523 | } |
| @@ -5426,7 +5534,6 @@ android_wc_lookup_string (android_key_pressed_event *event, | |||
| 5426 | } | 5534 | } |
| 5427 | 5535 | ||
| 5428 | *status_return = status; | 5536 | *status_return = status; |
| 5429 | |||
| 5430 | return rc; | 5537 | return rc; |
| 5431 | } | 5538 | } |
| 5432 | 5539 | ||
| @@ -5482,6 +5589,15 @@ android_wc_lookup_string (android_key_pressed_event *event, | |||
| 5482 | 5589 | ||
| 5483 | *status_return = status; | 5590 | *status_return = status; |
| 5484 | return rc; | 5591 | return rc; |
| 5592 | |||
| 5593 | dead_key: | ||
| 5594 | /* event->unicode_char is a dead key, which are diacritic marks that | ||
| 5595 | should not be directly inserted but instead be combined with a | ||
| 5596 | subsequent character before insertion. */ | ||
| 5597 | *status_return = ANDROID_LOOKUP_NONE; | ||
| 5598 | compose_status->chars_matched = 1; | ||
| 5599 | compose_status->accent = event->unicode_char & ~0x80000000; | ||
| 5600 | return 0; | ||
| 5485 | } | 5601 | } |
| 5486 | 5602 | ||
| 5487 | 5603 | ||