mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-07 09:26:06 -10:00
575 lines
17 KiB
Go
575 lines
17 KiB
Go
package uv
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"image"
|
|
"image/color"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/x/ansi"
|
|
"github.com/charmbracelet/x/ansi/kitty"
|
|
)
|
|
|
|
// Event represents an input event that can be received from an input source.
|
|
type Event interface{}
|
|
|
|
// EventStreamer is an interface that defines a method to stream events from an
|
|
// input source. It takes a context and a channel to send events to. The
|
|
// streamer should block until the context is done or an error occurs. The
|
|
// channel should never be closed by the streamer, as it is the responsibility
|
|
// of the consumer to close it when done.
|
|
type EventStreamer interface {
|
|
StreamEvents(ctx context.Context, ch chan<- Event) error
|
|
}
|
|
|
|
// UnknownEvent represents an unknown event.
|
|
type UnknownEvent string
|
|
|
|
// String returns a string representation of the unknown event.
|
|
func (e UnknownEvent) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// UnknownCsiEvent represents an unknown CSI (Control Sequence Introducer) event.
|
|
type UnknownCsiEvent string
|
|
|
|
// String returns a string representation of the unknown CSI event.
|
|
func (e UnknownCsiEvent) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// UnknownSs3Event represents an unknown SS3 (Single Shift 3) event.
|
|
type UnknownSs3Event string
|
|
|
|
// String returns a string representation of the unknown SS3 event.
|
|
func (e UnknownSs3Event) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// UnknownOscEvent represents an unknown OSC (Operating System Command) event.
|
|
type UnknownOscEvent string
|
|
|
|
// String returns a string representation of the unknown OSC event.
|
|
func (e UnknownOscEvent) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// UnknownDcsEvent represents an unknown DCS (Device Control String) event.
|
|
type UnknownDcsEvent string
|
|
|
|
// String returns a string representation of the unknown DCS event.
|
|
func (e UnknownDcsEvent) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// UnknownSosEvent represents an unknown SOS (Start of String) event.
|
|
type UnknownSosEvent string
|
|
|
|
// String returns a string representation of the unknown SOS event.
|
|
func (e UnknownSosEvent) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// UnknownPmEvent represents an unknown PM (Privacy Message) event.
|
|
type UnknownPmEvent string
|
|
|
|
// String returns a string representation of the unknown PM event.
|
|
func (e UnknownPmEvent) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// UnknownApcEvent represents an unknown APC (Application Program Command) event.
|
|
type UnknownApcEvent string
|
|
|
|
// String returns a string representation of the unknown APC event.
|
|
func (e UnknownApcEvent) String() string {
|
|
return fmt.Sprintf("%q", string(e))
|
|
}
|
|
|
|
// MultiEvent represents multiple messages event.
|
|
type MultiEvent []Event
|
|
|
|
// String returns a string representation of the multiple messages event.
|
|
func (e MultiEvent) String() string {
|
|
var sb strings.Builder
|
|
for _, ev := range e {
|
|
fmt.Fprintf(&sb, "%v\n", ev)
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// Size represents the size of the terminal window.
|
|
type Size struct {
|
|
Width int
|
|
Height int
|
|
}
|
|
|
|
// Bounds returns the bounds corresponding to the size.
|
|
func (s Size) Bounds() Rectangle {
|
|
return Rectangle{
|
|
Min: image.Point{X: 0, Y: 0},
|
|
Max: image.Point{X: s.Width, Y: s.Height},
|
|
}
|
|
}
|
|
|
|
// WindowSizeEvent represents the window size in cells.
|
|
type WindowSizeEvent Size
|
|
|
|
// Bounds returns the bounds corresponding to the size.
|
|
func (s WindowSizeEvent) Bounds() Rectangle {
|
|
return Size(s).Bounds()
|
|
}
|
|
|
|
// PixelSizeEvent represents the window size in pixels.
|
|
type PixelSizeEvent Size
|
|
|
|
// Bounds returns the bounds corresponding to the size.
|
|
func (s PixelSizeEvent) Bounds() Rectangle {
|
|
return Size(s).Bounds()
|
|
}
|
|
|
|
// CellSizeEvent represents the cell size in pixels.
|
|
type CellSizeEvent Size
|
|
|
|
// Bounds returns the bounds corresponding to the size.
|
|
func (s CellSizeEvent) Bounds() Rectangle {
|
|
return Size(s).Bounds()
|
|
}
|
|
|
|
// KeyPressEvent represents a key press event.
|
|
type KeyPressEvent Key
|
|
|
|
// MatchString returns true if the [Key] matches one of the given strings.
|
|
//
|
|
// A string can be a key name like "enter", "tab", "a", or a printable
|
|
// character like "1" or " ". It can also have combinations of modifiers like
|
|
// "ctrl+a", "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
|
|
func (k KeyPressEvent) MatchString(s ...string) bool {
|
|
return Key(k).MatchString(s...)
|
|
}
|
|
|
|
// String implements [fmt.Stringer] and is quite useful for matching key
|
|
// events. For details, on what this returns see [Key.String].
|
|
func (k KeyPressEvent) String() string {
|
|
return Key(k).String()
|
|
}
|
|
|
|
// Keystroke returns the keystroke representation of the [Key]. While less type
|
|
// safe than looking at the individual fields, it will usually be more
|
|
// convenient and readable to use this method when matching against keys.
|
|
//
|
|
// Note that modifier keys are always printed in the following order:
|
|
// - ctrl
|
|
// - alt
|
|
// - shift
|
|
// - meta
|
|
// - hyper
|
|
// - super
|
|
//
|
|
// For example, you'll always see "ctrl+shift+alt+a" and never
|
|
// "shift+ctrl+alt+a".
|
|
func (k KeyPressEvent) Keystroke() string {
|
|
return Key(k).Keystroke()
|
|
}
|
|
|
|
// Key returns the underlying key event. This is a syntactic sugar for casting
|
|
// the key event to a [Key].
|
|
func (k KeyPressEvent) Key() Key {
|
|
return Key(k)
|
|
}
|
|
|
|
// KeyReleaseEvent represents a key release event.
|
|
type KeyReleaseEvent Key
|
|
|
|
// MatchString returns true if the [Key] matches one of the given strings.
|
|
//
|
|
// A string can be a key name like "enter", "tab", "a", or a printable
|
|
// character like "1" or " ". It can also have combinations of modifiers like
|
|
// "ctrl+a", "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
|
|
func (k KeyReleaseEvent) MatchString(s ...string) bool {
|
|
return Key(k).MatchString(s...)
|
|
}
|
|
|
|
// String implements [fmt.Stringer] and is quite useful for matching key
|
|
// events. For details, on what this returns see [Key.String].
|
|
func (k KeyReleaseEvent) String() string {
|
|
return Key(k).String()
|
|
}
|
|
|
|
// Keystroke returns the keystroke representation of the [Key]. While less type
|
|
// safe than looking at the individual fields, it will usually be more
|
|
// convenient and readable to use this method when matching against keys.
|
|
//
|
|
// Note that modifier keys are always printed in the following order:
|
|
// - ctrl
|
|
// - alt
|
|
// - shift
|
|
// - meta
|
|
// - hyper
|
|
// - super
|
|
//
|
|
// For example, you'll always see "ctrl+shift+alt+a" and never
|
|
// "shift+ctrl+alt+a".
|
|
func (k KeyReleaseEvent) Keystroke() string {
|
|
return Key(k).Keystroke()
|
|
}
|
|
|
|
// Key returns the underlying key event. This is a convenience method and
|
|
// syntactic sugar to satisfy the [KeyEvent] interface, and cast the key event to
|
|
// [Key].
|
|
func (k KeyReleaseEvent) Key() Key {
|
|
return Key(k)
|
|
}
|
|
|
|
// KeyEvent represents a key event. This can be either a key press or a key
|
|
// release event.
|
|
type KeyEvent interface {
|
|
fmt.Stringer
|
|
|
|
// Key returns the underlying key event.
|
|
Key() Key
|
|
}
|
|
|
|
// MouseEvent represents a mouse message. This is a generic mouse message that
|
|
// can represent any kind of mouse event.
|
|
type MouseEvent interface {
|
|
fmt.Stringer
|
|
|
|
// Mouse returns the underlying mouse event.
|
|
Mouse() Mouse
|
|
}
|
|
|
|
// MouseClickEvent represents a mouse button click event.
|
|
type MouseClickEvent Mouse
|
|
|
|
// String returns a string representation of the mouse click event.
|
|
func (e MouseClickEvent) String() string {
|
|
return Mouse(e).String()
|
|
}
|
|
|
|
// Mouse returns the underlying mouse event. This is a convenience method and
|
|
// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
|
|
// event to [Mouse].
|
|
func (e MouseClickEvent) Mouse() Mouse {
|
|
return Mouse(e)
|
|
}
|
|
|
|
// MouseReleaseEvent represents a mouse button release event.
|
|
type MouseReleaseEvent Mouse
|
|
|
|
// String returns a string representation of the mouse release event.
|
|
func (e MouseReleaseEvent) String() string {
|
|
return Mouse(e).String()
|
|
}
|
|
|
|
// Mouse returns the underlying mouse event. This is a convenience method and
|
|
// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
|
|
// event to [Mouse].
|
|
func (e MouseReleaseEvent) Mouse() Mouse {
|
|
return Mouse(e)
|
|
}
|
|
|
|
// MouseWheelEvent represents a mouse wheel message event.
|
|
type MouseWheelEvent Mouse
|
|
|
|
// String returns a string representation of the mouse wheel event.
|
|
func (e MouseWheelEvent) String() string {
|
|
return Mouse(e).String()
|
|
}
|
|
|
|
// Mouse returns the underlying mouse event. This is a convenience method and
|
|
// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
|
|
// event to [Mouse].
|
|
func (e MouseWheelEvent) Mouse() Mouse {
|
|
return Mouse(e)
|
|
}
|
|
|
|
// MouseMotionEvent represents a mouse motion event.
|
|
type MouseMotionEvent Mouse
|
|
|
|
// String returns a string representation of the mouse motion event.
|
|
func (e MouseMotionEvent) String() string {
|
|
m := Mouse(e)
|
|
if m.Button != 0 {
|
|
return m.String() + "+motion"
|
|
}
|
|
return m.String() + "motion"
|
|
}
|
|
|
|
// Mouse returns the underlying mouse event. This is a convenience method and
|
|
// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
|
|
// event to [Mouse].
|
|
func (e MouseMotionEvent) Mouse() Mouse {
|
|
return Mouse(e)
|
|
}
|
|
|
|
// CursorPositionEvent represents a cursor position event. Where X is the
|
|
// zero-based column and Y is the zero-based row.
|
|
type CursorPositionEvent struct {
|
|
X, Y int
|
|
}
|
|
|
|
// FocusEvent represents a terminal focus event.
|
|
// This occurs when the terminal gains focus.
|
|
type FocusEvent struct{}
|
|
|
|
// BlurEvent represents a terminal blur event.
|
|
// This occurs when the terminal loses focus.
|
|
type BlurEvent struct{}
|
|
|
|
// DarkColorSchemeEvent is sent when the operating system is using a dark color
|
|
// scheme. This is typically used to notify applications of the current or new
|
|
// system color scheme.
|
|
type DarkColorSchemeEvent struct{}
|
|
|
|
// LightColorSchemeEvent is sent when the operating system is using a light color
|
|
// scheme. This is typically used to notify applications of the current or new
|
|
// system color scheme.
|
|
type LightColorSchemeEvent struct{}
|
|
|
|
// PasteEvent is an message that is emitted when a terminal receives pasted text
|
|
// using bracketed-paste.
|
|
type PasteEvent struct {
|
|
// Content is the pasted text content.
|
|
Content string
|
|
}
|
|
|
|
// String returns the pasted content as a string.
|
|
func (e PasteEvent) String() string {
|
|
return e.Content
|
|
}
|
|
|
|
// PasteStartEvent is an message that is emitted when the terminal starts the
|
|
// bracketed-paste text.
|
|
type PasteStartEvent struct{}
|
|
|
|
// PasteEndEvent is an message that is emitted when the terminal ends the
|
|
// bracketed-paste text.
|
|
type PasteEndEvent struct{}
|
|
|
|
// TerminalVersionEvent is a message that represents the terminal version.
|
|
type TerminalVersionEvent struct {
|
|
Name string
|
|
}
|
|
|
|
// String returns the terminal version as a string.
|
|
func (e TerminalVersionEvent) String() string {
|
|
return e.Name
|
|
}
|
|
|
|
// ModifyOtherKeysEvent represents a modifyOtherKeys event.
|
|
//
|
|
// 0: disable
|
|
// 1: enable mode 1
|
|
// 2: enable mode 2
|
|
//
|
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
|
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
|
type ModifyOtherKeysEvent struct {
|
|
Mode int
|
|
}
|
|
|
|
// KittyGraphicsEvent represents a Kitty Graphics response event.
|
|
//
|
|
// See https://sw.kovidgoyal.net/kitty/graphics-protocol/
|
|
type KittyGraphicsEvent struct {
|
|
Options kitty.Options
|
|
Payload []byte
|
|
}
|
|
|
|
// KeyboardEnhancementsEvent represents a keyboard enhancements report event.
|
|
type KeyboardEnhancementsEvent struct {
|
|
// Flags are the Kitty Keyboard Enhancement flags.
|
|
//
|
|
// Bit values:
|
|
//
|
|
// 00000001: Disambiguate escape codes
|
|
// 00000010: Report event types
|
|
// 00000100: Report alternate keys
|
|
// 00001000: Report all keys as escape codes
|
|
// 00010000: Report associated text
|
|
//
|
|
// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#keyboard-enhancements
|
|
Flags int
|
|
}
|
|
|
|
// Contains reports whether m contains the given enhancements.
|
|
func (e KeyboardEnhancementsEvent) Contains(enhancements int) bool {
|
|
return e.Flags&enhancements == enhancements
|
|
}
|
|
|
|
// SupportsKeyDisambiguation returns whether the terminal supports reporting
|
|
// disambiguous keys as escape codes.
|
|
func (e KeyboardEnhancementsEvent) SupportsKeyDisambiguation() bool {
|
|
return e.Flags&ansi.KittyDisambiguateEscapeCodes != 0
|
|
}
|
|
|
|
// SupportsKeyReleases returns whether the terminal supports key release
|
|
// events.
|
|
func (e KeyboardEnhancementsEvent) SupportsKeyReleases() bool {
|
|
return e.Flags&ansi.KittyReportEventTypes != 0
|
|
}
|
|
|
|
// SupportsUniformKeyLayout returns whether the terminal supports reporting key
|
|
// events as though they were on a PC-101 layout.
|
|
func (e KeyboardEnhancementsEvent) SupportsUniformKeyLayout() bool {
|
|
return e.SupportsKeyDisambiguation() &&
|
|
e.Flags&ansi.KittyReportAlternateKeys != 0 &&
|
|
e.Flags&ansi.KittyReportAllKeysAsEscapeCodes != 0
|
|
}
|
|
|
|
// PrimaryDeviceAttributesEvent is an event that represents the terminal
|
|
// primary device attributes.
|
|
//
|
|
// Common attributes include:
|
|
// - 1 132 columns
|
|
// - 2 Printer port
|
|
// - 4 Sixel
|
|
// - 6 Selective erase
|
|
// - 7 Soft character set (DRCS)
|
|
// - 8 User-defined keys (UDKs)
|
|
// - 9 National replacement character sets (NRCS) (International terminal only)
|
|
// - 12 Yugoslavian (SCS)
|
|
// - 15 Technical character set
|
|
// - 18 Windowing capability
|
|
// - 21 Horizontal scrolling
|
|
// - 23 Greek
|
|
// - 24 Turkish
|
|
// - 42 ISO Latin-2 character set
|
|
// - 44 PCTerm
|
|
// - 45 Soft key map
|
|
// - 46 ASCII emulation
|
|
//
|
|
// See [ansi.PrimaryDeviceAttributes] for more details.
|
|
type PrimaryDeviceAttributesEvent []int
|
|
|
|
// SecondaryDeviceAttributesEvent is an event that represents the terminal
|
|
// secondary device attributes.
|
|
//
|
|
// See [ansi.SecondaryDeviceAttributes] for more details.
|
|
type SecondaryDeviceAttributesEvent []int
|
|
|
|
// TertiaryDeviceAttributesEvent is an event that represents the terminal
|
|
// tertiary device attributes.
|
|
//
|
|
// See [ansi.TertiaryDeviceAttributes] for more details.
|
|
type TertiaryDeviceAttributesEvent string
|
|
|
|
// ModeReportEvent is a message that represents a mode report event (DECRPM).
|
|
//
|
|
// See: https://vt100.net/docs/vt510-rm/DECRPM.html
|
|
type ModeReportEvent struct {
|
|
// Mode is the mode number.
|
|
Mode ansi.Mode
|
|
|
|
// Value is the mode value.
|
|
Value ansi.ModeSetting
|
|
}
|
|
|
|
// ForegroundColorEvent represents a foreground color event. This event is
|
|
// emitted when the terminal requests the terminal foreground color using
|
|
// [ansi.RequestForegroundColor].
|
|
type ForegroundColorEvent struct{ color.Color }
|
|
|
|
// String returns the hex representation of the color.
|
|
func (e ForegroundColorEvent) String() string {
|
|
return colorToHex(e.Color)
|
|
}
|
|
|
|
// IsDark returns whether the color is dark.
|
|
func (e ForegroundColorEvent) IsDark() bool {
|
|
return isDarkColor(e.Color)
|
|
}
|
|
|
|
// BackgroundColorEvent represents a background color event. This event is
|
|
// emitted when the terminal requests the terminal background color using
|
|
// [ansi.RequestBackgroundColor].
|
|
type BackgroundColorEvent struct{ color.Color }
|
|
|
|
// String returns the hex representation of the color.
|
|
func (e BackgroundColorEvent) String() string {
|
|
return colorToHex(e)
|
|
}
|
|
|
|
// IsDark returns whether the color is dark.
|
|
func (e BackgroundColorEvent) IsDark() bool {
|
|
return isDarkColor(e.Color)
|
|
}
|
|
|
|
// CursorColorEvent represents a cursor color change event. This event is
|
|
// emitted when the program requests the terminal cursor color using
|
|
// [ansi.RequestCursorColor].
|
|
type CursorColorEvent struct{ color.Color }
|
|
|
|
// String returns the hex representation of the color.
|
|
func (e CursorColorEvent) String() string {
|
|
return colorToHex(e)
|
|
}
|
|
|
|
// IsDark returns whether the color is dark.
|
|
func (e CursorColorEvent) IsDark() bool {
|
|
return isDarkColor(e)
|
|
}
|
|
|
|
// WindowOpEvent is a window operation (XTWINOPS) report event. This is used to
|
|
// report various window operations such as reporting the window size or cell
|
|
// size.
|
|
type WindowOpEvent struct {
|
|
Op int
|
|
Args []int
|
|
}
|
|
|
|
// CapabilityEvent represents a Termcap/Terminfo response event. Termcap
|
|
// responses are generated by the terminal in response to RequestTermcap
|
|
// (XTGETTCAP) requests.
|
|
//
|
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
|
type CapabilityEvent struct {
|
|
Content string
|
|
}
|
|
|
|
// String returns the capability content.
|
|
func (e CapabilityEvent) String() string {
|
|
return e.Content
|
|
}
|
|
|
|
// ClipboardSelection represents a clipboard selection. The most common
|
|
// clipboard selections are "system" and "primary" and selections.
|
|
type ClipboardSelection = byte
|
|
|
|
// Clipboard selections.
|
|
const (
|
|
SystemClipboard ClipboardSelection = ansi.SystemClipboard
|
|
PrimaryClipboard ClipboardSelection = ansi.PrimaryClipboard
|
|
)
|
|
|
|
// ClipboardEvent is a clipboard read message event. This message is emitted when
|
|
// a terminal receives an OSC52 clipboard read message event.
|
|
type ClipboardEvent struct {
|
|
Content string
|
|
Selection ClipboardSelection
|
|
}
|
|
|
|
// String returns the string representation of the clipboard message.
|
|
func (e ClipboardEvent) String() string {
|
|
return e.Content
|
|
}
|
|
|
|
// Clipboard returns the clipboard selection. This can be either
|
|
// [SystemClipboard] 'c' or [PrimaryClipboard] 'p'.
|
|
func (e ClipboardEvent) Clipboard() ClipboardSelection {
|
|
return e.Selection
|
|
}
|
|
|
|
// ProgramStatusSupportEvent is emitted when the terminal replies to a Program
|
|
// Status Protocol (OSC 7501) feature detection query, meaning the terminal
|
|
// supports the protocol.
|
|
//
|
|
// See: https://www.superlogical.com/rex/docs/build/program-status
|
|
type ProgramStatusSupportEvent struct{}
|
|
|
|
// ignoredEvent represents a sequence event that is ignored by the terminal
|
|
// reader. This is used to ignore certain sequences that can be canceled.
|
|
type ignoredEvent string
|