Skip to content

Commit 7422790

Browse files
committed
feat: Add CallbackGlobalShortcuts and GlobalShortcuts Widgets.
1 parent badd689 commit 7422790

File tree

7 files changed

+187
-9
lines changed

7 files changed

+187
-9
lines changed

README-ZH.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
```yaml
5151
dependencies:
52-
hotkey_manager: ^0.2.1
52+
hotkey_manager: ^0.2.2
5353
```
5454
5555

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Add this to your package's pubspec.yaml file:
4949

5050
```yaml
5151
dependencies:
52-
hotkey_manager: ^0.2.1
52+
hotkey_manager: ^0.2.2
5353
```
5454
5555
Or

packages/hotkey_manager/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.2
2+
3+
* feat: Add `CallbackGlobalShortcuts` and `GlobalShortcuts` Widgets.
4+
15
## 0.2.1
26

37
* Fixed issue where modifiers do not work #50

packages/hotkey_manager/example/lib/pages/home.dart

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@ import 'package:bot_toast/bot_toast.dart';
22
import 'package:flutter/cupertino.dart';
33
import 'package:flutter/foundation.dart';
44
import 'package:flutter/material.dart';
5+
import 'package:flutter/services.dart';
56
import 'package:hotkey_manager/hotkey_manager.dart';
67
import 'package:hotkey_manager_example/widgets/record_hotkey_dialog.dart';
78
import 'package:preference_list/preference_list.dart';
89

10+
class ExampleIntent extends Intent {}
11+
12+
class ExampleAction extends Action<ExampleIntent> {
13+
@override
14+
void invoke(covariant ExampleIntent intent) {
15+
BotToast.showText(text: 'ExampleAction invoked');
16+
}
17+
}
18+
919
class HomePage extends StatefulWidget {
1020
const HomePage({super.key});
1121

@@ -139,13 +149,34 @@ class _HomePageState extends State<HomePage> {
139149
);
140150
}
141151

142-
@override
143-
Widget build(BuildContext context) {
152+
Widget _build(BuildContext context) {
144153
return Scaffold(
145154
appBar: AppBar(
146155
title: const Text('Example'),
147156
),
148-
body: _buildBody(context),
157+
body: Column(
158+
children: [
159+
Expanded(
160+
child: _buildBody(context),
161+
),
162+
],
163+
),
164+
);
165+
}
166+
167+
@override
168+
Widget build(BuildContext context) {
169+
return Actions(
170+
actions: <Type, Action<Intent>>{
171+
ExampleIntent: ExampleAction(),
172+
},
173+
child: GlobalShortcuts(
174+
shortcuts: {
175+
const SingleActivator(LogicalKeyboardKey.keyA, alt: true):
176+
ExampleIntent(),
177+
},
178+
child: _build(context),
179+
),
149180
);
150181
}
151182
}

packages/hotkey_manager/lib/hotkey_manager.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1+
export 'package:hotkey_manager/src/hotkey_manager.dart';
2+
export 'package:hotkey_manager/src/widgets/global_shortcuts.dart';
3+
export 'package:hotkey_manager/src/widgets/hotkey_recorder.dart';
4+
export 'package:hotkey_manager/src/widgets/hotkey_virtual_view.dart';
15
export 'package:hotkey_manager_platform_interface/hotkey_manager_platform_interface.dart';
2-
export './src/hotkey_manager.dart';
3-
export './src/widgets/hotkey_recorder.dart';
4-
export './src/widgets/hotkey_virtual_view.dart';
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import 'package:flutter/widgets.dart';
2+
import 'package:hotkey_manager/hotkey_manager.dart';
3+
4+
extension _SingleActivatorExtension on SingleActivator {
5+
HotKey _toHotKey() {
6+
List<HotKeyModifier> modifiers = [
7+
if (control) HotKeyModifier.control,
8+
if (shift) HotKeyModifier.shift,
9+
if (alt) HotKeyModifier.alt,
10+
if (meta) HotKeyModifier.meta,
11+
];
12+
return HotKey(
13+
identifier: [
14+
...modifiers.map((m) => m.name),
15+
'${trigger.keyId}',
16+
].join('+'),
17+
key: trigger,
18+
modifiers: modifiers,
19+
scope: HotKeyScope.system,
20+
);
21+
}
22+
}
23+
24+
class GlobalShortcuts extends StatefulWidget {
25+
const GlobalShortcuts({
26+
super.key,
27+
required this.shortcuts,
28+
required this.child,
29+
});
30+
31+
final Map<SingleActivator, Intent> shortcuts;
32+
33+
final Widget child;
34+
35+
@override
36+
State<GlobalShortcuts> createState() => _GlobalShortcutsState();
37+
}
38+
39+
class _GlobalShortcutsState extends State<GlobalShortcuts> {
40+
final List<HotKey> _registeredHotKeys = [];
41+
42+
@override
43+
void initState() {
44+
super.initState();
45+
for (final entry in widget.shortcuts.entries) {
46+
final hotKey = entry.key._toHotKey();
47+
hotKeyManager.register(hotKey, keyDownHandler: _onKeyDown);
48+
_registeredHotKeys.add(hotKey);
49+
}
50+
}
51+
52+
@override
53+
void dispose() {
54+
super.dispose();
55+
for (final hotKey in _registeredHotKeys) {
56+
hotKeyManager.unregister(hotKey);
57+
}
58+
_registeredHotKeys.clear();
59+
}
60+
61+
void _onKeyDown(HotKey hotKey) {
62+
final activator = widget.shortcuts.keys.firstWhere(
63+
(activator) => activator._toHotKey().identifier == hotKey.identifier,
64+
);
65+
final Intent? matchedIntent = widget.shortcuts[activator];
66+
if (matchedIntent != null) {
67+
final Action<Intent>? action = Actions.maybeFind<Intent>(
68+
context,
69+
intent: matchedIntent,
70+
);
71+
if (action != null) {
72+
final (bool enabled, Object? invokeResult) =
73+
Actions.of(context).invokeActionIfEnabled(
74+
action,
75+
matchedIntent,
76+
context,
77+
);
78+
if (enabled) {
79+
action.toKeyEventResult(matchedIntent, invokeResult);
80+
}
81+
}
82+
}
83+
}
84+
85+
@override
86+
Widget build(BuildContext context) {
87+
return widget.child;
88+
}
89+
}
90+
91+
class CallbackGlobalShortcuts extends StatefulWidget {
92+
const CallbackGlobalShortcuts({
93+
super.key,
94+
required this.bindings,
95+
required this.child,
96+
});
97+
98+
final Map<SingleActivator, VoidCallback> bindings;
99+
100+
final Widget child;
101+
102+
@override
103+
State<CallbackGlobalShortcuts> createState() =>
104+
_CallbackGlobalShortcutsState();
105+
}
106+
107+
class _CallbackGlobalShortcutsState extends State<CallbackGlobalShortcuts> {
108+
final List<HotKey> _registeredHotKeys = [];
109+
110+
Map<SingleActivator, VoidCallback> get bindings => widget.bindings;
111+
112+
@override
113+
void initState() {
114+
super.initState();
115+
for (final entry in widget.bindings.entries) {
116+
final hotKey = entry.key._toHotKey();
117+
hotKeyManager.register(hotKey, keyDownHandler: _onKeyDown);
118+
_registeredHotKeys.add(hotKey);
119+
}
120+
}
121+
122+
@override
123+
void dispose() {
124+
super.dispose();
125+
for (final hotKey in _registeredHotKeys) {
126+
hotKeyManager.unregister(hotKey);
127+
}
128+
_registeredHotKeys.clear();
129+
}
130+
131+
void _onKeyDown(HotKey hotKey) {
132+
final activator = bindings.keys.firstWhere(
133+
(activator) => activator._toHotKey().identifier == hotKey.identifier,
134+
);
135+
bindings[activator]!.call();
136+
}
137+
138+
@override
139+
Widget build(BuildContext context) {
140+
return widget.child;
141+
}
142+
}

packages/hotkey_manager/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: hotkey_manager
22
description: This plugin allows Flutter desktop apps to defines system/inapp wide hotkey (i.e. shortcut).
3-
version: 0.2.1
3+
version: 0.2.2
44
homepage: https://github.com/leanflutter/hotkey_manager
55

66
platforms:

0 commit comments

Comments
 (0)