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