Flutter桌面端开发——快捷键

hotkey_manager

该插件由LeanFlutter维护支持

安装🛠

点击hotkey_manager获取最新版本。以下是在编写本文章时的最新版本:

hotkey_manager: ^0.1.7

使用🍚

如果全局使用,需要在main方法中插入以下代码

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await hotKeyManager.unregisterAll();
  runApp(MyApp());
}

如果在某个页面使用,在 initState 方法中进行操作

void initState() {
  super.initState();
  _init();
}

_init() async {
  await hotKeyManager.unregisterAll();
}

注册快捷键

注册快捷键需要使用 hotKeyManager.register 方法。该方法可以传递3个参数:

  • HotKey hotKey:快捷键对象,可以传入4个属性
    • KeyCode keyCode:快捷键
    • List ? modifiers:修饰符,Alt、Shift 等
    • String? identifier:标识符
    • HotKeyScope? scope:快捷键范围。有 HotKeyScope.system(默认) 和 HotKeyScope.inapp 两个值
  • void Function(HotKey)? keyDownHandler:快捷键按下事件
  • void Function(HotKey)? keyUpHandler:快捷键抬起事件(仅macOS )

定义两个变量来存储按下的信息

String _message = '你还未按下任何快捷键';
int _count = 0;
_init() async {
  await hotKeyManager.unregisterAll();
  await hotKeyManager.register(
    HotKey(KeyCode.f1),
    keyDownHandler: (_) {
      _count++;
      _message = '按下了F1键$_count次';
      setState(() {});
    },
  );
}

image

默认注册的是全局快捷键,如果你焦点不在自己的程序上,也会调用该方法

我们给快捷键加上修饰符

HotKey(KeyCode.f1, modifiers: [KeyModifier.alt]),

现在只有同时按下 Alt + F1 才会调用,无法演示我按了什么键,所以可以自己试一下。

注销快捷键

注销快捷键需要使用 hotKeyManager.unregister,为了方便管理,我们把 HotKey 对象提取出来

final _hotKey = HotKey(KeyCode.f1, modifiers: [KeyModifier.alt]);
_unregister(HotKey hotKey) async {
  if (hotKeyManager.registeredHotKeyList.contains(hotKey)) {
    await hotKeyManager.unregister(hotKey);
    _message = '快捷键注销成功';
    setState(() {});
  }
}

image

显示快捷键

该插件中有一个组件可以显示设置的快捷键

HotKeyVirtualView(hotKey: _hotKey),

录制快捷键

插件中还有一个 HotKeyRecorder 组件可以帮我们录制快捷键。该组件一共有3个属性:

  • Key? key:标识
  • HotKey? initalHotKey:初始快捷键
  • void Function(HotKey) onHotKeyRecorded:录制快捷键的方法

为了方便,我们把注册快捷键的方法提取出来更改一下

_register(HotKey hotKey) async {
  await hotKeyManager.register(
    hotKey,
    keyDownHandler: (_) {
      _count++;
      if (hotKey.modifiers == null) {
        _message = '按下了快捷键${hotKey.keyCode.keyLabel} $_count次';
      } else {
        _message = '按下了快捷键';
        for (var key in hotKey.modifiers!) {
          _message += '${key.keyLabel} + ';
        }
        _message += '${hotKey.keyCode.keyLabel} $_count次';
      }
      setState(() {});
    },
  );
  hotKeyManager.registeredHotKeyList;
}

再使用 HotKeyRecorder 组件

HotKeyRecorder(
  initalHotKey: _hotKey,
  onHotKeyRecorded: (hotKey) {
    _newHotKey = hotKey;
    // _newHotKey?.scope = HotKeyScope.inapp;
    setState(() {});
  },
),

这里我修改了以前的快捷键,以前那个可能冲突了突然用不了

HotKey _hotKey = HotKey(KeyCode.f2, modifiers: [KeyModifier.alt]);

这里我使用一个变量来存储新建的快捷键

TextButton(
  onPressed: _newHotKey == null
      ? () {}
      : () async {
          _count = 0;
          _unregister(_hotKey);
          _hotKey = _newHotKey!;
          _register(_hotKey);
          _newHotKey = null;
          _message = '快捷键修改成功';
          setState(() {});
        },
  child: const Text('更改快捷键'),
),

image

FocusableActionDetector

以下内容来源于《Using Keyboard Shortcuts in Flutter Desktop. A Simple Guide.》

Flutter中有一个 RawKeyboardListener 组件可以监听用户按下的键盘,但是一次只能监听一个。而FocusableActionDetector附带了一个非常简单的用于侦听键盘快捷键的 API,它接受一个快捷键(LogicalKeySet: Intent)和动作(Intent: Action)的映射。

我们先来做个简单的数字加减功能

import 'package:flutter/material.dart';

class UseFlutterWidget extends StatefulWidget {
  const UseFlutterWidget({Key? key}) : super(key: key);

  @override
  State<UseFlutterWidget> createState() => _UseFlutterWidgetState();
}

class _UseFlutterWidgetState extends State<UseFlutterWidget> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('$_count', style: const TextStyle(fontSize: 48)),
          const SizedBox(height: 24),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(onPressed: _increment, child: const Text('+1')),
              const SizedBox(width: 24),
              ElevatedButton(onPressed: _decrement, child: const Text('-1')),
            ],
          ),
        ],
      ),
    );
  }

  void _increment() {
    _count++;
    setState(() {});
  }

  void _decrement() {
    _count--;
    setState(() {});
  }
}

image

接下来就可以为这两个方法来创建快捷键了。

首先,我们需要为该方法创建快捷键和意图

final incrementKey = LogicalKeySet(
  LogicalKeyboardKey.control,
  LogicalKeyboardKey.arrowUp,
);

final decrementKey = LogicalKeySet(
  LogicalKeyboardKey.control,
  LogicalKeyboardKey.arrowDown,
);

class IncrementIntent extends Intent {}

class DecrementIntent extends Intent {}

关于Flutter中键盘按键相关的可以查看文档

创建一个计数快捷键的组件

class CounterShortcuts extends StatelessWidget {
  const CounterShortcuts({
    Key? key,
    required this.child,
    required this.onIncrementDetected,
    required this.onDecrementDetected,
  }) : super(key: key);

  final Widget child;
  final VoidCallback onIncrementDetected;
  final VoidCallback onDecrementDetected;

  @override
  Widget build(BuildContext context) {
    return FocusableActionDetector(
      autofocus: true,
      shortcuts: {
        incrementKey: IncrementIntent(),
        decrementKey: DecrementIntent(),
      },
      actions: {
        IncrementIntent: CallbackAction(
          onInvoke: (_) => onIncrementDetected.call(),
        ),
        DecrementIntent: CallbackAction(
          onInvoke: (_) => onDecrementDetected.call(),
        ),
      },
      child: child,
    );
  }
}

把该组件作为前面写的父组件

class _UseFlutterWidgetState extends State<UseFlutterWidget> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return CounterShortcuts(
      onIncrementDetected: _increment,
      onDecrementDetected: _decrement,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('$_count', style: const TextStyle(fontSize: 48)),
            const SizedBox(height: 24),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(onPressed: _increment, child: const Text('+1')),
                const SizedBox(width: 24),
                ElevatedButton(onPressed: _decrement, child: const Text('-1')),
              ],
            ),
          ],
        ),
      ),
    );
  }

  void _increment() {
    _count++;
    setState(() {});
  }

  void _decrement() {
    _count--;
    setState(() {});
  }
}

image

🛫OK,以上就是这篇文章的全部内容,在使用插件前请先对照好版本,新版本可能会更改用法。本实例代码已上传至 githubgitee,有需要的可以下载下来查看学习。

posted @ 2022-05-11 11:30  菠萝橙子丶  阅读(1266)  评论(0编辑  收藏  举报