• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import commonEventManager from '@ohos.commonEventManager';
17import display from '@ohos.display';
18import inputMethodEngine from '@ohos.inputMethodEngine';
19import InputMethodExtensionContext from '@ohos.InputMethodExtensionContext';
20
21// Call the getInputMethodAbility method of the input method framework to get the instance
22const inputMethodAbility: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility();
23const DEFAULT_DIRECTION: number = 1;
24const DEFAULT_LENGTH: number = 1;
25const DEFAULT_SELECT_RANGE: number = 10;
26
27enum TEST_RESULT_CODE {
28  SUCCESS,
29  FAILED
30}
31
32enum TEST_FUNCTION {
33  INSERT_TEXT_SYNC,
34  MOVE_CURSOR_SYNC,
35  GET_ATTRIBUTE_SYNC,
36  SELECT_BY_RANGE_SYNC,
37  SELECT_BY_MOVEMENT_SYNC,
38  GET_INDEX_AT_CURSOR_SYNC,
39  DELETE_FORWARD_SYNC,
40  DELETE_BACKWARD_SYNC,
41  GET_FORWARD_SYNC,
42  GET_BACKWARD_SYNC,
43  CHANGE_FLAG_TO_FIXED,
44  CHANGE_FLAG_TO_FLOATING,
45  SETPRIVACYMODE_WITHOUT_PERMISSION,
46  SETPRIVACYMODE_ERROR_PARAM,
47  ADJUST_WITH_INVALID_FLAG,
48  ADJUST_WITH_NON_FULL_SCREEN_NO_PANEL_RECT,
49  ADJUST_WITH_FULL_SCREEN_NO_AVOID_Y,
50  ADJUST_WITH_INVALID_AVOID_Y,
51  ADJUST_WITH_INVALID_TYPE,
52  ADJUST_SUCCESS,
53  SET_PREVIEW_TEXT,
54  FINISH_TEXT_PREVIEW,
55}
56
57export class KeyboardController {
58  private TAG: string = 'inputDemo: KeyboardController ';
59  private mContext: InputMethodExtensionContext | undefined = undefined; // save the context property of InputMethodExtensionAbility
60  private panel: inputMethodEngine.Panel | undefined = undefined;
61  private subscriber = undefined;
62
63  constructor() {
64  }
65
66  public onCreate(context: InputMethodExtensionContext): void {
67    this.mContext = context;
68    this.initWindow(); // init window
69    this.registerListener(); //register input listener
70  }
71
72  public onDestroy(): void {
73    this.unRegisterListener();
74    if (this.panel) {
75      this.panel.hide();
76      inputMethodAbility.destroyPanel(this.panel);
77    }
78    this.mContext.destroy();
79  }
80
81  private initWindow(): void {
82    if (this.mContext === undefined) {
83      return;
84    }
85    let dis = display.getDefaultDisplaySync();
86    let dWidth = dis.width;
87    let dHeight = dis.height;
88    let keyHeightRate = 0.47;
89    let keyHeight = dHeight * keyHeightRate;
90    let nonBarPosition = dHeight - keyHeight;
91    let panelInfo: inputMethodEngine.PanelInfo = {
92      type: inputMethodEngine.PanelType.SOFT_KEYBOARD,
93      flag: inputMethodEngine.PanelFlag.FLG_FIXED
94    };
95    inputMethodAbility.createPanel(this.mContext, panelInfo).then(async (inputPanel: inputMethodEngine.Panel) => {
96      this.panel = inputPanel;
97      if (this.panel) {
98        await this.panel.resize(dWidth, keyHeight);
99        await this.panel.moveTo(0, nonBarPosition);
100        await this.panel.setUiContent('pages/Index');
101      }
102    });
103  }
104
105  publishCommonEvent(event: string, codeNumber: number): void {
106    this.addLog(`[inputDemo] publish event, event= ${event}, codeNumber= ${codeNumber}`);
107    commonEventManager.publish(event, { code: codeNumber }, (err) => {
108      if (err) {
109        this.addLog(`inputDemo publish ${event} failed, err = ${JSON.stringify(err)}`);
110      } else {
111        this.addLog(`inputDemo publish ${event} success`);
112      }
113    })
114  }
115
116  private registerListener(): void {
117    this.registerInputListener();
118    let subscribeInfo = {
119      events: ['syncTestFunction']
120    }
121    commonEventManager.createSubscriber(subscribeInfo).then((data) => {
122      this.subscriber = data;
123      commonEventManager.subscribe(this.subscriber, (err, eventData) => {
124        this.addLog(`[inputDemo] subscribe, eventData.code = ${eventData.code}`);
125        if (globalThis.textInputClient === undefined) {
126          return;
127        }
128        switch (eventData.code) {
129          case TEST_FUNCTION.INSERT_TEXT_SYNC:
130            globalThis.textInputClient.insertTextSync("text");
131            break;
132          case TEST_FUNCTION.MOVE_CURSOR_SYNC:
133            globalThis.textInputClient.moveCursorSync(DEFAULT_DIRECTION);
134            break;
135          case TEST_FUNCTION.GET_ATTRIBUTE_SYNC:
136            this.getAttributeSync();
137            break;
138          case TEST_FUNCTION.SELECT_BY_RANGE_SYNC:
139            globalThis.textInputClient.selectByRangeSync({ start: 0, end: DEFAULT_SELECT_RANGE });
140            break;
141          case TEST_FUNCTION.SELECT_BY_MOVEMENT_SYNC:
142            globalThis.textInputClient.selectByMovementSync({ direction: inputMethodEngine.CURSOR_LEFT });
143            break;
144          case TEST_FUNCTION.GET_INDEX_AT_CURSOR_SYNC:
145            this.getIndexAtCursorSync()
146            break;
147          case TEST_FUNCTION.DELETE_FORWARD_SYNC:
148            globalThis.textInputClient.deleteForwardSync(DEFAULT_LENGTH);
149            break;
150          case TEST_FUNCTION.DELETE_BACKWARD_SYNC:
151            globalThis.textInputClient.deleteBackwardSync(DEFAULT_LENGTH);
152            break;
153          case TEST_FUNCTION.GET_FORWARD_SYNC:
154            this.getForwardSync();
155            break;
156          case TEST_FUNCTION.GET_BACKWARD_SYNC:
157            this.getBackwardSync();
158            break;
159          case TEST_FUNCTION.CHANGE_FLAG_TO_FIXED:
160            this.changePanelFlag(inputMethodEngine.PanelFlag.FLG_FIXED);
161            break;
162          case TEST_FUNCTION.CHANGE_FLAG_TO_FLOATING:
163            this.changePanelFlag(inputMethodEngine.PanelFlag.FLG_FLOATING);
164            break;
165          case TEST_FUNCTION.SETPRIVACYMODE_WITHOUT_PERMISSION:
166            this.setPrivacyModeWithoutPermission();
167            break;
168          case TEST_FUNCTION.SETPRIVACYMODE_ERROR_PARAM:
169            this.setPrivacyModeErrorParam();
170            break;
171          case TEST_FUNCTION.ADJUST_WITH_INVALID_FLAG:
172            this.adjustWithInvalidFlag();
173            break;
174          case TEST_FUNCTION.ADJUST_WITH_NON_FULL_SCREEN_NO_PANEL_RECT:
175            this.adjustWithNonFullScreenNoPanelRect();
176            break;
177          case TEST_FUNCTION.ADJUST_WITH_FULL_SCREEN_NO_AVOID_Y:
178            this.adjustWithFullScreenNoAvoidY();
179            break;
180          case TEST_FUNCTION.ADJUST_WITH_INVALID_AVOID_Y:
181            this.adjustWithInvalidAvoidY();
182            break;
183          case TEST_FUNCTION.ADJUST_WITH_INVALID_TYPE:
184            this.adjustWithInvalidPanelType();
185            break;
186          case TEST_FUNCTION.ADJUST_SUCCESS:
187            this.adjustEnhancedPanelRect();
188            break;
189          case TEST_FUNCTION.SET_PREVIEW_TEXT:
190            globalThis.textInputClient.setPreviewTextSync("text", { start: 0, end: DEFAULT_SELECT_RANGE });
191            break;
192          case TEST_FUNCTION.FINISH_TEXT_PREVIEW:
193            globalThis.textInputClient.finishTextPreviewSync();
194            break;
195          default:
196            break;
197        }
198      })
199    })
200  }
201
202  private registerInputListener(): void { // 注册对输入法框架服务的开启及停止事件监听
203    inputMethodAbility.on('inputStart', (kbController, textInputClient) => {
204      globalThis.textInputClient = textInputClient; // 此为输入法客户端实例,由此调用输入法框架提供给输入法应用的功能接口
205      globalThis.keyboardController = kbController;
206    })
207    inputMethodAbility.on('inputStop', () => {
208      this.onDestroy();
209    });
210  }
211
212  private unRegisterListener(): void {
213    inputMethodAbility.off('inputStart');
214    inputMethodAbility.off('inputStop', () => {
215    });
216  }
217
218  getBackwardSync() {
219    let backward: string = globalThis.textInputClient.getBackwardSync(1);
220    if (backward.length >= 0) {
221      this.publishCommonEvent('getBackwardSyncResult', TEST_RESULT_CODE.SUCCESS);
222    } else {
223      this.publishCommonEvent('getBackwardSyncResult', TEST_RESULT_CODE.FAILED);
224    }
225  }
226
227  getForwardSync() {
228    let forward: string = globalThis.textInputClient.getForwardSync(1);
229    if (forward.length >= 0) {
230      this.publishCommonEvent('getForwardSyncResult', TEST_RESULT_CODE.SUCCESS);
231    } else {
232      this.publishCommonEvent('getForwardSyncResult', TEST_RESULT_CODE.FAILED);
233    }
234  }
235
236  async getAttributeSync() {
237    try {
238      let editAttribute = globalThis.textInputClient.getEditorAttributeSync();
239      let editAttribute1 = await globalThis.textInputClient.getEditorAttribute();
240      this.addLog(`[inputDemo] publish getEditorAttributeSync editAttribute= ${JSON.stringify(editAttribute)}`);
241      if(editAttribute.inputPattern == editAttribute1.inputPattern && editAttribute.enterKeyType == editAttribute1.enterKeyType) {
242        this.publishCommonEvent('getEditorAttributeSyncResult', TEST_RESULT_CODE.SUCCESS);
243      } else{
244        this.publishCommonEvent('getEditorAttributeSyncResult', TEST_RESULT_CODE.FAILED);
245      }
246    } catch (err) {
247      this.publishCommonEvent('getEditorAttributeSyncResult', TEST_RESULT_CODE.FAILED);
248    }
249  }
250
251  getIndexAtCursorSync() {
252    try {
253      let index = globalThis.textInputClient.getTextIndexAtCursorSync();
254      this.addLog(`[inputDemo] publish getTextIndexAtCursorSync index= ${index}`);
255      this.publishCommonEvent('getTextIndexAtCursorSyncResult', TEST_RESULT_CODE.SUCCESS);
256    } catch (err) {
257      this.publishCommonEvent('getTextIndexAtCursorSyncResult', TEST_RESULT_CODE.FAILED);
258    }
259  }
260
261  changePanelFlag(panelFlag: inputMethodEngine.PanelFlag) {
262    try {
263      this.panel.hide((err) => {
264        if (err) {
265          this.addLog(`Failed to hide panel: ${JSON.stringify(err)}`);
266          this.publishCommonEvent('changeFlag', TEST_RESULT_CODE.FAILED);
267          return;
268        }
269        this.panel.changeFlag(panelFlag);
270        this.panel.show((err) => {
271          this.addLog(`Failed to show panel: ${JSON.stringify(err)}`);
272          this.publishCommonEvent('changeFlag', TEST_RESULT_CODE.SUCCESS);
273        });
274      });
275    } catch (err) {
276      this.addLog(`failed: ${JSON.stringify(err)}`);
277      this.publishCommonEvent('changeFlag', TEST_RESULT_CODE.FAILED);
278    }
279  }
280
281  setPrivacyModeWithoutPermission() {
282    try {
283      let isSetPrivacyMode: boolean = true;
284      this.panel.setPrivacyMode(isSetPrivacyMode);
285      this.publishCommonEvent('setPrivacyModeWithoutPermissionResult', TEST_RESULT_CODE.FAILED);
286    } catch (err) {
287      this.addLog(`failed: ${JSON.stringify(err)}`);
288      if (err.code === 201) {
289        this.publishCommonEvent('setPrivacyModeWithoutPermissionResult', TEST_RESULT_CODE.SUCCESS);
290        return;
291      }
292    }
293  }
294
295  setPrivacyModeErrorParam() {
296    try {
297      this.panel.setPrivacyMode(undefined);
298      this.publishCommonEvent('setPrivacyModeErrorParamResult', TEST_RESULT_CODE.FAILED);
299    } catch (err) {
300      this.addLog(`failed: ${JSON.stringify(err)}`);
301      if (err.code === 401) {
302        this.publishCommonEvent('setPrivacyModeErrorParamResult', TEST_RESULT_CODE.SUCCESS);
303        return;
304      }
305    }
306  }
307
308  adjustWithInvalidFlag() {
309    try {
310      let defaultDisplay = display.getDefaultDisplaySync();
311      let displayWidth = defaultDisplay.width;
312      let displayHeight = defaultDisplay.height;
313      let heightRate = 0.7;
314      let portraitAvoidY = 0;
315      let landscapeAvoidY = 0;
316      if (displayWidth < displayHeight) {
317        portraitAvoidY = displayHeight - (displayHeight * heightRate - 1);
318        landscapeAvoidY = displayWidth - (displayWidth * heightRate - 1);
319      } else {
320        portraitAvoidY = displayWidth - (displayWidth * heightRate - 1);
321        landscapeAvoidY = displayHeight - (displayHeight * heightRate - 1);
322      }
323      let panelRect: inputMethodEngine.EnhancedPanelRect = {
324        landscapeAvoidY: landscapeAvoidY,
325        portraitAvoidY: portraitAvoidY,
326        fullScreenMode: true
327      }
328      this.panel.adjustPanelRect(2, panelRect);
329      this.publishCommonEvent('adjustWithInvalidFlagResult', TEST_RESULT_CODE.FAILED);
330    } catch (err) {
331      this.addLog(`failed: ${JSON.stringify(err)}`);
332      if (err.code === 12800017) {
333        this.publishCommonEvent('adjustWithInvalidFlagResult', TEST_RESULT_CODE.SUCCESS);
334        return;
335      }
336    }
337  }
338
339  adjustWithNonFullScreenNoPanelRect() {
340    try {
341      let panelRect: inputMethodEngine.EnhancedPanelRect = {
342        fullScreenMode: false
343      }
344      this.panel.adjustPanelRect(inputMethodEngine.PanelFlag.FLG_FIXED, panelRect);
345      this.publishCommonEvent('adjustWithNonFullScreenNoPanelRectResult', TEST_RESULT_CODE.FAILED);
346    } catch (err) {
347      this.addLog(`failed: ${JSON.stringify(err)}`);
348      if (err.code === 401) {
349        this.publishCommonEvent('adjustWithNonFullScreenNoPanelRectResult', TEST_RESULT_CODE.SUCCESS);
350        return;
351      }
352    }
353  }
354
355  adjustWithFullScreenNoAvoidY() {
356    try {
357      let panelRect: inputMethodEngine.EnhancedPanelRect = {
358        fullScreenMode: true
359      }
360      this.panel.adjustPanelRect(inputMethodEngine.PanelFlag.FLG_FIXED, panelRect);
361      this.publishCommonEvent('adjustWithFullScreenNoAvoidYResult', TEST_RESULT_CODE.FAILED);
362    } catch (err) {
363      this.addLog(`failed: ${JSON.stringify(err)}`);
364      if (err.code === 401) {
365        this.publishCommonEvent('adjustWithFullScreenNoAvoidYResult', TEST_RESULT_CODE.SUCCESS);
366        return;
367      }
368    }
369  }
370
371  adjustWithInvalidAvoidY() {
372    try {
373      let defaultDisplay = display.getDefaultDisplaySync();
374      let displayWidth = defaultDisplay.width;
375      let displayHeight = defaultDisplay.height;
376      let heightRate = 0.7;
377      let portraitAvoidY = 0;
378      let landscapeAvoidY = 0;
379      if (displayWidth < displayHeight) {
380        portraitAvoidY = displayHeight - (displayHeight * heightRate + 1);
381        landscapeAvoidY = displayWidth - (displayWidth * heightRate + 1);
382      } else {
383        portraitAvoidY = displayWidth - (displayWidth * heightRate + 1);
384        landscapeAvoidY = displayHeight - (displayHeight * heightRate + 1);
385      }
386      let panelRect: inputMethodEngine.EnhancedPanelRect = {
387        landscapeAvoidY: landscapeAvoidY,
388        portraitAvoidY: portraitAvoidY,
389        fullScreenMode: true
390      }
391      this.panel.adjustPanelRect(inputMethodEngine.PanelFlag.FLG_FIXED, panelRect);
392      this.publishCommonEvent('adjustWithInvalidAvoidYResult', TEST_RESULT_CODE.FAILED);
393    } catch (err) {
394      this.addLog(`failed: ${JSON.stringify(err)}`);
395      if (err.code === 401) {
396        this.publishCommonEvent('adjustWithInvalidAvoidYResult', TEST_RESULT_CODE.SUCCESS);
397        return;
398      }
399    }
400  }
401
402  adjustWithInvalidPanelType() {
403    let panelInfo: inputMethodEngine.PanelInfo = {
404      type: inputMethodEngine.PanelType.STATUS_BAR
405    };
406    inputMethodAbility.createPanel(this.mContext, panelInfo).then(async (inputPanel: inputMethodEngine.Panel) => {
407      try {
408        let defaultDisplay = display.getDefaultDisplaySync();
409        let displayWidth = defaultDisplay.width;
410        let displayHeight = defaultDisplay.height;
411        let heightRate = 0.7;
412        let portraitAvoidY = 0;
413        let landscapeAvoidY = 0;
414        if (displayWidth < displayHeight) {
415          portraitAvoidY = displayHeight - (displayHeight * heightRate - 1);
416          landscapeAvoidY = displayWidth - (displayWidth * heightRate - 1);
417        } else {
418          portraitAvoidY = displayWidth - (displayWidth * heightRate - 1);
419          landscapeAvoidY = displayHeight - (displayHeight * heightRate - 1);
420        }
421        let panelRect: inputMethodEngine.EnhancedPanelRect = {
422          landscapeAvoidY: landscapeAvoidY,
423          portraitAvoidY: portraitAvoidY,
424          fullScreenMode: true
425        }
426        inputPanel.adjustPanelRect(inputMethodEngine.PanelFlag.FLG_FIXED, panelRect);
427        this.addLog('adjustPanelRect success');
428        this.publishCommonEvent('adjustWithInvalidTypeResult', TEST_RESULT_CODE.FAILED);
429        inputMethodAbility.destroyPanel(inputPanel);
430      } catch (err) {
431        this.addLog(`failed: ${JSON.stringify(err)}`);
432        inputMethodAbility.destroyPanel(inputPanel);
433        if (err.code === 12800017) {
434          this.publishCommonEvent('adjustWithInvalidTypeResult', TEST_RESULT_CODE.SUCCESS);
435          return;
436        }
437      }
438    });
439  }
440
441  adjustEnhancedPanelRect() {
442    try {
443      let defaultDisplay = display.getDefaultDisplaySync();
444      let displayWidth = defaultDisplay.width;
445      let displayHeight = defaultDisplay.height;
446      let heightRate = 0.7;
447      let portraitAvoidY = 0;
448      let landscapeAvoidY = 0;
449      if (displayWidth < displayHeight) {
450        portraitAvoidY = displayHeight - (displayHeight * heightRate - 1);
451        landscapeAvoidY = displayWidth - (displayWidth * heightRate - 1);
452      } else {
453        portraitAvoidY = displayWidth - (displayWidth * heightRate - 1);
454        landscapeAvoidY = displayHeight - (displayHeight * heightRate - 1);
455      }
456      let panelRect: inputMethodEngine.EnhancedPanelRect = {
457        landscapeAvoidY: landscapeAvoidY,
458        portraitAvoidY: portraitAvoidY,
459        fullScreenMode: true
460      }
461      this.panel.adjustPanelRect(inputMethodEngine.PanelFlag.FLG_FIXED, panelRect);
462      this.addLog('adjustPanelRect success');
463      this.publishCommonEvent('adjustSuccessResult', TEST_RESULT_CODE.SUCCESS);
464    } catch (err) {
465      this.addLog(`failed: ${JSON.stringify(err)}`);
466      this.publishCommonEvent('adjustSuccessResult', TEST_RESULT_CODE.FAILED);
467      return;
468    }
469  }
470
471  private addLog(message): void {
472    console.log(this.TAG + message)
473  }
474}
475
476const keyboardController = new KeyboardController();
477
478export default keyboardController;