HarmonyOS @ohos.multimodalInput.inputConsumer(全局快捷键)使用指南
效果
一、概述
@ohos.multimodalInput.inputConsumer 是 HarmonyOS 提供的全局快捷键监听模块,允许应用在后台或前台状态下捕获用户的物理按键事件。该模块最常见的应用场景是音量键翻页——在阅读类应用中监听音量键按下事件,实现翻页操作而不影响系统音量调节功能。
1.1 核心优势
- 全局监听:不依赖组件焦点,应用在前台时即可捕获按键事件
- 精确控制:支持指定按键类型、按键动作(按下/抬起)、是否重复触发
- 非侵入式:仅监听事件,不阻断系统默认行为(如音量调节)
- 易于集成:API 简洁,几行代码即可实现按键监听
1.2 导入方式
import { inputConsumer, KeyCode } from '@kit.InputKit';
1.3 适用场景
| 音量键翻页 | 阅读应用中通过音量+/-键控制前后翻页 |
| 快捷操作 | 通过物理按键触发特定功能(如拍照快门) |
| 游戏控制 | 使用音量键作为辅助游戏按键 |
| 无障碍辅助 | 为特殊用户提供物理按键快捷操作 |
二、核心 API 详解
2.1 KeyPressedConfig(按键配置)
KeyPressedConfig 接口定义了要监听的按键事件的筛选条件:
interface KeyPressedConfig {
key: KeyCode; // 按键码,指定要监听的物理按键
action: number; // 按键动作:0=抬起(KEY_ACTION_UP),1=按下(KEY_ACTION_DOWN)
isRepeat: boolean; // 是否监听长按重复事件
}
参数详解
| key | KeyCode | 按键码枚举值,如 KeyCode.KEYCODE_VOLUME_UP |
| action | number | 1 表示监听按下事件,0 表示监听抬起事件 |
| isRepeat | boolean | false 表示仅在首次按下时触发,true 表示长按时持续触发 |
常用按键码
| KeyCode.KEYCODE_VOLUME_UP | 音量增加键 |
| KeyCode.KEYCODE_VOLUME_DOWN | 音量减少键 |
| KeyCode.KEYCODE_POWER | 电源键 |
| KeyCode.KEYCODE_CAMERA | 相机键 |
2.2 inputConsumer.on(‘keyPressed’)
注册按键事件监听器。
inputConsumer.on(
type: 'keyPressed',
config: KeyPressedConfig,
callback: () => void
): void;
使用示例:
// 监听音量+键按下事件
let config: inputConsumer.KeyPressedConfig = {
key: KeyCode.KEYCODE_VOLUME_UP,
action: 1, // 按下事件
isRepeat: false // 不监听长按重复
};
inputConsumer.on('keyPressed', config, () => {
console.info('Volume UP key pressed!');
// 执行翻页等操作
});
2.3 inputConsumer.off(‘keyPressed’)
取消按键事件监听器。
inputConsumer.off(type: 'keyPressed'): void;
使用示例:
try {
inputConsumer.off('keyPressed');
console.info('Key listeners removed');
} catch (err) {
console.error('Failed to remove listeners:', JSON.stringify(err));
}
注意:off('keyPressed') 会取消所有已注册的 keyPressed 类型监听器,无法选择性取消单个监听。
三、完整实现示例
3.1 基础示例:监听音量键
import { inputConsumer, KeyCode } from '@kit.InputKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Component
struct VolumeKeyDemo {
@State message: string = '按下音量键试试';
aboutToAppear(): void {
this.registerVolumeKeys();
}
aboutToDisappear(): void {
this.unregisterVolumeKeys();
}
private registerVolumeKeys(): void {
try {
// 监听音量+键
let upConfig: inputConsumer.KeyPressedConfig = {
key: KeyCode.KEYCODE_VOLUME_UP,
action: 1,
isRepeat: false
};
inputConsumer.on('keyPressed', upConfig, () => {
this.message = '音量+ 被按下 → 翻到上一页';
});
// 监听音量-键
let downConfig: inputConsumer.KeyPressedConfig = {
key: KeyCode.KEYCODE_VOLUME_DOWN,
action: 1,
isRepeat: false
};
inputConsumer.on('keyPressed', downConfig, () => {
this.message = '音量- 被按下 → 翻到下一页';
});
} catch (err) {
let e = err as BusinessError;
console.error(`Register failed: code=${e.code}, message=${e.message}`);
}
}
private unregisterVolumeKeys(): void {
try {
inputConsumer.off('keyPressed');
} catch (err) {
let e = err as BusinessError;
console.error(`Unregister failed: code=${e.code}, message=${e.message}`);
}
}
build() {
Column() {
Text(this.message)
.fontSize(20)
.textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
3.2 进阶示例:结合 Reader Kit 实现音量键翻页
这是最常见的实际应用场景——将全局快捷键与阅读器结合使用:
import { bookParser, ReadPageComponent, readerCore } from '@kit.ReaderKit';
import { inputConsumer, KeyCode } from '@kit.InputKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Component
struct ReaderWithVolumeKey {
@State volumeKeyEnabled: boolean = false;
private controller: readerCore.ReaderComponentController =
new readerCore.ReaderComponentController();
// 注册音量键监听
private registerVolumeKeys(): void {
try {
// 音量+键 → 翻到上一页
let upConfig: inputConsumer.KeyPressedConfig = {
key: KeyCode.KEYCODE_VOLUME_UP,
action: 1,
isRepeat: false
};
inputConsumer.on('keyPressed', upConfig, () => {
this.controller.flipPage(false); // false = 上一页
});
// 音量-键 → 翻到下一页
let downConfig: inputConsumer.KeyPressedConfig = {
key: KeyCode.KEYCODE_VOLUME_DOWN,
action: 1,
isRepeat: false
};
inputConsumer.on('keyPressed', downConfig, () => {
this.controller.flipPage(true); // true = 下一页
});
} catch (err) {
let e = err as BusinessError;
console.error(`Volume key register failed: ${e.message}`);
}
}
// 取消监听
private unregisterVolumeKeys(): void {
try {
inputConsumer.off('keyPressed');
} catch (err) {
let e = err as BusinessError;
console.error(`Volume key unregister failed: ${e.message}`);
}
}
build() {
Column() {
ReadPageComponent({
controller: this.controller,
readerCallback: (err: BusinessError, data: readerCore.ReaderComponentController) => {
this.controller = data;
}
})
Button(this.volumeKeyEnabled ? '关闭音量键翻页' : '开启音量键翻页')
.onClick(() => {
this.volumeKeyEnabled = !this.volumeKeyEnabled;
if (this.volumeKeyEnabled) {
this.registerVolumeKeys();
} else {
this.unregisterVolumeKeys();
}
})
}
}
}
3.3 使用状态管理 V2 的写法
在使用 @ComponentV2 的场景下,可以通过 @Monitor 自动响应状态变化:
@ComponentV2
struct VolumeKeyReader {
@Param volumeKeyEnabled: boolean = false;
private controller: readerCore.ReaderComponentController =
new readerCore.ReaderComponentController();
// 当 volumeKeyEnabled 变化时自动触发
@Monitor('volumeKeyEnabled')
onVolumeKeyChanged(): void {
if (this.volumeKeyEnabled) {
this.registerKeys();
} else {
this.unregisterKeys();
}
}
private registerKeys(): void {
try {
inputConsumer.on('keyPressed', {
key: KeyCode.KEYCODE_VOLUME_UP, action: 1, isRepeat: false
}, () => { this.controller.flipPage(false); });
inputConsumer.on('keyPressed', {
key: KeyCode.KEYCODE_VOLUME_DOWN, action: 1, isRepeat: false
}, () => { this.controller.flipPage(true); });
} catch (err) {
console.error('Register failed');
}
}
private unregisterKeys(): void {
try {
inputConsumer.off('keyPressed');
} catch (err) {
console.error('Unregister failed');
}
}
aboutToDisappear(): void {
if (this.volumeKeyEnabled) {
this.unregisterKeys();
}
}
build() {
ReadPageComponent({
controller: this.controller,
readerCallback: (err, data) => { this.controller = data; }
})
}
}
四、生命周期管理
4.1 注册与注销时机
正确的生命周期管理是确保资源不泄漏的关键:
| aboutToAppear() | 注册监听 | 组件即将显示时注册 |
| aboutToDisappear() | 注销监听 | 组件即将销毁时注销 |
| 功能开关切换时 | 注册/注销 | 根据用户设置动态控制 |
4.2 完整的生命周期管理示例
@ComponentV2
struct VolumeKeyManager {
@Local enabled: boolean = false;
@Monitor('enabled')
onEnabledChanged(): void {
this.enabled ? this.register() : this.unregister();
}
private register(): void { /* … */ }
private unregister(): void { /* … */ }
aboutToDisappear(): void {
// 无论状态如何,页面销毁时都尝试注销
this.unregister();
}
}
五、注意事项与常见问题
5.1 不阻断系统行为
inputConsumer.on('keyPressed') 仅监听按键事件,不会阻止系统默认的音量调节行为。这意味着用户按下音量键时,系统音量仍然会变化,同时你的回调也会执行。
5.2 isRepeat 的选择
- isRepeat: false(推荐):长按音量键不会持续触发翻页,避免快速翻过多页
- isRepeat: true:长按会持续触发,适合需要连续操作的场景
5.3 action 参数说明
| 1 | 按键按下(KEY_ACTION_DOWN) | 最常用,按下即触发操作 |
| 0 | 按键抬起(KEY_ACTION_UP) | 需要检测按键释放时 |
大多数翻页场景使用 action: 1(按下事件)即可。
5.4 错误处理
所有 inputConsumer 的调用都应该包裹在 try-catch 中:
try {
inputConsumer.on('keyPressed', config, callback);
} catch (err) {
let e = err as BusinessError;
console.error(`Failed: code=${e.code}, message=${e.message}`);
}
5.5 多次注册问题
每次调用 inputConsumer.on('keyPressed') 都会注册一个新的监听器。如果在功能开关切换时不先调用 off() 就直接 on(),会导致多个监听器叠加,一次按键触发多次回调。
正确做法:先 off() 取消旧监听,再 on() 注册新监听。或者如示例中所示,通过开关状态统一管理注册和注销。
六、最佳实践
七、总结
@ohos.multimodalInput.inputConsumer 模块提供了简洁高效的全局按键监听能力,是实现音量键翻页的核心依赖。结合 Reader Kit 的 flipPage() 方法,仅需少量代码即可为阅读应用添加音量键翻页功能。
关键要点回顾:
- 使用 KeyPressedConfig 精确指定要监听的按键和事件类型
- on('keyPressed') 注册监听,off('keyPressed') 取消监听
- 在组件生命周期中正确管理监听的注册与注销
- 不阻断系统默认行为,用户仍可正常调节音量
参考文档
- @ohos.multimodalInput.inputConsumer 官方文档
- KeyCode 按键码枚举


