1mod text_config;
16mod text_editor;
17
18pub use crate::text_config::{TextConfig, TextConfigBuilder, TextSelection};
19use crate::text_editor::DISPATCHER;
20use log::{error, warn};
21use ohos_ime_sys::attach_options::{
22 InputMethod_AttachOptions, OH_AttachOptions_Create, OH_AttachOptions_Destroy,
23 OH_AttachOptions_IsShowKeyboard,
24};
25use ohos_ime_sys::controller::{OH_InputMethodController_Attach, OH_InputMethodController_Detach};
26use ohos_ime_sys::inputmethod_proxy::{
27 InputMethod_InputMethodProxy, OH_InputMethodProxy_HideKeyboard,
28 OH_InputMethodProxy_ShowKeyboard,
29};
30use ohos_ime_sys::text_editor_proxy::{
31 InputMethod_TextEditorProxy, OH_TextEditorProxy_Create, OH_TextEditorProxy_Destroy,
32 OH_TextEditorProxy_SetDeleteBackwardFunc, OH_TextEditorProxy_SetDeleteForwardFunc,
33 OH_TextEditorProxy_SetFinishTextPreviewFunc, OH_TextEditorProxy_SetGetLeftTextOfCursorFunc,
34 OH_TextEditorProxy_SetGetRightTextOfCursorFunc, OH_TextEditorProxy_SetGetTextConfigFunc,
35 OH_TextEditorProxy_SetGetTextIndexAtCursorFunc, OH_TextEditorProxy_SetHandleExtendActionFunc,
36 OH_TextEditorProxy_SetHandleSetSelectionFunc, OH_TextEditorProxy_SetInsertTextFunc,
37 OH_TextEditorProxy_SetMoveCursorFunc, OH_TextEditorProxy_SetReceivePrivateCommandFunc,
38 OH_TextEditorProxy_SetSendEnterKeyFunc, OH_TextEditorProxy_SetSendKeyboardStatusFunc,
39 OH_TextEditorProxy_SetSetPreviewTextFunc,
40};
41use ohos_ime_sys::types::{
42 InputMethodErrorCode, InputMethodResult, InputMethod_EnterKeyType, InputMethod_KeyboardStatus,
43};
44use std::fmt::Debug;
45use std::ptr::NonNull;
46
47pub trait Ime: Send + Sync {
50 fn insert_text(&self, text: String);
52 fn delete_forward(&self, len: usize);
54
55 fn delete_backward(&self, len: usize);
57
58 fn get_text_config(&self) -> &TextConfig;
60
61 fn send_enter_key(&self, enter_key: InputMethod_EnterKeyType);
68
69 fn keyboard_status_changed(&self, status: KeyboardStatus) {
71 log::debug!("Keyboard status changed to {:?}", status);
72 }
73 }
75
76pub struct ImeProxy {
77 raw: NonNull<InputMethod_InputMethodProxy>,
78 #[allow(dead_code)]
80 editor: RawTextEditorProxy,
81}
82
83impl Drop for ImeProxy {
84 fn drop(&mut self) {
85 if let Err(e) = unsafe { OH_InputMethodController_Detach(self.raw.as_ptr()) } {
88 error!("IME: Detach failed for InputMethodController {:?}", e);
89 }
90 let res = DISPATCHER.unregister(self.editor.raw);
91 #[cfg(debug_assertions)]
92 if let Err(e) = res {
93 error!("IME: ImeProxy destroy failed {:?}", e);
94 }
95 #[cfg(not(debug_assertions))]
96 drop(res)
97 }
98}
99
100pub struct CreateImeProxyError {
101 pub editor: RawTextEditorProxy,
102 pub options: AttachOptions,
103 pub error_code: InputMethodErrorCode,
104}
105
106impl Debug for CreateImeProxyError {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 f.write_fmt(format_args!("InputMethodErrorCode: {:?}", self.error_code))
109 }
110}
111
112impl ImeProxy {
113 pub fn new(
115 editor: RawTextEditorProxy,
116 options: AttachOptions,
117 ) -> Result<Self, CreateImeProxyError> {
118 unsafe {
119 let mut ime_proxy: *mut InputMethod_InputMethodProxy = core::ptr::null_mut();
120 if let Err(error_code) = OH_InputMethodController_Attach(
121 editor.raw.as_ptr(),
122 options.raw.as_ptr(),
123 &raw mut ime_proxy,
124 ) {
125 return Err(CreateImeProxyError {
126 editor,
127 options,
128 error_code,
129 });
130 }
131
132 Ok(Self {
133 raw: NonNull::new(ime_proxy).expect("Wrong Errorcode"),
135 editor,
136 })
137 }
138 }
139
140 pub fn show_keyboard(&self) -> InputMethodResult {
141 unsafe { OH_InputMethodProxy_ShowKeyboard(self.raw.as_ptr()) }
142 }
143
144 pub fn hide_keyboard(&self) -> InputMethodResult {
145 unsafe { OH_InputMethodProxy_HideKeyboard(self.raw.as_ptr()) }
146 }
147}
148
149pub struct AttachOptions {
150 raw: NonNull<InputMethod_AttachOptions>,
151}
152
153pub enum KeyboardVisibility {
154 Hide,
155 Show,
156}
157
158impl AttachOptions {
159 pub fn new(show_keyboard: bool) -> Self {
160 let raw = unsafe {
163 let raw = OH_AttachOptions_Create(show_keyboard);
164 NonNull::new(raw).expect("OOM?")
165 };
166 Self { raw }
167 }
168
169 pub fn get_visibility(&self) -> KeyboardVisibility {
170 let mut show_keyboard: u8 = 0;
171 const _: () = assert!(size_of::<u8>() == size_of::<bool>());
172 unsafe {
176 let err =
177 OH_AttachOptions_IsShowKeyboard(self.raw.as_ptr(), (&raw mut show_keyboard).cast());
178 debug_assert!(err.is_ok());
181 if show_keyboard == 0 {
184 KeyboardVisibility::Hide
185 } else {
186 KeyboardVisibility::Show
187 }
188 }
189 }
190}
191
192impl Drop for AttachOptions {
193 fn drop(&mut self) {
194 unsafe {
197 OH_AttachOptions_Destroy(self.raw.as_ptr());
198 }
199 }
200}
201
202pub struct RawTextEditorProxy {
208 raw: NonNull<InputMethod_TextEditorProxy>,
209}
210
211#[derive(Debug)]
212pub enum CreateTextEditorProxyErrorKind {
213 CreateProxyFailed,
215 RegisterCallbacksFailed(InputMethodErrorCode),
217}
218pub struct CreateTextEditorProxyError {
219 pub ime: Box<dyn Ime>,
221 pub reason: CreateTextEditorProxyErrorKind,
222}
223
224impl Debug for CreateTextEditorProxyError {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 f.write_fmt(format_args!("{:?}", self.reason))
227 }
228}
229
230impl RawTextEditorProxy {
231 pub fn new(ime: Box<dyn Ime>) -> Result<Self, CreateTextEditorProxyError> {
232 let raw_proxy = unsafe { OH_TextEditorProxy_Create() };
233 let Some(raw_proxy) = NonNull::new(raw_proxy) else {
234 let err = Err(CreateTextEditorProxyError {
235 ime,
236 reason: CreateTextEditorProxyErrorKind::CreateProxyFailed,
237 });
238 return err;
239 };
240 let mut proxy = Self { raw: raw_proxy };
241 DISPATCHER.register(proxy.raw, ime);
242 proxy.register_dispatcher_callbacks().map_err(|e| {
243 let ime = DISPATCHER.unregister(proxy.raw).expect("Unregister failed");
245 CreateTextEditorProxyError {
246 ime,
247 reason: CreateTextEditorProxyErrorKind::RegisterCallbacksFailed(e),
248 }
249 })?;
250 Ok(proxy)
251 }
252
253 fn register_dispatcher_callbacks(&mut self) -> InputMethodResult {
254 use text_editor::*;
255 unsafe {
256 OH_TextEditorProxy_SetGetTextConfigFunc(self.raw.as_ptr(), Some(get_text_config))?;
257 OH_TextEditorProxy_SetInsertTextFunc(self.raw.as_ptr(), Some(insert_text))?;
258 OH_TextEditorProxy_SetDeleteForwardFunc(self.raw.as_ptr(), Some(delete_forward))?;
259 OH_TextEditorProxy_SetDeleteBackwardFunc(self.raw.as_ptr(), Some(delete_backward))?;
260 OH_TextEditorProxy_SetSendKeyboardStatusFunc(
261 self.raw.as_ptr(),
262 Some(send_keyboard_status),
263 )?;
264 OH_TextEditorProxy_SetSendEnterKeyFunc(self.raw.as_ptr(), Some(send_enter_key))?;
265 OH_TextEditorProxy_SetMoveCursorFunc(self.raw.as_ptr(), Some(move_cursor))?;
266 OH_TextEditorProxy_SetHandleSetSelectionFunc(
267 self.raw.as_ptr(),
268 Some(handle_set_selection),
269 )?;
270 OH_TextEditorProxy_SetHandleExtendActionFunc(
271 self.raw.as_ptr(),
272 Some(handle_extend_action),
273 )?;
274 OH_TextEditorProxy_SetGetLeftTextOfCursorFunc(
275 self.raw.as_ptr(),
276 Some(get_left_text_of_cursor),
277 )?;
278 OH_TextEditorProxy_SetGetRightTextOfCursorFunc(
279 self.raw.as_ptr(),
280 Some(get_right_text_of_cursor),
281 )?;
282 OH_TextEditorProxy_SetGetTextIndexAtCursorFunc(
283 self.raw.as_ptr(),
284 Some(get_text_index_at_cursor),
285 )?;
286 OH_TextEditorProxy_SetReceivePrivateCommandFunc(
287 self.raw.as_ptr(),
288 Some(receive_private_command),
289 )?;
290 OH_TextEditorProxy_SetSetPreviewTextFunc(self.raw.as_ptr(), Some(set_preview_text))?;
291 OH_TextEditorProxy_SetFinishTextPreviewFunc(
292 self.raw.as_ptr(),
293 Some(finish_text_preview),
294 )?;
295 Ok(())
296 }
297 }
298}
299
300impl Drop for RawTextEditorProxy {
301 fn drop(&mut self) {
302 unsafe {
303 OH_TextEditorProxy_Destroy(self.raw.as_ptr());
304 }
305 }
306}
307
308#[derive(Copy, Clone, Debug)]
309pub enum KeyboardStatus {
310 None,
311 Hidden,
312 Shown,
313 Unknown(u32),
314}
315
316impl From<InputMethod_KeyboardStatus> for KeyboardStatus {
317 fn from(status: InputMethod_KeyboardStatus) -> Self {
318 match status {
319 status if status == InputMethod_KeyboardStatus::IME_KEYBOARD_STATUS_NONE => {
320 KeyboardStatus::None
321 }
322 status if status == InputMethod_KeyboardStatus::IME_KEYBOARD_STATUS_HIDE => {
323 KeyboardStatus::Hidden
324 }
325 status if status == InputMethod_KeyboardStatus::IME_KEYBOARD_STATUS_SHOW => {
326 KeyboardStatus::Shown
327 }
328 status => {
329 warn!("Unknown keyboard status enum variant: {}", status.0);
330 KeyboardStatus::Unknown(status.0)
331 }
332 }
333 }
334}