Skip to content

Instantly share code, notes, and snippets.

@iapicca
Last active August 12, 2022 12:20
Show Gist options
  • Select an option

  • Save iapicca/58d67ce83695b65db788f4a213115ff7 to your computer and use it in GitHub Desktop.

Select an option

Save iapicca/58d67ce83695b65db788f4a213115ff7 to your computer and use it in GitHub Desktop.
issue_109437
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MaterialApp(home: HomePage()));
extension HumanReadableRawKeyEventX on RawKeyEvent {
String get details => [
this is RawKeyDownEvent ? 'down' : 'up',
'$logicalKey',
'$physicalKey',
].join('\n');
}
class KeyLogger extends StatefulWidget {
final FocusNode focus;
const KeyLogger({
required this.focus,
super.key,
});
@override
State<KeyLogger> createState() => _KeyLoggerState();
}
class _KeyLoggerState extends State<KeyLogger> {
late final ValueNotifier<List<RawKeyEvent>> _events;
late final ScrollController _controller;
@override
void initState() {
_events = ValueNotifier([])..addListener(_onEventsUpdated);
_controller = ScrollController();
super.initState();
}
@override
void dispose() {
_events..removeListener(_onEventsUpdated)..dispose();
_controller.dispose();
super.dispose();
}
void addEvent(RawKeyEvent event) => _events.value = [..._events.value, event];
void _onEventsUpdated() {
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: kThemeAnimationDuration,
curve: Curves.easeIn,
);
}
@override
Widget build(context) => RawKeyboardListener(
focusNode: widget.focus,
onKey: addEvent,
autofocus: true,
child: ValueListenableBuilder<List<RawKeyEvent>>(
valueListenable: _events,
builder: (context, events, child) => ListView.separated(
controller: _controller,
itemCount: events.length,
itemBuilder: (context, index) => Text(events[index].details),
separatorBuilder: (context, index) => const Divider(),
),
),
);
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late final FocusNode _focus;
late final ValueNotifier<bool> _hasFocus;
@override
void initState() {
_focus = FocusNode()..addListener(_onFocusChanged);
_hasFocus = ValueNotifier(_focus.hasFocus);
super.initState();
}
@override
void dispose() {
_focus
..removeListener(_onFocusChanged)
..dispose();
_hasFocus.dispose();
super.dispose();
}
void _onFocusChanged() {
_hasFocus.value = _focus.hasFocus;
}
void _changeFocus() {
_focus.hasFocus ? _focus.unfocus() : _focus.requestFocus();
}
@override
Widget build(context) => Scaffold(
body: KeyLogger(focus: _focus),
floatingActionButton: FloatingActionButton(
onPressed: _changeFocus,
child: ValueListenableBuilder<bool>(
valueListenable: _hasFocus,
builder: (context, hasFocus, child) =>
hasFocus ? const Icon(Icons.done) : const Icon(Icons.error),
),
),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment