| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- import 'package:xterm/src/core/input/keys.dart';
- import 'package:xterm/src/core/input/keytab/keytab.dart';
- import 'package:xterm/src/core/state.dart';
- import 'package:xterm/src/core/platform.dart';
- /// The key event received from the keyboard, along with the state of the
- /// modifier keys and state of the terminal. Typically consumed by the
- /// [TerminalInputHandler] to produce a escape sequence that can be recognized
- /// by the terminal.
- ///
- /// See also:
- /// - [TerminalInputHandler]
- class TerminalKeyboardEvent {
- final TerminalKey key;
- final bool shift;
- final bool ctrl;
- final bool alt;
- final TerminalState state;
- final bool altBuffer;
- final TerminalTargetPlatform platform;
- TerminalKeyboardEvent({
- required this.key,
- required this.shift,
- required this.ctrl,
- required this.alt,
- required this.state,
- required this.altBuffer,
- required this.platform,
- });
- TerminalKeyboardEvent copyWith({
- TerminalKey? key,
- bool? shift,
- bool? ctrl,
- bool? alt,
- TerminalState? state,
- bool? altBuffer,
- TerminalTargetPlatform? platform,
- }) {
- return TerminalKeyboardEvent(
- key: key ?? this.key,
- shift: shift ?? this.shift,
- ctrl: ctrl ?? this.ctrl,
- alt: alt ?? this.alt,
- state: state ?? this.state,
- altBuffer: altBuffer ?? this.altBuffer,
- platform: platform ?? this.platform,
- );
- }
- @override
- String toString() {
- return 'TerminalKeyboardEvent(key: $key, shift: $shift, ctrl: $ctrl, alt: $alt, state: $state, altBuffer: $altBuffer, platform: $platform)';
- }
- }
- /// TerminalInputHandler contains the logic for translating a [TerminalKeyboardEvent]
- /// into escape sequences that can be recognized by the terminal.
- abstract class TerminalInputHandler {
- /// Translates a [TerminalKeyboardEvent] into an escape sequence. If the event
- /// cannot be translated, null is returned.
- String? call(TerminalKeyboardEvent event);
- }
- /// A [TerminalInputHandler] that chains multiple handlers together. If any
- /// handler returns a non-null value, it is returned. Otherwise, null is
- /// returned.
- class CascadeInputHandler implements TerminalInputHandler {
- final List<TerminalInputHandler> _handlers;
- const CascadeInputHandler(this._handlers);
- @override
- String? call(TerminalKeyboardEvent event) {
- for (var handler in _handlers) {
- final result = handler(event);
- if (result != null) {
- return result;
- }
- }
- return null;
- }
- }
- /// The default input handler for the terminal. That is composed of a
- /// [KeytabInputHandler], a [CtrlInputHandler], and a [AltInputHandler].
- ///
- /// It's possible to override the default input handler behavior by chaining
- /// another input handler before or after the default input handler using
- /// [CascadeInputHandler].
- ///
- /// See also:
- /// * [CascadeInputHandler]
- const defaultInputHandler = CascadeInputHandler([
- KeytabInputHandler(),
- CtrlInputHandler(),
- AltInputHandler(),
- ]);
- /// A [TerminalInputHandler] that translates key events according to a keytab
- /// file. If no keytab is provided, [Keytab.defaultKeytab] is used.
- class KeytabInputHandler implements TerminalInputHandler {
- const KeytabInputHandler([this.keytab]);
- final Keytab? keytab;
- @override
- String? call(TerminalKeyboardEvent event) {
- final keytab = this.keytab ?? Keytab.defaultKeytab;
- final record = keytab.find(
- event.key,
- ctrl: event.ctrl,
- alt: event.alt,
- shift: event.shift,
- newLineMode: event.state.lineFeedMode,
- appCursorKeys: event.state.appKeypadMode,
- appKeyPad: event.state.appKeypadMode,
- appScreen: event.altBuffer,
- macos: event.platform == TerminalTargetPlatform.macos,
- );
- if (record == null) {
- return null;
- }
- var result = record.action.unescapedValue();
- result = insertModifiers(event, result);
- return result;
- }
- String insertModifiers(TerminalKeyboardEvent event, String action) {
- String? code;
- if (event.shift && event.alt && event.ctrl) {
- code = '8';
- } else if (event.ctrl && event.alt) {
- code = '7';
- } else if (event.shift && event.ctrl) {
- code = '6';
- } else if (event.ctrl) {
- code = '5';
- } else if (event.shift && event.alt) {
- code = '4';
- } else if (event.alt) {
- code = '3';
- } else if (event.shift) {
- code = '2';
- }
- if (code != null) {
- return action.replaceAll('*', code);
- }
- return action;
- }
- }
- /// A [TerminalInputHandler] that translates ctrl + key events into escape
- /// sequences. For example, ctrl + a becomes ^A.
- class CtrlInputHandler implements TerminalInputHandler {
- const CtrlInputHandler();
- @override
- String? call(TerminalKeyboardEvent event) {
- if (!event.ctrl || event.shift || event.alt) {
- return null;
- }
- final key = event.key;
- if (key.index >= TerminalKey.keyA.index &&
- key.index <= TerminalKey.keyZ.index) {
- final input = key.index - TerminalKey.keyA.index + 1;
- return String.fromCharCode(input);
- }
- return null;
- }
- }
- /// A [TerminalInputHandler] that translates alt + key events into escape
- /// sequences. For example, alt + a becomes ^[a.
- class AltInputHandler implements TerminalInputHandler {
- const AltInputHandler();
- @override
- String? call(TerminalKeyboardEvent event) {
- if (!event.alt || event.ctrl || event.shift) {
- return null;
- }
- if (event.platform == TerminalTargetPlatform.macos) {
- return null;
- }
- final key = event.key;
- if (key.index >= TerminalKey.keyA.index &&
- key.index <= TerminalKey.keyZ.index) {
- final charCode = key.index - TerminalKey.keyA.index + 65;
- final input = [0x1b, charCode];
- return String.fromCharCodes(input);
- }
- return null;
- }
- }
|