Skip to content

[web] Handling keyboard event doesn't prevent IME perform action #136460

@knopp

Description

@knopp
Code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    super.key,
  });

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with DeltaTextInputClient {
  TextInputConnection? _imeConnection;

  @override
  void initState() {
    super.initState();
    _attachToIme();
  }

  @override
  void dispose() {
    _detachFromIme();
    super.dispose();
  }

  @override
  void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {}

  void _attachToIme() {
    if (_imeConnection != null && _imeConnection!.attached) {
      return;
    }

    const config = TextInputConfiguration(
      enableDeltaModel: false,
      inputType: TextInputType.multiline,
      inputAction: TextInputAction.newline,
    );
    _imeConnection = TextInput.attach(this, config);
    _imeConnection!.setEditingState(const TextEditingValue());
    _imeConnection!.show();
  }

  void _detachFromIme() {
    _imeConnection?.close();
    _imeConnection = null;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Focus(
          autofocus: true,
          onKeyEvent: (node, event) {
            if (event is KeyDownEvent) {
              if (event.logicalKey == LogicalKeyboardKey.enter) {
                print('Enter pressed');
                return KeyEventResult.handled;
              }
            }
            return KeyEventResult.ignored;
          },
          child: const SizedBox()),
    );
  }

  @override
  void connectionClosed() {}

  @override
  AutofillScope? get currentAutofillScope => null;

  @override
  TextEditingValue? get currentTextEditingValue => TextEditingValue.empty;

  @override
  void didChangeInputControl(
      TextInputControl? oldControl, TextInputControl? newControl) {}

  @override
  void insertContent(KeyboardInsertedContent content) {}

  @override
  void insertTextPlaceholder(Size size) {}

  @override
  void performAction(TextInputAction action) {
    print('Action $action');
  }

  @override
  void performPrivateCommand(String action, Map<String, dynamic> data) {}

  @override
  void performSelector(String selectorName) {}

  @override
  void removeTextPlaceholder() {}

  @override
  void showAutocorrectionPromptRect(int start, int end) {}

  @override
  void showToolbar() {}

  @override
  void updateEditingValue(TextEditingValue value) {}

  @override
  void updateFloatingCursor(RawFloatingCursorPoint point) {}
}

Run and press enter. Expected output

flutter: Enter pressed

Output on web:

Action TextInputAction.newline
Enter pressed

This happens because the IME DOM keyboard event listener is separate and unaffected by raw keyboard event handler. Possible solution would be to run the raw keyboard handler in capture mode and then stop propagation for events that are handled by framework.

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: text inputEntering text in a text field or keyboard related problemsengineflutter/engine related. See also e: labels.found in release: 3.13Found to occur in 3.13found in release: 3.16Found to occur in 3.16has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyr: fixedIssue is closed as already fixed in a newer versionteam-webOwned by Web platform team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions