import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/models/settings/key_combinations.dart'; import 'package:fladder/screens/settings/widgets/key_listener.dart'; class InputHandler extends ConsumerStatefulWidget { final bool autoFocus; final KeyEventResult Function(FocusNode node, KeyEvent event)? onKeyEvent; final bool Function(T result)? keyMapResult; final Map? keyMap; final Widget child; const InputHandler({ required this.child, this.autoFocus = true, this.onKeyEvent, this.keyMapResult, this.keyMap, super.key, }); @override ConsumerState createState() => _InputHandlerState(); } class _InputHandlerState extends ConsumerState> { final focusNode = FocusNode(); LogicalKeyboardKey? pressedModifier; @override void initState() { super.initState(); // Focus on start focusNode.requestFocus(); } @override Widget build(BuildContext context) { return Focus( autofocus: widget.autoFocus, focusNode: focusNode, skipTraversal: true, onFocusChange: (value) { if (!focusNode.hasFocus && widget.autoFocus) { focusNode.requestFocus(); } }, onKeyEvent: widget.onKeyEvent ?? (node, event) => _onKey(event), child: widget.child, ); } KeyEventResult _onKey(KeyEvent value) { if (changingShortCut) return KeyEventResult.ignored; final keyMap = widget.keyMap?.entries.nonNulls.toList() ?? []; if (value is KeyDownEvent || value is KeyRepeatEvent) { if (KeyCombination.modifierKeys.contains(value.logicalKey)) { pressedModifier = value.logicalKey; } for (var entry in keyMap) { final hotKey = entry.key; final keyCombination = entry.value; bool isMainKeyPressed = value.logicalKey == keyCombination.key; bool isModifierKeyPressed = pressedModifier == keyCombination.modifier; bool isAltKeyPressed = value.logicalKey == keyCombination.altKey; bool isAltModifierKeyPressed = pressedModifier == keyCombination.altModifier; if ((isMainKeyPressed && isModifierKeyPressed) || isAltKeyPressed && isAltModifierKeyPressed) { if (widget.keyMapResult?.call(hotKey) ?? false) { return KeyEventResult.handled; } else { return KeyEventResult.ignored; } } } } else if (value is KeyUpEvent) { if (KeyCombination.modifierKeys.contains(value.logicalKey)) { pressedModifier = null; } } return KeyEventResult.ignored; } }