OpenHarmony定制系统组合按键(二)
一、开发环境
系统版本:OpenHarmony 4.0.10.13
设备平台:rk3568
SDK版本:fullSDK 4.0.10.13
DevEco Studio版本:4.1.0.400
二、需求背景
定制OpenHarmony 系统组合按键功能,例如仿Android Power + VOL_Up组合键实现截屏功能
为了实现需求,上一文OpenHarmony定制系统组合按键(一)中创建了一个开机自启的后台服务,将用来订阅组合按键事件,本文详细介绍如何订阅系统组合事件
三、ServiceExtensionAbility订阅组合按键
3.1 定义组合按键配置
首先在ServiceExtAbility.ets中定义好组合按键的配置
这里定义了两组:
- Power + volUp > 截屏
- Mute + volDown >系统设置
const SCREENSHOT_KEY_OPTIONS: inputConsumer.KeyOptions = {preKeys: [KeyCode.KEYCODE_POWER],finalKey: KeyCode.KEYCODE_VOLUME_UP,isFinalKeyDown: true,finalKeyDownDuration: 0
}const SETTINGS_KEY_OPTIONS: inputConsumer.KeyOptions = {preKeys: [KeyCode.KEYCODE_MUTE],finalKey: KeyCode.KEYCODE_VOLUME_DOWN,isFinalKeyDown: true,finalKeyDownDuration: 0
}
3.2 订阅组合按键
在ServiceExtAbility.ets的onCreate()中
export default class ServiceExtAbility extends ServiceExtensionAbility {onCreate(want: Want): void {let serviceExtensionContext = this.context;hilog.info(DOMAIN_NUMBER, TAG, `onCreate, want: ${want.abilityName}`);//订阅截屏组合按键this.registerScreenshotKeys();//订阅打开设置组合按键this.registerSettingsKeys();};//订阅截屏组合按键registerScreenshotKeys() {console.info(TAG, "registerScreenshotKeys is called")//订阅截屏组合按键let screenshotCallback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `screenshotKeyOptions: ${JSON.stringify(keyOptions)}`);//跳转截屏应用this.context.startAbility({bundleName: 'com.ohos.screenshot',abilityName: 'com.ohos.screenshot.ServiceExtAbility',parameters: undefined}).then(() => {console.info(TAG, 'startAbility, then');}).catch((error: BusinessError) => {console.error(TAG, `startAbility, error: ${JSON.stringify(error)}`);});}try {inputConsumer.on("key", SCREENSHOT_KEY_OPTIONS, screenshotCallback);} catch (error) {console.error(TAG, `Subscribe screenshot failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}//订阅打开设置组合按键registerSettingsKeys() {console.info(TAG, "registerSettingsKeys is called")//订阅截屏组合按键let openSettingsCallback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `registerSettingsKeys: ${JSON.stringify(keyOptions)}`);//跳转系统设置this.context.startAbility({bundleName: 'com.ohos.settings',abilityName: 'com.ohos.settings.MainAbility',parameters: undefined}).then(() => {console.info(TAG, 'startAbility, then');}).catch((error: BusinessError) => {console.error(TAG, `startAbility, error: ${JSON.stringify(error)}`);});}try {inputConsumer.on("key", SETTINGS_KEY_OPTIONS, openSettingsCallback);} catch (error) {console.error(TAG, `Subscribe open Settings failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}}
3.3
当service 关闭时也需取消订阅
export default class ServiceExtAbility extends ServiceExtensionAbility {...//取消订阅截屏组合按键unregisterScreenshotKeys() {console.info(TAG, "unregisterScreenshotKeys is called");let callback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `keyOptions: ${JSON.stringify(keyOptions)}`);}try {inputConsumer.off("key", SCREENSHOT_KEY_OPTIONS, callback);console.info(`Unsubscribe screenshot keys success`);} catch (error) {console.error(`Execute failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}//取消订阅打开设置组合按键unregisterSettingsKeys() {console.info(TAG, "unregisterSettingsKeys is called");let callback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `keyOptions: ${JSON.stringify(keyOptions)}`);}try {inputConsumer.off("key", SETTINGS_KEY_OPTIONS, callback);console.info(`Unsubscribe open Settings keys success`);} catch (error) {console.error(`Execute failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}...onDestroy(): void {this.unregisterScreenshotKeys()this.unregisterSettingsKeys()hilog.info(DOMAIN_NUMBER, TAG, 'onDestroy');};
}
效果
Power + volUp > 截屏
Power + volDown > 跳转系统设置
总结
通过本文已基本实现组合键截屏和跳转设置功能,不过细心的同学肯定也发现了,在响应组合键的同时也响应了单独的音量键,这体验并不好,后文将通过另外一种方式实现需求,并改善这一问题
源码
module.json5
{"module": {"name": "entry","type": "entry","description": "$string:module_desc","mainElement": "ServiceExtAbility","deviceTypes": ["default","tablet"],"deliveryWithInstall": true,"installationFree": false,"pages": "$profile:main_pages","abilities": [{"name": "EntryAbility","srcEntry": "./ets/entryability/EntryAbility.ets","description": "$string:EntryAbility_desc","icon": "$media:icon","label": "$string:EntryAbility_label","startWindowIcon": "$media:startIcon","startWindowBackground": "$color:start_window_background","exported": true,"skills": [{"entities": ["entity.system.home"],"actions": ["action.system.home"]}]}],"extensionAbilities": [{"name": "ServiceExtAbility","icon": "$media:icon","label": "$string:EntryAbility_label","description": "service","type": "service","exported": true,"srcEntry": "./ets/services/ServiceExtAbility.ets"}],"requestPermissions": [{"name": "ohos.permission.START_ABILITIES_FROM_BACKGROUND"},{"name": "ohos.permission.CAPTURE_SCREEN"}]}
}
ServiceExtAbility.ets源码
import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility';
import Want from '@ohos.app.ability.Want';
import hilog from '@ohos.hilog';
import rpc from '@ohos.rpc';
import inputConsumer from '@ohos.multimodalInput.inputConsumer';
import { KeyCode } from '@ohos.multimodalInput.keyCode';
import { BusinessError } from '@ohos.base';const TAG: string = '[ServiceExtAbility]';
const DOMAIN_NUMBER: number = 0xFF00;const SCREENSHOT_KEY_OPTIONS: inputConsumer.KeyOptions = {preKeys: [KeyCode.KEYCODE_POWER],finalKey: KeyCode.KEYCODE_VOLUME_UP,isFinalKeyDown: true,finalKeyDownDuration: 0
}const SETTINGS_KEY_OPTIONS: inputConsumer.KeyOptions = {preKeys: [KeyCode.KEYCODE_POWER],finalKey: KeyCode.KEYCODE_VOLUME_DOWN,isFinalKeyDown: true,finalKeyDownDuration: 0
}class ServiceStub extends rpc.RemoteObject {constructor(des: string) {super(des);}
}export default class ServiceExtAbility extends ServiceExtensionAbility {onCreate(want: Want): void {let serviceExtensionContext = this.context;hilog.info(DOMAIN_NUMBER, TAG, `onCreate, want: ${want.abilityName}`);//订阅截屏组合按键this.registerScreenshotKeys();//订阅打开设置组合按键this.registerSettingsKeys();};registerScreenshotKeys() {console.info(TAG, "registerScreenshotKeys is called")//订阅截屏组合按键let screenshotCallback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `screenshotKeyOptions: ${JSON.stringify(keyOptions)}`);this.context.startAbility({bundleName: 'com.ohos.screenshot',abilityName: 'com.ohos.screenshot.ServiceExtAbility',parameters: undefined}).then(() => {console.info(TAG, 'startAbility, then');}).catch((error: BusinessError) => {console.error(TAG, `startAbility, error: ${JSON.stringify(error)}`);});}try {inputConsumer.on("key", SCREENSHOT_KEY_OPTIONS, screenshotCallback);} catch (error) {console.error(TAG, `Subscribe screenshot failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}unregisterScreenshotKeys() {console.info(TAG, "unregisterScreenshotKeys is called");let callback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `keyOptions: ${JSON.stringify(keyOptions)}`);}try {inputConsumer.off("key", SCREENSHOT_KEY_OPTIONS, callback);console.info(`Unsubscribe screenshot keys success`);} catch (error) {console.error(`Execute failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}registerSettingsKeys() {console.info(TAG, "registerSettingsKeys is called")//订阅截屏组合按键let openSettingsCallback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `registerSettingsKeys: ${JSON.stringify(keyOptions)}`);this.context.startAbility({bundleName: 'com.ohos.settings',abilityName: 'com.ohos.settings.MainAbility',parameters: undefined}).then(() => {console.info(TAG, 'startAbility, then');}).catch((error: BusinessError) => {console.error(TAG, `startAbility, error: ${JSON.stringify(error)}`);});}try {inputConsumer.on("key", SETTINGS_KEY_OPTIONS, openSettingsCallback);} catch (error) {console.error(TAG, `Subscribe open Settings failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}unregisterSettingsKeys() {console.info(TAG, "unregisterSettingsKeys is called");let callback = (keyOptions: inputConsumer.KeyOptions) => {console.info(TAG, `keyOptions: ${JSON.stringify(keyOptions)}`);}try {inputConsumer.off("key", SETTINGS_KEY_OPTIONS, callback);console.info(`Unsubscribe open Settings keys success`);} catch (error) {console.error(`Execute failed, error: ${JSON.stringify(error, [`code`, `message`])}`);}}onRequest(want: Want, startId: number): void {hilog.info(DOMAIN_NUMBER, TAG, `onRequest, want: ${want.abilityName}`);};onConnect(want: Want): rpc.RemoteObject {hilog.info(DOMAIN_NUMBER, TAG, `onConnect, want: ${want.abilityName}`);// 返回ServiceExtImpl对象,客户端获取后便可以与ServiceExtensionAbility进行通信return new ServiceStub('ServiceExtAbilityService');};onDisconnect(want: Want): void {hilog.info(DOMAIN_NUMBER, TAG, `onDisconnect, want: ${want.abilityName}`);};onDestroy(): void {this.unregisterScreenshotKeys()this.unregisterSettingsKeys()hilog.info(DOMAIN_NUMBER, TAG, 'onDestroy');};
};