一、开发环境
系统版本: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');
};
};