blob: 86e92127f13a85916e6e4ad198530b183ff9c7d3 [file] [log] [blame]
// Copyright 2014 The Flutter 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/material.dart';
import 'package:flutter/services.dart';
import 'binding.dart';
/// Processes text input events that were not handled by the framework.
abstract class TestTextInputKeyHandler {
/// Process key down event that was not handled by the framework.
Future<void> handleKeyDownEvent(LogicalKeyboardKey key);
/// Process key up event that was not handled by the framework.
Future<void> handleKeyUpEvent(LogicalKeyboardKey key);
}
/// MacOS specific key input handler. This class translates standard macOS text editing shortcuts
/// into appropriate selectors similarly to what NSTextInputContext does in Flutter Engine.
class MacOSTestTextInputKeyHandler extends TestTextInputKeyHandler {
/// Create a new macOS specific text input handler.
MacOSTestTextInputKeyHandler(this.client);
/// ClientId of TextInput
final int client;
Future<void> _sendSelectors(List<String> selectors) async {
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger
.handlePlatformMessage(
SystemChannels.textInput.name,
SystemChannels.textInput.codec.encodeMethodCall(
MethodCall(
'TextInputClient.performSelectors', <dynamic>[client, selectors]),
),
(ByteData? data) {/* response from framework is discarded */},
);
}
// These combinations must match NSStandardKeyBindingResponding.
static final Map<SingleActivator, List<String>> _macOSActivatorToSelectors =
<SingleActivator, List<String>>{
for (final bool pressShift in const <bool>[
true,
false
]) ...<SingleActivator, List<String>>{
SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift):
<String>['deleteBackward:'],
SingleActivator(LogicalKeyboardKey.backspace,
alt: true, shift: pressShift): <String>['deleteWordBackward:'],
SingleActivator(LogicalKeyboardKey.backspace,
meta: true, shift: pressShift): <String>['deleteToBeginningOfLine:'],
SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): <String>[
'deleteForward:'
],
SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: pressShift):
<String>['deleteWordForward:'],
SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: pressShift):
<String>['deleteToEndOfLine:'],
},
const SingleActivator(LogicalKeyboardKey.arrowLeft): <String>['moveLeft:'],
const SingleActivator(LogicalKeyboardKey.arrowRight): <String>[
'moveRight:'
],
const SingleActivator(LogicalKeyboardKey.arrowUp): <String>['moveUp:'],
const SingleActivator(LogicalKeyboardKey.arrowDown): <String>['moveDown:'],
const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): <String>[
'moveLeftAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): <String>[
'moveRightAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): <String>[
'moveUpAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): <String>[
'moveDownAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): <String>[
'moveWordLeft:'
],
const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): <String>[
'moveWordRight:'
],
const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): <String>[
'moveBackward:',
'moveToBeginningOfParagraph:'
],
const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): <String>[
'moveForward:',
'moveToEndOfParagraph:'
],
const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true, shift: true):
<String>['moveWordLeftAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.arrowRight,
alt: true, shift: true): <String>['moveWordRightAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true, shift: true):
<String>['moveParagraphBackwardAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true, shift: true):
<String>['moveParagraphForwardAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): <String>[
'moveToLeftEndOfLine:'
],
const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): <String>[
'moveToRightEndOfLine:'
],
const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): <String>[
'moveToBeginningOfDocument:'
],
const SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): <String>[
'moveToEndOfDocument:'
],
const SingleActivator(LogicalKeyboardKey.arrowLeft,
meta: true,
shift: true): <String>['moveToLeftEndOfLineAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.arrowRight,
meta: true,
shift: true): <String>['moveToRightEndOfLineAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true, shift: true):
<String>['moveToBeginningOfDocumentAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.arrowDown,
meta: true,
shift: true): <String>['moveToEndOfDocumentAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyA, control: true, shift: true):
<String>['moveToBeginningOfParagraphAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyA, control: true): <String>[
'moveToBeginningOfParagraph:'
],
const SingleActivator(LogicalKeyboardKey.keyB, control: true, shift: true):
<String>['moveBackwardAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyB, control: true): <String>[
'moveBackward:'
],
const SingleActivator(LogicalKeyboardKey.keyE, control: true, shift: true):
<String>['moveToEndOfParagraphAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyE, control: true): <String>[
'moveToEndOfParagraph:'
],
const SingleActivator(LogicalKeyboardKey.keyF, control: true, shift: true):
<String>['moveForwardAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyF, control: true): <String>[
'moveForward:'
],
const SingleActivator(LogicalKeyboardKey.keyK, control: true): <String>[
'deleteToEndOfParagraph'
],
const SingleActivator(LogicalKeyboardKey.keyL, control: true): <String>[
'centerSelectionInVisibleArea'
],
const SingleActivator(LogicalKeyboardKey.keyN, control: true): <String>[
'moveDown:'
],
const SingleActivator(LogicalKeyboardKey.keyN, control: true, shift: true):
<String>['moveDownAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyO, control: true): <String>[
'insertNewlineIgnoringFieldEditor:'
],
const SingleActivator(LogicalKeyboardKey.keyP, control: true): <String>[
'moveUp:'
],
const SingleActivator(LogicalKeyboardKey.keyP, control: true, shift: true):
<String>['moveUpAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyT, control: true): <String>[
'transpose:'
],
const SingleActivator(LogicalKeyboardKey.keyV, control: true): <String>[
'pageDown:'
],
const SingleActivator(LogicalKeyboardKey.keyV, control: true, shift: true):
<String>['pageDownAndModifySelection:'],
const SingleActivator(LogicalKeyboardKey.keyY, control: true): <String>[
'yank:'
],
const SingleActivator(LogicalKeyboardKey.quoteSingle, control: true):
<String>['insertSingleQuoteIgnoringSubstitution:'],
const SingleActivator(LogicalKeyboardKey.quote, control: true): <String>[
'insertDoubleQuoteIgnoringSubstitution:'
],
const SingleActivator(LogicalKeyboardKey.home): <String>[
'scrollToBeginningOfDocument:'
],
const SingleActivator(LogicalKeyboardKey.end): <String>[
'scrollToEndOfDocument:'
],
const SingleActivator(LogicalKeyboardKey.home, shift: true): <String>[
'moveToBeginningOfDocumentAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.end, shift: true): <String>[
'moveToEndOfDocumentAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.pageUp): <String>['scrollPageUp:'],
const SingleActivator(LogicalKeyboardKey.pageDown): <String>[
'scrollPageDown:'
],
const SingleActivator(LogicalKeyboardKey.pageUp, shift: true): <String>[
'pageUpAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.pageDown, shift: true): <String>[
'pageDownAndModifySelection:'
],
const SingleActivator(LogicalKeyboardKey.escape): <String>[
'cancelOperation:'
],
const SingleActivator(LogicalKeyboardKey.enter): <String>['insertNewline:'],
const SingleActivator(LogicalKeyboardKey.enter, alt: true): <String>[
'insertNewlineIgnoringFieldEditor:'
],
const SingleActivator(LogicalKeyboardKey.enter, control: true): <String>[
'insertLineBreak:'
],
const SingleActivator(LogicalKeyboardKey.tab): <String>['insertTab:'],
const SingleActivator(LogicalKeyboardKey.tab, alt: true): <String>[
'insertTabIgnoringFieldEditor:'
],
const SingleActivator(LogicalKeyboardKey.tab, shift: true): <String>[
'insertBacktab:'
],
};
@override
Future<void> handleKeyDownEvent(LogicalKeyboardKey key) async {
if (key == LogicalKeyboardKey.shift ||
key == LogicalKeyboardKey.shiftLeft ||
key == LogicalKeyboardKey.shiftRight) {
_shift = true;
} else if (key == LogicalKeyboardKey.alt ||
key == LogicalKeyboardKey.altLeft ||
key == LogicalKeyboardKey.altRight) {
_alt = true;
} else if (key == LogicalKeyboardKey.meta ||
key == LogicalKeyboardKey.metaLeft ||
key == LogicalKeyboardKey.metaRight) {
_meta = true;
} else if (key == LogicalKeyboardKey.control ||
key == LogicalKeyboardKey.controlLeft ||
key == LogicalKeyboardKey.controlRight) {
_control = true;
} else {
for (final MapEntry<SingleActivator, List<String>> entry
in _macOSActivatorToSelectors.entries) {
final SingleActivator activator = entry.key;
if (activator.triggers.first == key &&
activator.shift == _shift &&
activator.alt == _alt &&
activator.meta == _meta &&
activator.control == _control) {
await _sendSelectors(entry.value);
return;
}
}
}
}
@override
Future<void> handleKeyUpEvent(LogicalKeyboardKey key) async {
if (key == LogicalKeyboardKey.shift ||
key == LogicalKeyboardKey.shiftLeft ||
key == LogicalKeyboardKey.shiftRight) {
_shift = false;
} else if (key == LogicalKeyboardKey.alt ||
key == LogicalKeyboardKey.altLeft ||
key == LogicalKeyboardKey.altRight) {
_alt = false;
} else if (key == LogicalKeyboardKey.meta ||
key == LogicalKeyboardKey.metaLeft ||
key == LogicalKeyboardKey.metaRight) {
_meta = false;
} else if (key == LogicalKeyboardKey.control ||
key == LogicalKeyboardKey.controlLeft ||
key == LogicalKeyboardKey.controlRight) {
_control = false;
}
}
bool _shift = false;
bool _alt = false;
bool _meta = false;
bool _control = false;
}