blob: 0db2898b799a79c6d0256b8afdff62157cee35fd [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'basic.dart';
import 'focus_manager.dart';
import 'framework.dart';
export 'package:flutter/services.dart' show RawKeyEvent;
/// A widget that calls a callback whenever the user presses or releases a key
/// on a keyboard.
///
/// A [RawKeyboardListener] is useful for listening to raw key events and
/// hardware buttons that are represented as keys. Typically used by games and
/// other apps that use keyboards for purposes other than text entry.
///
/// For text entry, consider using a [EditableText], which integrates with
/// on-screen keyboards and input method editors (IMEs).
///
/// See also:
///
/// * [EditableText], which should be used instead of this widget for text
/// entry.
class RawKeyboardListener extends StatefulWidget {
/// Creates a widget that receives raw keyboard events.
///
/// For text entry, consider using a [EditableText], which integrates with
/// on-screen keyboards and input method editors (IMEs).
const RawKeyboardListener({
Key key,
@required this.focusNode,
@required this.onKey,
@required this.child,
}) : assert(focusNode != null),
assert(child != null),
super(key: key);
/// Controls whether this widget has keyboard focus.
final FocusNode focusNode;
/// Called whenever this widget receives a raw keyboard event.
final ValueChanged<RawKeyEvent> onKey;
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.child}
final Widget child;
@override
_RawKeyboardListenerState createState() => new _RawKeyboardListenerState();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<FocusNode>('focusNode', focusNode));
}
}
class _RawKeyboardListenerState extends State<RawKeyboardListener> {
@override
void initState() {
super.initState();
widget.focusNode.addListener(_handleFocusChanged);
}
@override
void didUpdateWidget(RawKeyboardListener oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.focusNode != oldWidget.focusNode) {
oldWidget.focusNode.removeListener(_handleFocusChanged);
widget.focusNode.addListener(_handleFocusChanged);
}
}
@override
void dispose() {
widget.focusNode.removeListener(_handleFocusChanged);
_detachKeyboardIfAttached();
super.dispose();
}
void _handleFocusChanged() {
if (widget.focusNode.hasFocus)
_attachKeyboardIfDetached();
else
_detachKeyboardIfAttached();
}
bool _listening = false;
void _attachKeyboardIfDetached() {
if (_listening)
return;
RawKeyboard.instance.addListener(_handleRawKeyEvent);
_listening = true;
}
void _detachKeyboardIfAttached() {
if (!_listening)
return;
RawKeyboard.instance.removeListener(_handleRawKeyEvent);
_listening = false;
}
void _handleRawKeyEvent(RawKeyEvent event) {
if (widget.onKey != null)
widget.onKey(event);
}
@override
Widget build(BuildContext context) => widget.child;
}