1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-19 19:31:49 +03:00
wezterm/wezterm-input-types/src/lib.rs
Wez Furlong 1178639a22 windows: implement decoration setting, change to bitfield
Can now set `window_decorations = "TITLE|RESIZE"` or variations
on those flags.  `NONE` is a shortcut for no flags.
2021-03-04 09:40:38 -08:00

293 lines
7.4 KiB
Rust

use bitflags::*;
use serde::*;
use std::convert::TryFrom;
pub struct PixelUnit;
pub struct ScreenPixelUnit;
pub type Point = euclid::Point2D<isize, PixelUnit>;
pub type ScreenPoint = euclid::Point2D<isize, ScreenPixelUnit>;
/// Which key is pressed. Not all of these are probable to appear
/// on most systems. A lot of this list is @wez trawling docs and
/// making an entry for things that might be possible in this first pass.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum KeyCode {
/// The decoded unicode character
Char(char),
Composed(String),
RawCode(u32),
Hyper,
Super,
Meta,
/// Ctrl-break on windows
Cancel,
// There is no `Backspace`; use `Char('\u{8}') instead
// There is no `Tab`; use `Char('\t')` instead
Clear,
// There is no `Enter`; use `Char('\r')` instead
Shift,
// There is no `Escape`; use `Char('\u{1b}') instead
LeftShift,
RightShift,
Control,
LeftControl,
RightControl,
Alt,
LeftAlt,
RightAlt,
Pause,
CapsLock,
PageUp,
PageDown,
End,
Home,
LeftArrow,
RightArrow,
UpArrow,
DownArrow,
Select,
Print,
Execute,
PrintScreen,
Insert,
// There is no `Delete`; use `Char('\u{7f}')` instead
Help,
LeftWindows,
RightWindows,
Applications,
Sleep,
/// Numeric keypad digits 0-9
Numpad(u8),
Multiply,
Add,
Separator,
Subtract,
Decimal,
Divide,
/// F1-F24 are possible
Function(u8),
NumLock,
ScrollLock,
BrowserBack,
BrowserForward,
BrowserRefresh,
BrowserStop,
BrowserSearch,
BrowserFavorites,
BrowserHome,
VolumeMute,
VolumeDown,
VolumeUp,
MediaNextTrack,
MediaPrevTrack,
MediaStop,
MediaPlayPause,
ApplicationLeftArrow,
ApplicationRightArrow,
ApplicationUpArrow,
ApplicationDownArrow,
}
impl KeyCode {
/// Return true if the key represents a modifier key.
pub fn is_modifier(&self) -> bool {
match self {
Self::Hyper
| Self::Super
| Self::Meta
| Self::Shift
| Self::LeftShift
| Self::RightShift
| Self::Control
| Self::LeftControl
| Self::RightControl
| Self::Alt
| Self::LeftAlt
| Self::RightAlt
| Self::LeftWindows
| Self::RightWindows => true,
_ => false,
}
}
pub fn normalize_shift(&self, modifiers: Modifiers) -> (KeyCode, Modifiers) {
normalize_shift(self.clone(), modifiers)
}
}
bitflags! {
#[derive(Default, Deserialize, Serialize)]
pub struct Modifiers: u8 {
const NONE = 0;
const SHIFT = 1<<1;
const ALT = 1<<2;
const CTRL = 1<<3;
const SUPER = 1<<4;
const LEFT_ALT = 1<<5;
const RIGHT_ALT = 1<<6;
const LEADER = 1<<7;
}
}
bitflags! {
#[derive(Default)]
pub struct MouseButtons: u8 {
const NONE = 0;
#[allow(clippy::identity_op)]
const LEFT = 1<<0;
const RIGHT = 1<<1;
const MIDDLE = 1<<2;
const X1 = 1<<3;
const X2 = 1<<4;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MousePress {
Left,
Right,
Middle,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MouseEventKind {
Move,
Press(MousePress),
Release(MousePress),
VertWheel(i16),
HorzWheel(i16),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MouseEvent {
pub kind: MouseEventKind,
/// Coordinates of the mouse relative to the top left of the window
pub coords: Point,
/// The mouse position in screen coordinates
pub screen_coords: crate::ScreenPoint,
pub mouse_buttons: MouseButtons,
pub modifiers: Modifiers,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyEvent {
/// Which key was pressed.
/// This is the potentially processed/composed version
/// of the input.
pub key: KeyCode,
/// Which modifiers are down
pub modifiers: Modifiers,
/// The raw unprocessed key press if it was different from
/// the processed/composed version
pub raw_key: Option<KeyCode>,
pub raw_modifiers: Modifiers,
pub raw_code: Option<u32>,
/// How many times this key repeats
pub repeat_count: u16,
/// If true, this is a key down rather than a key up event
pub key_is_down: bool,
}
fn normalize_shift(key: KeyCode, modifiers: Modifiers) -> (KeyCode, Modifiers) {
if modifiers.contains(Modifiers::SHIFT) {
match key {
KeyCode::Char(c) if c.is_ascii_uppercase() => (key, modifiers - Modifiers::SHIFT),
KeyCode::Char(c) if c.is_ascii_lowercase() => (
KeyCode::Char(c.to_ascii_uppercase()),
modifiers - Modifiers::SHIFT,
),
_ => (key, modifiers),
}
} else {
(key, modifiers)
}
}
fn normalize_ctrl(key: KeyCode, modifiers: Modifiers) -> (KeyCode, Modifiers) {
if modifiers.contains(Modifiers::CTRL) {
if let KeyCode::Char(c) = key {
if (c as u32) < 0x20 {
let de_ctrl = ((c as u8) | 0x40) as char;
return (KeyCode::Char(de_ctrl.to_ascii_lowercase()), modifiers);
}
}
}
(key, modifiers)
}
impl KeyEvent {
/// if SHIFT is held and we have KeyCode::Char('c') we want to normalize
/// that keycode to KeyCode::Char('C'); that is what this function does.
pub fn normalize_shift(mut self) -> Self {
let (key, modifiers) = normalize_shift(self.key, self.modifiers);
self.key = key;
self.modifiers = modifiers;
if let Some(raw) = self.raw_key.take() {
let (key, modifiers) = normalize_shift(raw, self.raw_modifiers);
self.raw_key.replace(key);
self.raw_modifiers = modifiers;
}
self
}
/// If CTRL is held down and we have KeyCode::Char(_) with the
/// ASCII control value encoded, decode it back to the ASCII
/// alpha keycode instead.
pub fn normalize_ctrl(mut self) -> Self {
let (key, modifiers) = normalize_ctrl(self.key, self.modifiers);
self.key = key;
self.modifiers = modifiers;
if let Some(raw) = self.raw_key.take() {
let (key, modifiers) = normalize_ctrl(raw, self.raw_modifiers);
self.raw_key.replace(key);
self.raw_modifiers = modifiers;
}
self
}
}
bitflags! {
#[derive(Deserialize, Serialize)]
#[serde(try_from = "String")]
pub struct WindowDecorations: u8 {
const TITLE = 1;
const RESIZE = 2;
const NONE = 0;
}
}
impl TryFrom<String> for WindowDecorations {
type Error = String;
fn try_from(s: String) -> std::result::Result<WindowDecorations, String> {
let mut flags = Self::NONE;
for ele in s.split('|') {
let ele = ele.trim();
if ele == "TITLE" {
flags |= Self::TITLE;
} else if ele == "NONE" || ele == "None" {
flags = Self::NONE;
} else if ele == "RESIZE" {
flags |= Self::RESIZE;
} else {
return Err(format!("invalid WindowDecoration name {} in {}", ele, s));
}
}
Ok(flags)
}
}
impl Default for WindowDecorations {
fn default() -> Self {
WindowDecorations::TITLE | WindowDecorations::RESIZE
}
}