diff --git a/lib/app.dart b/lib/app.dart index 883c28d8c4..8d830eadd4 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -30,6 +30,7 @@ import 'utils/extension/extension.dart'; import 'utils/hook.dart'; import 'utils/logger.dart'; import 'utils/system/system_fonts.dart'; +import 'utils/system/text_input.dart'; import 'utils/system/tray.dart'; import 'widgets/brightness_observer.dart'; import 'widgets/focus_helper.dart'; @@ -226,7 +227,11 @@ class _App extends StatelessWidget { ? textScaleFactor : mediaQueryData.textScaleFactor, ), - child: SystemTrayWidget(child: child!), + child: SystemTrayWidget( + child: TextInputActionHandler( + child: child!, + ), + ), ), ); }, diff --git a/lib/utils/system/text_input.dart b/lib/utils/system/text_input.dart new file mode 100644 index 0000000000..cf5a29d83d --- /dev/null +++ b/lib/utils/system/text_input.dart @@ -0,0 +1,86 @@ +import 'dart:io'; + +import 'package:flutter/widgets.dart'; + +import '../logger.dart'; + +// remove this once https://github.com/flutter/flutter/issues/111113 is fixed. +class TextInputActionHandler extends StatefulWidget { + const TextInputActionHandler({ + super.key, + required this.child, + }); + + final Widget child; + + @override + State createState() => _TextInputActionHandlerState(); +} + +class _TextInputActionHandlerState extends State { + late final _actions = >{ + DeleteCharacterIntent: makeAction(context), + ExtendSelectionByCharacterIntent: + makeAction(context), + ExtendSelectionVerticallyToAdjacentLineIntent: + makeAction(context), + SelectAllTextIntent: makeAction(context), + PasteTextIntent: makeAction(context), + RedoTextIntent: makeAction(context), + UndoTextIntent: makeAction(context), + }; + + @override + Widget build(BuildContext context) { + if (!Platform.isMacOS) { + return widget.child; + } + return Actions( + actions: _actions, + child: widget.child, + ); + } +} + +Action makeAction(BuildContext context) => + Action.overridable( + defaultAction: _CallbackContextAction(), + context: context, + ); + +class _CallbackContextAction extends ContextAction { + _CallbackContextAction(); + + bool? _consumeKey; + + @override + bool consumesKey(T intent) { + final consumeKey = _consumeKey; + _consumeKey = null; + if (consumeKey != null) { + return consumeKey; + } + return callingAction?.consumesKey(intent) ?? true; + } + + @override + Object? invoke(T intent, [BuildContext? context]) { + if (context == null) { + e('No context provided to _CallbackContextAction'); + return callingAction?.invoke(intent); + } + final state = context.findAncestorStateOfType(); + if (state == null) { + e('failed to find EditableTextState'); + return callingAction?.invoke(intent); + } + + final composingRange = state.textEditingValue.composing; + + if (composingRange.isValid && !composingRange.isCollapsed) { + _consumeKey = false; + return null; + } + return callingAction?.invoke(intent); + } +}