Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion android-activity/src/game_activity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ use crate::input::{Axis, KeyCharacterMap, KeyCharacterMapBinding};
use crate::jni_utils::{self, CloneJavaVM};
use crate::util::{abort_on_panic, forward_stdio_to_logcat, log_panic, try_get_path_from_ptr};
use crate::{
AndroidApp, ConfigurationRef, InputStatus, MainEvent, PollEvent, Rect, WindowManagerFlags,
AndroidApp, ConfigurationRef, ImeOptions, InputStatus, InputType, MainEvent, PollEvent, Rect,
WindowManagerFlags,
};

mod ffi;
Expand Down Expand Up @@ -206,6 +207,22 @@ impl NativeAppGlue {
}
}

pub fn set_ime_editor_info(&self, input_type: InputType, options: ImeOptions) {
unsafe {
let activity = (*self.as_ptr()).activity;
let action_id = 0; // IME_ACTION_UNSPECIFIED
// (https://developer.android.com/reference/android/view/inputmethod/EditorInfo#IME_ACTION_DONE)
// TODO: expose this later?

ffi::GameActivity_setImeEditorInfo(
activity,
input_type.bits(),
action_id,
options.bits(),
);
}
}

// TODO: move into a trait
pub fn set_text_input_state(&self, state: TextInputState) {
unsafe {
Expand Down Expand Up @@ -521,6 +538,10 @@ impl AndroidAppInner {
self.native_app.set_text_input_state(state);
}

pub fn set_ime_editor_info(&self, input_type: InputType, options: ImeOptions) {
self.native_app.set_ime_editor_info(input_type, options);
}

pub(crate) fn device_key_character_map(
&self,
device_id: i32,
Expand Down
224 changes: 224 additions & 0 deletions android-activity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,222 @@ pub enum InputStatus {
use activity_impl::AndroidAppInner;
pub use activity_impl::AndroidAppWaker;

bitflags! {
/// Flags for [`AndroidApp::set_ime_editor_info`]
/// as per the [android.view.inputmethod.EditorInfo Java API](https://developer.android.com/reference/android/view/inputmethod/EditorInfo)
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ImeOptions: u32 {
/// If this flag is not set, IMEs will normally replace the "enter" key with the action
/// supplied. This flag indicates that the action should not be available in-line as a
/// replacement for the "enter" key. Typically this is because the action has such a
/// significant impact or is not recoverable enough that accidentally hitting it should be
/// avoided, such as sending a message.
const IME_FLAG_NO_ENTER_ACTION = 1073741824;

/// Generic unspecified type for ImeOptions
const IME_NULL = 0;

// TODO: remaining ime flags
}
}

bitflags! {
/// Flags for [`AndroidApp::set_ime_editor_info`]
/// as per the [android.view.inputmethod.EditorInfo Java API](https://developer.android.com/reference/android/view/inputmethod/EditorInfo)
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct InputType: u32 {
/// Mask of bits that determine the overall class of text being given. Currently
/// supported classes are: TYPE_CLASS_TEXT, TYPE_CLASS_NUMBER, TYPE_CLASS_PHONE,
/// TYPE_CLASS_DATETIME. IME authors: If the class is not one you understand, assume
/// TYPE_CLASS_TEXT with NO variation or flags.
const TYPE_MASK_CLASS = 15;

/// Mask of bits that determine the variation of the base content class.
const TYPE_MASK_VARIATION = 4080;

/// Mask of bits that provide addition bit flags of options.
const TYPE_MASK_FLAGS = 16773120;

/// Special content type for when no explicit type has been specified. This should be
/// interpreted to mean that the target input connection is not rich, it can not process
/// and show things like candidate text nor retrieve the current text, so the input
/// method will need to run in a limited "generate key events" mode, if it supports
/// it. Note that some input methods may not support it, for example a voice-based
/// input method will likely not be able to generate key events even if this flag is
/// set.
const TYPE_NULL = 0;

/// Class for normal text. This class supports the following flags (only one of which
/// should be set): TYPE_TEXT_FLAG_CAP_CHARACTERS, TYPE_TEXT_FLAG_CAP_WORDS, and.
/// TYPE_TEXT_FLAG_CAP_SENTENCES. It also supports the following variations:
/// TYPE_TEXT_VARIATION_NORMAL, and TYPE_TEXT_VARIATION_URI. If you do not recognize the
/// variation, normal should be assumed.
const TYPE_CLASS_TEXT = 1;

/// Flag for TYPE_CLASS_TEXT: capitalize all characters. Overrides
/// #TYPE_TEXT_FLAG_CAP_WORDS} and #TYPE_TEXT_FLAG_CAP_SENTENCES}. This value is
/// explicitly defined to be the same as TextUtils#CAP_MODE_CHARACTERS}. Of
/// course, this only affects languages where there are upper-case and lower-case
/// letters.
const TYPE_TEXT_FLAG_CAP_CHARACTERS = 4096;

/// Flag for TYPE_CLASS_TEXT: capitalize the first character of every word.
/// Overrides TYPE_TEXT_FLAG_CAP_SENTENCES. This value is explicitly defined
/// to be the same as TextUtils#CAP_MODE_WORDS. Of course, this only affects
/// languages where there are upper-case and lower-case letters.
const TYPE_TEXT_FLAG_CAP_WORDS = 8192;

/// Flag for TYPE_CLASS_TEXT: capitalize the first character of each sentence. This value
/// is explicitly defined to be the same as TextUtils#CAP_MODE_SENTENCES. For example in
/// English it means to capitalize after a period and a space (note that other languages
/// may have different characters for period, or not use spaces, or use different
/// grammatical rules). Of course, this only affects languages where there are upper-case
/// and lower-case letters.
const TYPE_TEXT_FLAG_CAP_SENTENCES = 16384;

/// Flag for TYPE_CLASS_TEXT: the user is entering free-form text that should have
/// auto-correction applied to it. Without this flag, the IME will not try to correct
/// typos. You should always set this flag unless you really expect users to type
/// non-words in this field, for example to choose a name for a character in a game.
/// Contrast this with TYPE_TEXT_FLAG_AUTO_COMPLETE and TYPE_TEXT_FLAG_NO_SUGGESTIONS:
/// TYPE_TEXT_FLAG_AUTO_CORRECT means that the IME will try to auto-correct typos as the
/// user is typing, but does not define whether the IME offers an interface to show
/// suggestions.
const TYPE_TEXT_FLAG_AUTO_CORRECT = 32768;

/// Flag for TYPE_CLASS_TEXT: the text editor (which means the application) is performing
/// auto-completion of the text being entered based on its own semantics, which it will
/// present to the user as they type. This generally means that the input method should
/// not be showing candidates itself, but can expect the editor to supply its own
/// completions/candidates from
/// android.view.inputmethod.InputMethodSession#displayCompletions
/// InputMethodSession.displayCompletions()} as a result of the editor calling
/// android.view.inputmethod.InputMethodManager#displayCompletions
/// InputMethodManager.displayCompletions()}. Note the contrast with
/// TYPE_TEXT_FLAG_AUTO_CORRECT and TYPE_TEXT_FLAG_NO_SUGGESTIONS:
/// TYPE_TEXT_FLAG_AUTO_COMPLETE means the editor should show an interface for displaying
/// suggestions, but instead of supplying its own it will rely on the Editor to pass
/// completions/corrections.
const TYPE_TEXT_FLAG_AUTO_COMPLETE = 65536;

/// Flag for TYPE_CLASS_TEXT: multiple lines of text can be entered into the
/// field. If this flag is not set, the text field will be constrained to a single
/// line. The IME may also choose not to display an enter key when this flag is not set,
/// as there should be no need to create new lines.
const TYPE_TEXT_FLAG_MULTI_LINE = 131072;

/// Flag for TYPE_CLASS_TEXT: the regular text view associated with this should
/// not be multi-line, but when a fullscreen input method is providing text it should
/// use multiple lines if it can.
const TYPE_TEXT_FLAG_IME_MULTI_LINE = 262144;

/// Flag for TYPE_CLASS_TEXT: the input method does not need to display any
/// dictionary-based candidates. This is useful for text views that do not contain words
/// from the language and do not benefit from any dictionary-based completions or
/// corrections. It overrides the TYPE_TEXT_FLAG_AUTO_CORRECT value when set. Please
/// avoid using this unless you are certain this is what you want. Many input methods need
/// suggestions to work well, for example the ones based on gesture typing. Consider
/// clearing TYPE_TEXT_FLAG_AUTO_CORRECT instead if you just do not want the IME to
/// correct typos. Note the contrast with TYPE_TEXT_FLAG_AUTO_CORRECT and
/// TYPE_TEXT_FLAG_AUTO_COMPLETE: TYPE_TEXT_FLAG_NO_SUGGESTIONS means the IME does not
/// need to show an interface to display suggestions. Most IMEs will also take this to
/// mean they do not need to try to auto-correct what the user is typing.
const TYPE_TEXT_FLAG_NO_SUGGESTIONS = 524288;

/// Flag for TYPE_CLASS_TEXT: Let the IME know the text conversion suggestions are
/// required by the application. Text conversion suggestion is for the transliteration
/// languages which has pronunciation characters and target characters. When the user is
/// typing the pronunciation charactes, the IME could provide the possible target
/// characters to the user. When this flag is set, the IME should insert the text
/// conversion suggestions through Builder#setTextConversionSuggestions(List)} and the
/// TextAttribute} with initialized with the text conversion suggestions is provided by
/// the IME to the application. To receive the additional information, the application
/// needs to implement InputConnection#setComposingText(CharSequence, int,
/// TextAttribute)}, InputConnection#setComposingRegion(int, int, TextAttribute)}, and
/// InputConnection#commitText(CharSequence, int, TextAttribute)}.
const TYPE_TEXT_FLAG_ENABLE_TEXT_CONVERSION_SUGGESTIONS = 1048576;
/// Default variation of TYPE_CLASS_TEXT: plain old normal text.
const TYPE_TEXT_VARIATION_NORMAL = 0;
/// Variation of TYPE_CLASS_TEXT: entering a URI.
const TYPE_TEXT_VARIATION_URI = 16;
/// Variation of TYPE_CLASS_TEXT: entering an e-mail address.
const TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 32;
/// Variation of TYPE_CLASS_TEXT: entering the subject line of an e-mail.
const TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 48;
/// Variation of TYPE_CLASS_TEXT: entering a short, possibly informal message such as an instant message or a text message.
const TYPE_TEXT_VARIATION_SHORT_MESSAGE = 64;
/// Variation of TYPE_CLASS_TEXT: entering the content of a long, possibly formal message such as the body of an e-mail.
const TYPE_TEXT_VARIATION_LONG_MESSAGE = 80;
/// Variation of TYPE_CLASS_TEXT: entering the name of a person.
const TYPE_TEXT_VARIATION_PERSON_NAME = 96;
/// Variation of TYPE_CLASS_TEXT: entering a postal mailing address.
const TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 112;
/// Variation of TYPE_CLASS_TEXT: entering a password.
const TYPE_TEXT_VARIATION_PASSWORD = 128;
/// Variation of TYPE_CLASS_TEXT: entering a password, which should be visible to the user.
const TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 144;
/// Variation of TYPE_CLASS_TEXT: entering text inside of a web form.
const TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 160;
/// Variation of TYPE_CLASS_TEXT: entering text to filter contents of a list etc.
const TYPE_TEXT_VARIATION_FILTER = 176;
/// Variation of TYPE_CLASS_TEXT: entering text for phonetic pronunciation, such as a
/// phonetic name field in contacts. This is mostly useful for languages where one
/// spelling may have several phonetic readings, like Japanese.
const TYPE_TEXT_VARIATION_PHONETIC = 192;
/// Variation of TYPE_CLASS_TEXT: entering e-mail address inside of a web form. This
/// was added in android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target this API
/// version or later to see this input type; if it doesn't, a request for this type will
/// be seen as #TYPE_TEXT_VARIATION_EMAIL_ADDRESS} when passed through
/// android.view.inputmethod.EditorInfo#makeCompatible(int)
/// EditorInfo.makeCompatible(int)}.
const TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 208;
/// Variation of TYPE_CLASS_TEXT: entering password inside of a web form. This was
/// added in android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target this API
/// version or later to see this input type; if it doesn't, a request for this type will
/// be seen as #TYPE_TEXT_VARIATION_PASSWORD} when passed through
/// android.view.inputmethod.EditorInfo#makeCompatible(int)
/// EditorInfo.makeCompatible(int)}.
const TYPE_TEXT_VARIATION_WEB_PASSWORD = 224;
/// Class for numeric text. This class supports the following flags:
/// #TYPE_NUMBER_FLAG_SIGNED} and #TYPE_NUMBER_FLAG_DECIMAL}. It also supports the
/// following variations: #TYPE_NUMBER_VARIATION_NORMAL} and
/// #TYPE_NUMBER_VARIATION_PASSWORD}. <p>IME authors: If you do not recognize the
/// variation, normal should be assumed.</p>
const TYPE_CLASS_NUMBER = 2;
/// Flag of TYPE_CLASS_NUMBER: the number is signed, allowing a positive or negative
/// sign at the start.
const TYPE_NUMBER_FLAG_SIGNED = 4096;
/// Flag of TYPE_CLASS_NUMBER: the number is decimal, allowing a decimal point to
/// provide fractional values.
const TYPE_NUMBER_FLAG_DECIMAL = 8192;
/// Default variation of TYPE_CLASS_NUMBER: plain normal numeric text. This was added
/// in android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target this API version or
/// later to see this input type; if it doesn't, a request for this type will be dropped
/// when passed through android.view.inputmethod.EditorInfo#makeCompatible(int)
/// EditorInfo.makeCompatible(int)}.
const TYPE_NUMBER_VARIATION_NORMAL = 0;
/// Variation of TYPE_CLASS_NUMBER: entering a numeric password. This was added in
/// android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target this API version or
/// later to see this input type; if it doesn't, a request for this type will be dropped
/// when passed through android.view.inputmethod.EditorInfo#makeCompatible(int)
/// EditorInfo.makeCompatible(int)}.
const TYPE_NUMBER_VARIATION_PASSWORD = 16;
/// Class for a phone number. This class currently supports no variations or flags.
const TYPE_CLASS_PHONE = 3;
/// Class for dates and times. It supports the following variations:
/// #TYPE_DATETIME_VARIATION_NORMAL} #TYPE_DATETIME_VARIATION_DATE}, and
/// #TYPE_DATETIME_VARIATION_TIME}.
const TYPE_CLASS_DATETIME = 4;
/// Default variation of #TYPE_CLASS_DATETIME}: allows entering both a date and time.
const TYPE_DATETIME_VARIATION_NORMAL = 0;
/// Default variation of #TYPE_CLASS_DATETIME}: allows entering only a date.
const TYPE_DATETIME_VARIATION_DATE = 16;
/// Default variation of #TYPE_CLASS_DATETIME}: allows entering only a time.
const TYPE_DATETIME_VARIATION_TIME = 32;

}
}

bitflags! {
/// Flags for [`AndroidApp::set_window_flags`]
/// as per the [android.view.WindowManager.LayoutParams Java API](https://developer.android.com/reference/android/view/WindowManager.LayoutParams)
Expand Down Expand Up @@ -712,6 +928,14 @@ impl AndroidApp {
self.inner.read().unwrap().set_text_input_state(state);
}

/// Set IME editor flags
pub fn set_ime_editor_info(&self, input_type: InputType, options: ImeOptions) {
self.inner
.read()
.unwrap()
.set_ime_editor_info(input_type, options);
}

/// Get an exclusive, lending iterator over buffered input events
///
/// Applications are expected to call this in-sync with their rendering or
Expand Down
8 changes: 7 additions & 1 deletion android-activity/src/native_activity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use crate::input::{Axis, KeyCharacterMap, KeyCharacterMapBinding};
use crate::input::{TextInputState, TextSpan};
use crate::jni_utils::{self, CloneJavaVM};
use crate::{
util, AndroidApp, ConfigurationRef, InputStatus, MainEvent, PollEvent, Rect, WindowManagerFlags,
util, AndroidApp, ConfigurationRef, ImeOptions, InputStatus, InputType, MainEvent, PollEvent,
Rect, WindowManagerFlags,
};

pub mod input;
Expand Down Expand Up @@ -391,6 +392,11 @@ impl AndroidAppInner {
// NOP: Unsupported
}

// TODO: move into a trait
pub fn set_ime_editor_info(&self, _input_type: InputType, _options: ImeOptions) {
// NOP: Unsupported
}

pub fn device_key_character_map(&self, device_id: i32) -> InternalResult<KeyCharacterMap> {
let mut guard = self.key_maps.lock().unwrap();

Expand Down