1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/foundation.dart'; |
6 | import 'package:flutter/services.dart'; |
7 | |
8 | import 'focus_manager.dart'; |
9 | import 'focus_scope.dart'; |
10 | import 'framework.dart'; |
11 | |
12 | export 'package:flutter/services.dart' show RawKeyEvent; |
13 | |
14 | /// A widget that calls a callback whenever the user presses or releases a key |
15 | /// on a keyboard. |
16 | /// |
17 | /// The [RawKeyboardListener] is deprecated and will be removed. Use |
18 | /// [KeyboardListener] instead. |
19 | /// |
20 | /// A [RawKeyboardListener] is useful for listening to raw key events and |
21 | /// hardware buttons that are represented as keys. Typically used by games and |
22 | /// other apps that use keyboards for purposes other than text entry. |
23 | /// |
24 | /// For text entry, consider using a [EditableText], which integrates with |
25 | /// on-screen keyboards and input method editors (IMEs). |
26 | /// |
27 | /// See also: |
28 | /// |
29 | /// * [EditableText], which should be used instead of this widget for text |
30 | /// entry. |
31 | /// * [KeyboardListener], a similar widget based on the newer [HardwareKeyboard] |
32 | /// API. |
33 | @Deprecated( |
34 | 'Use KeyboardListener instead. ' |
35 | 'This feature was deprecated after v3.18.0-2.0.pre.' , |
36 | ) |
37 | class RawKeyboardListener extends StatefulWidget { |
38 | /// Creates a widget that receives raw keyboard events. |
39 | /// |
40 | /// For text entry, consider using a [EditableText], which integrates with |
41 | /// on-screen keyboards and input method editors (IMEs). |
42 | @Deprecated( |
43 | 'Use KeyboardListener instead. ' |
44 | 'This feature was deprecated after v3.18.0-2.0.pre.' , |
45 | ) |
46 | const RawKeyboardListener({ |
47 | super.key, |
48 | required this.focusNode, |
49 | this.autofocus = false, |
50 | this.includeSemantics = true, |
51 | this.onKey, |
52 | required this.child, |
53 | }); |
54 | |
55 | /// Controls whether this widget has keyboard focus. |
56 | final FocusNode focusNode; |
57 | |
58 | /// {@macro flutter.widgets.Focus.autofocus} |
59 | final bool autofocus; |
60 | |
61 | /// {@macro flutter.widgets.Focus.includeSemantics} |
62 | final bool includeSemantics; |
63 | |
64 | /// Called whenever this widget receives a raw keyboard event. |
65 | final ValueChanged<RawKeyEvent>? onKey; |
66 | |
67 | /// The widget below this widget in the tree. |
68 | /// |
69 | /// {@macro flutter.widgets.ProxyWidget.child} |
70 | final Widget child; |
71 | |
72 | @override |
73 | State<RawKeyboardListener> createState() => _RawKeyboardListenerState(); |
74 | |
75 | @override |
76 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
77 | super.debugFillProperties(properties); |
78 | properties.add(DiagnosticsProperty<FocusNode>('focusNode' , focusNode)); |
79 | } |
80 | } |
81 | |
82 | class _RawKeyboardListenerState extends State<RawKeyboardListener> { |
83 | @override |
84 | void initState() { |
85 | super.initState(); |
86 | widget.focusNode.addListener(_handleFocusChanged); |
87 | } |
88 | |
89 | @override |
90 | void didUpdateWidget(RawKeyboardListener oldWidget) { |
91 | super.didUpdateWidget(oldWidget); |
92 | if (widget.focusNode != oldWidget.focusNode) { |
93 | oldWidget.focusNode.removeListener(_handleFocusChanged); |
94 | widget.focusNode.addListener(_handleFocusChanged); |
95 | } |
96 | } |
97 | |
98 | @override |
99 | void dispose() { |
100 | widget.focusNode.removeListener(_handleFocusChanged); |
101 | _detachKeyboardIfAttached(); |
102 | super.dispose(); |
103 | } |
104 | |
105 | void _handleFocusChanged() { |
106 | if (widget.focusNode.hasFocus) { |
107 | _attachKeyboardIfDetached(); |
108 | } else { |
109 | _detachKeyboardIfAttached(); |
110 | } |
111 | } |
112 | |
113 | bool _listening = false; |
114 | |
115 | void _attachKeyboardIfDetached() { |
116 | if (_listening) { |
117 | return; |
118 | } |
119 | RawKeyboard.instance.addListener(_handleRawKeyEvent); |
120 | _listening = true; |
121 | } |
122 | |
123 | void _detachKeyboardIfAttached() { |
124 | if (!_listening) { |
125 | return; |
126 | } |
127 | RawKeyboard.instance.removeListener(_handleRawKeyEvent); |
128 | _listening = false; |
129 | } |
130 | |
131 | void _handleRawKeyEvent(RawKeyEvent event) { |
132 | widget.onKey?.call(event); |
133 | } |
134 | |
135 | @override |
136 | Widget build(BuildContext context) { |
137 | return Focus( |
138 | focusNode: widget.focusNode, |
139 | autofocus: widget.autofocus, |
140 | includeSemantics: widget.includeSemantics, |
141 | child: widget.child, |
142 | ); |
143 | } |
144 | } |
145 | |