HarmonyOS鸿蒙Next中PC怎么监听键盘按键

HarmonyOS鸿蒙Next中PC怎么监听键盘按键 想要监听CTRL键,鼠标左键点击,实现列表多选。怎么监听CTRL。onKeyEvent没有效果

尝试

try {
  let options: inputConsumer.HotkeyOptions = {
    preKeys: [KeyCode.KEYCODE_CTRL_LEFT],
    finalKey: KeyCode.KEYCODE_FN
  };
  inputConsumer.on("hotkeyChange", options, this.ctrlCallback);
} catch (error) {
  console.log(`>>>>>>>>>>>Subscribe failed, Cause code: ${error.code}, message: ${error.message}`);
}

但是 finalKey 必选的。

有什么方法实现监听键盘按键吗


更多关于HarmonyOS鸿蒙Next中PC怎么监听键盘按键的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

方案一:使用 onKeyEvent 监听修饰键状态(推荐)

这是最简单直接的方案,通过 KeyEvent 对象的 ctrlKey 属性来判断:

@Entry
@Component
struct MultiSelectList {
  @State selectedItems: number[] = []
  @State ctrlPressed: boolean = false
  private listData: string[] = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']
  build() {
    Column() {
      List() {
        ForEach(this.listData, (item: string, index: number) => {
          ListItem() {
            Text(item)
              .width('100%')
              .height(50)
              .backgroundColor(this.selectedItems.includes(index) ? '#4CAF50' : '#FFFFFF')
              .padding(10)
              .onClick(() => {
                // CTRL键按下时多选,否则单选
                if (this.ctrlPressed) {
                  const idx = this.selectedItems.indexOf(index)
                  if (idx > -1) {
                    // 已选中,取消选中
                    this.selectedItems.splice(idx, 1)
                  } else {
                    // 未选中,添加选中
                    this.selectedItems.push(index)
                  }
                } else {
                  // 单选模式
                  this.selectedItems = [index]
                }
              })
          }
        })
      }
      .width('100%')
      .height('80%')
      .defaultFocus(true)  // 关键:获取焦点
      .focusable(true)     // 允许获取焦点
      .onKeyEvent((event?: KeyEvent) => {
        if (event) {
          // 监听CTRL键的按下和释放
          if (event.keyCode === 2072 || event.keyCode === 2073) { // CTRL_LEFT 或 CTRL_RIGHT
            if (event.type === KeyType.Down) {
              this.ctrlPressed = true
              console.info('CTRL键按下')
            } else if (event.type === KeyType.Up) {
              this.ctrlPressed = false
              console.info('CTRL键释放')
            }
          }
          // 或者直接使用 ctrlKey 属性(推荐)
          this.ctrlPressed = event.ctrlKey || false
        }
      })
      Text(`已选择: ${this.selectedItems.length} 项`)
        .margin({ top: 20 })
      Text(`CTRL状态: ${this.ctrlPressed ? '按下' : '释放'}`)
    }
    .width('100%')
    .height('100%')
  }
}

方案二:使用 inputConsumer.on(‘keyPressed’) 全局监听(API 16+)

如果你的应用需要全局监听CTRL键(不依赖组件焦点),可以使用这个方案:

import { inputConsumer, KeyEvent } from '@kit.InputKit'
import { KeyCode } from '@kit.InputKit'
@Entry
@Component
struct MultiSelectList {
  @State selectedItems: number[] = []
  @State ctrlPressed: boolean = false
  private listData: string[] = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']
  private ctrlDownCallback: (event: KeyEvent) => void = () => {}
  private ctrlUpCallback: (event: KeyEvent) => void = () => {}
  aboutToAppear(): void {
    try {
      // 监听CTRL键按下
      let downOptions: inputConsumer.KeyPressedConfig = {
        key: KeyCode.KEYCODE_CTRL_LEFT,
        action: 1,  // 按下事件
        isRepeat: false
      }
      this.ctrlDownCallback = (event: KeyEvent) => {
        this.ctrlPressed = true
        console.info('CTRL键按下(全局)')
      }
      inputConsumer.on('keyPressed', downOptions, this.ctrlDownCallback)
      // 注意:目前API没有直接监听抬起事件的方法
      // 需要配合 onKeyEvent 或其他方式监听释放
    } catch (error) {
      console.error(`监听失败: ${JSON.stringify(error)}`)
    }
  }
  aboutToDisappear(): void {
    // 取消订阅
    try {
      inputConsumer.off('keyPressed', this.ctrlDownCallback)
    } catch (error) {
      console.error(`取消订阅失败: ${error}`)
    }
  }
  build() {
    Column() {
      List() {
        ForEach(this.listData, (item: string, index: number) => {
          ListItem() {
            Text(item)
              .width('100%')
              .height(50)
              .backgroundColor(this.selectedItems.includes(index) ? '#4CAF50' : '#FFFFFF')
              .padding(10)
              .onClick(() => {
                if (this.ctrlPressed) {
                  // 多选逻辑
                  const idx = this.selectedItems.indexOf(index)
                  if (idx > -1) {
                    this.selectedItems.splice(idx, 1)
                  } else {
                    this.selectedItems.push(index)
                  }
                } else {
                  // 单选逻辑
                  this.selectedItems = [index]
                }
              })
          }
        })
      }
      .width('100%')
      .height('80%')
      // 仍需监听按键释放
      .defaultFocus(true)
      .onKeyEvent((event?: KeyEvent) => {
        if (event && (event.keyCode === 2072 || event.keyCode === 2073)) {
          if (event.type === KeyType.Up) {
            this.ctrlPressed = false
            console.info('CTRL键释放')
          }
        }
      })
      Text(`已选择: ${this.selectedItems.length} 项`)
        .margin({ top: 20 })
    }
    .width('100%')
    .height('100%')
  }
}

方案三:使用 getModifierKeyState 实时查询(API 12+)

这个方案在点击时实时查询修饰键状态:

@Entry
@Component
struct MultiSelectList {
  @State selectedItems: number[] = []
  private listData: string[] = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']
  private lastKeyEvent: KeyEvent | null = null
  build() {
    Column() {
      List() {
        ForEach(this.listData, (item: string, index: number) => {
          ListItem() {
            Text(item)
              .width('100%')
              .height(50)
              .backgroundColor(this.selectedItems.includes(index) ? '#4CAF50' : '#FFFFFF')
              .padding(10)
              .onClick(() => {
                // 点击时检查CTRL键状态
                let isCtrlPressed = false
                if (this.lastKeyEvent && this.lastKeyEvent.getModifierKeyState) {
                  isCtrlPressed = this.lastKeyEvent.getModifierKeyState(['Ctrl'])
                } else if (this.lastKeyEvent) {
                  isCtrlPressed = this.lastKeyEvent.ctrlKey || false
                }
                if (isCtrlPressed) {
                  // 多选
                  const idx = this.selectedItems.indexOf(index)
                  if (idx > -1) {
                    this.selectedItems.splice(idx, 1)
                  } else {
                    this.selectedItems.push(index)
                  }
                } else {
                  // 单选
                  this.selectedItems = [index]
                }
              })
          }
        })
      }
      .width('100%')
      .height('80%')
      .defaultFocus(true)
      .onKeyEvent((event?: KeyEvent) => {
        // 保存最新的键盘事件
        if (event) {
          this.lastKeyEvent = event
        }
      })
      Text(`已选择: ${this.selectedItems.length} 项`)
        .margin({ top: 20 })
    }
    .width('100%')
    .height('100%')
  }
}

方案四:完整的多选实现(支持CTRL和SHIFT)

这是一个更完善的多选列表实现:

import { KeyCode } from '@kit.InputKit'
@Entry
@Component
struct AdvancedMultiSelectList {
  @State selectedItems: Set<number> = new Set()
  @State lastSelectedIndex: number = -1
  @State ctrlPressed: boolean = false
  @State shiftPressed: boolean = false
  private listData: string[] = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`)
  build() {
    Column() {
      Text(`多选模式: ${this.ctrlPressed ? 'CTRL' : this.shiftPressed ? 'SHIFT' : '单选'}`)
        .fontSize(14)
        .margin({ bottom: 10 })
      List({ space: 2 }) {
        ForEach(this.listData, (item: string, index: number) => {
          ListItem() {
            Row() {
              Checkbox()
                .select(this.selectedItems.has(index))
                .margin({ right: 10 })
              Text(item)
                .fontSize(16)
            }
            .width('100%')
            .height(50)
            .padding({ left: 15, right: 15 })
            .backgroundColor(this.selectedItems.has(index) ? '#E3F2FD' : '#FFFFFF')
            .onClick(() => {
              this.handleItemClick(index)
            })
          }
        })
      }
      .width('100%')
      .height('80%')
      .defaultFocus(true)
      .focusable(true)
      .onKeyEvent((event?: KeyEvent) => {
        if (event) {
          // 更新修饰键状态
          this.ctrlPressed = event.ctrlKey || false
          this.shiftPressed = event.shiftKey || false
          console.info(`按键状态 - CTRL: ${this.ctrlPressed}, SHIFT: ${this.shiftPressed}`)
        }
      })
      Row() {
        Text(`已选择: ${this.selectedItems.size} 项`)
        Button('清空选择')
          .margin({ left: 20 })
          .onClick(() => {
            this.selectedItems.clear()
          })
      }
      .margin({ top: 20 })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
  private handleItemClick(index: number): void {
    if (this.shiftPressed && this.lastSelectedIndex !== -1) {
      // SHIFT模式: 范围选择
      const start = Math.min(this.lastSelectedIndex, index)
      const end = Math.max(this.lastSelectedIndex, index)
      for (let i = start; i <= end; i++) {
        this.selectedItems.add(i)
      }
    } else if (this.ctrlPressed) {
      // CTRL模式: 多选切换
      if (this.selectedItems.has(index)) {
        this.selectedItems.delete(index)
      } else {
        this.selectedItems.add(index)
        this.lastSelectedIndex = index
      }
    } else {
      // 单选模式
      this.selectedItems.clear()
      this.selectedItems.add(index)
      this.lastSelectedIndex = index
    }
    // 触发UI更新
    this.selectedItems = new Set(this.selectedItems)
  }
}

关键要点

  1. onKeyEvent 必须在获得焦点的组件上才有效,需要设置:

    • .defaultFocus(true) 或
    • .focusable(true) + 手动获取焦点
  2. CTRL键的KeyCode:

    • 左CTRL: 2072 (KeyCode.KEYCODE_CTRL_LEFT)
    • 右CTRL: 2073 (KeyCode.KEYCODE_CTRL_RIGHT)
  3. 推荐使用 event.ctrlKey 属性,而不是判断keyCode,因为它会自动处理左右CTRL

  4. inputConsumer.on(‘hotkeyChange’) 必须有 finalKey,所以不适合只监听CTRL键

  5. 最佳方案: 使用方案一的 onKeyEvent + event.ctrlKey 属性

更多关于HarmonyOS鸿蒙Next中PC怎么监听键盘按键的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


技术大牛,佩服,

在HarmonyOS Next中,PC端监听键盘按键可通过@ohos.multimodalInput.inputEventClient模块实现。使用on('key')方法注册按键监听器,指定监听类型为key,并在回调函数中处理按键事件。示例代码:

import inputEventClient from '@ohos.multimodalInput.inputEventClient';

inputEventClient.on('key', (event) => {
  console.log('Key pressed: ' + event.keyCode);
});

该方法可捕获全局键盘事件,包括功能键和组合键。

在HarmonyOS Next中,监听单个按键(如CTRL键)可以使用@ohos.multimodalInput.inputEventClient模块的on('key')方法。以下是实现代码:

import inputEventClient from '@ohos.multimodalInput.inputEventClient';

// 注册按键监听
let keyDownListener = inputEventClient.on('key', (keyEvent) => {
  if (keyEvent.keyCode === 2039) { // KEYCODE_CTRL_LEFT
    console.log('CTRL键按下');
    // 处理多选逻辑
  }
});

// 取消监听(在适当时机调用)
// keyDownListener.off();

对于鼠标左键点击监听,可以使用@ohos.UiTest或组件自带的点击事件:

// 在列表项组件中
struct ListItem {
  build() {
    ListItem() {
      // ...
    }
    .onClick((event) => {
      if (/* 判断CTRL状态 */) {
        // 执行多选逻辑
      }
    })
  }
}

关键点:

  1. inputEventClient.on('key')可以监听所有按键事件
  2. 通过keyEvent.keyCode判断具体按键(2039对应左CTRL)
  3. 需要在module.json5中申请ohos.permission.INPUT_MONITORING权限
  4. 鼠标点击时检查CTRL键状态,实现多选逻辑

这种方法比hotkeyChange更适用于监听单个按键状态。

回到顶部