├── .gitignore ├── Cargo.toml ├── README.md ├── src ├── config │ ├── values.rs │ ├── structs.rs │ ├── modifier.rs │ ├── layout.rs │ ├── command.rs │ ├── filehandler.rs │ ├── keybind.rs │ ├── check.rs │ └── mod.rs ├── utils │ ├── mod.rs │ └── x11_keys.rs ├── main.rs └── tui │ ├── mod.rs │ └── popups.rs ├── .github └── workflows │ └── rust.yml ├── LICENCE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | 4 | /aur 5 | 6 | issue.md 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "leftwm-config" 3 | version = "0.1.0" 4 | authors = ["BlackDragon2447 "] 5 | edition = "2021" 6 | license = "MIT" 7 | readme = "README.md" 8 | #description = "A window manager for Adventurers" 9 | 10 | [dependencies] 11 | anyhow = {version="1.0.69", features=["backtrace"]} 12 | clap = "4.5.41" 13 | xdg = "3.0.0" 14 | serde = { version = "1.0.152", features = ["derive", "rc"] } 15 | ron = "0.10.1" 16 | serde_json = "1.0.94" 17 | log = "0.4.17" 18 | git-version = "0.3.5" 19 | thiserror = "2.0.12" 20 | tui = "0.19.0" 21 | crossterm = "0.29.0" 22 | glob = "0.3.1" 23 | toml = "0.8.2" 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeftWM Config 2 | 3 | This is a little satellite utility to LeftWM. 4 | 5 | It serves these main purposes: 6 | - create a default config file in `$HOME/.config/leftwm/config.ron` 7 | - migrate legacy `toml` config files to the new stander `ron` 8 | - edit the config with a TUI 9 | 10 | For usage please refer to `leftwm-config --help` for now. 11 | 12 | *Note: this tool is BETA software, so expect some kinks and wrinkles here and there.* 13 | 14 | To install... 15 | 16 | ``` 17 | git clone https://github.com/leftwm/leftwm-config.git && 18 | cd leftwm-config && 19 | cargo build --release && 20 | sudo ln -s "$(pwd)"/target/release/leftwm-config /usr/bin/leftwm-config ## Dev Install 21 | sudo cp "$(pwd)"/target/release/leftwm-config /usr/bin/leftwm-config ## Normal Install 22 | ``` 23 | -------------------------------------------------------------------------------- /src/config/values.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::os::raw::c_ulong; 3 | 4 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy)] 5 | #[serde(untagged)] 6 | pub enum Size { 7 | Pixel(i32), 8 | Ratio(f32), 9 | } 10 | 11 | #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] 12 | pub enum LayoutMode { 13 | Tag, 14 | Workspace, 15 | } 16 | 17 | #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default)] 18 | pub enum InsertBehavior { 19 | Top, 20 | #[default] 21 | Bottom, 22 | BeforeCurrent, 23 | AfterCurrent, 24 | } 25 | 26 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 27 | pub enum FocusBehaviour { 28 | Sloppy, 29 | ClickTo, 30 | Driven, 31 | } 32 | 33 | pub type Window = c_ulong; 34 | type MockHandle = i32; 35 | 36 | #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] 37 | pub enum WindowHandle { 38 | MockHandle(MockHandle), 39 | XlibHandle(Window), 40 | } 41 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | RUSTFLAGS: -Dwarnings 12 | RUSTDOCFLAGS: -Dwarnings 13 | 14 | 15 | jobs: 16 | build: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - uses: actions-rs/toolchain@v1 23 | with: 24 | toolchain: stable 25 | override: true 26 | - name: apt update 27 | run: sudo apt update 28 | - name: Build 29 | run: cargo build --verbose 30 | 31 | clippy: 32 | 33 | runs-on: ubuntu-latest 34 | 35 | steps: 36 | - uses: actions/checkout@v3 37 | - uses: actions-rs/toolchain@v1 38 | with: 39 | toolchain: stable 40 | components: clippy 41 | override: true 42 | - name: apt update 43 | run: sudo apt update 44 | - name: Clippy 45 | run: cargo clippy --all-targets 46 | 47 | fmt: 48 | runs-on: ubuntu-latest 49 | 50 | steps: 51 | - uses: actions/checkout@v3 52 | - uses: actions-rs/toolchain@v1 53 | with: 54 | toolchain: stable 55 | components: rustfmt 56 | override: true 57 | - name: fmt 58 | run: cargo fmt -- --check 59 | 60 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, leftwm 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /src/config/structs.rs: -------------------------------------------------------------------------------- 1 | use crate::config::layout::Layout; 2 | use crate::config::values::Size; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Serialize, Default, Deserialize, Debug, Clone, PartialEq)] 6 | pub struct Workspace { 7 | pub x: i32, 8 | pub y: i32, 9 | pub height: i32, 10 | pub width: i32, 11 | pub id: Option, 12 | pub max_window_width: Option, 13 | pub layouts: Option>, 14 | } 15 | 16 | #[derive(Serialize, Default, Deserialize, Debug, Clone, PartialEq)] 17 | pub struct ScratchPad { 18 | pub name: String, 19 | pub value: String, 20 | // relative x of scratchpad, 25 means 25% of workspace x 21 | pub x: Option, 22 | // relative y of scratchpad, 25 means 25% of workspace y 23 | pub y: Option, 24 | // relative height of scratchpad, 50 means 50% of workspace height 25 | pub height: Option, 26 | // relative width of scratchpad, 50 means 50% of workspace width 27 | pub width: Option, 28 | } 29 | 30 | /// Selecting by `WM_CLASS` and/or window title, allow the user to define if a 31 | /// window should spawn on a specified tag and/or its floating state. 32 | /// 33 | /// # Example 34 | /// 35 | /// In `config.toml` 36 | /// 37 | /// ```toml 38 | /// [[window_config_by_class]] 39 | /// wm_class = "krita" 40 | /// spawn_on_tag = 3 41 | /// spawn_floating = false 42 | /// ``` 43 | /// 44 | /// windows whose `WM_CLASS` is "krita" will spawn on tag 3 (1-indexed) and not floating. 45 | #[derive(Serialize, Deserialize, Default, Debug, Clone)] 46 | pub struct WindowHook { 47 | /// `WM_CLASS` in X11 48 | pub window_class: Option, 49 | /// `_NET_WM_NAME` in X11 50 | pub window_title: Option, 51 | pub spawn_on_tag: Option, 52 | pub spawn_floating: Option, 53 | } 54 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | use ::tui::layout::{Constraint, Direction, Layout, Rect}; 2 | use anyhow::{bail, Context, Result}; 3 | 4 | mod x11_keys; 5 | pub(crate) mod xkeysym_lookup; 6 | 7 | pub(crate) fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { 8 | let popup_layout = Layout::default() 9 | .direction(Direction::Vertical) 10 | .constraints( 11 | [ 12 | Constraint::Percentage((100 - percent_y) / 2), 13 | Constraint::Min(3), 14 | Constraint::Percentage((100 - percent_y) / 2), 15 | ] 16 | .as_ref(), 17 | ) 18 | .split(r); 19 | 20 | Layout::default() 21 | .direction(Direction::Horizontal) 22 | .constraints( 23 | [ 24 | Constraint::Percentage((100 - percent_x) / 2), 25 | Constraint::Percentage(percent_x), 26 | Constraint::Percentage((100 - percent_x) / 2), 27 | ] 28 | .as_ref(), 29 | ) 30 | .split(popup_layout[1])[1] 31 | } 32 | 33 | //used to transform an option into a result to be able to easily 34 | // propagate the fact that is was empty instead of panicking 35 | pub trait TryUnwrap { 36 | fn try_unwrap(self) -> Result; 37 | } 38 | 39 | impl TryUnwrap for Option { 40 | fn try_unwrap(self) -> Result { 41 | self.context("called `Option::unwrap()` on a `None` value") 42 | } 43 | } 44 | 45 | pub trait TryRemove { 46 | fn try_remove(&mut self, index: usize) -> Result; 47 | } 48 | 49 | impl TryRemove for Vec { 50 | fn try_remove(&mut self, index: usize) -> Result { 51 | if index < self.len() { 52 | Ok(self.remove(index)) 53 | } else { 54 | bail!("Index out of bounds") 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/config/modifier.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)] 4 | #[serde(untagged)] 5 | pub enum Modifier { 6 | Single(String), 7 | List(Vec), 8 | } 9 | 10 | impl Modifier { 11 | pub fn is_empty(&self) -> bool { 12 | match self { 13 | Modifier::Single(single) => single.is_empty(), 14 | Modifier::List(list) => list.is_empty(), 15 | } 16 | } 17 | } 18 | 19 | impl std::convert::From for Vec { 20 | fn from(m: Modifier) -> Self { 21 | match m { 22 | Modifier::Single(modifier) => vec![modifier], 23 | Modifier::List(modifiers) => modifiers, 24 | } 25 | } 26 | } 27 | 28 | impl IntoIterator for &Modifier { 29 | type Item = String; 30 | type IntoIter = std::vec::IntoIter; 31 | 32 | fn into_iter(self) -> Self::IntoIter { 33 | let ms = match self { 34 | Modifier::Single(m) => vec![m.clone()], 35 | Modifier::List(ms) => ms.clone(), 36 | }; 37 | ms.into_iter() 38 | } 39 | } 40 | 41 | impl std::convert::From> for Modifier { 42 | fn from(l: Vec) -> Self { 43 | Self::List(l) 44 | } 45 | } 46 | 47 | impl std::convert::From<&str> for Modifier { 48 | fn from(m: &str) -> Self { 49 | Self::Single(m.to_owned()) 50 | } 51 | } 52 | 53 | impl std::fmt::Display for Modifier { 54 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 55 | match self { 56 | Self::Single(modifier) => write!(f, "{modifier}"), 57 | Self::List(modifiers) => write!(f, "{}", modifiers.join("+")), 58 | } 59 | } 60 | } 61 | 62 | impl Modifier { 63 | pub fn sort_unstable(&mut self) { 64 | match self { 65 | Self::Single(_) => {} 66 | Self::List(modifiers) => modifiers.sort_unstable(), 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/config/layout.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::str::FromStr; 3 | use thiserror::Error; 4 | 5 | #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] 6 | pub enum Layout { 7 | MainAndVertStack, 8 | MainAndHorizontalStack, 9 | MainAndDeck, 10 | GridHorizontal, 11 | EvenHorizontal, 12 | EvenVertical, 13 | Fibonacci, 14 | LeftMain, 15 | CenterMain, 16 | CenterMainBalanced, 17 | CenterMainFluid, 18 | Monocle, 19 | RightWiderLeftStack, 20 | LeftWiderRightStack, 21 | } 22 | 23 | // TODO fix this by matching the layout handling to leftwm 24 | #[allow(dead_code)] 25 | pub const LAYOUTS: &[Layout] = &[ 26 | Layout::MainAndVertStack, 27 | Layout::MainAndHorizontalStack, 28 | Layout::MainAndDeck, 29 | Layout::GridHorizontal, 30 | Layout::EvenHorizontal, 31 | Layout::EvenVertical, 32 | Layout::Fibonacci, 33 | Layout::LeftMain, 34 | Layout::CenterMain, 35 | Layout::CenterMainBalanced, 36 | Layout::CenterMainFluid, 37 | Layout::Monocle, 38 | Layout::RightWiderLeftStack, 39 | Layout::LeftWiderRightStack, 40 | ]; 41 | 42 | impl Default for Layout { 43 | fn default() -> Self { 44 | Self::MainAndVertStack 45 | } 46 | } 47 | 48 | #[derive(Debug, Error)] 49 | #[error("Could not parse layout: {0}")] 50 | pub struct ParseLayoutError(String); 51 | 52 | impl FromStr for Layout { 53 | type Err = ParseLayoutError; 54 | 55 | fn from_str(s: &str) -> Result { 56 | match s { 57 | "MainAndVertStack" => Ok(Self::MainAndVertStack), 58 | "MainAndHorizontalStack" => Ok(Self::MainAndHorizontalStack), 59 | "MainAndDeck" => Ok(Self::MainAndDeck), 60 | "GridHorizontal" => Ok(Self::GridHorizontal), 61 | "EvenHorizontal" => Ok(Self::EvenHorizontal), 62 | "EvenVertical" => Ok(Self::EvenVertical), 63 | "Fibonacci" => Ok(Self::Fibonacci), 64 | "LeftMain" => Ok(Self::LeftMain), 65 | "CenterMain" => Ok(Self::CenterMain), 66 | "CenterMainBalanced" => Ok(Self::CenterMainBalanced), 67 | "CenterMainFluid" => Ok(Self::CenterMainFluid), 68 | "Monocle" => Ok(Self::Monocle), 69 | "RightWiderLeftStack" => Ok(Self::RightWiderLeftStack), 70 | "LeftWiderRightStack" => Ok(Self::LeftWiderRightStack), 71 | _ => Err(ParseLayoutError(s.to_string())), 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | clippy::module_name_repetitions, 3 | clippy::too_many_lines, 4 | //a lot of unimplemented arms 5 | clippy::match_same_arms, 6 | )] 7 | 8 | extern crate core; 9 | 10 | mod config; 11 | mod tui; 12 | mod utils; 13 | 14 | use crate::config::check_config; 15 | use crate::config::filehandler::{load_from_file, write_to_file}; 16 | use anyhow::Result; 17 | use clap::{Arg, Command as ClapCmd}; 18 | use std::path::Path; 19 | use std::process::Command; 20 | use std::{env, fs, io}; 21 | use xdg::BaseDirectories; 22 | 23 | #[cfg(debug_assertions)] 24 | const CONFIG_NAME: &str = "test_config"; 25 | #[cfg(not(debug_assertions))] 26 | const CONFIG_NAME: &str = "config"; 27 | 28 | fn main() -> Result<()> { 29 | let matches = ClapCmd::new("LeftWM Command") 30 | .author("BlackDragon2447 ") 31 | .version(env!("CARGO_PKG_VERSION")) 32 | .about("a tool for managing your LeftWM config") 33 | .arg( 34 | Arg::new("New") 35 | .short('n') 36 | .long("new") 37 | .help("Generate a new config file"), 38 | ) 39 | .arg( 40 | Arg::new("Editor") 41 | .short('e') 42 | .long("editor") 43 | .help("Open the current config file in the default editor (default)"), 44 | ) 45 | .arg( 46 | Arg::new("TUI") 47 | .short('t') 48 | .long("tui") 49 | .help("Open the current config file in the TUI"), 50 | ) 51 | .arg( 52 | Arg::new("Check") 53 | .short('c') 54 | .long("check") 55 | .help("Check if the current config is valid"), 56 | ) 57 | .arg( 58 | Arg::new("Verbose") 59 | .short('v') 60 | .long("verbose") 61 | .help("Outputs received configuration file."), 62 | ) 63 | .arg( 64 | Arg::new("Migrate") 65 | .long("migrate") 66 | .help("Migrate an old .toml config to the RON format."), 67 | ) 68 | .get_matches(); 69 | 70 | let verbose = matches.get_flag("Verbose"); 71 | 72 | if matches.get_flag("Migrate") { 73 | println!("\x1b[0;94m::\x1b[0m Migrating configuration . . ."); 74 | let path = BaseDirectories::with_prefix("leftwm"); 75 | let ron_file = path.place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 76 | let toml_file = path.place_config_file(crate::CONFIG_NAME.to_string() + ".toml")?; 77 | 78 | let config = load_from_file(toml_file.as_os_str().to_str(), verbose)?; 79 | 80 | write_to_file(&ron_file, &config)?; 81 | 82 | return Ok(()); 83 | } else if matches.get_flag("Editor") { 84 | run_editor(config::filehandler::get_config_file()?.as_path())?; 85 | } else if matches.get_flag("TUI") { 86 | crate::tui::run()?; 87 | } else if matches.get_flag("New") { 88 | config::filehandler::generate_new_config()?; 89 | } else if matches.get_flag("Check") { 90 | check_config(None, verbose)?; 91 | } else { 92 | run_editor(config::filehandler::get_config_file()?.as_path())?; 93 | } 94 | 95 | Ok(()) 96 | } 97 | 98 | fn run_editor(file: &Path) -> Result<()> { 99 | let editor = env::var("EDITOR")?; 100 | 101 | let tmp_file = Path::new("/tmp/leftwm-config.ron"); 102 | fs::copy(file, tmp_file)?; 103 | 104 | let run_internal = || -> Result<()> { 105 | let mut process = Command::new(&editor).arg(tmp_file.as_os_str()).spawn()?; 106 | if process.wait()?.success() { 107 | Ok(()) 108 | } else { 109 | Err(anyhow::Error::msg(format!("Failed to run {}", &editor))) 110 | }?; 111 | Ok(()) 112 | }; 113 | 114 | run_internal()?; 115 | 116 | while check_config(Some("/tmp/leftwm-config.ron"), false).is_err() { 117 | println!("Do you want to reopen your editor? [Y/n] "); 118 | 119 | let mut buffer = String::new(); 120 | io::stdin().read_line(&mut buffer)?; 121 | 122 | if let Some("y" | "Y") = buffer.get(0..1) { 123 | run_internal()?; 124 | } else if let Some("n" | "N") = buffer.get(0..1) { 125 | break; 126 | } else { 127 | run_internal()?; 128 | } 129 | } 130 | 131 | fs::copy(tmp_file, file)?; 132 | 133 | Ok(()) 134 | } 135 | -------------------------------------------------------------------------------- /src/config/command.rs: -------------------------------------------------------------------------------- 1 | use crate::config::values::WindowHandle; 2 | use crate::config::Layout; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[allow(clippy::module_name_repetitions)] 6 | #[derive(Debug, Serialize, Default, Deserialize, Clone, PartialEq, Eq, Hash)] 7 | pub enum BaseCommand { 8 | #[default] 9 | Execute, 10 | CloseWindow, 11 | SwapTags, 12 | SoftReload, 13 | HardReload, 14 | ToggleScratchPad, 15 | ToggleFullScreen, 16 | ToggleSticky, 17 | GotoTag, 18 | ReturnToLastTag, 19 | FloatingToTile, 20 | TileToFloating, 21 | ToggleFloating, 22 | MoveWindowUp, 23 | MoveWindowDown, 24 | MoveWindowTop, 25 | FocusNextTag, 26 | FocusPreviousTag, 27 | FocusWindow, 28 | FocusWindowUp, 29 | FocusWindowDown, 30 | FocusWindowTop, 31 | FocusWorkspaceNext, 32 | FocusWorkspacePrevious, 33 | MoveToTag, 34 | MoveToLastWorkspace, 35 | MoveWindowToNextWorkspace, 36 | MoveWindowToPreviousWorkspace, 37 | MouseMoveWindow, 38 | NextLayout, 39 | PreviousLayout, 40 | SetLayout, 41 | RotateTag, 42 | IncreaseMainWidth, 43 | DecreaseMainWidth, 44 | SetMarginMultiplier, 45 | // Custom commands 46 | UnloadTheme, 47 | LoadTheme, 48 | CloseAllOtherWindows, 49 | } 50 | 51 | impl BaseCommand { 52 | pub fn needs_value(&self) -> bool { 53 | match self { 54 | BaseCommand::Execute => true, 55 | BaseCommand::CloseWindow => false, 56 | BaseCommand::SwapTags => false, 57 | BaseCommand::SoftReload => false, 58 | BaseCommand::HardReload => false, 59 | BaseCommand::ToggleScratchPad => true, 60 | BaseCommand::ToggleFullScreen => false, 61 | BaseCommand::ToggleSticky => false, 62 | BaseCommand::GotoTag => true, 63 | BaseCommand::ReturnToLastTag => false, 64 | BaseCommand::FloatingToTile => false, 65 | BaseCommand::TileToFloating => false, 66 | BaseCommand::ToggleFloating => false, 67 | BaseCommand::MoveWindowUp => false, 68 | BaseCommand::MoveWindowDown => false, 69 | BaseCommand::MoveWindowTop => false, 70 | BaseCommand::FocusNextTag => false, 71 | BaseCommand::FocusPreviousTag => false, 72 | BaseCommand::FocusWindow => false, 73 | BaseCommand::FocusWindowUp => false, 74 | BaseCommand::FocusWindowDown => false, 75 | BaseCommand::FocusWindowTop => false, 76 | BaseCommand::FocusWorkspaceNext => false, 77 | BaseCommand::FocusWorkspacePrevious => false, 78 | BaseCommand::MoveToTag => true, 79 | BaseCommand::MoveToLastWorkspace => false, 80 | BaseCommand::MoveWindowToNextWorkspace => false, 81 | BaseCommand::MoveWindowToPreviousWorkspace => false, 82 | BaseCommand::MouseMoveWindow => false, 83 | BaseCommand::NextLayout => false, 84 | BaseCommand::PreviousLayout => false, 85 | BaseCommand::SetLayout => true, 86 | BaseCommand::RotateTag => false, 87 | BaseCommand::IncreaseMainWidth => true, 88 | BaseCommand::DecreaseMainWidth => true, 89 | BaseCommand::SetMarginMultiplier => true, 90 | // 91 | BaseCommand::UnloadTheme => true, 92 | BaseCommand::LoadTheme => true, 93 | BaseCommand::CloseAllOtherWindows => false, 94 | } 95 | } 96 | } 97 | 98 | pub type TagId = usize; 99 | 100 | #[allow(dead_code)] 101 | pub enum CoreCommand { 102 | Execute(String), 103 | CloseWindow, 104 | SwapScreens, 105 | SoftReload, 106 | HardReload, 107 | ToggleScratchPad(String), 108 | ToggleFullScreen, 109 | ToggleSticky, 110 | GoToTag { 111 | tag: TagId, 112 | swap: bool, 113 | }, 114 | ReturnToLastTag, 115 | FloatingToTile, 116 | TileToFloating, 117 | ToggleFloating, 118 | MoveWindowUp, 119 | MoveWindowDown, 120 | MoveWindowTop { 121 | swap: bool, 122 | }, 123 | FocusNextTag, 124 | FocusPreviousTag, 125 | FocusWindow(String), 126 | FocusWindowUp, 127 | FocusWindowDown, 128 | FocusWindowTop { 129 | swap: bool, 130 | }, 131 | FocusWorkspaceNext, 132 | FocusWorkspacePrevious, 133 | SendWindowToTag { 134 | window: Option, 135 | tag: TagId, 136 | }, 137 | MoveWindowToLastWorkspace, 138 | MoveWindowToNextWorkspace, 139 | MoveWindowToPreviousWorkspace, 140 | MouseMoveWindow, 141 | NextLayout, 142 | PreviousLayout, 143 | SetLayout(Layout), 144 | RotateTag, 145 | IncreaseMainWidth(i8), 146 | DecreaseMainWidth(i8), 147 | SetMarginMultiplier(f32), 148 | SendWorkspaceToTag(usize, usize), 149 | CloseAllOtherWindows, 150 | Other(String), 151 | } 152 | -------------------------------------------------------------------------------- /src/config/filehandler.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::fs::File; 3 | use std::io::Write; 4 | use std::path::{Path, PathBuf}; 5 | 6 | use anyhow::Result; 7 | use xdg::BaseDirectories; 8 | 9 | use crate::config::Config; 10 | 11 | #[must_use] 12 | pub fn load() -> Config { 13 | load_from_file(None, false) 14 | .map_err(|err| eprintln!("ERROR LOADING CONFIG: {err:?}")) 15 | .unwrap_or_default() 16 | } 17 | 18 | /// Loads configuration from either specified file (preferred) or default. 19 | /// # Errors 20 | /// 21 | /// Errors if file cannot be read. Indicates filesystem error 22 | /// (inadequate permissions, disk full, etc.) 23 | /// If a path is specified and does not exist, returns `LeftError`. 24 | pub fn load_from_file(fspath: Option<&str>, verbose: bool) -> Result { 25 | let config_filename = if let Some(fspath) = fspath { 26 | println!("\x1b[1;35mNote: Using file {fspath} \x1b[0m"); 27 | PathBuf::from(fspath) 28 | } else { 29 | let ron_file = BaseDirectories::with_prefix("leftwm") 30 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 31 | let toml_file = BaseDirectories::with_prefix("leftwm") 32 | .place_config_file(crate::CONFIG_NAME.to_string() + ".toml")?; 33 | if Path::new(&ron_file).exists() { 34 | ron_file 35 | } else if Path::new(&toml_file).exists() { 36 | println!( 37 | "\x1b[1;93mWARN: TOML as config format is about to be deprecated. 38 | Please consider migrating to RON manually or by using `leftwm-check -m`.\x1b[0m" 39 | ); 40 | toml_file 41 | } else { 42 | let config = Config::default(); 43 | write_to_file(&ron_file, &config)?; 44 | return Ok(config); 45 | } 46 | }; 47 | if verbose { 48 | dbg!(&config_filename); 49 | } 50 | let contents = fs::read_to_string(&config_filename)?; 51 | if verbose { 52 | dbg!(&contents); 53 | } 54 | if config_filename.as_path().extension() == Some(std::ffi::OsStr::new("ron")) { 55 | let config = ron::from_str(&contents)?; 56 | Ok(config) 57 | } else { 58 | let config = toml::from_str(&contents)?; 59 | Ok(config) 60 | } 61 | } 62 | 63 | pub fn get_config_file() -> Result { 64 | let ron_file = BaseDirectories::with_prefix("leftwm") 65 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 66 | let toml_file = BaseDirectories::with_prefix("leftwm") 67 | .place_config_file(crate::CONFIG_NAME.to_string() + ".toml")?; 68 | if Path::new(&ron_file).exists() { 69 | Ok(ron_file) 70 | } else if Path::new(&toml_file).exists() { 71 | println!( 72 | "\x1b[1;93mWARN: TOML as config format is about to be deprecated. 73 | Please consider migrating to RON manually or by using `leftwm-config --migrate`.\x1b[0m" 74 | ); 75 | Ok(toml_file) 76 | } else { 77 | let config = Config::default(); 78 | write_to_file(&ron_file, &config)?; 79 | Ok(ron_file) 80 | } 81 | } 82 | 83 | pub fn save_to_file(config: &Config) -> Result<()> { 84 | write_to_file( 85 | &BaseDirectories::with_prefix("leftwm") 86 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?, 87 | config, 88 | ) 89 | } 90 | 91 | pub fn write_to_file(ron_file: &PathBuf, config: &Config) -> Result<(), anyhow::Error> { 92 | let ron_pretty_conf = ron::ser::PrettyConfig::new() 93 | .depth_limit(2) 94 | .extensions(ron::extensions::Extensions::IMPLICIT_SOME); 95 | let ron = ron::ser::to_string_pretty(&config, ron_pretty_conf)?; 96 | let comment_header = String::from( 97 | r"// _ ___ ___ _ 98 | // | | / __)_ / __|_) 99 | // | | ____| |__| |_ _ _ _ ____ ____ ___ ____ | |__ _ ____ ____ ___ ____ 100 | // | |/ _ ) __) _) | | | \ / ___) _ \| _ \| __) |/ _ | / ___) _ \| _ \ 101 | // | ( (/ /| | | |_| | | | | | | ( (__| |_| | | | | | | ( ( | |_| | | |_| | | | | 102 | // |_|\____)_| \___)____|_|_|_| \____)___/|_| |_|_| |_|\_|| (_)_| \___/|_| |_| 103 | // A WindowManager for Adventurers (____/ 104 | // For info about configuration please visit https://github.com/leftwm/leftwm/wiki 105 | ", 106 | ); 107 | let ron_with_header = comment_header + &ron; 108 | let mut file = File::create(ron_file)?; 109 | file.write_all(ron_with_header.as_bytes())?; 110 | Ok(()) 111 | } 112 | 113 | pub fn generate_new_config() -> Result<()> { 114 | let file = BaseDirectories::with_prefix("leftwm") 115 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 116 | 117 | if file.exists() { 118 | println!( 119 | "\x1b[0;94m::\x1b[0m A config file already exists, do you want to override it? [y/N]" 120 | ); 121 | let mut line = String::new(); 122 | let _ = std::io::stdin() 123 | .read_line(&mut line) 124 | .expect("Failed to read line"); 125 | if line.contains('y') || line.contains('Y') { 126 | let config = Config::default(); 127 | let ron_pretty_conf = ron::ser::PrettyConfig::new() 128 | .depth_limit(2) 129 | .extensions(ron::extensions::Extensions::IMPLICIT_SOME); 130 | let text = ron::ser::to_string_pretty(&config, ron_pretty_conf)?; 131 | let mut file = File::create(&file)?; 132 | file.write_all(text.as_bytes())?; 133 | } 134 | } 135 | 136 | Ok(()) 137 | } 138 | -------------------------------------------------------------------------------- /src/config/keybind.rs: -------------------------------------------------------------------------------- 1 | use crate::config::command::{BaseCommand, CoreCommand}; 2 | use crate::config::layout::Layout; 3 | use crate::config::modifier::Modifier; 4 | use crate::config::Config; 5 | use anyhow::ensure; 6 | use anyhow::{Context, Result}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::str::FromStr; 9 | 10 | #[derive(Serialize, Default, Deserialize, Debug, Clone)] 11 | pub struct Keybind { 12 | pub command: BaseCommand, 13 | #[serde(default)] 14 | pub value: String, 15 | pub modifier: Option, 16 | pub key: String, 17 | } 18 | 19 | // TODO lift this allow by actually using those items 20 | #[allow(dead_code)] 21 | pub struct CoreKeybind { 22 | pub command: CoreCommand, 23 | pub modifier: Vec, 24 | pub key: String, 25 | } 26 | 27 | macro_rules! ensure_non_empty { 28 | ($value:expr) => {{ 29 | ensure!(!$value.is_empty(), "value must not be empty"); 30 | $value 31 | }}; 32 | } 33 | 34 | impl Keybind { 35 | pub fn try_convert_to_core_keybind(&self, config: &Config) -> Result { 36 | let command = match &self.command { 37 | BaseCommand::Execute => CoreCommand::Execute(ensure_non_empty!(self.value.clone())), 38 | BaseCommand::CloseWindow => CoreCommand::CloseWindow, 39 | BaseCommand::SwapTags => CoreCommand::SwapScreens, 40 | BaseCommand::SoftReload => CoreCommand::SoftReload, 41 | BaseCommand::HardReload => CoreCommand::HardReload, 42 | BaseCommand::ToggleScratchPad => { 43 | CoreCommand::ToggleScratchPad(ensure_non_empty!(self.value.clone())) 44 | } 45 | BaseCommand::ToggleFullScreen => CoreCommand::ToggleFullScreen, 46 | BaseCommand::ToggleSticky => CoreCommand::ToggleSticky, 47 | BaseCommand::GotoTag => CoreCommand::GoToTag { 48 | tag: usize::from_str(&self.value).context("invalid index value for GotoTag")?, 49 | swap: !config.disable_current_tag_swap, 50 | }, 51 | BaseCommand::ReturnToLastTag => CoreCommand::ReturnToLastTag, 52 | BaseCommand::FloatingToTile => CoreCommand::FloatingToTile, 53 | BaseCommand::TileToFloating => CoreCommand::TileToFloating, 54 | BaseCommand::ToggleFloating => CoreCommand::ToggleFloating, 55 | BaseCommand::MoveWindowUp => CoreCommand::MoveWindowUp, 56 | BaseCommand::MoveWindowDown => CoreCommand::MoveWindowDown, 57 | BaseCommand::MoveWindowTop => CoreCommand::MoveWindowTop { 58 | swap: if self.value.is_empty() { 59 | true 60 | } else { 61 | bool::from_str(&self.value) 62 | .context("invalid boolean value for MoveWindowTop")? 63 | }, 64 | }, 65 | BaseCommand::FocusNextTag => CoreCommand::FocusNextTag, 66 | BaseCommand::FocusPreviousTag => CoreCommand::FocusPreviousTag, 67 | BaseCommand::FocusWindow => CoreCommand::FocusWindow(self.value.clone()), 68 | BaseCommand::FocusWindowUp => CoreCommand::FocusWindowUp, 69 | BaseCommand::FocusWindowDown => CoreCommand::FocusWindowDown, 70 | BaseCommand::FocusWindowTop => CoreCommand::FocusWindowTop { 71 | swap: if self.value.is_empty() { 72 | false 73 | } else { 74 | bool::from_str(&self.value) 75 | .context("invalid boolean value for FocusWindowTop")? 76 | }, 77 | }, 78 | BaseCommand::FocusWorkspaceNext => CoreCommand::FocusWorkspaceNext, 79 | BaseCommand::FocusWorkspacePrevious => CoreCommand::FocusWorkspacePrevious, 80 | BaseCommand::MoveToTag => CoreCommand::SendWindowToTag { 81 | window: None, 82 | tag: usize::from_str(&self.value) 83 | .context("invalid index value for SendWindowToTag")?, 84 | }, 85 | BaseCommand::MoveToLastWorkspace => CoreCommand::MoveWindowToLastWorkspace, 86 | BaseCommand::MoveWindowToNextWorkspace => CoreCommand::MoveWindowToNextWorkspace, 87 | BaseCommand::MoveWindowToPreviousWorkspace => { 88 | CoreCommand::MoveWindowToPreviousWorkspace 89 | } 90 | BaseCommand::MouseMoveWindow => CoreCommand::MouseMoveWindow, 91 | BaseCommand::NextLayout => CoreCommand::NextLayout, 92 | BaseCommand::PreviousLayout => CoreCommand::PreviousLayout, 93 | BaseCommand::SetLayout => CoreCommand::SetLayout( 94 | Layout::from_str(&self.value) 95 | .context("could not parse layout for command SetLayout")?, 96 | ), 97 | BaseCommand::RotateTag => CoreCommand::RotateTag, 98 | BaseCommand::IncreaseMainWidth => CoreCommand::IncreaseMainWidth( 99 | i8::from_str(&self.value).context("invalid width value for IncreaseMainWidth")?, 100 | ), 101 | BaseCommand::DecreaseMainWidth => CoreCommand::DecreaseMainWidth( 102 | i8::from_str(&self.value).context("invalid width value for DecreaseMainWidth")?, 103 | ), 104 | BaseCommand::SetMarginMultiplier => CoreCommand::SetMarginMultiplier( 105 | f32::from_str(&self.value) 106 | .context("invalid margin multiplier for SetMarginMultiplier")?, 107 | ), 108 | BaseCommand::UnloadTheme => CoreCommand::Other("UnloadTheme".into()), 109 | BaseCommand::LoadTheme => CoreCommand::Other(format!( 110 | "LoadTheme {}", 111 | ensure_non_empty!(self.value.clone()) 112 | )), 113 | BaseCommand::CloseAllOtherWindows => CoreCommand::CloseAllOtherWindows, 114 | }; 115 | 116 | Ok(CoreKeybind { 117 | command, 118 | modifier: self 119 | .modifier 120 | .as_ref() 121 | .unwrap_or(&"None".into()) 122 | .clone() 123 | .into(), 124 | key: self.key.clone(), 125 | }) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/config/check.rs: -------------------------------------------------------------------------------- 1 | use crate::config; 2 | use crate::config::Config; 3 | use crate::config::{all_ids_some, all_ids_unique, get_workspace_ids}; 4 | use anyhow::bail; 5 | use anyhow::Result; 6 | use std::collections::HashSet; 7 | use std::{env, fs}; 8 | 9 | pub fn check_config(path: Option<&str>, verbose: bool) -> Result<()> { 10 | println!( 11 | "\x1b[0;94m::\x1b[0m LeftWM Config version: {}", 12 | std::env::var("CARGO_PKG_VERSON").unwrap_or("unknown".to_string()) 13 | ); 14 | println!( 15 | "\x1b[0;94m::\x1b[0m LeftWM git hash: {}", 16 | option_env!("GIT_HASH").unwrap_or(git_version::git_version!(fallback = "unknown")) 17 | ); 18 | println!("\x1b[0;94m::\x1b[0m Loading configuration . . ."); 19 | match config::filehandler::load_from_file(path, verbose) { 20 | Ok(config) => { 21 | println!("\x1b[0;92m -> Configuration loaded OK \x1b[0m"); 22 | if verbose { 23 | dbg!(&config); 24 | } 25 | config.check_mousekey(verbose); 26 | config.check_workspace_ids(verbose); 27 | config.check_keybinds(verbose); 28 | } 29 | Err(e) => { 30 | println!("Configuration failed. Reason: {e:?}"); 31 | bail!("Configuration failed. Reason: {:?}", e); 32 | } 33 | } 34 | println!("\x1b[0;94m::\x1b[0m Checking environment . . ."); 35 | check_elogind(verbose)?; 36 | 37 | Ok(()) 38 | } 39 | 40 | impl Config { 41 | pub fn check_mousekey(&self, verbose: bool) { 42 | if verbose { 43 | println!("Checking if mousekey is set."); 44 | } 45 | if let Some(mousekey) = &self.mousekey { 46 | if verbose { 47 | println!("Mousekey is set."); 48 | } 49 | if mousekey.is_empty() { 50 | println!("Your mousekey is set to nothing, this will cause windows to move/resize with just a mouse press."); 51 | return; 52 | } 53 | if verbose { 54 | println!("Mousekey is okay."); 55 | } 56 | } 57 | } 58 | 59 | /// Checks defined workspaces to ensure no ID collisions occur. 60 | pub fn check_workspace_ids(&self, verbose: bool) { 61 | if let Some(wss) = self.workspaces.as_ref() { 62 | if verbose { 63 | println!("Checking config for valid workspace definitions."); 64 | } 65 | let ids = get_workspace_ids(wss); 66 | if ids.iter().any(std::option::Option::is_some) { 67 | if all_ids_some(&ids) { 68 | if !all_ids_unique(&ids) { 69 | println!("Your config.toml contains duplicate workspace IDs. Please assign unique IDs to workspaces. The default config will be used instead."); 70 | } 71 | } else { 72 | println!("Your config.toml specifies an ID for some but not all workspaces. This can lead to ID collisions and is not allowed. The default config will be used instead."); 73 | } 74 | } 75 | } 76 | } 77 | 78 | /// Check all keybinds to ensure that required values are provided 79 | /// Checks to see if value is provided (if required) 80 | /// Checks to see if keys are valid against Xkeysym 81 | /// Ideally, we will pass this to the command handler with a dummy config 82 | pub fn check_keybinds(&self, verbose: bool) { 83 | let mut returns = Vec::new(); 84 | println!("\x1b[0;94m::\x1b[0m Checking keybinds . . ."); 85 | let mut bindings = HashSet::new(); 86 | for keybind in &self.keybind { 87 | if verbose { 88 | println!("Keybind: {:?} {}", keybind, keybind.value.is_empty()); 89 | } 90 | if let Err(err) = keybind.try_convert_to_core_keybind(self) { 91 | returns.push((Some(keybind.clone()), err.to_string())); 92 | } 93 | if crate::utils::xkeysym_lookup::into_keysym(&keybind.key).is_none() { 94 | returns.push(( 95 | Some(keybind.clone()), 96 | format!("Key `{}` is not valid", keybind.key), 97 | )); 98 | } 99 | 100 | let mut modkey = keybind.modifier.as_ref().unwrap_or(&"None".into()).clone(); 101 | for m in &modkey.clone() { 102 | if m != "modkey" 103 | && m != "mousekey" 104 | && crate::utils::xkeysym_lookup::into_mod(&m) == 0 105 | { 106 | returns.push(( 107 | Some(keybind.clone()), 108 | format!("Modifier `{m}` is not valid"), 109 | )); 110 | } 111 | } 112 | 113 | modkey.sort_unstable(); 114 | if let Some(conflict_key) = bindings.replace((modkey.clone(), &keybind.key)) { 115 | returns.push(( 116 | None, 117 | format!( 118 | "\x1b[0m\x1b[1mMultiple commands bound to key combination {} + {}:\ 119 | \n\x1b[1;91m -> {:?}\ 120 | \n -> {:?}\ 121 | \n\x1b[0mHelp: change one of the keybindings to something else.\n", 122 | modkey, keybind.key, conflict_key, keybind.command, 123 | ), 124 | )); 125 | } 126 | } 127 | if returns.is_empty() { 128 | println!("\x1b[0;92m -> All keybinds OK\x1b[0m"); 129 | } else { 130 | for error in returns { 131 | match error.0 { 132 | Some(binding) => { 133 | println!( 134 | "\x1b[1;91mERROR: {} for keybind {:?}\x1b[0m", 135 | error.1, binding 136 | ); 137 | } 138 | None => { 139 | println!("\x1b[1;91mERROR: {} \x1b[0m", error.1); 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | 147 | fn check_elogind(verbose: bool) -> Result<()> { 148 | // We assume that if it is in the path it's all good 149 | // We also cross-reference the ENV variable 150 | match ( 151 | std::env::var("XDG_RUNTIME_DIR"), 152 | is_program_in_path("loginctl"), 153 | ) { 154 | (Ok(val), true) => { 155 | if verbose { 156 | println!(":: XDG_RUNTIME_DIR: {val}, LOGINCTL OKAY"); 157 | } 158 | 159 | println!("\x1b[0;92m -> Environment OK \x1b[0m"); 160 | 161 | Ok(()) 162 | } 163 | (Ok(val), false) => { 164 | if verbose { 165 | println!(":: XDG_RUNTIME_DIR: {val}, LOGINCTL not installed"); 166 | } 167 | 168 | println!("\x1b[0;92m -> Environment OK (has XDG_RUNTIME_DIR) \x1b[0m"); 169 | 170 | Ok(()) 171 | } 172 | (Err(e), false) => { 173 | if verbose { 174 | println!(":: XDG_RUNTIME_DIR_ERROR: {e:?}, LOGINCTL BAD"); 175 | } 176 | 177 | bail!( 178 | "Elogind not installed/operating and no alternative XDG_RUNTIME_DIR is set. \ 179 | See https://github.com/leftwm/leftwm/wiki/XDG_RUNTIME_DIR for more information." 180 | ); 181 | } 182 | (Err(e), true) => { 183 | if verbose { 184 | println!(":: XDG_RUNTIME_DIR: {e:?}, LOGINCTL OKAY"); 185 | } 186 | println!( 187 | "\x1b[1;93mWARN: Elogind/systemd installed but XDG_RUNTIME_DIR not set.\nThis may be because elogind isn't started. \x1b[0m", 188 | ); 189 | Ok(()) 190 | } 191 | } 192 | } 193 | 194 | #[must_use] 195 | fn is_program_in_path(program: &str) -> bool { 196 | if let Ok(path) = env::var("PATH") { 197 | for p in path.split(':') { 198 | let p_str = format!("{p}/{program}"); 199 | if fs::metadata(p_str).is_ok() { 200 | return true; 201 | } 202 | } 203 | } 204 | false 205 | } 206 | -------------------------------------------------------------------------------- /src/config/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs}; 2 | 3 | pub use check::check_config; 4 | use layout::Layout; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | use crate::config::command::BaseCommand; 8 | use crate::config::keybind::Keybind; 9 | use crate::config::modifier::Modifier; 10 | use crate::config::structs::{ScratchPad, WindowHook, Workspace}; 11 | use crate::config::values::{FocusBehaviour, InsertBehavior, LayoutMode, Size}; 12 | 13 | mod check; 14 | pub mod command; 15 | pub mod filehandler; 16 | pub mod keybind; 17 | pub mod layout; 18 | pub mod modifier; 19 | pub mod structs; 20 | pub mod values; 21 | 22 | #[derive(Copy, Clone)] 23 | #[allow(dead_code)] 24 | pub enum Language { 25 | Ron, 26 | Unsupported, 27 | } 28 | 29 | #[derive(Serialize, Deserialize, Debug)] 30 | #[serde(default)] 31 | pub struct Config { 32 | pub modkey: String, 33 | pub mousekey: Option, 34 | pub tags: Option>, 35 | pub max_window_width: Option, 36 | pub layouts: Vec, 37 | pub layout_mode: LayoutMode, 38 | pub insert_behavior: InsertBehavior, 39 | pub scratchpad: Option>, 40 | pub window_rules: Option>, 41 | //of you are on tag "1" and you goto tag "1" this takes you to the previous tag 42 | pub disable_current_tag_swap: bool, 43 | pub disable_tile_drag: bool, 44 | pub focus_behaviour: FocusBehaviour, 45 | pub focus_new_windows: bool, 46 | pub keybind: Vec, 47 | pub workspaces: Option>, 48 | } 49 | 50 | fn default_terminal<'s>() -> &'s str { 51 | // order from least common to most common. 52 | // the thinking is if a machine has an uncommon terminal installed, it is intentional 53 | let terms = &[ 54 | "alacritty", 55 | "termite", 56 | "kitty", 57 | "urxvt", 58 | "rxvt", 59 | "st", 60 | "roxterm", 61 | "eterm", 62 | "xterm", 63 | "terminator", 64 | "terminology", 65 | "gnome-terminal", 66 | "xfce4-terminal", 67 | "konsole", 68 | "uxterm", 69 | "guake", // at the bottom because of odd behaviour. guake wants F12 and should really be 70 | // started using autostart instead of LeftWM keybind. 71 | ]; 72 | 73 | // If no terminal found in path, default to a good one 74 | terms 75 | .iter() 76 | .find(|terminal| is_program_in_path(terminal)) 77 | .unwrap_or(&"termite") 78 | } 79 | 80 | #[must_use] 81 | pub fn is_program_in_path(program: &str) -> bool { 82 | if let Ok(path) = env::var("PATH") { 83 | for p in path.split(':') { 84 | let p_str = format!("{p}/{program}"); 85 | if fs::metadata(p_str).is_ok() { 86 | return true; 87 | } 88 | } 89 | } 90 | false 91 | } 92 | 93 | impl Default for Config { 94 | // We allow this because this function would be difficult to reduce. If someone would like to 95 | // move the commands builder out, perhaps make a macro, this function could be reduced in size 96 | // considerably. 97 | #[allow(clippy::too_many_lines)] 98 | fn default() -> Self { 99 | const WORKSPACES_NUM: usize = 10; 100 | let mut commands = vec![ 101 | // Mod + p => Open dmenu 102 | Keybind { 103 | command: BaseCommand::Execute, 104 | value: "dmenu_run".to_owned(), 105 | modifier: Some(vec!["modkey".to_owned()].into()), 106 | key: "p".to_owned(), 107 | }, 108 | // Mod + Shift + Enter => Open A Shell 109 | Keybind { 110 | command: BaseCommand::Execute, 111 | value: default_terminal().to_owned(), 112 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 113 | key: "Return".to_owned(), 114 | }, 115 | // Mod + Shift + q => kill focused window 116 | Keybind { 117 | command: BaseCommand::CloseWindow, 118 | value: String::default(), 119 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 120 | key: "q".to_owned(), 121 | }, 122 | // Mod + Shift + r => soft reload leftwm 123 | Keybind { 124 | command: BaseCommand::SoftReload, 125 | value: String::default(), 126 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 127 | key: "r".to_owned(), 128 | }, 129 | // Mod + Shift + x => exit leftwm 130 | Keybind { 131 | command: BaseCommand::Execute, 132 | value: exit_strategy().to_owned(), 133 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 134 | key: "x".to_owned(), 135 | }, 136 | // Mod + Ctrl + l => lock the screen 137 | Keybind { 138 | command: BaseCommand::Execute, 139 | value: "slock".to_owned(), 140 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 141 | key: "l".to_owned(), 142 | }, 143 | // Mod + Shift + w => swap the tags on the last to active workspaces 144 | Keybind { 145 | command: BaseCommand::MoveToLastWorkspace, 146 | value: String::default(), 147 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 148 | key: "w".to_owned(), 149 | }, 150 | // Mod + w => move the active window to the previous workspace 151 | Keybind { 152 | command: BaseCommand::SwapTags, 153 | value: String::default(), 154 | modifier: Some(vec!["modkey".to_owned()].into()), 155 | key: "w".to_owned(), 156 | }, 157 | Keybind { 158 | command: BaseCommand::MoveWindowUp, 159 | value: String::default(), 160 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 161 | key: "k".to_owned(), 162 | }, 163 | Keybind { 164 | command: BaseCommand::MoveWindowDown, 165 | value: String::default(), 166 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 167 | key: "j".to_owned(), 168 | }, 169 | Keybind { 170 | command: BaseCommand::MoveWindowTop, 171 | value: String::default(), 172 | modifier: Some(vec!["modkey".to_owned()].into()), 173 | key: "Return".to_owned(), 174 | }, 175 | Keybind { 176 | command: BaseCommand::FocusWindowUp, 177 | value: String::default(), 178 | modifier: Some(vec!["modkey".to_owned()].into()), 179 | key: "k".to_owned(), 180 | }, 181 | Keybind { 182 | command: BaseCommand::FocusWindowDown, 183 | value: String::default(), 184 | modifier: Some(vec!["modkey".to_owned()].into()), 185 | key: "j".to_owned(), 186 | }, 187 | Keybind { 188 | command: BaseCommand::NextLayout, 189 | value: String::default(), 190 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 191 | key: "k".to_owned(), 192 | }, 193 | Keybind { 194 | command: BaseCommand::PreviousLayout, 195 | value: String::default(), 196 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 197 | key: "j".to_owned(), 198 | }, 199 | Keybind { 200 | command: BaseCommand::FocusWorkspaceNext, 201 | value: String::default(), 202 | modifier: Some(vec!["modkey".to_owned()].into()), 203 | key: "l".to_owned(), 204 | }, 205 | Keybind { 206 | command: BaseCommand::FocusWorkspacePrevious, 207 | value: String::default(), 208 | modifier: Some(vec!["modkey".to_owned()].into()), 209 | key: "h".to_owned(), 210 | }, 211 | Keybind { 212 | command: BaseCommand::MoveWindowUp, 213 | value: String::default(), 214 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 215 | key: "Up".to_owned(), 216 | }, 217 | Keybind { 218 | command: BaseCommand::MoveWindowDown, 219 | value: String::default(), 220 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 221 | key: "Down".to_owned(), 222 | }, 223 | Keybind { 224 | command: BaseCommand::FocusWindowUp, 225 | value: String::default(), 226 | modifier: Some(vec!["modkey".to_owned()].into()), 227 | key: "Up".to_owned(), 228 | }, 229 | Keybind { 230 | command: BaseCommand::FocusWindowDown, 231 | value: String::default(), 232 | modifier: Some(vec!["modkey".to_owned()].into()), 233 | key: "Down".to_owned(), 234 | }, 235 | Keybind { 236 | command: BaseCommand::NextLayout, 237 | value: String::default(), 238 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 239 | key: "Up".to_owned(), 240 | }, 241 | Keybind { 242 | command: BaseCommand::PreviousLayout, 243 | value: String::default(), 244 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 245 | key: "Down".to_owned(), 246 | }, 247 | Keybind { 248 | command: BaseCommand::FocusWorkspaceNext, 249 | value: String::default(), 250 | modifier: Some(vec!["modkey".to_owned()].into()), 251 | key: "Right".to_owned(), 252 | }, 253 | Keybind { 254 | command: BaseCommand::FocusWorkspacePrevious, 255 | value: String::default(), 256 | modifier: Some(vec!["modkey".to_owned()].into()), 257 | key: "Left".to_owned(), 258 | }, 259 | ]; 260 | 261 | // add "goto workspace" 262 | for i in 1..WORKSPACES_NUM { 263 | commands.push(Keybind { 264 | command: BaseCommand::GotoTag, 265 | value: i.to_string(), 266 | modifier: Some(vec!["modkey".to_owned()].into()), 267 | key: i.to_string(), 268 | }); 269 | } 270 | 271 | // and "move to workspace" 272 | for i in 1..WORKSPACES_NUM { 273 | commands.push(Keybind { 274 | command: BaseCommand::MoveToTag, 275 | value: i.to_string(), 276 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 277 | key: i.to_string(), 278 | }); 279 | } 280 | 281 | let tags = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] 282 | .iter() 283 | .map(|s| (*s).to_string()) 284 | .collect(); 285 | 286 | Self { 287 | workspaces: Some(vec![]), 288 | tags: Some(tags), 289 | layouts: vec![], 290 | layout_mode: LayoutMode::Workspace, 291 | // TODO: add sane default for scratchpad config. 292 | // Currently default values are set in sane_dimension fn. 293 | scratchpad: Some(vec![]), 294 | window_rules: Some(vec![]), 295 | disable_current_tag_swap: false, 296 | disable_tile_drag: false, 297 | focus_behaviour: FocusBehaviour::Sloppy, // default behaviour: mouse move auto-focuses window 298 | focus_new_windows: true, // default behaviour: focuses windows on creation 299 | insert_behavior: InsertBehavior::default(), 300 | modkey: "Mod4".to_owned(), //win key 301 | mousekey: Some("Mod4".into()), //win key 302 | keybind: commands, 303 | max_window_width: None, 304 | } 305 | } 306 | } 307 | 308 | fn exit_strategy<'s>() -> &'s str { 309 | if is_program_in_path("loginctl") { 310 | return "loginctl kill-session $XDG_SESSION_ID"; 311 | } 312 | "pkill leftwm" 313 | } 314 | 315 | #[allow(dead_code)] 316 | #[must_use] 317 | pub fn check_workspace_ids(config: &Config) -> bool { 318 | config.workspaces.clone().is_none_or(|wss| { 319 | let ids = get_workspace_ids(&wss); 320 | if ids.iter().any(Option::is_some) { 321 | all_ids_some(&ids) && all_ids_unique(&ids) 322 | } else { 323 | true 324 | } 325 | }) 326 | } 327 | 328 | #[must_use] 329 | pub fn get_workspace_ids(wss: &[Workspace]) -> Vec> { 330 | wss.iter().map(|ws| ws.id).collect() 331 | } 332 | 333 | pub fn all_ids_some(ids: &[Option]) -> bool { 334 | ids.iter().all(Option::is_some) 335 | } 336 | 337 | #[must_use] 338 | pub fn all_ids_unique(ids: &[Option]) -> bool { 339 | let mut sorted = ids.to_vec(); 340 | sorted.sort(); 341 | sorted.dedup(); 342 | ids.len() == sorted.len() 343 | } 344 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 | 20 | [[package]] 21 | name = "anstream" 22 | version = "0.6.19" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" 25 | dependencies = [ 26 | "anstyle", 27 | "anstyle-parse", 28 | "anstyle-query", 29 | "anstyle-wincon", 30 | "colorchoice", 31 | "is_terminal_polyfill", 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle" 37 | version = "1.0.11" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" 40 | 41 | [[package]] 42 | name = "anstyle-parse" 43 | version = "0.2.7" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 46 | dependencies = [ 47 | "utf8parse", 48 | ] 49 | 50 | [[package]] 51 | name = "anstyle-query" 52 | version = "1.1.3" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" 55 | dependencies = [ 56 | "windows-sys 0.59.0", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-wincon" 61 | version = "3.0.9" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" 64 | dependencies = [ 65 | "anstyle", 66 | "once_cell_polyfill", 67 | "windows-sys 0.59.0", 68 | ] 69 | 70 | [[package]] 71 | name = "anyhow" 72 | version = "1.0.98" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 75 | dependencies = [ 76 | "backtrace", 77 | ] 78 | 79 | [[package]] 80 | name = "autocfg" 81 | version = "1.5.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 84 | 85 | [[package]] 86 | name = "backtrace" 87 | version = "0.3.75" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 90 | dependencies = [ 91 | "addr2line", 92 | "cfg-if", 93 | "libc", 94 | "miniz_oxide", 95 | "object", 96 | "rustc-demangle", 97 | "windows-targets 0.52.6", 98 | ] 99 | 100 | [[package]] 101 | name = "base64" 102 | version = "0.22.1" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 105 | 106 | [[package]] 107 | name = "bitflags" 108 | version = "1.3.2" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 111 | 112 | [[package]] 113 | name = "bitflags" 114 | version = "2.9.1" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 117 | dependencies = [ 118 | "serde", 119 | ] 120 | 121 | [[package]] 122 | name = "cassowary" 123 | version = "0.3.0" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 126 | 127 | [[package]] 128 | name = "cfg-if" 129 | version = "1.0.1" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" 132 | 133 | [[package]] 134 | name = "clap" 135 | version = "4.5.41" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" 138 | dependencies = [ 139 | "clap_builder", 140 | ] 141 | 142 | [[package]] 143 | name = "clap_builder" 144 | version = "4.5.41" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" 147 | dependencies = [ 148 | "anstream", 149 | "anstyle", 150 | "clap_lex", 151 | "strsim", 152 | ] 153 | 154 | [[package]] 155 | name = "clap_lex" 156 | version = "0.7.5" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" 159 | 160 | [[package]] 161 | name = "colorchoice" 162 | version = "1.0.4" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 165 | 166 | [[package]] 167 | name = "convert_case" 168 | version = "0.7.1" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" 171 | dependencies = [ 172 | "unicode-segmentation", 173 | ] 174 | 175 | [[package]] 176 | name = "crossterm" 177 | version = "0.25.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" 180 | dependencies = [ 181 | "bitflags 1.3.2", 182 | "crossterm_winapi", 183 | "libc", 184 | "mio 0.8.11", 185 | "parking_lot", 186 | "signal-hook", 187 | "signal-hook-mio", 188 | "winapi", 189 | ] 190 | 191 | [[package]] 192 | name = "crossterm" 193 | version = "0.29.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" 196 | dependencies = [ 197 | "bitflags 2.9.1", 198 | "crossterm_winapi", 199 | "derive_more", 200 | "document-features", 201 | "mio 1.0.4", 202 | "parking_lot", 203 | "rustix", 204 | "signal-hook", 205 | "signal-hook-mio", 206 | "winapi", 207 | ] 208 | 209 | [[package]] 210 | name = "crossterm_winapi" 211 | version = "0.9.1" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 214 | dependencies = [ 215 | "winapi", 216 | ] 217 | 218 | [[package]] 219 | name = "derive_more" 220 | version = "2.0.1" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" 223 | dependencies = [ 224 | "derive_more-impl", 225 | ] 226 | 227 | [[package]] 228 | name = "derive_more-impl" 229 | version = "2.0.1" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" 232 | dependencies = [ 233 | "convert_case", 234 | "proc-macro2", 235 | "quote", 236 | "syn", 237 | ] 238 | 239 | [[package]] 240 | name = "document-features" 241 | version = "0.2.11" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" 244 | dependencies = [ 245 | "litrs", 246 | ] 247 | 248 | [[package]] 249 | name = "equivalent" 250 | version = "1.0.2" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 253 | 254 | [[package]] 255 | name = "errno" 256 | version = "0.3.13" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" 259 | dependencies = [ 260 | "libc", 261 | "windows-sys 0.60.2", 262 | ] 263 | 264 | [[package]] 265 | name = "gimli" 266 | version = "0.31.1" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 269 | 270 | [[package]] 271 | name = "git-version" 272 | version = "0.3.9" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" 275 | dependencies = [ 276 | "git-version-macro", 277 | ] 278 | 279 | [[package]] 280 | name = "git-version-macro" 281 | version = "0.3.9" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" 284 | dependencies = [ 285 | "proc-macro2", 286 | "quote", 287 | "syn", 288 | ] 289 | 290 | [[package]] 291 | name = "glob" 292 | version = "0.3.2" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" 295 | 296 | [[package]] 297 | name = "hashbrown" 298 | version = "0.15.4" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" 301 | 302 | [[package]] 303 | name = "indexmap" 304 | version = "2.10.0" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" 307 | dependencies = [ 308 | "equivalent", 309 | "hashbrown", 310 | ] 311 | 312 | [[package]] 313 | name = "is_terminal_polyfill" 314 | version = "1.70.1" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 317 | 318 | [[package]] 319 | name = "itoa" 320 | version = "1.0.15" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 323 | 324 | [[package]] 325 | name = "leftwm-config" 326 | version = "0.1.0" 327 | dependencies = [ 328 | "anyhow", 329 | "clap", 330 | "crossterm 0.29.0", 331 | "git-version", 332 | "glob", 333 | "log", 334 | "ron", 335 | "serde", 336 | "serde_json", 337 | "thiserror", 338 | "toml", 339 | "tui", 340 | "xdg", 341 | ] 342 | 343 | [[package]] 344 | name = "libc" 345 | version = "0.2.174" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" 348 | 349 | [[package]] 350 | name = "linux-raw-sys" 351 | version = "0.9.4" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 354 | 355 | [[package]] 356 | name = "litrs" 357 | version = "0.4.1" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" 360 | 361 | [[package]] 362 | name = "lock_api" 363 | version = "0.4.13" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 366 | dependencies = [ 367 | "autocfg", 368 | "scopeguard", 369 | ] 370 | 371 | [[package]] 372 | name = "log" 373 | version = "0.4.27" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 376 | 377 | [[package]] 378 | name = "memchr" 379 | version = "2.7.5" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 382 | 383 | [[package]] 384 | name = "miniz_oxide" 385 | version = "0.8.9" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 388 | dependencies = [ 389 | "adler2", 390 | ] 391 | 392 | [[package]] 393 | name = "mio" 394 | version = "0.8.11" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 397 | dependencies = [ 398 | "libc", 399 | "log", 400 | "wasi", 401 | "windows-sys 0.48.0", 402 | ] 403 | 404 | [[package]] 405 | name = "mio" 406 | version = "1.0.4" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" 409 | dependencies = [ 410 | "libc", 411 | "log", 412 | "wasi", 413 | "windows-sys 0.59.0", 414 | ] 415 | 416 | [[package]] 417 | name = "object" 418 | version = "0.36.7" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 421 | dependencies = [ 422 | "memchr", 423 | ] 424 | 425 | [[package]] 426 | name = "once_cell_polyfill" 427 | version = "1.70.1" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 430 | 431 | [[package]] 432 | name = "parking_lot" 433 | version = "0.12.4" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 436 | dependencies = [ 437 | "lock_api", 438 | "parking_lot_core", 439 | ] 440 | 441 | [[package]] 442 | name = "parking_lot_core" 443 | version = "0.9.11" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 446 | dependencies = [ 447 | "cfg-if", 448 | "libc", 449 | "redox_syscall", 450 | "smallvec", 451 | "windows-targets 0.52.6", 452 | ] 453 | 454 | [[package]] 455 | name = "proc-macro2" 456 | version = "1.0.95" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 459 | dependencies = [ 460 | "unicode-ident", 461 | ] 462 | 463 | [[package]] 464 | name = "quote" 465 | version = "1.0.40" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 468 | dependencies = [ 469 | "proc-macro2", 470 | ] 471 | 472 | [[package]] 473 | name = "redox_syscall" 474 | version = "0.5.13" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" 477 | dependencies = [ 478 | "bitflags 2.9.1", 479 | ] 480 | 481 | [[package]] 482 | name = "ron" 483 | version = "0.10.1" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "beceb6f7bf81c73e73aeef6dd1356d9a1b2b4909e1f0fc3e59b034f9572d7b7f" 486 | dependencies = [ 487 | "base64", 488 | "bitflags 2.9.1", 489 | "serde", 490 | "serde_derive", 491 | "unicode-ident", 492 | ] 493 | 494 | [[package]] 495 | name = "rustc-demangle" 496 | version = "0.1.25" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" 499 | 500 | [[package]] 501 | name = "rustix" 502 | version = "1.0.8" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" 505 | dependencies = [ 506 | "bitflags 2.9.1", 507 | "errno", 508 | "libc", 509 | "linux-raw-sys", 510 | "windows-sys 0.60.2", 511 | ] 512 | 513 | [[package]] 514 | name = "ryu" 515 | version = "1.0.20" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 518 | 519 | [[package]] 520 | name = "scopeguard" 521 | version = "1.2.0" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 524 | 525 | [[package]] 526 | name = "serde" 527 | version = "1.0.219" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 530 | dependencies = [ 531 | "serde_derive", 532 | ] 533 | 534 | [[package]] 535 | name = "serde_derive" 536 | version = "1.0.219" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 539 | dependencies = [ 540 | "proc-macro2", 541 | "quote", 542 | "syn", 543 | ] 544 | 545 | [[package]] 546 | name = "serde_json" 547 | version = "1.0.141" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" 550 | dependencies = [ 551 | "itoa", 552 | "memchr", 553 | "ryu", 554 | "serde", 555 | ] 556 | 557 | [[package]] 558 | name = "serde_spanned" 559 | version = "0.6.9" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" 562 | dependencies = [ 563 | "serde", 564 | ] 565 | 566 | [[package]] 567 | name = "signal-hook" 568 | version = "0.3.18" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" 571 | dependencies = [ 572 | "libc", 573 | "signal-hook-registry", 574 | ] 575 | 576 | [[package]] 577 | name = "signal-hook-mio" 578 | version = "0.2.4" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" 581 | dependencies = [ 582 | "libc", 583 | "mio 0.8.11", 584 | "mio 1.0.4", 585 | "signal-hook", 586 | ] 587 | 588 | [[package]] 589 | name = "signal-hook-registry" 590 | version = "1.4.5" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" 593 | dependencies = [ 594 | "libc", 595 | ] 596 | 597 | [[package]] 598 | name = "smallvec" 599 | version = "1.15.1" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 602 | 603 | [[package]] 604 | name = "strsim" 605 | version = "0.11.1" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 608 | 609 | [[package]] 610 | name = "syn" 611 | version = "2.0.104" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" 614 | dependencies = [ 615 | "proc-macro2", 616 | "quote", 617 | "unicode-ident", 618 | ] 619 | 620 | [[package]] 621 | name = "thiserror" 622 | version = "2.0.12" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 625 | dependencies = [ 626 | "thiserror-impl", 627 | ] 628 | 629 | [[package]] 630 | name = "thiserror-impl" 631 | version = "2.0.12" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 634 | dependencies = [ 635 | "proc-macro2", 636 | "quote", 637 | "syn", 638 | ] 639 | 640 | [[package]] 641 | name = "toml" 642 | version = "0.8.23" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" 645 | dependencies = [ 646 | "serde", 647 | "serde_spanned", 648 | "toml_datetime", 649 | "toml_edit", 650 | ] 651 | 652 | [[package]] 653 | name = "toml_datetime" 654 | version = "0.6.11" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" 657 | dependencies = [ 658 | "serde", 659 | ] 660 | 661 | [[package]] 662 | name = "toml_edit" 663 | version = "0.22.27" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" 666 | dependencies = [ 667 | "indexmap", 668 | "serde", 669 | "serde_spanned", 670 | "toml_datetime", 671 | "toml_write", 672 | "winnow", 673 | ] 674 | 675 | [[package]] 676 | name = "toml_write" 677 | version = "0.1.2" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" 680 | 681 | [[package]] 682 | name = "tui" 683 | version = "0.19.0" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" 686 | dependencies = [ 687 | "bitflags 1.3.2", 688 | "cassowary", 689 | "crossterm 0.25.0", 690 | "unicode-segmentation", 691 | "unicode-width", 692 | ] 693 | 694 | [[package]] 695 | name = "unicode-ident" 696 | version = "1.0.18" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 699 | 700 | [[package]] 701 | name = "unicode-segmentation" 702 | version = "1.12.0" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 705 | 706 | [[package]] 707 | name = "unicode-width" 708 | version = "0.1.14" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 711 | 712 | [[package]] 713 | name = "utf8parse" 714 | version = "0.2.2" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 717 | 718 | [[package]] 719 | name = "wasi" 720 | version = "0.11.1+wasi-snapshot-preview1" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 723 | 724 | [[package]] 725 | name = "winapi" 726 | version = "0.3.9" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 729 | dependencies = [ 730 | "winapi-i686-pc-windows-gnu", 731 | "winapi-x86_64-pc-windows-gnu", 732 | ] 733 | 734 | [[package]] 735 | name = "winapi-i686-pc-windows-gnu" 736 | version = "0.4.0" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 739 | 740 | [[package]] 741 | name = "winapi-x86_64-pc-windows-gnu" 742 | version = "0.4.0" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 745 | 746 | [[package]] 747 | name = "windows-sys" 748 | version = "0.48.0" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 751 | dependencies = [ 752 | "windows-targets 0.48.5", 753 | ] 754 | 755 | [[package]] 756 | name = "windows-sys" 757 | version = "0.59.0" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 760 | dependencies = [ 761 | "windows-targets 0.52.6", 762 | ] 763 | 764 | [[package]] 765 | name = "windows-sys" 766 | version = "0.60.2" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 769 | dependencies = [ 770 | "windows-targets 0.53.2", 771 | ] 772 | 773 | [[package]] 774 | name = "windows-targets" 775 | version = "0.48.5" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 778 | dependencies = [ 779 | "windows_aarch64_gnullvm 0.48.5", 780 | "windows_aarch64_msvc 0.48.5", 781 | "windows_i686_gnu 0.48.5", 782 | "windows_i686_msvc 0.48.5", 783 | "windows_x86_64_gnu 0.48.5", 784 | "windows_x86_64_gnullvm 0.48.5", 785 | "windows_x86_64_msvc 0.48.5", 786 | ] 787 | 788 | [[package]] 789 | name = "windows-targets" 790 | version = "0.52.6" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 793 | dependencies = [ 794 | "windows_aarch64_gnullvm 0.52.6", 795 | "windows_aarch64_msvc 0.52.6", 796 | "windows_i686_gnu 0.52.6", 797 | "windows_i686_gnullvm 0.52.6", 798 | "windows_i686_msvc 0.52.6", 799 | "windows_x86_64_gnu 0.52.6", 800 | "windows_x86_64_gnullvm 0.52.6", 801 | "windows_x86_64_msvc 0.52.6", 802 | ] 803 | 804 | [[package]] 805 | name = "windows-targets" 806 | version = "0.53.2" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" 809 | dependencies = [ 810 | "windows_aarch64_gnullvm 0.53.0", 811 | "windows_aarch64_msvc 0.53.0", 812 | "windows_i686_gnu 0.53.0", 813 | "windows_i686_gnullvm 0.53.0", 814 | "windows_i686_msvc 0.53.0", 815 | "windows_x86_64_gnu 0.53.0", 816 | "windows_x86_64_gnullvm 0.53.0", 817 | "windows_x86_64_msvc 0.53.0", 818 | ] 819 | 820 | [[package]] 821 | name = "windows_aarch64_gnullvm" 822 | version = "0.48.5" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 825 | 826 | [[package]] 827 | name = "windows_aarch64_gnullvm" 828 | version = "0.52.6" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 831 | 832 | [[package]] 833 | name = "windows_aarch64_gnullvm" 834 | version = "0.53.0" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 837 | 838 | [[package]] 839 | name = "windows_aarch64_msvc" 840 | version = "0.48.5" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 843 | 844 | [[package]] 845 | name = "windows_aarch64_msvc" 846 | version = "0.52.6" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 849 | 850 | [[package]] 851 | name = "windows_aarch64_msvc" 852 | version = "0.53.0" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 855 | 856 | [[package]] 857 | name = "windows_i686_gnu" 858 | version = "0.48.5" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 861 | 862 | [[package]] 863 | name = "windows_i686_gnu" 864 | version = "0.52.6" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 867 | 868 | [[package]] 869 | name = "windows_i686_gnu" 870 | version = "0.53.0" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 873 | 874 | [[package]] 875 | name = "windows_i686_gnullvm" 876 | version = "0.52.6" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 879 | 880 | [[package]] 881 | name = "windows_i686_gnullvm" 882 | version = "0.53.0" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 885 | 886 | [[package]] 887 | name = "windows_i686_msvc" 888 | version = "0.48.5" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 891 | 892 | [[package]] 893 | name = "windows_i686_msvc" 894 | version = "0.52.6" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 897 | 898 | [[package]] 899 | name = "windows_i686_msvc" 900 | version = "0.53.0" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 903 | 904 | [[package]] 905 | name = "windows_x86_64_gnu" 906 | version = "0.48.5" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 909 | 910 | [[package]] 911 | name = "windows_x86_64_gnu" 912 | version = "0.52.6" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 915 | 916 | [[package]] 917 | name = "windows_x86_64_gnu" 918 | version = "0.53.0" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 921 | 922 | [[package]] 923 | name = "windows_x86_64_gnullvm" 924 | version = "0.48.5" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 927 | 928 | [[package]] 929 | name = "windows_x86_64_gnullvm" 930 | version = "0.52.6" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 933 | 934 | [[package]] 935 | name = "windows_x86_64_gnullvm" 936 | version = "0.53.0" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 939 | 940 | [[package]] 941 | name = "windows_x86_64_msvc" 942 | version = "0.48.5" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 945 | 946 | [[package]] 947 | name = "windows_x86_64_msvc" 948 | version = "0.52.6" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 951 | 952 | [[package]] 953 | name = "windows_x86_64_msvc" 954 | version = "0.53.0" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 957 | 958 | [[package]] 959 | name = "winnow" 960 | version = "0.7.12" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" 963 | dependencies = [ 964 | "memchr", 965 | ] 966 | 967 | [[package]] 968 | name = "xdg" 969 | version = "3.0.0" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" 972 | -------------------------------------------------------------------------------- /src/tui/mod.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Stdout}; 2 | 3 | use anyhow::Result; 4 | use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; 5 | use crossterm::execute; 6 | use crossterm::terminal::{ 7 | disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, 8 | }; 9 | use tui::layout::{Alignment, Constraint, Direction, Layout}; 10 | use tui::style::{Color, Modifier, Style}; 11 | use tui::text::{Span, Spans}; 12 | use tui::widgets::{BorderType, List, ListItem, ListState}; 13 | use tui::{ 14 | backend::CrosstermBackend, 15 | widgets::{Block, Borders, Paragraph, Wrap}, 16 | Terminal, 17 | }; 18 | 19 | use crate::config::filehandler::load; 20 | use crate::config::modifier::Modifier as KeyModifier; 21 | use crate::config::values::{FocusBehaviour, InsertBehavior, LayoutMode}; 22 | use crate::config::Config; 23 | use crate::utils; 24 | use crate::utils::TryUnwrap; 25 | 26 | mod key_handler; 27 | mod popups; 28 | 29 | #[derive(Clone)] 30 | pub enum PopupState { 31 | None, 32 | List(ListState), 33 | MultiList(MultiselectListState), 34 | String(String), 35 | Int { 36 | current: isize, 37 | min: isize, 38 | max: isize, 39 | }, 40 | } 41 | 42 | #[derive(Clone)] 43 | pub struct MultiselectListState { 44 | pub liststate: ListState, 45 | pub selected: Vec, 46 | } 47 | 48 | // We allow the use of `WindowRules` as it refers to a config item contrary 49 | // to the enum name `Window` which refers to a window of the TUI 50 | #[allow(clippy::enum_variant_names)] 51 | pub enum Window { 52 | Home, 53 | Workspaces { index: usize, empty: bool }, 54 | Tags { index: usize, empty: bool }, 55 | WindowRules { index: usize, empty: bool }, 56 | Scratchpads { index: usize, empty: bool }, 57 | KeyBinds { index: usize, empty: bool }, 58 | } 59 | 60 | impl Window { 61 | fn try_increment_index(&mut self) { 62 | match self { 63 | Window::Home => {} 64 | Window::Workspaces { index, .. } 65 | | Window::Tags { index, .. } 66 | | Window::WindowRules { index, .. } 67 | | Window::Scratchpads { index, .. } 68 | | Window::KeyBinds { index, .. } => { 69 | *index += 1; 70 | } 71 | } 72 | } 73 | 74 | fn try_decrement_index(&mut self) { 75 | match self { 76 | Window::Home => {} 77 | Window::Workspaces { index, .. } 78 | | Window::Tags { index, .. } 79 | | Window::WindowRules { index, .. } 80 | | Window::Scratchpads { index, .. } 81 | | Window::KeyBinds { index, .. } => { 82 | *index -= 1; 83 | } 84 | } 85 | } 86 | 87 | fn try_set_index(&mut self, new_index: usize) { 88 | match self { 89 | Window::Home => {} 90 | Window::Workspaces { index, .. } 91 | | Window::Tags { index, .. } 92 | | Window::WindowRules { index, .. } 93 | | Window::Scratchpads { index, .. } 94 | | Window::KeyBinds { index, .. } => { 95 | *index = new_index; 96 | } 97 | } 98 | } 99 | } 100 | 101 | struct App<'a> { 102 | config_list: Vec>, 103 | config_list_state: ListState, 104 | current_popup: Option, 105 | current_window: Window, 106 | current_popup_state: PopupState, 107 | current_config: Config, 108 | alive: Result<()>, 109 | } 110 | 111 | pub fn run() -> Result<()> { 112 | enable_raw_mode()?; 113 | let mut stdout = io::stdout(); 114 | execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; 115 | let backend = CrosstermBackend::new(stdout); 116 | let mut terminal = Terminal::new(backend)?; 117 | 118 | let mut state = ListState::default(); 119 | state.select(Some(0)); 120 | 121 | let app = App { 122 | config_list: vec![], 123 | config_list_state: state, 124 | current_popup: None, 125 | current_window: Window::Home, 126 | current_popup_state: PopupState::None, 127 | current_config: load(), 128 | alive: Ok(()), 129 | }; 130 | 131 | let app_result = app.run(&mut terminal); 132 | 133 | // restore terminal 134 | disable_raw_mode()?; 135 | execute!( 136 | terminal.backend_mut(), 137 | LeaveAlternateScreen, 138 | DisableMouseCapture 139 | )?; 140 | terminal.show_cursor()?; 141 | 142 | app_result 143 | } 144 | 145 | impl App<'_> { 146 | fn run(mut self, terminal: &mut Terminal>) -> Result<()> { 147 | while self.alive.is_ok() { 148 | terminal.draw(|f| { 149 | match self.format_config_list() { 150 | Err(e) => self.alive = Err(e), 151 | Ok(l) => self.config_list = l, 152 | } 153 | let size = f.size(); 154 | 155 | let chunks = Layout::default() 156 | .direction(Direction::Vertical) 157 | .constraints([Constraint::Percentage(95), Constraint::Percentage(5)].as_ref()) 158 | .split(size); 159 | 160 | let frame = Block::default() 161 | .borders(Borders::ALL) 162 | .border_style(Style::default().fg(Color::White)) 163 | .border_type(BorderType::Rounded) 164 | .style(Style::default().bg(Color::Black)) 165 | .title("LeftWM-Config"); 166 | 167 | let list = List::new(self.config_list.clone()) 168 | .block(Block::default().borders(Borders::NONE)) 169 | .style(Style::default().fg(Color::White)) 170 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 171 | .highlight_symbol(">>"); 172 | 173 | let help_text = match self.current_window { 174 | Window::Workspaces { .. } => { 175 | let mut spans = vec![ 176 | Span::raw("Exit: q, "), 177 | Span::raw("Save: s, "), 178 | Span::raw("Delete Optional Value: Delete, "), 179 | Span::raw("Back: Backspace"), 180 | ]; 181 | 182 | if let Some(6) = self.current_popup { 183 | spans.push(Span::raw(", Space: Toggle item")); 184 | } 185 | 186 | vec![Spans::from(spans)] 187 | } 188 | Window::WindowRules { .. } | Window::Scratchpads { .. } => { 189 | vec![Spans::from(vec![ 190 | Span::raw("Exit: q, "), 191 | Span::raw("Save: s, "), 192 | Span::raw("Delete Optional Value: Delete, "), 193 | Span::raw("Back: Backspace"), 194 | ])] 195 | } 196 | Window::Tags { .. } => { 197 | vec![Spans::from(vec![ 198 | Span::raw("Exit: q, "), 199 | Span::raw("Save: s, "), 200 | Span::raw("Back: Backspace"), 201 | ])] 202 | } 203 | Window::KeyBinds { .. } => { 204 | let mut spans = vec![Span::raw("Exit: q, "), Span::raw("Save: s")]; 205 | 206 | if let Some(2) = self.current_popup { 207 | spans.push(Span::raw(", Space: Toggle item")); 208 | } 209 | 210 | vec![Spans::from(spans)] 211 | } 212 | Window::Home => { 213 | let mut spans = vec![Span::raw("Exit: q, "), Span::raw("Save: s")]; 214 | 215 | if let Some(9) = self.current_popup { 216 | spans.push(Span::raw(", Space: Toggle item")); 217 | } 218 | 219 | vec![Spans::from(spans)] 220 | } 221 | }; 222 | 223 | let help = Paragraph::new(help_text) 224 | .style(Style::default().fg(Color::White).bg(Color::Black)) 225 | .alignment(Alignment::Center) 226 | .wrap(Wrap { trim: true }); 227 | 228 | f.render_widget(frame, size); 229 | f.render_stateful_widget( 230 | list, 231 | utils::centered_rect(50, 50, *chunks.first().unwrap_or(&size)), 232 | &mut self.config_list_state, 233 | ); 234 | f.render_widget(help, *chunks.get(1).unwrap_or(&size)); 235 | 236 | if let Err(e) = match self.current_window { 237 | Window::Home => { 238 | if let Some(s) = self.current_popup { 239 | match s { 240 | 0 => popups::modkey( 241 | &self.current_config, 242 | &mut self.current_popup_state, 243 | f, 244 | false, 245 | ), 246 | 1 => popups::modkey( 247 | &self.current_config, 248 | &mut self.current_popup_state, 249 | f, 250 | true, 251 | ), 252 | 2 => popups::max_window_width(&mut self.current_popup_state, f), 253 | // 3, 4 and 5 dont need a popup 254 | 6 => popups::focus_behavior( 255 | &self.current_config, 256 | &mut self.current_popup_state, 257 | f, 258 | ), 259 | 7 => popups::insert_behavior( 260 | &self.current_config, 261 | &mut self.current_popup_state, 262 | f, 263 | ), 264 | 8 => popups::layout_mode( 265 | &self.current_config, 266 | &mut self.current_popup_state, 267 | f, 268 | ), 269 | 9 => popups::layouts(&mut self.current_popup_state, f), 270 | 15 => popups::saved(f), 271 | _ => Ok(()), 272 | } 273 | } else { 274 | Ok(()) 275 | } 276 | } 277 | Window::Workspaces { .. } => { 278 | if let Some(s) = self.current_popup { 279 | match s { 280 | 0 => popups::text_input( 281 | &mut self.current_popup_state, 282 | "X".to_string(), 283 | f, 284 | ), 285 | 1 => popups::text_input( 286 | &mut self.current_popup_state, 287 | "Y".to_string(), 288 | f, 289 | ), 290 | 2 => popups::text_input( 291 | &mut self.current_popup_state, 292 | "Widht".to_string(), 293 | f, 294 | ), 295 | 3 => popups::text_input( 296 | &mut self.current_popup_state, 297 | "Height".to_string(), 298 | f, 299 | ), 300 | 4 => popups::text_input( 301 | &mut self.current_popup_state, 302 | "Id".to_string(), 303 | f, 304 | ), 305 | 5 => popups::text_input( 306 | &mut self.current_popup_state, 307 | "Max window width".to_string(), 308 | f, 309 | ), 310 | 6 => popups::layouts(&mut self.current_popup_state, f), 311 | 15 => popups::saved(f), 312 | _ => Ok(()), 313 | } 314 | } else { 315 | Ok(()) 316 | } 317 | } 318 | Window::Tags { .. } => { 319 | if let Some(15) = self.current_popup { 320 | popups::saved(f) 321 | } else if self.current_popup.is_some() { 322 | popups::text_input(&mut self.current_popup_state, "Name".to_string(), f) 323 | } else { 324 | Ok(()) 325 | } 326 | } 327 | Window::WindowRules { .. } => match self.current_popup { 328 | Some(0) => popups::text_input( 329 | &mut self.current_popup_state, 330 | "Title".to_string(), 331 | f, 332 | ), 333 | Some(1) => popups::text_input( 334 | &mut self.current_popup_state, 335 | "Class".to_string(), 336 | f, 337 | ), 338 | Some(2) => popups::counter( 339 | &mut self.current_popup_state, 340 | "Spawn on tag".to_string(), 341 | f, 342 | ), 343 | Some(15) => popups::saved(f), 344 | _ => Ok(()), 345 | }, 346 | Window::Scratchpads { .. } => match self.current_popup { 347 | Some(0) => { 348 | popups::text_input(&mut self.current_popup_state, "Name".to_string(), f) 349 | } 350 | Some(1) => popups::text_input( 351 | &mut self.current_popup_state, 352 | "Value".to_string(), 353 | f, 354 | ), 355 | Some(2) => { 356 | popups::text_input(&mut self.current_popup_state, "X".to_string(), f) 357 | } 358 | Some(3) => { 359 | popups::text_input(&mut self.current_popup_state, "Y".to_string(), f) 360 | } 361 | Some(4) => popups::text_input( 362 | &mut self.current_popup_state, 363 | "Width".to_string(), 364 | f, 365 | ), 366 | Some(5) => popups::text_input( 367 | &mut self.current_popup_state, 368 | "Height".to_string(), 369 | f, 370 | ), 371 | Some(15) => popups::saved(f), 372 | _ => Ok(()), 373 | }, 374 | Window::KeyBinds { index, .. } => match self.current_popup { 375 | Some(0) => popups::keybind_command( 376 | &self.current_config, 377 | index, 378 | &mut self.current_popup_state, 379 | f, 380 | ), 381 | Some(1) => popups::text_input( 382 | &mut self.current_popup_state, 383 | "Value".to_string(), 384 | f, 385 | ), 386 | Some(2) => popups::keybind_modkey(&mut self.current_popup_state, f), 387 | Some(3) => { 388 | popups::keybind_key(&mut self.current_popup_state, "Key".to_string(), f) 389 | } 390 | Some(15) => popups::saved(f), 391 | _ => Ok(()), 392 | }, 393 | } { 394 | self.alive = Err(e); 395 | } 396 | })?; 397 | 398 | if key_handler::handle_keys(&mut self)? { 399 | return Ok(()); 400 | } 401 | } 402 | 403 | match self.alive { 404 | Ok(()) => Ok(()), 405 | Err(e) => Err(e), 406 | } 407 | } 408 | 409 | fn format_config_list<'a>(&mut self) -> Result>> { 410 | Ok(match self.current_window { 411 | Window::Home => Vec::from([ 412 | ListItem::new(format!( 413 | "Modkey - {}", 414 | format_modkey_name(self.current_config.modkey.clone()) 415 | )), 416 | ListItem::new(format!( 417 | "Mousekey - {}", 418 | format_modkey_name( 419 | self.current_config 420 | .mousekey 421 | .clone() 422 | .unwrap_or_else(|| KeyModifier::Single("None".to_string())) 423 | .to_string() 424 | ) 425 | )), 426 | ListItem::new(match &self.current_config.max_window_width { 427 | Some(w) => format!("Max Window Width - {w:?}"), 428 | None => "Max Window Width - not set".to_string(), 429 | }), 430 | ListItem::new(format!( 431 | "Disable Current Tag Swap - {}", 432 | self.current_config.disable_current_tag_swap 433 | )), 434 | ListItem::new(format!( 435 | "Disable Tile Drag - {}", 436 | self.current_config.disable_tile_drag 437 | )), 438 | ListItem::new(format!( 439 | "Focus New Windows - {}", 440 | self.current_config.focus_new_windows 441 | )), 442 | ListItem::new(format!( 443 | "Focus Behavior - {}", 444 | match self.current_config.focus_behaviour { 445 | FocusBehaviour::Sloppy => "Sloppy".to_string(), 446 | FocusBehaviour::ClickTo => "Click To".to_string(), 447 | FocusBehaviour::Driven => "Driven".to_string(), 448 | } 449 | )), 450 | ListItem::new(format!( 451 | "Insert Behavior - {}", 452 | match self.current_config.insert_behavior { 453 | InsertBehavior::AfterCurrent => "Afer Current".to_string(), 454 | InsertBehavior::BeforeCurrent => "Before Current".to_string(), 455 | InsertBehavior::Bottom => "Bottom".to_string(), 456 | InsertBehavior::Top => "Top".to_string(), 457 | } 458 | )), 459 | ListItem::new(format!( 460 | "Layout Mode - {}", 461 | match self.current_config.layout_mode { 462 | LayoutMode::Tag => "Tag".to_string(), 463 | LayoutMode::Workspace => "Workspace".to_string(), 464 | } 465 | )), 466 | ListItem::new(format!( 467 | "Layouts - {} set", 468 | self.current_config.layouts.len() 469 | )), 470 | ListItem::new(match &self.current_config.workspaces { 471 | Some(v) => format!("Workspaces - {} set", v.len()), 472 | None => "Workspaces".to_string(), 473 | }), 474 | ListItem::new(match &self.current_config.tags { 475 | Some(v) => format!("Tags - {} set", v.len()), 476 | None => "Tags".to_string(), 477 | }), 478 | ListItem::new(match &self.current_config.window_rules { 479 | Some(v) => format!("Window Rules - {} set", v.len()), 480 | None => "Window Rules".to_string(), 481 | }), 482 | ListItem::new(match &self.current_config.scratchpad { 483 | Some(v) => format!("Scratchpads - {} set", v.len()), 484 | None => "Scratchpads".to_string(), 485 | }), 486 | ListItem::new(format!( 487 | "Keybinds - {} set", 488 | self.current_config.keybind.len() 489 | )), 490 | ]), 491 | Window::Workspaces { index, .. } => { 492 | let current_workspace = if let Some(w) = &self.current_config.workspaces { 493 | if self 494 | .current_config 495 | .workspaces 496 | .as_ref() 497 | .try_unwrap()? 498 | .is_empty() 499 | { 500 | None 501 | } else { 502 | w.get(index) 503 | } 504 | } else { 505 | None 506 | }; 507 | 508 | if let Some(c) = current_workspace { 509 | vec![ 510 | ListItem::new(format!( 511 | "{} out of {}", 512 | index + 1, 513 | self.current_config.workspaces.as_ref().try_unwrap()?.len() 514 | )), 515 | ListItem::new("--------------------------"), 516 | ListItem::new(format!("X - {}", c.x)), 517 | ListItem::new(format!("Y - {}", c.y)), 518 | ListItem::new(format!("Width - {}", c.width)), 519 | ListItem::new(format!("Height - {}", c.height)), 520 | ListItem::new(format!("Id - {:?}", c.id)), 521 | ListItem::new(format!("Max Window Width - {:?}", c.max_window_width)), 522 | ListItem::new(format!( 523 | "Layouts - {}", 524 | if c.layouts.is_some() { 525 | "Some(Open to see more)" 526 | } else { 527 | "None" 528 | } 529 | )), 530 | ListItem::new("--------------------------"), 531 | ListItem::new("Add new workspace"), 532 | ListItem::new("Delete this workspace"), 533 | ] 534 | } else { 535 | vec![ 536 | ListItem::new(format!( 537 | "None out of {}", 538 | self.current_config.workspaces.as_ref().try_unwrap()?.len() 539 | )), 540 | ListItem::new("--------------------------"), 541 | ListItem::new("Add new workspace"), 542 | ] 543 | } 544 | } 545 | Window::Tags { index, .. } => { 546 | let current_workspace = if let Some(w) = &self.current_config.tags { 547 | if self.current_config.tags.as_ref().try_unwrap()?.is_empty() { 548 | None 549 | } else { 550 | w.get(index) 551 | } 552 | } else { 553 | None 554 | }; 555 | 556 | if let Some(c) = current_workspace { 557 | vec![ 558 | ListItem::new(format!( 559 | "{} out of {}", 560 | index + 1, 561 | self.current_config.tags.as_ref().try_unwrap()?.len() 562 | )), 563 | ListItem::new("--------------------------"), 564 | ListItem::new(format!("Name - {c}")), 565 | ListItem::new("--------------------------"), 566 | ListItem::new("Add new tag"), 567 | ListItem::new("Delete this tag"), 568 | ] 569 | } else { 570 | vec![ 571 | ListItem::new(format!( 572 | "None out of {}", 573 | self.current_config.tags.as_ref().try_unwrap()?.len() 574 | )), 575 | ListItem::new("--------------------------"), 576 | ListItem::new("Add new tag"), 577 | ] 578 | } 579 | } 580 | Window::WindowRules { index, empty } => { 581 | if empty { 582 | vec![ 583 | ListItem::new("None out of 0"), 584 | ListItem::new("--------------------------"), 585 | ListItem::new("Add new rule"), 586 | ] 587 | } else { 588 | let rule = self 589 | .current_config 590 | .window_rules 591 | .as_ref() 592 | .try_unwrap()? 593 | .get(index) 594 | .try_unwrap()?; 595 | 596 | let mut vec = vec![ 597 | ListItem::new(format!( 598 | "{} out of {}", 599 | index + 1, 600 | self.current_config 601 | .window_rules 602 | .as_ref() 603 | .try_unwrap()? 604 | .len() 605 | )), 606 | ListItem::new("--------------------------"), 607 | ListItem::new(format!("Title - {:?}", rule.window_title)), 608 | ListItem::new(format!("Class - {:?}", rule.window_class)), 609 | ListItem::new(format!("Spawn on tag - {:?}", rule.spawn_on_tag)), 610 | ListItem::new(format!( 611 | "Spawn floating - {}", 612 | rule.spawn_floating.unwrap_or(false) 613 | )), 614 | ListItem::new("--------------------------"), 615 | ]; 616 | 617 | if rule.window_class.is_none() && rule.window_title.is_none() { 618 | vec.push(ListItem::new("WARNING:").style(Style::default().fg(Color::Red))); 619 | vec.push( 620 | ListItem::new("Neither title nor class are set") 621 | .style(Style::default().fg(Color::Red)), 622 | ); 623 | vec.push( 624 | ListItem::new("This rule will be ignored") 625 | .style(Style::default().fg(Color::Red)), 626 | ); 627 | vec.push(ListItem::new("--------------------------")); 628 | } else if rule.window_class.is_some() && rule.window_title.is_some() { 629 | vec.push(ListItem::new("WARNING:").style(Style::default().fg(Color::Red))); 630 | vec.push( 631 | ListItem::new("Both the title and class are set") 632 | .style(Style::default().fg(Color::Red)), 633 | ); 634 | vec.push( 635 | ListItem::new("Class will be ignored") 636 | .style(Style::default().fg(Color::Red)), 637 | ); 638 | vec.push(ListItem::new("--------------------------")); 639 | } 640 | 641 | vec.push(ListItem::new("Add new rule")); 642 | vec.push(ListItem::new("Delete this rule")); 643 | 644 | vec 645 | } 646 | } 647 | Window::Scratchpads { index, empty } => { 648 | if empty { 649 | vec![ 650 | ListItem::new("None out of 0"), 651 | ListItem::new("--------------------------"), 652 | ListItem::new("Add new scratchpad"), 653 | ] 654 | } else { 655 | let scratchpad = self 656 | .current_config 657 | .scratchpad 658 | .as_ref() 659 | .try_unwrap()? 660 | .get(index) 661 | .try_unwrap()?; 662 | 663 | vec![ 664 | ListItem::new(format!( 665 | "{} out of {}", 666 | index + 1, 667 | self.current_config.scratchpad.as_ref().try_unwrap()?.len() 668 | )), 669 | ListItem::new("--------------------------"), 670 | ListItem::new(format!("Name - {}", scratchpad.name)), 671 | ListItem::new(format!("Value - {}", scratchpad.value)), 672 | ListItem::new(format!("X - {:?}", scratchpad.x)), 673 | ListItem::new(format!("Y - {:?}", scratchpad.y)), 674 | ListItem::new(format!("Width - {:?}", scratchpad.width)), 675 | ListItem::new(format!("Height - {:?}", scratchpad.height)), 676 | ListItem::new("--------------------------"), 677 | ListItem::new("Add new scratchpad"), 678 | ListItem::new("Delete this scratchpad"), 679 | ] 680 | } 681 | } 682 | Window::KeyBinds { index, empty } => { 683 | if empty { 684 | vec![ 685 | ListItem::new("None out of 0"), 686 | ListItem::new("--------------------------"), 687 | ListItem::new("Add new keybind"), 688 | ] 689 | } else { 690 | let keybind = self.current_config.keybind.get(index).try_unwrap()?; 691 | let mut vec = vec![ 692 | ListItem::new(format!( 693 | "{} out of {}", 694 | index + 1, 695 | self.current_config.keybind.len() 696 | )), 697 | ListItem::new("--------------------------"), 698 | ListItem::new(format!("Command - {:?}", keybind.command)), 699 | ]; 700 | 701 | if keybind.command.needs_value() { 702 | vec.push(ListItem::new(format!("Value - {}", keybind.value))); 703 | } 704 | 705 | vec.push(ListItem::new(format!( 706 | "Modifier - {}", 707 | if let Some(m) = &keybind.modifier { 708 | format!("{m}") 709 | } else { 710 | "None".to_string() 711 | } 712 | ))); 713 | 714 | vec.push(ListItem::new(format!("Key - {}", keybind.key))); 715 | 716 | vec.push(ListItem::new("--------------------------")); 717 | vec.push(ListItem::new("Add new keybind")); 718 | vec.push(ListItem::new("Delete this keybind")); 719 | 720 | vec 721 | } 722 | } 723 | }) 724 | } 725 | } 726 | 727 | fn next(state: &mut ListState, len: usize) { 728 | let i = match state.selected() { 729 | Some(i) => { 730 | if i >= len - 1 { 731 | 0 732 | } else { 733 | i + 1 734 | } 735 | } 736 | None => 0, 737 | }; 738 | state.select(Some(i)); 739 | } 740 | 741 | fn previous(state: &mut ListState, len: usize) { 742 | let i = match state.selected() { 743 | Some(i) => { 744 | if i == 0 { 745 | len - 1 746 | } else { 747 | i - 1 748 | } 749 | } 750 | None => 0, 751 | }; 752 | state.select(Some(i)); 753 | } 754 | 755 | fn format_modkey_name(modkey: String) -> String { 756 | match modkey.as_str() { 757 | "Mod1" | "Alt" => "Alt".to_string(), 758 | "Mod4" | "Super" => "Super".to_string(), 759 | _ => modkey, 760 | } 761 | } 762 | -------------------------------------------------------------------------------- /src/tui/popups.rs: -------------------------------------------------------------------------------- 1 | use std::io::Stdout; 2 | use std::mem; 3 | 4 | use anyhow::{bail, Result}; 5 | use tui::backend::CrosstermBackend; 6 | use tui::layout::{Alignment, Constraint, Direction, Layout}; 7 | use tui::style::{Color, Modifier, Style}; 8 | use tui::text::{Span, Spans}; 9 | use tui::widgets::{Block, BorderType, Borders, Clear, List, ListItem, Paragraph, Wrap}; 10 | use tui::Frame; 11 | 12 | use crate::config::command::BaseCommand; 13 | use crate::config::modifier::Modifier as KeyModifier; 14 | use crate::config::modifier::Modifier::Single; 15 | use crate::config::values::{FocusBehaviour, InsertBehavior, LayoutMode}; 16 | use crate::config::Config; 17 | use crate::tui::PopupState; 18 | use crate::utils::xkeysym_lookup::into_keysym; 19 | use crate::utils::{centered_rect, TryUnwrap}; 20 | 21 | pub fn modkey( 22 | current_config: &Config, 23 | current_popup_state: &mut PopupState, 24 | f: &mut Frame>, 25 | is_mousekey: bool, 26 | ) -> Result<()> { 27 | let block = Block::default() 28 | .borders(Borders::ALL) 29 | .border_style(Style::default().fg(Color::White)) 30 | .border_type(BorderType::Rounded) 31 | .style(Style::default().bg(Color::Black)) 32 | .title(if is_mousekey { "Mousekey" } else { "Modkey" }); 33 | let area = centered_rect(60, 20, f.size()); 34 | f.render_widget(Clear, area); //this clears out the background 35 | f.render_widget(block, area); 36 | let modkey_list = if is_mousekey { 37 | [ 38 | if current_config.mousekey.is_none() { 39 | ListItem::new("None").style(Style::default().fg(Color::Green)) 40 | } else { 41 | ListItem::new("None") 42 | }, 43 | if check_modifier(current_config.mousekey.as_ref(), "Shift") { 44 | ListItem::new("Shift").style(Style::default().fg(Color::Green)) 45 | } else { 46 | ListItem::new("Shift") 47 | }, 48 | if check_modifier(current_config.mousekey.as_ref(), "Control") { 49 | ListItem::new("Control").style(Style::default().fg(Color::Green)) 50 | } else { 51 | ListItem::new("Control") 52 | }, 53 | if check_modifier(current_config.mousekey.as_ref(), "Mod1") 54 | || check_modifier(current_config.mousekey.as_ref(), "Alt") 55 | { 56 | ListItem::new("Alt").style(Style::default().fg(Color::Green)) 57 | } else { 58 | ListItem::new("Alt") 59 | }, 60 | if check_modifier(current_config.mousekey.as_ref(), "Mod3") { 61 | ListItem::new("Mod3").style(Style::default().fg(Color::Green)) 62 | } else { 63 | ListItem::new("Mod3") 64 | }, 65 | if check_modifier(current_config.mousekey.as_ref(), "Mod4") 66 | || check_modifier(current_config.mousekey.as_ref(), "Super") 67 | { 68 | ListItem::new("Super").style(Style::default().fg(Color::Green)) 69 | } else { 70 | ListItem::new("Super") 71 | }, 72 | if check_modifier(current_config.mousekey.as_ref(), "Mod5") { 73 | ListItem::new("Mod5").style(Style::default().fg(Color::Green)) 74 | } else { 75 | ListItem::new("Mod5") 76 | }, 77 | ] 78 | } else { 79 | [ 80 | if current_config.modkey == "None" { 81 | ListItem::new("None").style(Style::default().fg(Color::Green)) 82 | } else { 83 | ListItem::new("None") 84 | }, 85 | if current_config.modkey == "Shift" { 86 | ListItem::new("Shift").style(Style::default().fg(Color::Green)) 87 | } else { 88 | ListItem::new("Shift") 89 | }, 90 | if current_config.modkey == "Control" { 91 | ListItem::new("Control").style(Style::default().fg(Color::Green)) 92 | } else { 93 | ListItem::new("Control") 94 | }, 95 | if current_config.modkey == "Alt" || current_config.modkey == "Mod1" { 96 | ListItem::new("Alt").style(Style::default().fg(Color::Green)) 97 | } else { 98 | ListItem::new("Alt") 99 | }, 100 | if current_config.modkey == "Mod3" { 101 | ListItem::new("Mod3").style(Style::default().fg(Color::Green)) 102 | } else { 103 | ListItem::new("Mod3") 104 | }, 105 | if current_config.modkey == "Super" || current_config.modkey == "Mod4" { 106 | ListItem::new("Super").style(Style::default().fg(Color::Green)) 107 | } else { 108 | ListItem::new("Super") 109 | }, 110 | if current_config.modkey == "Mod5" { 111 | ListItem::new("Mod5").style(Style::default().fg(Color::Green)) 112 | } else { 113 | ListItem::new("Mod5") 114 | }, 115 | ] 116 | }; 117 | let list = List::new(modkey_list) 118 | .block(Block::default().borders(Borders::NONE)) 119 | .style(Style::default().fg(Color::White)) 120 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 121 | .highlight_symbol(">>"); 122 | 123 | if let PopupState::List(e) = current_popup_state { 124 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 125 | } else { 126 | bail!("Invalid popup state"); 127 | } 128 | 129 | Ok(()) 130 | } 131 | 132 | fn check_modifier(modifier: Option<&KeyModifier>, name: &str) -> bool { 133 | if let Some(Single(s)) = modifier { 134 | name == s 135 | } else { 136 | false 137 | } 138 | } 139 | 140 | pub fn max_window_width( 141 | current_popup_state: &mut PopupState, 142 | f: &mut Frame>, 143 | ) -> Result<()> { 144 | let block = Block::default() 145 | .borders(Borders::ALL) 146 | .border_style(Style::default().fg(Color::White)) 147 | .border_type(BorderType::Rounded) 148 | .style(Style::default().bg(Color::Black)) 149 | .title("Max Window Width"); 150 | 151 | let area = centered_rect(60, 4, f.size()); 152 | 153 | let chunks = Layout::default() 154 | .direction(Direction::Vertical) 155 | .constraints( 156 | [ 157 | Constraint::Ratio(1, 3), 158 | Constraint::Ratio(1, 3), 159 | Constraint::Ratio(1, 3), 160 | ] 161 | .as_ref(), 162 | ) 163 | .split(area); 164 | 165 | let string = if let PopupState::String(s) = current_popup_state { 166 | s.clone() 167 | } else { 168 | bail!("Invalid popup state"); 169 | }; 170 | 171 | let text = vec![Spans::from(vec![Span::raw(string)])]; 172 | 173 | let text = Paragraph::new(text) 174 | .style(Style::default().fg(Color::White).bg(Color::Black)) 175 | .alignment(Alignment::Center) 176 | .wrap(Wrap { trim: true }); 177 | 178 | f.render_widget(Clear, area); //this clears out the background 179 | f.render_widget(block, area); 180 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 181 | 182 | Ok(()) 183 | } 184 | 185 | pub fn focus_behavior( 186 | current_config: &Config, 187 | current_popup_state: &mut PopupState, 188 | f: &mut Frame>, 189 | ) -> Result<()> { 190 | let block = Block::default() 191 | .borders(Borders::ALL) 192 | .border_style(Style::default().fg(Color::White)) 193 | .border_type(BorderType::Rounded) 194 | .style(Style::default().bg(Color::Black)) 195 | .title("Focus Behavior"); 196 | let area = centered_rect(60, 20, f.size()); 197 | f.render_widget(Clear, area); //this clears out the background 198 | f.render_widget(block, area); 199 | let mode_list = [ 200 | { 201 | if current_config.focus_behaviour == FocusBehaviour::Sloppy { 202 | ListItem::new("Sloppy").style(Style::default().fg(Color::Green)) 203 | } else { 204 | ListItem::new("Sloppy") 205 | } 206 | }, 207 | { 208 | if current_config.focus_behaviour == FocusBehaviour::ClickTo { 209 | ListItem::new("Click To").style(Style::default().fg(Color::Green)) 210 | } else { 211 | ListItem::new("Click To") 212 | } 213 | }, 214 | { 215 | if current_config.focus_behaviour == FocusBehaviour::Driven { 216 | ListItem::new("Driven").style(Style::default().fg(Color::Green)) 217 | } else { 218 | ListItem::new("Driven") 219 | } 220 | }, 221 | ]; 222 | let list = List::new(mode_list) 223 | .block(Block::default().borders(Borders::NONE)) 224 | .style(Style::default().fg(Color::White)) 225 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 226 | .highlight_symbol(">>"); 227 | 228 | if let PopupState::List(e) = current_popup_state { 229 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 230 | } else { 231 | bail!("Invalid popup state"); 232 | } 233 | 234 | Ok(()) 235 | } 236 | 237 | pub fn insert_behavior( 238 | current_config: &Config, 239 | current_popup_state: &mut PopupState, 240 | f: &mut Frame>, 241 | ) -> Result<()> { 242 | let block = Block::default() 243 | .borders(Borders::ALL) 244 | .border_style(Style::default().fg(Color::White)) 245 | .border_type(BorderType::Rounded) 246 | .style(Style::default().bg(Color::Black)) 247 | .title("Insert Behavior"); 248 | let area = centered_rect(60, 20, f.size()); 249 | let mode_list = [ 250 | { 251 | if current_config.insert_behavior == InsertBehavior::Top { 252 | ListItem::new("Top").style(Style::default().fg(Color::Green)) 253 | } else { 254 | ListItem::new("Top") 255 | } 256 | }, 257 | { 258 | if current_config.insert_behavior == InsertBehavior::Bottom { 259 | ListItem::new("Bottom").style(Style::default().fg(Color::Green)) 260 | } else { 261 | ListItem::new("Bottom") 262 | } 263 | }, 264 | { 265 | if current_config.insert_behavior == InsertBehavior::BeforeCurrent { 266 | ListItem::new("Before Current").style(Style::default().fg(Color::Green)) 267 | } else { 268 | ListItem::new("Before Current") 269 | } 270 | }, 271 | { 272 | if current_config.insert_behavior == InsertBehavior::AfterCurrent { 273 | ListItem::new("After Current").style(Style::default().fg(Color::Green)) 274 | } else { 275 | ListItem::new("After Current") 276 | } 277 | }, 278 | ]; 279 | let list = List::new(mode_list) 280 | .block(Block::default().borders(Borders::NONE)) 281 | .style(Style::default().fg(Color::White)) 282 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 283 | .highlight_symbol(">>"); 284 | 285 | f.render_widget(Clear, area); //this clears out the background 286 | f.render_widget(block, area); 287 | 288 | if let PopupState::List(e) = current_popup_state { 289 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 290 | } else { 291 | bail!("Invalid popup state"); 292 | } 293 | 294 | Ok(()) 295 | } 296 | 297 | pub fn layout_mode( 298 | current_config: &Config, 299 | current_popup_state: &mut PopupState, 300 | f: &mut Frame>, 301 | ) -> Result<()> { 302 | let block = Block::default() 303 | .borders(Borders::ALL) 304 | .border_style(Style::default().fg(Color::White)) 305 | .border_type(BorderType::Rounded) 306 | .style(Style::default().bg(Color::Black)) 307 | .title("Layout Mode"); 308 | let area = centered_rect(60, 20, f.size()); 309 | let mode_list = [ 310 | { 311 | if current_config.layout_mode == LayoutMode::Tag { 312 | ListItem::new("Tag").style(Style::default().fg(Color::Green)) 313 | } else { 314 | ListItem::new("Tag") 315 | } 316 | }, 317 | { 318 | if current_config.layout_mode == LayoutMode::Workspace { 319 | ListItem::new("Workspace").style(Style::default().fg(Color::Green)) 320 | } else { 321 | ListItem::new("Workspace") 322 | } 323 | }, 324 | ]; 325 | let list = List::new(mode_list) 326 | .block(Block::default().borders(Borders::NONE)) 327 | .style(Style::default().fg(Color::White)) 328 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 329 | .highlight_symbol(">>"); 330 | 331 | f.render_widget(Clear, area); //this clears out the background 332 | f.render_widget(block, area); 333 | 334 | if let PopupState::List(e) = current_popup_state { 335 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 336 | } else { 337 | bail!("Invalid popup state"); 338 | } 339 | 340 | Ok(()) 341 | } 342 | 343 | pub fn layouts( 344 | current_popup_state: &mut PopupState, 345 | f: &mut Frame>, 346 | ) -> Result<()> { 347 | let block = Block::default() 348 | .borders(Borders::ALL) 349 | .border_style(Style::default().fg(Color::White)) 350 | .border_type(BorderType::Rounded) 351 | .style(Style::default().bg(Color::Black)) 352 | .title("Layouts"); 353 | let area = centered_rect(60, 20, f.size()); 354 | 355 | let mut layout_list = vec![ 356 | ListItem::new("MainAndVertStack"), 357 | ListItem::new("MainAndHorizontalStack"), 358 | ListItem::new("MainAndDeck"), 359 | ListItem::new("GridHorizontal"), 360 | ListItem::new("EvenHorizontal"), 361 | ListItem::new("EvenVertical"), 362 | ListItem::new("Fibonacci"), 363 | ListItem::new("LeftMain"), 364 | ListItem::new("CenterMain"), 365 | ListItem::new("CenterMainBalanced"), 366 | ListItem::new("CenterMainFluid"), 367 | ListItem::new("Monocle"), 368 | ListItem::new("RightWiderLeftStack"), 369 | ListItem::new("LeftWiderRightStack"), 370 | ]; 371 | 372 | if let PopupState::MultiList(e) = current_popup_state { 373 | for i in &e.selected { 374 | // we allow this here because clippy thinks 375 | // we are initializing a new thing here (probably because of the _ => {..}) 376 | // while we are just using the let _ to get rid of the result of mem::replace() 377 | #[allow(let_underscore_drop)] 378 | let _ = match i { 379 | 0 => mem::replace::>( 380 | layout_list.get_mut(0).try_unwrap()?, 381 | ListItem::new("MainAndVertStack").style(Style::default().fg(Color::Green)), 382 | ), 383 | 1 => mem::replace::>( 384 | layout_list.get_mut(1).try_unwrap()?, 385 | ListItem::new("MainAndHorizontalStack") 386 | .style(Style::default().fg(Color::Green)), 387 | ), 388 | 2 => mem::replace::>( 389 | layout_list.get_mut(2).try_unwrap()?, 390 | ListItem::new("MainAndDeck").style(Style::default().fg(Color::Green)), 391 | ), 392 | 3 => mem::replace::>( 393 | layout_list.get_mut(3).try_unwrap()?, 394 | ListItem::new("GridHorizontal").style(Style::default().fg(Color::Green)), 395 | ), 396 | 4 => mem::replace::>( 397 | layout_list.get_mut(4).try_unwrap()?, 398 | ListItem::new("EvenHorizontal").style(Style::default().fg(Color::Green)), 399 | ), 400 | 5 => mem::replace::>( 401 | layout_list.get_mut(5).try_unwrap()?, 402 | ListItem::new("EvenVertical").style(Style::default().fg(Color::Green)), 403 | ), 404 | 6 => mem::replace::>( 405 | layout_list.get_mut(6).try_unwrap()?, 406 | ListItem::new("Fibonacci").style(Style::default().fg(Color::Green)), 407 | ), 408 | 7 => mem::replace::>( 409 | layout_list.get_mut(7).try_unwrap()?, 410 | ListItem::new("LeftMain").style(Style::default().fg(Color::Green)), 411 | ), 412 | 8 => mem::replace::>( 413 | layout_list.get_mut(8).try_unwrap()?, 414 | ListItem::new("CenterMain").style(Style::default().fg(Color::Green)), 415 | ), 416 | 9 => mem::replace::>( 417 | layout_list.get_mut(9).try_unwrap()?, 418 | ListItem::new("CenterMainBalanced").style(Style::default().fg(Color::Green)), 419 | ), 420 | 10 => mem::replace::>( 421 | layout_list.get_mut(10).try_unwrap()?, 422 | ListItem::new("CenterMainFluid").style(Style::default().fg(Color::Green)), 423 | ), 424 | 11 => mem::replace::>( 425 | layout_list.get_mut(11).try_unwrap()?, 426 | ListItem::new("Monocle").style(Style::default().fg(Color::Green)), 427 | ), 428 | 12 => mem::replace::>( 429 | layout_list.get_mut(12).try_unwrap()?, 430 | ListItem::new("RightWiderLeftStack").style(Style::default().fg(Color::Green)), 431 | ), 432 | 13 => mem::replace::>( 433 | layout_list.get_mut(13).try_unwrap()?, 434 | ListItem::new("LeftWiderRightStack").style(Style::default().fg(Color::Green)), 435 | ), 436 | _ => ListItem::new(""), 437 | }; 438 | } 439 | } else { 440 | bail!("Invalid popup state"); 441 | } 442 | let list = List::new(layout_list) 443 | .block(Block::default().borders(Borders::NONE)) 444 | .style(Style::default().fg(Color::White)) 445 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 446 | .highlight_symbol(">>"); 447 | 448 | f.render_widget(Clear, area); //this clears out the background 449 | f.render_widget(block, area); 450 | 451 | if let PopupState::MultiList(e) = current_popup_state { 452 | f.render_stateful_widget(list, centered_rect(75, 70, area), &mut e.liststate); 453 | } else { 454 | bail!("Invalid popup state"); 455 | } 456 | 457 | Ok(()) 458 | } 459 | 460 | //we allow this case if it saves having an explicit `Ok(())` after every call to this function 461 | #[allow(clippy::unnecessary_wraps)] 462 | pub fn saved(f: &mut Frame>) -> Result<()> { 463 | let block = Block::default() 464 | .borders(Borders::ALL) 465 | .border_style(Style::default().fg(Color::White)) 466 | .border_type(BorderType::Rounded) 467 | .style(Style::default().bg(Color::Black)); 468 | let mut area = centered_rect(60, 4, f.size()); 469 | area.height = 3; 470 | 471 | let text = vec![Spans::from(Span::raw("Saved"))]; 472 | 473 | let message = Paragraph::new(text) 474 | .style(Style::default().fg(Color::White).bg(Color::Black)) 475 | .alignment(Alignment::Center) 476 | .wrap(Wrap { trim: true }); 477 | 478 | f.render_widget(Clear, area); //this clears out the background 479 | f.render_widget(block, area); 480 | area.y += 1; 481 | f.render_widget(message, area); 482 | 483 | Ok(()) 484 | } 485 | 486 | pub fn text_input( 487 | current_popup_state: &mut PopupState, 488 | name: String, 489 | f: &mut Frame>, 490 | ) -> Result<()> { 491 | let block = Block::default() 492 | .borders(Borders::ALL) 493 | .border_style(Style::default().fg(Color::White)) 494 | .border_type(BorderType::Rounded) 495 | .style(Style::default().bg(Color::Black)) 496 | .title(name); 497 | 498 | let area = centered_rect(60, 4, f.size()); 499 | 500 | let chunks = Layout::default() 501 | .direction(Direction::Vertical) 502 | .constraints( 503 | [ 504 | Constraint::Ratio(1, 3), 505 | Constraint::Ratio(1, 3), 506 | Constraint::Ratio(1, 3), 507 | ] 508 | .as_ref(), 509 | ) 510 | .split(area); 511 | 512 | let string = if let PopupState::String(s) = current_popup_state { 513 | s.clone() 514 | } else { 515 | bail!("Invalid popup state") 516 | }; 517 | 518 | let text_len = u16::try_from(if string.len() % 2 == 0 { 519 | string.len() 520 | } else { 521 | string.len() + 1 522 | })?; 523 | 524 | let text = vec![Spans::from(vec![Span::raw(string)])]; 525 | 526 | let text = Paragraph::new(text) 527 | .style(Style::default().fg(Color::White).bg(Color::Black)) 528 | .alignment(Alignment::Center) 529 | .wrap(Wrap { trim: true }); 530 | 531 | f.render_widget(Clear, area); //this clears out the background 532 | f.render_widget(block, area); 533 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 534 | 535 | f.set_cursor( 536 | area.x + area.width / 2 + text_len / 2, 537 | area.y + area.height / 2, 538 | ); 539 | 540 | Ok(()) 541 | } 542 | 543 | pub fn counter( 544 | current_popup_state: &mut PopupState, 545 | name: String, 546 | f: &mut Frame>, 547 | ) -> Result<()> { 548 | let block = Block::default() 549 | .borders(Borders::ALL) 550 | .border_style(Style::default().fg(Color::White)) 551 | .border_type(BorderType::Rounded) 552 | .style(Style::default().bg(Color::Black)) 553 | .title(name); 554 | 555 | let area = centered_rect(60, 4, f.size()); 556 | 557 | let chunks = Layout::default() 558 | .direction(Direction::Vertical) 559 | .constraints( 560 | [ 561 | Constraint::Ratio(1, 3), 562 | Constraint::Ratio(1, 3), 563 | Constraint::Ratio(1, 3), 564 | ] 565 | .as_ref(), 566 | ) 567 | .split(area); 568 | 569 | let string = if let PopupState::Int { current, min, max } = current_popup_state { 570 | if current <= min { 571 | format!(" {} >", (*current)) 572 | } else if current >= max { 573 | format!("< {} ", (*current)) 574 | } else { 575 | format!("< {} >", (*current)) 576 | } 577 | } else { 578 | bail!("Invalid popup state") 579 | }; 580 | 581 | let text = vec![Spans::from(vec![Span::raw(string)])]; 582 | 583 | let text = Paragraph::new(text) 584 | .style(Style::default().fg(Color::White).bg(Color::Black)) 585 | .alignment(Alignment::Center) 586 | .wrap(Wrap { trim: true }); 587 | 588 | f.render_widget(Clear, area); 589 | f.render_widget(block, area); 590 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 591 | 592 | Ok(()) 593 | } 594 | 595 | pub fn keybind_command( 596 | current_config: &Config, 597 | index: usize, 598 | current_popup_state: &mut PopupState, 599 | f: &mut Frame>, 600 | ) -> Result<()> { 601 | let block = Block::default() 602 | .borders(Borders::ALL) 603 | .border_style(Style::default().fg(Color::White)) 604 | .border_type(BorderType::Rounded) 605 | .style(Style::default().bg(Color::Black)) 606 | .title("Command"); 607 | let area = centered_rect(60, 20, f.size()); 608 | let mut command_list = [ 609 | ListItem::new("Execute"), 610 | ListItem::new("CloseWindow"), 611 | ListItem::new("SwapTags"), 612 | ListItem::new("SoftReload"), 613 | ListItem::new("HardReload"), 614 | ListItem::new("ToggleScratchPad"), 615 | ListItem::new("ToggleFullScreen"), 616 | ListItem::new("ToggleSticky"), 617 | ListItem::new("GotoTag"), 618 | ListItem::new("ReturnToLastTag"), 619 | ListItem::new("FloatingToTile"), 620 | ListItem::new("TileToFloating"), 621 | ListItem::new("ToggleFloating"), 622 | ListItem::new("MoveWindowUp"), 623 | ListItem::new("MoveWindowDown"), 624 | ListItem::new("MoveWindowTop"), 625 | ListItem::new("FocusNextTag"), 626 | ListItem::new("FocusPreviousTag"), 627 | ListItem::new("FocusWindow"), 628 | ListItem::new("FocusWindowUp"), 629 | ListItem::new("FocusWindowDown"), 630 | ListItem::new("FocusWindowTop"), 631 | ListItem::new("FocusWorkspaceNext"), 632 | ListItem::new("FocusWorkspacePrevious"), 633 | ListItem::new("MoveToTag"), 634 | ListItem::new("MoveToLastWorkspace"), 635 | ListItem::new("MoveWindowToNextWorkspace"), 636 | ListItem::new("MoveWindowToPreviousWorkspace"), 637 | ListItem::new("MouseMoveWindow"), 638 | ListItem::new("NextLayout"), 639 | ListItem::new("PreviousLayout"), 640 | ListItem::new("SetLayout"), 641 | ListItem::new("RotateTag"), 642 | ListItem::new("IncreaseMainWidth"), 643 | ListItem::new("DecreaseMainWidth"), 644 | ListItem::new("SetMarginMultiplier"), 645 | ListItem::new("UnloadTheme"), 646 | ListItem::new("LoadTheme"), 647 | ListItem::new("CloseAllOtherWindows"), 648 | ]; 649 | 650 | match current_config.keybind.get(index).try_unwrap()?.command { 651 | BaseCommand::Execute => mem::replace::( 652 | &mut command_list[0], 653 | ListItem::new("Execute").style(Style::default().fg(Color::Green)), 654 | ), 655 | BaseCommand::CloseWindow => mem::replace::( 656 | &mut command_list[1], 657 | ListItem::new("CloseWindow").style(Style::default().fg(Color::Green)), 658 | ), 659 | BaseCommand::SwapTags => mem::replace::( 660 | &mut command_list[2], 661 | ListItem::new("SwapTags").style(Style::default().fg(Color::Green)), 662 | ), 663 | BaseCommand::SoftReload => mem::replace::( 664 | &mut command_list[3], 665 | ListItem::new("SoftReload").style(Style::default().fg(Color::Green)), 666 | ), 667 | BaseCommand::HardReload => mem::replace::( 668 | &mut command_list[4], 669 | ListItem::new("HardReload").style(Style::default().fg(Color::Green)), 670 | ), 671 | BaseCommand::ToggleScratchPad => mem::replace::( 672 | &mut command_list[5], 673 | ListItem::new("ToggleScratchPad").style(Style::default().fg(Color::Green)), 674 | ), 675 | BaseCommand::ToggleFullScreen => mem::replace::( 676 | &mut command_list[6], 677 | ListItem::new("ToggleFullScreen").style(Style::default().fg(Color::Green)), 678 | ), 679 | BaseCommand::ToggleSticky => mem::replace::( 680 | &mut command_list[7], 681 | ListItem::new("ToggleSticky").style(Style::default().fg(Color::Green)), 682 | ), 683 | BaseCommand::GotoTag => mem::replace::( 684 | &mut command_list[8], 685 | ListItem::new("GotoTag").style(Style::default().fg(Color::Green)), 686 | ), 687 | BaseCommand::ReturnToLastTag => mem::replace::( 688 | &mut command_list[9], 689 | ListItem::new("ReturnToLastTag").style(Style::default().fg(Color::Green)), 690 | ), 691 | BaseCommand::FloatingToTile => mem::replace::( 692 | &mut command_list[10], 693 | ListItem::new("FloatingToTile").style(Style::default().fg(Color::Green)), 694 | ), 695 | BaseCommand::TileToFloating => mem::replace::( 696 | &mut command_list[11], 697 | ListItem::new("TileToFloating").style(Style::default().fg(Color::Green)), 698 | ), 699 | BaseCommand::ToggleFloating => mem::replace::( 700 | &mut command_list[12], 701 | ListItem::new("ToggleFloating").style(Style::default().fg(Color::Green)), 702 | ), 703 | BaseCommand::MoveWindowUp => mem::replace::( 704 | &mut command_list[13], 705 | ListItem::new("MoveWindowUp").style(Style::default().fg(Color::Green)), 706 | ), 707 | BaseCommand::MoveWindowDown => mem::replace::( 708 | &mut command_list[14], 709 | ListItem::new("MoveWindowDown").style(Style::default().fg(Color::Green)), 710 | ), 711 | BaseCommand::MoveWindowTop => mem::replace::( 712 | &mut command_list[15], 713 | ListItem::new("MoveWindowTop ").style(Style::default().fg(Color::Green)), 714 | ), 715 | BaseCommand::FocusNextTag => mem::replace::( 716 | &mut command_list[16], 717 | ListItem::new("FocusNextTag ").style(Style::default().fg(Color::Green)), 718 | ), 719 | BaseCommand::FocusPreviousTag => mem::replace::( 720 | &mut command_list[17], 721 | ListItem::new("FocusPreviousTag").style(Style::default().fg(Color::Green)), 722 | ), 723 | BaseCommand::FocusWindow => mem::replace::( 724 | &mut command_list[18], 725 | ListItem::new("FocusWindow").style(Style::default().fg(Color::Green)), 726 | ), 727 | BaseCommand::FocusWindowUp => mem::replace::( 728 | &mut command_list[19], 729 | ListItem::new("FocusWindowUp").style(Style::default().fg(Color::Green)), 730 | ), 731 | BaseCommand::FocusWindowDown => mem::replace::( 732 | &mut command_list[20], 733 | ListItem::new("FocusWindowDown").style(Style::default().fg(Color::Green)), 734 | ), 735 | BaseCommand::FocusWindowTop => mem::replace::( 736 | &mut command_list[21], 737 | ListItem::new("FocusWindowTop ").style(Style::default().fg(Color::Green)), 738 | ), 739 | BaseCommand::FocusWorkspaceNext => mem::replace::( 740 | &mut command_list[22], 741 | ListItem::new("FocusWorkspaceNext").style(Style::default().fg(Color::Green)), 742 | ), 743 | BaseCommand::FocusWorkspacePrevious => mem::replace::( 744 | &mut command_list[23], 745 | ListItem::new("FocusWorkspacePrevious").style(Style::default().fg(Color::Green)), 746 | ), 747 | BaseCommand::MoveToTag => mem::replace::( 748 | &mut command_list[24], 749 | ListItem::new("MoveToTag").style(Style::default().fg(Color::Green)), 750 | ), 751 | BaseCommand::MoveToLastWorkspace => mem::replace::( 752 | &mut command_list[25], 753 | ListItem::new("MoveToLastWorkspace").style(Style::default().fg(Color::Green)), 754 | ), 755 | BaseCommand::MoveWindowToNextWorkspace => mem::replace::( 756 | &mut command_list[26], 757 | ListItem::new("MoveWindowToNextWorkspace ").style(Style::default().fg(Color::Green)), 758 | ), 759 | BaseCommand::MoveWindowToPreviousWorkspace => mem::replace::( 760 | &mut command_list[27], 761 | ListItem::new("MoveWindowToPreviousWorkspace").style(Style::default().fg(Color::Green)), 762 | ), 763 | BaseCommand::MouseMoveWindow => mem::replace::( 764 | &mut command_list[28], 765 | ListItem::new("MouseMoveWindow").style(Style::default().fg(Color::Green)), 766 | ), 767 | BaseCommand::NextLayout => mem::replace::( 768 | &mut command_list[29], 769 | ListItem::new("NextLayout").style(Style::default().fg(Color::Green)), 770 | ), 771 | BaseCommand::PreviousLayout => mem::replace::( 772 | &mut command_list[30], 773 | ListItem::new("PreviousLayout").style(Style::default().fg(Color::Green)), 774 | ), 775 | BaseCommand::SetLayout => mem::replace::( 776 | &mut command_list[31], 777 | ListItem::new("SetLayout").style(Style::default().fg(Color::Green)), 778 | ), 779 | BaseCommand::RotateTag => mem::replace::( 780 | &mut command_list[32], 781 | ListItem::new("RotateTag").style(Style::default().fg(Color::Green)), 782 | ), 783 | BaseCommand::IncreaseMainWidth => mem::replace::( 784 | &mut command_list[33], 785 | ListItem::new("IncreaseMainWidth").style(Style::default().fg(Color::Green)), 786 | ), 787 | BaseCommand::DecreaseMainWidth => mem::replace::( 788 | &mut command_list[34], 789 | ListItem::new("DecreaseMainWidth").style(Style::default().fg(Color::Green)), 790 | ), 791 | BaseCommand::SetMarginMultiplier => mem::replace::( 792 | &mut command_list[35], 793 | ListItem::new("SetMarginMultiplier").style(Style::default().fg(Color::Green)), 794 | ), 795 | BaseCommand::UnloadTheme => mem::replace::( 796 | &mut command_list[36], 797 | ListItem::new("UnloadTheme").style(Style::default().fg(Color::Green)), 798 | ), 799 | BaseCommand::LoadTheme => mem::replace::( 800 | &mut command_list[37], 801 | ListItem::new("LoadTheme").style(Style::default().fg(Color::Green)), 802 | ), 803 | BaseCommand::CloseAllOtherWindows => mem::replace::( 804 | &mut command_list[38], 805 | ListItem::new("CloseAllOtherWindows").style(Style::default().fg(Color::Green)), 806 | ), 807 | }; 808 | 809 | let list = List::new(command_list) 810 | .block(Block::default().borders(Borders::NONE)) 811 | .style(Style::default().fg(Color::White)) 812 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 813 | .highlight_symbol(">>"); 814 | 815 | f.render_widget(Clear, area); //this clears out the background 816 | f.render_widget(block, area); 817 | 818 | if let PopupState::List(e) = current_popup_state { 819 | f.render_stateful_widget(list, centered_rect(60, 50, area), e); 820 | } else { 821 | bail!("Invalid popup state"); 822 | } 823 | 824 | Ok(()) 825 | } 826 | 827 | pub fn keybind_modkey( 828 | current_popup_state: &mut PopupState, 829 | f: &mut Frame>, 830 | ) -> Result<()> { 831 | let block = Block::default() 832 | .borders(Borders::ALL) 833 | .border_style(Style::default().fg(Color::White)) 834 | .border_type(BorderType::Rounded) 835 | .style(Style::default().bg(Color::Black)) 836 | .title("Modifier"); 837 | let area = centered_rect(60, 20, f.size()); 838 | f.render_widget(Clear, area); //this clears out the background 839 | f.render_widget(block, area); 840 | let PopupState::MultiList(state) = current_popup_state else { 841 | bail!("Invalid popup state") 842 | }; 843 | let modkey_list = [ 844 | if state.selected.contains(&0) { 845 | ListItem::new("None").style(Style::default().fg(Color::Green)) 846 | } else { 847 | ListItem::new("None") 848 | }, 849 | if state.selected.contains(&1) { 850 | ListItem::new("Shift").style(Style::default().fg(Color::Green)) 851 | } else { 852 | ListItem::new("Shift") 853 | }, 854 | if state.selected.contains(&2) { 855 | ListItem::new("Control").style(Style::default().fg(Color::Green)) 856 | } else { 857 | ListItem::new("Control") 858 | }, 859 | if state.selected.contains(&3) { 860 | ListItem::new("Alt").style(Style::default().fg(Color::Green)) 861 | } else { 862 | ListItem::new("Alt") 863 | }, 864 | if state.selected.contains(&4) { 865 | ListItem::new("Mod3").style(Style::default().fg(Color::Green)) 866 | } else { 867 | ListItem::new("Mod3") 868 | }, 869 | if state.selected.contains(&5) { 870 | ListItem::new("Super").style(Style::default().fg(Color::Green)) 871 | } else { 872 | ListItem::new("Super") 873 | }, 874 | if state.selected.contains(&6) { 875 | ListItem::new("Mod5").style(Style::default().fg(Color::Green)) 876 | } else { 877 | ListItem::new("Mod5") 878 | }, 879 | if state.selected.contains(&7) { 880 | ListItem::new("modkey").style(Style::default().fg(Color::Green)) 881 | } else { 882 | ListItem::new("modkey") 883 | }, 884 | ]; 885 | let list = List::new(modkey_list) 886 | .block(Block::default().borders(Borders::NONE)) 887 | .style(Style::default().fg(Color::White)) 888 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 889 | .highlight_symbol(">>"); 890 | 891 | f.render_stateful_widget(list, centered_rect(30, 50, area), &mut state.liststate); 892 | 893 | Ok(()) 894 | } 895 | 896 | pub fn keybind_key( 897 | current_popup_state: &mut PopupState, 898 | name: String, 899 | f: &mut Frame>, 900 | ) -> Result<()> { 901 | let block = Block::default() 902 | .borders(Borders::ALL) 903 | .border_style(Style::default().fg(Color::White)) 904 | .border_type(BorderType::Rounded) 905 | .style(Style::default().bg(Color::Black)) 906 | .title(name); 907 | 908 | let mut area = centered_rect(60, 4, f.size()); 909 | 910 | area.y -= area.height / 2; 911 | 912 | let chunks = Layout::default() 913 | .direction(Direction::Vertical) 914 | .constraints( 915 | [ 916 | Constraint::Ratio(1, 3), 917 | Constraint::Ratio(1, 3), 918 | Constraint::Ratio(1, 3), 919 | ] 920 | .as_ref(), 921 | ) 922 | .split(area); 923 | 924 | let string = if let PopupState::String(s) = current_popup_state { 925 | s.clone() 926 | } else { 927 | bail!("Invalid popup state") 928 | }; 929 | 930 | let text_len = u16::try_from(if string.len() % 2 == 0 { 931 | string.len() 932 | } else { 933 | string.len() + 1 934 | })?; 935 | 936 | let text = vec![Spans::from(vec![Span::raw(string)])]; 937 | 938 | let text = Paragraph::new(text) 939 | .style(Style::default().fg(Color::White).bg(Color::Black)) 940 | .alignment(Alignment::Center) 941 | .wrap(Wrap { trim: true }); 942 | 943 | f.render_widget(Clear, area); //this clears out the background 944 | f.render_widget(block, area); 945 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 946 | 947 | f.set_cursor( 948 | area.x + area.width / 2 + text_len / 2, 949 | area.y + area.height / 2, 950 | ); 951 | 952 | let mut block = Block::default() 953 | .borders(Borders::ALL) 954 | .border_type(BorderType::Rounded) 955 | .style(Style::default().bg(Color::Black)); 956 | 957 | let mut indicator_area = centered_rect(60, 4, f.size()); 958 | indicator_area.y += area.height; 959 | 960 | let chunks_indicator = Layout::default() 961 | .direction(Direction::Vertical) 962 | .constraints( 963 | [ 964 | Constraint::Ratio(1, 3), 965 | Constraint::Ratio(1, 3), 966 | Constraint::Ratio(1, 3), 967 | ] 968 | .as_ref(), 969 | ) 970 | .split(indicator_area); 971 | 972 | let indicator = if let PopupState::String(s) = current_popup_state { 973 | if into_keysym(s.as_str()).is_some() { 974 | let text = vec![Spans::from(vec![Span::raw("Key Ok")])]; 975 | block = block.border_style(Style::default().fg(Color::Green)); 976 | Paragraph::new(text) 977 | .style(Style::default().fg(Color::Green).bg(Color::Black)) 978 | .alignment(Alignment::Center) 979 | .wrap(Wrap { trim: true }) 980 | } else { 981 | let text = vec![Spans::from(vec![Span::raw("Key Doesn't Exist!")])]; 982 | block = block.border_style(Style::default().fg(Color::Red)); 983 | Paragraph::new(text) 984 | .style(Style::default().fg(Color::Red).bg(Color::Black)) 985 | .alignment(Alignment::Center) 986 | .wrap(Wrap { trim: true }) 987 | } 988 | } else { 989 | bail!("Invalid popup state") 990 | }; 991 | 992 | f.render_widget(Clear, indicator_area); //this clears out the background 993 | f.render_widget(block, indicator_area); 994 | f.render_widget( 995 | indicator, 996 | *chunks_indicator.get(1).unwrap_or(&indicator_area), 997 | ); 998 | 999 | Ok(()) 1000 | } 1001 | -------------------------------------------------------------------------------- /src/utils/x11_keys.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(unused)] 3 | #![allow(clippy::unreadable_literal)] 4 | // x11-rs: Rust bindings for X11 libraries 5 | // The X11 libraries are available under the MIT license. 6 | // These bindings are public domain. 7 | 8 | use std::os::raw::c_uint; 9 | 10 | pub const XK_BackSpace: c_uint = 0xFF08; 11 | pub const XK_Tab: c_uint = 0xFF09; 12 | pub const XK_Linefeed: c_uint = 0xFF0A; 13 | pub const XK_Clear: c_uint = 0xFF0B; 14 | pub const XK_Return: c_uint = 0xFF0D; 15 | pub const XK_Pause: c_uint = 0xFF13; 16 | pub const XK_Scroll_Lock: c_uint = 0xFF14; 17 | pub const XK_Sys_Req: c_uint = 0xFF15; 18 | pub const XK_Escape: c_uint = 0xFF1B; 19 | pub const XK_Delete: c_uint = 0xFFFF; 20 | pub const XK_Multi_key: c_uint = 0xFF20; 21 | pub const XK_Kanji: c_uint = 0xFF21; 22 | pub const XK_Muhenkan: c_uint = 0xFF22; 23 | pub const XK_Henkan_Mode: c_uint = 0xFF23; 24 | pub const XK_Henkan: c_uint = 0xFF23; 25 | pub const XK_Romaji: c_uint = 0xFF24; 26 | pub const XK_Hiragana: c_uint = 0xFF25; 27 | pub const XK_Katakana: c_uint = 0xFF26; 28 | pub const XK_Hiragana_Katakana: c_uint = 0xFF27; 29 | pub const XK_Zenkaku: c_uint = 0xFF28; 30 | pub const XK_Hankaku: c_uint = 0xFF29; 31 | pub const XK_Zenkaku_Hankaku: c_uint = 0xFF2A; 32 | pub const XK_Touroku: c_uint = 0xFF2B; 33 | pub const XK_Massyo: c_uint = 0xFF2C; 34 | pub const XK_Kana_Lock: c_uint = 0xFF2D; 35 | pub const XK_Kana_Shift: c_uint = 0xFF2E; 36 | pub const XK_Eisu_Shift: c_uint = 0xFF2F; 37 | pub const XK_Eisu_toggle: c_uint = 0xFF30; 38 | pub const XK_Home: c_uint = 0xFF50; 39 | pub const XK_Left: c_uint = 0xFF51; 40 | pub const XK_Up: c_uint = 0xFF52; 41 | pub const XK_Right: c_uint = 0xFF53; 42 | pub const XK_Down: c_uint = 0xFF54; 43 | pub const XK_Prior: c_uint = 0xFF55; 44 | pub const XK_Page_Up: c_uint = 0xFF55; 45 | pub const XK_Next: c_uint = 0xFF56; 46 | pub const XK_Page_Down: c_uint = 0xFF56; 47 | pub const XK_End: c_uint = 0xFF57; 48 | pub const XK_Begin: c_uint = 0xFF58; 49 | pub const XK_Win_L: c_uint = 0xFF5B; 50 | pub const XK_Win_R: c_uint = 0xFF5C; 51 | pub const XK_App: c_uint = 0xFF5D; 52 | pub const XK_Select: c_uint = 0xFF60; 53 | pub const XK_Print: c_uint = 0xFF61; 54 | pub const XK_Execute: c_uint = 0xFF62; 55 | pub const XK_Insert: c_uint = 0xFF63; 56 | pub const XK_Undo: c_uint = 0xFF65; 57 | pub const XK_Redo: c_uint = 0xFF66; 58 | pub const XK_Menu: c_uint = 0xFF67; 59 | pub const XK_Find: c_uint = 0xFF68; 60 | pub const XK_Cancel: c_uint = 0xFF69; 61 | pub const XK_Help: c_uint = 0xFF6A; 62 | pub const XK_Break: c_uint = 0xFF6B; 63 | pub const XK_Mode_switch: c_uint = 0xFF7E; 64 | pub const XK_script_switch: c_uint = 0xFF7E; 65 | pub const XK_Num_Lock: c_uint = 0xFF7F; 66 | pub const XK_KP_Space: c_uint = 0xFF80; 67 | pub const XK_KP_Tab: c_uint = 0xFF89; 68 | pub const XK_KP_Enter: c_uint = 0xFF8D; 69 | pub const XK_KP_F1: c_uint = 0xFF91; 70 | pub const XK_KP_F2: c_uint = 0xFF92; 71 | pub const XK_KP_F3: c_uint = 0xFF93; 72 | pub const XK_KP_F4: c_uint = 0xFF94; 73 | pub const XK_KP_Home: c_uint = 0xFF95; 74 | pub const XK_KP_Left: c_uint = 0xFF96; 75 | pub const XK_KP_Up: c_uint = 0xFF97; 76 | pub const XK_KP_Right: c_uint = 0xFF98; 77 | pub const XK_KP_Down: c_uint = 0xFF99; 78 | pub const XK_KP_Prior: c_uint = 0xFF9A; 79 | pub const XK_KP_Page_Up: c_uint = 0xFF9A; 80 | pub const XK_KP_Next: c_uint = 0xFF9B; 81 | pub const XK_KP_Page_Down: c_uint = 0xFF9B; 82 | pub const XK_KP_End: c_uint = 0xFF9C; 83 | pub const XK_KP_Begin: c_uint = 0xFF9D; 84 | pub const XK_KP_Insert: c_uint = 0xFF9E; 85 | pub const XK_KP_Delete: c_uint = 0xFF9F; 86 | pub const XK_KP_Equal: c_uint = 0xFFBD; 87 | pub const XK_KP_Multiply: c_uint = 0xFFAA; 88 | pub const XK_KP_Add: c_uint = 0xFFAB; 89 | pub const XK_KP_Separator: c_uint = 0xFFAC; 90 | pub const XK_KP_Subtract: c_uint = 0xFFAD; 91 | pub const XK_KP_Decimal: c_uint = 0xFFAE; 92 | pub const XK_KP_Divide: c_uint = 0xFFAF; 93 | pub const XK_KP_0: c_uint = 0xFFB0; 94 | pub const XK_KP_1: c_uint = 0xFFB1; 95 | pub const XK_KP_2: c_uint = 0xFFB2; 96 | pub const XK_KP_3: c_uint = 0xFFB3; 97 | pub const XK_KP_4: c_uint = 0xFFB4; 98 | pub const XK_KP_5: c_uint = 0xFFB5; 99 | pub const XK_KP_6: c_uint = 0xFFB6; 100 | pub const XK_KP_7: c_uint = 0xFFB7; 101 | pub const XK_KP_8: c_uint = 0xFFB8; 102 | pub const XK_KP_9: c_uint = 0xFFB9; 103 | pub const XK_F1: c_uint = 0xFFBE; 104 | pub const XK_F2: c_uint = 0xFFBF; 105 | pub const XK_F3: c_uint = 0xFFC0; 106 | pub const XK_F4: c_uint = 0xFFC1; 107 | pub const XK_F5: c_uint = 0xFFC2; 108 | pub const XK_F6: c_uint = 0xFFC3; 109 | pub const XK_F7: c_uint = 0xFFC4; 110 | pub const XK_F8: c_uint = 0xFFC5; 111 | pub const XK_F9: c_uint = 0xFFC6; 112 | pub const XK_F10: c_uint = 0xFFC7; 113 | pub const XK_F11: c_uint = 0xFFC8; 114 | pub const XK_L1: c_uint = 0xFFC8; 115 | pub const XK_F12: c_uint = 0xFFC9; 116 | pub const XK_L2: c_uint = 0xFFC9; 117 | pub const XK_F13: c_uint = 0xFFCA; 118 | pub const XK_L3: c_uint = 0xFFCA; 119 | pub const XK_F14: c_uint = 0xFFCB; 120 | pub const XK_L4: c_uint = 0xFFCB; 121 | pub const XK_F15: c_uint = 0xFFCC; 122 | pub const XK_L5: c_uint = 0xFFCC; 123 | pub const XK_F16: c_uint = 0xFFCD; 124 | pub const XK_L6: c_uint = 0xFFCD; 125 | pub const XK_F17: c_uint = 0xFFCE; 126 | pub const XK_L7: c_uint = 0xFFCE; 127 | pub const XK_F18: c_uint = 0xFFCF; 128 | pub const XK_L8: c_uint = 0xFFCF; 129 | pub const XK_F19: c_uint = 0xFFD0; 130 | pub const XK_L9: c_uint = 0xFFD0; 131 | pub const XK_F20: c_uint = 0xFFD1; 132 | pub const XK_L10: c_uint = 0xFFD1; 133 | pub const XK_F21: c_uint = 0xFFD2; 134 | pub const XK_R1: c_uint = 0xFFD2; 135 | pub const XK_F22: c_uint = 0xFFD3; 136 | pub const XK_R2: c_uint = 0xFFD3; 137 | pub const XK_F23: c_uint = 0xFFD4; 138 | pub const XK_R3: c_uint = 0xFFD4; 139 | pub const XK_F24: c_uint = 0xFFD5; 140 | pub const XK_R4: c_uint = 0xFFD5; 141 | pub const XK_F25: c_uint = 0xFFD6; 142 | pub const XK_R5: c_uint = 0xFFD6; 143 | pub const XK_F26: c_uint = 0xFFD7; 144 | pub const XK_R6: c_uint = 0xFFD7; 145 | pub const XK_F27: c_uint = 0xFFD8; 146 | pub const XK_R7: c_uint = 0xFFD8; 147 | pub const XK_F28: c_uint = 0xFFD9; 148 | pub const XK_R8: c_uint = 0xFFD9; 149 | pub const XK_F29: c_uint = 0xFFDA; 150 | pub const XK_R9: c_uint = 0xFFDA; 151 | pub const XK_F30: c_uint = 0xFFDB; 152 | pub const XK_R10: c_uint = 0xFFDB; 153 | pub const XK_F31: c_uint = 0xFFDC; 154 | pub const XK_R11: c_uint = 0xFFDC; 155 | pub const XK_F32: c_uint = 0xFFDD; 156 | pub const XK_R12: c_uint = 0xFFDD; 157 | pub const XK_F33: c_uint = 0xFFDE; 158 | pub const XK_R13: c_uint = 0xFFDE; 159 | pub const XK_F34: c_uint = 0xFFDF; 160 | pub const XK_R14: c_uint = 0xFFDF; 161 | pub const XK_F35: c_uint = 0xFFE0; 162 | pub const XK_R15: c_uint = 0xFFE0; 163 | pub const XK_Shift_L: c_uint = 0xFFE1; 164 | pub const XK_Shift_R: c_uint = 0xFFE2; 165 | pub const XK_Control_L: c_uint = 0xFFE3; 166 | pub const XK_Control_R: c_uint = 0xFFE4; 167 | pub const XK_Caps_Lock: c_uint = 0xFFE5; 168 | pub const XK_Shift_Lock: c_uint = 0xFFE6; 169 | pub const XK_Meta_L: c_uint = 0xFFE7; 170 | pub const XK_Meta_R: c_uint = 0xFFE8; 171 | pub const XK_Alt_L: c_uint = 0xFFE9; 172 | pub const XK_Alt_R: c_uint = 0xFFEA; 173 | pub const XK_Super_L: c_uint = 0xFFEB; 174 | pub const XK_Super_R: c_uint = 0xFFEC; 175 | pub const XK_Hyper_L: c_uint = 0xFFED; 176 | pub const XK_Hyper_R: c_uint = 0xFFEE; 177 | pub const XK_space: c_uint = 0x020; 178 | pub const XK_exclam: c_uint = 0x021; 179 | pub const XK_quotedbl: c_uint = 0x022; 180 | pub const XK_numbersign: c_uint = 0x023; 181 | pub const XK_dollar: c_uint = 0x024; 182 | pub const XK_percent: c_uint = 0x025; 183 | pub const XK_ampersand: c_uint = 0x026; 184 | pub const XK_apostrophe: c_uint = 0x027; 185 | pub const XK_quoteright: c_uint = 0x027; 186 | pub const XK_parenleft: c_uint = 0x028; 187 | pub const XK_parenright: c_uint = 0x029; 188 | pub const XK_asterisk: c_uint = 0x02a; 189 | pub const XK_plus: c_uint = 0x02b; 190 | pub const XK_comma: c_uint = 0x02c; 191 | pub const XK_minus: c_uint = 0x02d; 192 | pub const XK_period: c_uint = 0x02e; 193 | pub const XK_slash: c_uint = 0x02f; 194 | pub const XK_0: c_uint = 0x030; 195 | pub const XK_1: c_uint = 0x031; 196 | pub const XK_2: c_uint = 0x032; 197 | pub const XK_3: c_uint = 0x033; 198 | pub const XK_4: c_uint = 0x034; 199 | pub const XK_5: c_uint = 0x035; 200 | pub const XK_6: c_uint = 0x036; 201 | pub const XK_7: c_uint = 0x037; 202 | pub const XK_8: c_uint = 0x038; 203 | pub const XK_9: c_uint = 0x039; 204 | pub const XK_colon: c_uint = 0x03a; 205 | pub const XK_semicolon: c_uint = 0x03b; 206 | pub const XK_less: c_uint = 0x03c; 207 | pub const XK_equal: c_uint = 0x03d; 208 | pub const XK_greater: c_uint = 0x03e; 209 | pub const XK_question: c_uint = 0x03f; 210 | pub const XK_at: c_uint = 0x040; 211 | pub const XK_A: c_uint = 0x041; 212 | pub const XK_B: c_uint = 0x042; 213 | pub const XK_C: c_uint = 0x043; 214 | pub const XK_D: c_uint = 0x044; 215 | pub const XK_E: c_uint = 0x045; 216 | pub const XK_F: c_uint = 0x046; 217 | pub const XK_G: c_uint = 0x047; 218 | pub const XK_H: c_uint = 0x048; 219 | pub const XK_I: c_uint = 0x049; 220 | pub const XK_J: c_uint = 0x04a; 221 | pub const XK_K: c_uint = 0x04b; 222 | pub const XK_L: c_uint = 0x04c; 223 | pub const XK_M: c_uint = 0x04d; 224 | pub const XK_N: c_uint = 0x04e; 225 | pub const XK_O: c_uint = 0x04f; 226 | pub const XK_P: c_uint = 0x050; 227 | pub const XK_Q: c_uint = 0x051; 228 | pub const XK_R: c_uint = 0x052; 229 | pub const XK_S: c_uint = 0x053; 230 | pub const XK_T: c_uint = 0x054; 231 | pub const XK_U: c_uint = 0x055; 232 | pub const XK_V: c_uint = 0x056; 233 | pub const XK_W: c_uint = 0x057; 234 | pub const XK_X: c_uint = 0x058; 235 | pub const XK_Y: c_uint = 0x059; 236 | pub const XK_Z: c_uint = 0x05a; 237 | pub const XK_bracketleft: c_uint = 0x05b; 238 | pub const XK_backslash: c_uint = 0x05c; 239 | pub const XK_bracketright: c_uint = 0x05d; 240 | pub const XK_asciicircum: c_uint = 0x05e; 241 | pub const XK_underscore: c_uint = 0x05f; 242 | pub const XK_grave: c_uint = 0x060; 243 | pub const XK_quoteleft: c_uint = 0x060; 244 | pub const XK_a: c_uint = 0x061; 245 | pub const XK_b: c_uint = 0x062; 246 | pub const XK_c: c_uint = 0x063; 247 | pub const XK_d: c_uint = 0x064; 248 | pub const XK_e: c_uint = 0x065; 249 | pub const XK_f: c_uint = 0x066; 250 | pub const XK_g: c_uint = 0x067; 251 | pub const XK_h: c_uint = 0x068; 252 | pub const XK_i: c_uint = 0x069; 253 | pub const XK_j: c_uint = 0x06a; 254 | pub const XK_k: c_uint = 0x06b; 255 | pub const XK_l: c_uint = 0x06c; 256 | pub const XK_m: c_uint = 0x06d; 257 | pub const XK_n: c_uint = 0x06e; 258 | pub const XK_o: c_uint = 0x06f; 259 | pub const XK_p: c_uint = 0x070; 260 | pub const XK_q: c_uint = 0x071; 261 | pub const XK_r: c_uint = 0x072; 262 | pub const XK_s: c_uint = 0x073; 263 | pub const XK_t: c_uint = 0x074; 264 | pub const XK_u: c_uint = 0x075; 265 | pub const XK_v: c_uint = 0x076; 266 | pub const XK_w: c_uint = 0x077; 267 | pub const XK_x: c_uint = 0x078; 268 | pub const XK_y: c_uint = 0x079; 269 | pub const XK_z: c_uint = 0x07a; 270 | pub const XK_braceleft: c_uint = 0x07b; 271 | pub const XK_bar: c_uint = 0x07c; 272 | pub const XK_braceright: c_uint = 0x07d; 273 | pub const XK_asciitilde: c_uint = 0x07e; 274 | pub const XK_nobreakspace: c_uint = 0x0a0; 275 | pub const XK_exclamdown: c_uint = 0x0a1; 276 | pub const XK_cent: c_uint = 0x0a2; 277 | pub const XK_sterling: c_uint = 0x0a3; 278 | pub const XK_currency: c_uint = 0x0a4; 279 | pub const XK_yen: c_uint = 0x0a5; 280 | pub const XK_brokenbar: c_uint = 0x0a6; 281 | pub const XK_section: c_uint = 0x0a7; 282 | pub const XK_diaeresis: c_uint = 0x0a8; 283 | pub const XK_copyright: c_uint = 0x0a9; 284 | pub const XK_ordfeminine: c_uint = 0x0aa; 285 | pub const XK_guillemotleft: c_uint = 0x0ab; 286 | pub const XK_notsign: c_uint = 0x0ac; 287 | pub const XK_hyphen: c_uint = 0x0ad; 288 | pub const XK_registered: c_uint = 0x0ae; 289 | pub const XK_macron: c_uint = 0x0af; 290 | pub const XK_degree: c_uint = 0x0b0; 291 | pub const XK_plusminus: c_uint = 0x0b1; 292 | pub const XK_twosuperior: c_uint = 0x0b2; 293 | pub const XK_threesuperior: c_uint = 0x0b3; 294 | pub const XK_acute: c_uint = 0x0b4; 295 | pub const XK_mu: c_uint = 0x0b5; 296 | pub const XK_paragraph: c_uint = 0x0b6; 297 | pub const XK_periodcentered: c_uint = 0x0b7; 298 | pub const XK_cedilla: c_uint = 0x0b8; 299 | pub const XK_onesuperior: c_uint = 0x0b9; 300 | pub const XK_masculine: c_uint = 0x0ba; 301 | pub const XK_guillemotright: c_uint = 0x0bb; 302 | pub const XK_onequarter: c_uint = 0x0bc; 303 | pub const XK_onehalf: c_uint = 0x0bd; 304 | pub const XK_threequarters: c_uint = 0x0be; 305 | pub const XK_questiondown: c_uint = 0x0bf; 306 | pub const XK_Agrave: c_uint = 0x0c0; 307 | pub const XK_Aacute: c_uint = 0x0c1; 308 | pub const XK_Acircumflex: c_uint = 0x0c2; 309 | pub const XK_Atilde: c_uint = 0x0c3; 310 | pub const XK_Adiaeresis: c_uint = 0x0c4; 311 | pub const XK_Aring: c_uint = 0x0c5; 312 | pub const XK_AE: c_uint = 0x0c6; 313 | pub const XK_Ccedilla: c_uint = 0x0c7; 314 | pub const XK_Egrave: c_uint = 0x0c8; 315 | pub const XK_Eacute: c_uint = 0x0c9; 316 | pub const XK_Ecircumflex: c_uint = 0x0ca; 317 | pub const XK_Ediaeresis: c_uint = 0x0cb; 318 | pub const XK_Igrave: c_uint = 0x0cc; 319 | pub const XK_Iacute: c_uint = 0x0cd; 320 | pub const XK_Icircumflex: c_uint = 0x0ce; 321 | pub const XK_Idiaeresis: c_uint = 0x0cf; 322 | pub const XK_ETH: c_uint = 0x0d0; 323 | pub const XK_Eth: c_uint = 0x0d0; 324 | pub const XK_Ntilde: c_uint = 0x0d1; 325 | pub const XK_Ograve: c_uint = 0x0d2; 326 | pub const XK_Oacute: c_uint = 0x0d3; 327 | pub const XK_Ocircumflex: c_uint = 0x0d4; 328 | pub const XK_Otilde: c_uint = 0x0d5; 329 | pub const XK_Odiaeresis: c_uint = 0x0d6; 330 | pub const XK_multiply: c_uint = 0x0d7; 331 | pub const XK_Ooblique: c_uint = 0x0d8; 332 | pub const XK_Ugrave: c_uint = 0x0d9; 333 | pub const XK_Uacute: c_uint = 0x0da; 334 | pub const XK_Ucircumflex: c_uint = 0x0db; 335 | pub const XK_Udiaeresis: c_uint = 0x0dc; 336 | pub const XK_Yacute: c_uint = 0x0dd; 337 | pub const XK_THORN: c_uint = 0x0de; 338 | pub const XK_Thorn: c_uint = 0x0de; 339 | pub const XK_ssharp: c_uint = 0x0df; 340 | pub const XK_agrave: c_uint = 0x0e0; 341 | pub const XK_aacute: c_uint = 0x0e1; 342 | pub const XK_acircumflex: c_uint = 0x0e2; 343 | pub const XK_atilde: c_uint = 0x0e3; 344 | pub const XK_adiaeresis: c_uint = 0x0e4; 345 | pub const XK_aring: c_uint = 0x0e5; 346 | pub const XK_ae: c_uint = 0x0e6; 347 | pub const XK_ccedilla: c_uint = 0x0e7; 348 | pub const XK_egrave: c_uint = 0x0e8; 349 | pub const XK_eacute: c_uint = 0x0e9; 350 | pub const XK_ecircumflex: c_uint = 0x0ea; 351 | pub const XK_ediaeresis: c_uint = 0x0eb; 352 | pub const XK_igrave: c_uint = 0x0ec; 353 | pub const XK_iacute: c_uint = 0x0ed; 354 | pub const XK_icircumflex: c_uint = 0x0ee; 355 | pub const XK_idiaeresis: c_uint = 0x0ef; 356 | pub const XK_eth: c_uint = 0x0f0; 357 | pub const XK_ntilde: c_uint = 0x0f1; 358 | pub const XK_ograve: c_uint = 0x0f2; 359 | pub const XK_oacute: c_uint = 0x0f3; 360 | pub const XK_ocircumflex: c_uint = 0x0f4; 361 | pub const XK_otilde: c_uint = 0x0f5; 362 | pub const XK_odiaeresis: c_uint = 0x0f6; 363 | pub const XK_division: c_uint = 0x0f7; 364 | pub const XK_oslash: c_uint = 0x0f8; 365 | pub const XK_ugrave: c_uint = 0x0f9; 366 | pub const XK_uacute: c_uint = 0x0fa; 367 | pub const XK_ucircumflex: c_uint = 0x0fb; 368 | pub const XK_udiaeresis: c_uint = 0x0fc; 369 | pub const XK_yacute: c_uint = 0x0fd; 370 | pub const XK_thorn: c_uint = 0x0fe; 371 | pub const XK_ydiaeresis: c_uint = 0x0ff; 372 | pub const XK_Aogonek: c_uint = 0x1a1; 373 | pub const XK_breve: c_uint = 0x1a2; 374 | pub const XK_Lstroke: c_uint = 0x1a3; 375 | pub const XK_Lcaron: c_uint = 0x1a5; 376 | pub const XK_Sacute: c_uint = 0x1a6; 377 | pub const XK_Scaron: c_uint = 0x1a9; 378 | pub const XK_Scedilla: c_uint = 0x1aa; 379 | pub const XK_Tcaron: c_uint = 0x1ab; 380 | pub const XK_Zacute: c_uint = 0x1ac; 381 | pub const XK_Zcaron: c_uint = 0x1ae; 382 | pub const XK_Zabovedot: c_uint = 0x1af; 383 | pub const XK_aogonek: c_uint = 0x1b1; 384 | pub const XK_ogonek: c_uint = 0x1b2; 385 | pub const XK_lstroke: c_uint = 0x1b3; 386 | pub const XK_lcaron: c_uint = 0x1b5; 387 | pub const XK_sacute: c_uint = 0x1b6; 388 | pub const XK_caron: c_uint = 0x1b7; 389 | pub const XK_scaron: c_uint = 0x1b9; 390 | pub const XK_scedilla: c_uint = 0x1ba; 391 | pub const XK_tcaron: c_uint = 0x1bb; 392 | pub const XK_zacute: c_uint = 0x1bc; 393 | pub const XK_doubleacute: c_uint = 0x1bd; 394 | pub const XK_zcaron: c_uint = 0x1be; 395 | pub const XK_zabovedot: c_uint = 0x1bf; 396 | pub const XK_Racute: c_uint = 0x1c0; 397 | pub const XK_Abreve: c_uint = 0x1c3; 398 | pub const XK_Lacute: c_uint = 0x1c5; 399 | pub const XK_Cacute: c_uint = 0x1c6; 400 | pub const XK_Ccaron: c_uint = 0x1c8; 401 | pub const XK_Eogonek: c_uint = 0x1ca; 402 | pub const XK_Ecaron: c_uint = 0x1cc; 403 | pub const XK_Dcaron: c_uint = 0x1cf; 404 | pub const XK_Dstroke: c_uint = 0x1d0; 405 | pub const XK_Nacute: c_uint = 0x1d1; 406 | pub const XK_Ncaron: c_uint = 0x1d2; 407 | pub const XK_Odoubleacute: c_uint = 0x1d5; 408 | pub const XK_Rcaron: c_uint = 0x1d8; 409 | pub const XK_Uring: c_uint = 0x1d9; 410 | pub const XK_Udoubleacute: c_uint = 0x1db; 411 | pub const XK_Tcedilla: c_uint = 0x1de; 412 | pub const XK_racute: c_uint = 0x1e0; 413 | pub const XK_abreve: c_uint = 0x1e3; 414 | pub const XK_lacute: c_uint = 0x1e5; 415 | pub const XK_cacute: c_uint = 0x1e6; 416 | pub const XK_ccaron: c_uint = 0x1e8; 417 | pub const XK_eogonek: c_uint = 0x1ea; 418 | pub const XK_ecaron: c_uint = 0x1ec; 419 | pub const XK_dcaron: c_uint = 0x1ef; 420 | pub const XK_dstroke: c_uint = 0x1f0; 421 | pub const XK_nacute: c_uint = 0x1f1; 422 | pub const XK_ncaron: c_uint = 0x1f2; 423 | pub const XK_odoubleacute: c_uint = 0x1f5; 424 | pub const XK_udoubleacute: c_uint = 0x1fb; 425 | pub const XK_rcaron: c_uint = 0x1f8; 426 | pub const XK_uring: c_uint = 0x1f9; 427 | pub const XK_tcedilla: c_uint = 0x1fe; 428 | pub const XK_abovedot: c_uint = 0x1ff; 429 | pub const XK_Hstroke: c_uint = 0x2a1; 430 | pub const XK_Hcircumflex: c_uint = 0x2a6; 431 | pub const XK_Iabovedot: c_uint = 0x2a9; 432 | pub const XK_Gbreve: c_uint = 0x2ab; 433 | pub const XK_Jcircumflex: c_uint = 0x2ac; 434 | pub const XK_hstroke: c_uint = 0x2b1; 435 | pub const XK_hcircumflex: c_uint = 0x2b6; 436 | pub const XK_idotless: c_uint = 0x2b9; 437 | pub const XK_gbreve: c_uint = 0x2bb; 438 | pub const XK_jcircumflex: c_uint = 0x2bc; 439 | pub const XK_Cabovedot: c_uint = 0x2c5; 440 | pub const XK_Ccircumflex: c_uint = 0x2c6; 441 | pub const XK_Gabovedot: c_uint = 0x2d5; 442 | pub const XK_Gcircumflex: c_uint = 0x2d8; 443 | pub const XK_Ubreve: c_uint = 0x2dd; 444 | pub const XK_Scircumflex: c_uint = 0x2de; 445 | pub const XK_cabovedot: c_uint = 0x2e5; 446 | pub const XK_ccircumflex: c_uint = 0x2e6; 447 | pub const XK_gabovedot: c_uint = 0x2f5; 448 | pub const XK_gcircumflex: c_uint = 0x2f8; 449 | pub const XK_ubreve: c_uint = 0x2fd; 450 | pub const XK_scircumflex: c_uint = 0x2fe; 451 | pub const XK_kra: c_uint = 0x3a2; 452 | pub const XK_kappa: c_uint = 0x3a2; 453 | pub const XK_Rcedilla: c_uint = 0x3a3; 454 | pub const XK_Itilde: c_uint = 0x3a5; 455 | pub const XK_Lcedilla: c_uint = 0x3a6; 456 | pub const XK_Emacron: c_uint = 0x3aa; 457 | pub const XK_Gcedilla: c_uint = 0x3ab; 458 | pub const XK_Tslash: c_uint = 0x3ac; 459 | pub const XK_rcedilla: c_uint = 0x3b3; 460 | pub const XK_itilde: c_uint = 0x3b5; 461 | pub const XK_lcedilla: c_uint = 0x3b6; 462 | pub const XK_emacron: c_uint = 0x3ba; 463 | pub const XK_gcedilla: c_uint = 0x3bb; 464 | pub const XK_tslash: c_uint = 0x3bc; 465 | pub const XK_ENG: c_uint = 0x3bd; 466 | pub const XK_eng: c_uint = 0x3bf; 467 | pub const XK_Amacron: c_uint = 0x3c0; 468 | pub const XK_Iogonek: c_uint = 0x3c7; 469 | pub const XK_Eabovedot: c_uint = 0x3cc; 470 | pub const XK_Imacron: c_uint = 0x3cf; 471 | pub const XK_Ncedilla: c_uint = 0x3d1; 472 | pub const XK_Omacron: c_uint = 0x3d2; 473 | pub const XK_Kcedilla: c_uint = 0x3d3; 474 | pub const XK_Uogonek: c_uint = 0x3d9; 475 | pub const XK_Utilde: c_uint = 0x3dd; 476 | pub const XK_Umacron: c_uint = 0x3de; 477 | pub const XK_amacron: c_uint = 0x3e0; 478 | pub const XK_iogonek: c_uint = 0x3e7; 479 | pub const XK_eabovedot: c_uint = 0x3ec; 480 | pub const XK_imacron: c_uint = 0x3ef; 481 | pub const XK_ncedilla: c_uint = 0x3f1; 482 | pub const XK_omacron: c_uint = 0x3f2; 483 | pub const XK_kcedilla: c_uint = 0x3f3; 484 | pub const XK_uogonek: c_uint = 0x3f9; 485 | pub const XK_utilde: c_uint = 0x3fd; 486 | pub const XK_umacron: c_uint = 0x3fe; 487 | pub const XK_overline: c_uint = 0x47e; 488 | pub const XK_kana_fullstop: c_uint = 0x4a1; 489 | pub const XK_kana_openingbracket: c_uint = 0x4a2; 490 | pub const XK_kana_closingbracket: c_uint = 0x4a3; 491 | pub const XK_kana_comma: c_uint = 0x4a4; 492 | pub const XK_kana_conjunctive: c_uint = 0x4a5; 493 | pub const XK_kana_middledot: c_uint = 0x4a5; 494 | pub const XK_kana_WO: c_uint = 0x4a6; 495 | pub const XK_kana_a: c_uint = 0x4a7; 496 | pub const XK_kana_i: c_uint = 0x4a8; 497 | pub const XK_kana_u: c_uint = 0x4a9; 498 | pub const XK_kana_e: c_uint = 0x4aa; 499 | pub const XK_kana_o: c_uint = 0x4ab; 500 | pub const XK_kana_ya: c_uint = 0x4ac; 501 | pub const XK_kana_yu: c_uint = 0x4ad; 502 | pub const XK_kana_yo: c_uint = 0x4ae; 503 | pub const XK_kana_tsu: c_uint = 0x4af; 504 | pub const XK_kana_tu: c_uint = 0x4af; 505 | pub const XK_prolongedsound: c_uint = 0x4b0; 506 | pub const XK_kana_A: c_uint = 0x4b1; 507 | pub const XK_kana_I: c_uint = 0x4b2; 508 | pub const XK_kana_U: c_uint = 0x4b3; 509 | pub const XK_kana_E: c_uint = 0x4b4; 510 | pub const XK_kana_O: c_uint = 0x4b5; 511 | pub const XK_kana_KA: c_uint = 0x4b6; 512 | pub const XK_kana_KI: c_uint = 0x4b7; 513 | pub const XK_kana_KU: c_uint = 0x4b8; 514 | pub const XK_kana_KE: c_uint = 0x4b9; 515 | pub const XK_kana_KO: c_uint = 0x4ba; 516 | pub const XK_kana_SA: c_uint = 0x4bb; 517 | pub const XK_kana_SHI: c_uint = 0x4bc; 518 | pub const XK_kana_SU: c_uint = 0x4bd; 519 | pub const XK_kana_SE: c_uint = 0x4be; 520 | pub const XK_kana_SO: c_uint = 0x4bf; 521 | pub const XK_kana_TA: c_uint = 0x4c0; 522 | pub const XK_kana_CHI: c_uint = 0x4c1; 523 | pub const XK_kana_TI: c_uint = 0x4c1; 524 | pub const XK_kana_TSU: c_uint = 0x4c2; 525 | pub const XK_kana_TU: c_uint = 0x4c2; 526 | pub const XK_kana_TE: c_uint = 0x4c3; 527 | pub const XK_kana_TO: c_uint = 0x4c4; 528 | pub const XK_kana_NA: c_uint = 0x4c5; 529 | pub const XK_kana_NI: c_uint = 0x4c6; 530 | pub const XK_kana_NU: c_uint = 0x4c7; 531 | pub const XK_kana_NE: c_uint = 0x4c8; 532 | pub const XK_kana_NO: c_uint = 0x4c9; 533 | pub const XK_kana_HA: c_uint = 0x4ca; 534 | pub const XK_kana_HI: c_uint = 0x4cb; 535 | pub const XK_kana_FU: c_uint = 0x4cc; 536 | pub const XK_kana_HU: c_uint = 0x4cc; 537 | pub const XK_kana_HE: c_uint = 0x4cd; 538 | pub const XK_kana_HO: c_uint = 0x4ce; 539 | pub const XK_kana_MA: c_uint = 0x4cf; 540 | pub const XK_kana_MI: c_uint = 0x4d0; 541 | pub const XK_kana_MU: c_uint = 0x4d1; 542 | pub const XK_kana_ME: c_uint = 0x4d2; 543 | pub const XK_kana_MO: c_uint = 0x4d3; 544 | pub const XK_kana_YA: c_uint = 0x4d4; 545 | pub const XK_kana_YU: c_uint = 0x4d5; 546 | pub const XK_kana_YO: c_uint = 0x4d6; 547 | pub const XK_kana_RA: c_uint = 0x4d7; 548 | pub const XK_kana_RI: c_uint = 0x4d8; 549 | pub const XK_kana_RU: c_uint = 0x4d9; 550 | pub const XK_kana_RE: c_uint = 0x4da; 551 | pub const XK_kana_RO: c_uint = 0x4db; 552 | pub const XK_kana_WA: c_uint = 0x4dc; 553 | pub const XK_kana_N: c_uint = 0x4dd; 554 | pub const XK_voicedsound: c_uint = 0x4de; 555 | pub const XK_semivoicedsound: c_uint = 0x4df; 556 | pub const XK_kana_switch: c_uint = 0xFF7E; 557 | pub const XK_Arabic_comma: c_uint = 0x5ac; 558 | pub const XK_Arabic_semicolon: c_uint = 0x5bb; 559 | pub const XK_Arabic_question_mark: c_uint = 0x5bf; 560 | pub const XK_Arabic_hamza: c_uint = 0x5c1; 561 | pub const XK_Arabic_maddaonalef: c_uint = 0x5c2; 562 | pub const XK_Arabic_hamzaonalef: c_uint = 0x5c3; 563 | pub const XK_Arabic_hamzaonwaw: c_uint = 0x5c4; 564 | pub const XK_Arabic_hamzaunderalef: c_uint = 0x5c5; 565 | pub const XK_Arabic_hamzaonyeh: c_uint = 0x5c6; 566 | pub const XK_Arabic_alef: c_uint = 0x5c7; 567 | pub const XK_Arabic_beh: c_uint = 0x5c8; 568 | pub const XK_Arabic_tehmarbuta: c_uint = 0x5c9; 569 | pub const XK_Arabic_teh: c_uint = 0x5ca; 570 | pub const XK_Arabic_theh: c_uint = 0x5cb; 571 | pub const XK_Arabic_jeem: c_uint = 0x5cc; 572 | pub const XK_Arabic_hah: c_uint = 0x5cd; 573 | pub const XK_Arabic_khah: c_uint = 0x5ce; 574 | pub const XK_Arabic_dal: c_uint = 0x5cf; 575 | pub const XK_Arabic_thal: c_uint = 0x5d0; 576 | pub const XK_Arabic_ra: c_uint = 0x5d1; 577 | pub const XK_Arabic_zain: c_uint = 0x5d2; 578 | pub const XK_Arabic_seen: c_uint = 0x5d3; 579 | pub const XK_Arabic_sheen: c_uint = 0x5d4; 580 | pub const XK_Arabic_sad: c_uint = 0x5d5; 581 | pub const XK_Arabic_dad: c_uint = 0x5d6; 582 | pub const XK_Arabic_tah: c_uint = 0x5d7; 583 | pub const XK_Arabic_zah: c_uint = 0x5d8; 584 | pub const XK_Arabic_ain: c_uint = 0x5d9; 585 | pub const XK_Arabic_ghain: c_uint = 0x5da; 586 | pub const XK_Arabic_tatweel: c_uint = 0x5e0; 587 | pub const XK_Arabic_feh: c_uint = 0x5e1; 588 | pub const XK_Arabic_qaf: c_uint = 0x5e2; 589 | pub const XK_Arabic_kaf: c_uint = 0x5e3; 590 | pub const XK_Arabic_lam: c_uint = 0x5e4; 591 | pub const XK_Arabic_meem: c_uint = 0x5e5; 592 | pub const XK_Arabic_noon: c_uint = 0x5e6; 593 | pub const XK_Arabic_ha: c_uint = 0x5e7; 594 | pub const XK_Arabic_heh: c_uint = 0x5e7; 595 | pub const XK_Arabic_waw: c_uint = 0x5e8; 596 | pub const XK_Arabic_alefmaksura: c_uint = 0x5e9; 597 | pub const XK_Arabic_yeh: c_uint = 0x5ea; 598 | pub const XK_Arabic_fathatan: c_uint = 0x5eb; 599 | pub const XK_Arabic_dammatan: c_uint = 0x5ec; 600 | pub const XK_Arabic_kasratan: c_uint = 0x5ed; 601 | pub const XK_Arabic_fatha: c_uint = 0x5ee; 602 | pub const XK_Arabic_damma: c_uint = 0x5ef; 603 | pub const XK_Arabic_kasra: c_uint = 0x5f0; 604 | pub const XK_Arabic_shadda: c_uint = 0x5f1; 605 | pub const XK_Arabic_sukun: c_uint = 0x5f2; 606 | pub const XK_Arabic_switch: c_uint = 0xFF7E; 607 | pub const XK_Serbian_dje: c_uint = 0x6a1; 608 | pub const XK_Macedonia_gje: c_uint = 0x6a2; 609 | pub const XK_Cyrillic_io: c_uint = 0x6a3; 610 | pub const XK_Ukrainian_ie: c_uint = 0x6a4; 611 | pub const XK_Ukranian_je: c_uint = 0x6a4; 612 | pub const XK_Macedonia_dse: c_uint = 0x6a5; 613 | pub const XK_Ukrainian_i: c_uint = 0x6a6; 614 | pub const XK_Ukranian_i: c_uint = 0x6a6; 615 | pub const XK_Ukrainian_yi: c_uint = 0x6a7; 616 | pub const XK_Ukranian_yi: c_uint = 0x6a7; 617 | pub const XK_Cyrillic_je: c_uint = 0x6a8; 618 | pub const XK_Serbian_je: c_uint = 0x6a8; 619 | pub const XK_Cyrillic_lje: c_uint = 0x6a9; 620 | pub const XK_Serbian_lje: c_uint = 0x6a9; 621 | pub const XK_Cyrillic_nje: c_uint = 0x6aa; 622 | pub const XK_Serbian_nje: c_uint = 0x6aa; 623 | pub const XK_Serbian_tshe: c_uint = 0x6ab; 624 | pub const XK_Macedonia_kje: c_uint = 0x6ac; 625 | pub const XK_Byelorussian_shortu: c_uint = 0x6ae; 626 | pub const XK_Cyrillic_dzhe: c_uint = 0x6af; 627 | pub const XK_Serbian_dze: c_uint = 0x6af; 628 | pub const XK_numerosign: c_uint = 0x6b0; 629 | pub const XK_Serbian_DJE: c_uint = 0x6b1; 630 | pub const XK_Macedonia_GJE: c_uint = 0x6b2; 631 | pub const XK_Cyrillic_IO: c_uint = 0x6b3; 632 | pub const XK_Ukrainian_IE: c_uint = 0x6b4; 633 | pub const XK_Ukranian_JE: c_uint = 0x6b4; 634 | pub const XK_Macedonia_DSE: c_uint = 0x6b5; 635 | pub const XK_Ukrainian_I: c_uint = 0x6b6; 636 | pub const XK_Ukranian_I: c_uint = 0x6b6; 637 | pub const XK_Ukrainian_YI: c_uint = 0x6b7; 638 | pub const XK_Ukranian_YI: c_uint = 0x6b7; 639 | pub const XK_Cyrillic_JE: c_uint = 0x6b8; 640 | pub const XK_Serbian_JE: c_uint = 0x6b8; 641 | pub const XK_Cyrillic_LJE: c_uint = 0x6b9; 642 | pub const XK_Serbian_LJE: c_uint = 0x6b9; 643 | pub const XK_Cyrillic_NJE: c_uint = 0x6ba; 644 | pub const XK_Serbian_NJE: c_uint = 0x6ba; 645 | pub const XK_Serbian_TSHE: c_uint = 0x6bb; 646 | pub const XK_Macedonia_KJE: c_uint = 0x6bc; 647 | pub const XK_Byelorussian_SHORTU: c_uint = 0x6be; 648 | pub const XK_Cyrillic_DZHE: c_uint = 0x6bf; 649 | pub const XK_Serbian_DZE: c_uint = 0x6bf; 650 | pub const XK_Cyrillic_yu: c_uint = 0x6c0; 651 | pub const XK_Cyrillic_a: c_uint = 0x6c1; 652 | pub const XK_Cyrillic_be: c_uint = 0x6c2; 653 | pub const XK_Cyrillic_tse: c_uint = 0x6c3; 654 | pub const XK_Cyrillic_de: c_uint = 0x6c4; 655 | pub const XK_Cyrillic_ie: c_uint = 0x6c5; 656 | pub const XK_Cyrillic_ef: c_uint = 0x6c6; 657 | pub const XK_Cyrillic_ghe: c_uint = 0x6c7; 658 | pub const XK_Cyrillic_ha: c_uint = 0x6c8; 659 | pub const XK_Cyrillic_i: c_uint = 0x6c9; 660 | pub const XK_Cyrillic_shorti: c_uint = 0x6ca; 661 | pub const XK_Cyrillic_ka: c_uint = 0x6cb; 662 | pub const XK_Cyrillic_el: c_uint = 0x6cc; 663 | pub const XK_Cyrillic_em: c_uint = 0x6cd; 664 | pub const XK_Cyrillic_en: c_uint = 0x6ce; 665 | pub const XK_Cyrillic_o: c_uint = 0x6cf; 666 | pub const XK_Cyrillic_pe: c_uint = 0x6d0; 667 | pub const XK_Cyrillic_ya: c_uint = 0x6d1; 668 | pub const XK_Cyrillic_er: c_uint = 0x6d2; 669 | pub const XK_Cyrillic_es: c_uint = 0x6d3; 670 | pub const XK_Cyrillic_te: c_uint = 0x6d4; 671 | pub const XK_Cyrillic_u: c_uint = 0x6d5; 672 | pub const XK_Cyrillic_zhe: c_uint = 0x6d6; 673 | pub const XK_Cyrillic_ve: c_uint = 0x6d7; 674 | pub const XK_Cyrillic_softsign: c_uint = 0x6d8; 675 | pub const XK_Cyrillic_yeru: c_uint = 0x6d9; 676 | pub const XK_Cyrillic_ze: c_uint = 0x6da; 677 | pub const XK_Cyrillic_sha: c_uint = 0x6db; 678 | pub const XK_Cyrillic_e: c_uint = 0x6dc; 679 | pub const XK_Cyrillic_shcha: c_uint = 0x6dd; 680 | pub const XK_Cyrillic_che: c_uint = 0x6de; 681 | pub const XK_Cyrillic_hardsign: c_uint = 0x6df; 682 | pub const XK_Cyrillic_YU: c_uint = 0x6e0; 683 | pub const XK_Cyrillic_A: c_uint = 0x6e1; 684 | pub const XK_Cyrillic_BE: c_uint = 0x6e2; 685 | pub const XK_Cyrillic_TSE: c_uint = 0x6e3; 686 | pub const XK_Cyrillic_DE: c_uint = 0x6e4; 687 | pub const XK_Cyrillic_IE: c_uint = 0x6e5; 688 | pub const XK_Cyrillic_EF: c_uint = 0x6e6; 689 | pub const XK_Cyrillic_GHE: c_uint = 0x6e7; 690 | pub const XK_Cyrillic_HA: c_uint = 0x6e8; 691 | pub const XK_Cyrillic_I: c_uint = 0x6e9; 692 | pub const XK_Cyrillic_SHORTI: c_uint = 0x6ea; 693 | pub const XK_Cyrillic_KA: c_uint = 0x6eb; 694 | pub const XK_Cyrillic_EL: c_uint = 0x6ec; 695 | pub const XK_Cyrillic_EM: c_uint = 0x6ed; 696 | pub const XK_Cyrillic_EN: c_uint = 0x6ee; 697 | pub const XK_Cyrillic_O: c_uint = 0x6ef; 698 | pub const XK_Cyrillic_PE: c_uint = 0x6f0; 699 | pub const XK_Cyrillic_YA: c_uint = 0x6f1; 700 | pub const XK_Cyrillic_ER: c_uint = 0x6f2; 701 | pub const XK_Cyrillic_ES: c_uint = 0x6f3; 702 | pub const XK_Cyrillic_TE: c_uint = 0x6f4; 703 | pub const XK_Cyrillic_U: c_uint = 0x6f5; 704 | pub const XK_Cyrillic_ZHE: c_uint = 0x6f6; 705 | pub const XK_Cyrillic_VE: c_uint = 0x6f7; 706 | pub const XK_Cyrillic_SOFTSIGN: c_uint = 0x6f8; 707 | pub const XK_Cyrillic_YERU: c_uint = 0x6f9; 708 | pub const XK_Cyrillic_ZE: c_uint = 0x6fa; 709 | pub const XK_Cyrillic_SHA: c_uint = 0x6fb; 710 | pub const XK_Cyrillic_E: c_uint = 0x6fc; 711 | pub const XK_Cyrillic_SHCHA: c_uint = 0x6fd; 712 | pub const XK_Cyrillic_CHE: c_uint = 0x6fe; 713 | pub const XK_Cyrillic_HARDSIGN: c_uint = 0x6ff; 714 | pub const XK_Greek_ALPHAaccent: c_uint = 0x7a1; 715 | pub const XK_Greek_EPSILONaccent: c_uint = 0x7a2; 716 | pub const XK_Greek_ETAaccent: c_uint = 0x7a3; 717 | pub const XK_Greek_IOTAaccent: c_uint = 0x7a4; 718 | pub const XK_Greek_IOTAdiaeresis: c_uint = 0x7a5; 719 | pub const XK_Greek_OMICRONaccent: c_uint = 0x7a7; 720 | pub const XK_Greek_UPSILONaccent: c_uint = 0x7a8; 721 | pub const XK_Greek_UPSILONdieresis: c_uint = 0x7a9; 722 | pub const XK_Greek_OMEGAaccent: c_uint = 0x7ab; 723 | pub const XK_Greek_accentdieresis: c_uint = 0x7ae; 724 | pub const XK_Greek_horizbar: c_uint = 0x7af; 725 | pub const XK_Greek_alphaaccent: c_uint = 0x7b1; 726 | pub const XK_Greek_epsilonaccent: c_uint = 0x7b2; 727 | pub const XK_Greek_etaaccent: c_uint = 0x7b3; 728 | pub const XK_Greek_iotaaccent: c_uint = 0x7b4; 729 | pub const XK_Greek_iotadieresis: c_uint = 0x7b5; 730 | pub const XK_Greek_iotaaccentdieresis: c_uint = 0x7b6; 731 | pub const XK_Greek_omicronaccent: c_uint = 0x7b7; 732 | pub const XK_Greek_upsilonaccent: c_uint = 0x7b8; 733 | pub const XK_Greek_upsilondieresis: c_uint = 0x7b9; 734 | pub const XK_Greek_upsilonaccentdieresis: c_uint = 0x7ba; 735 | pub const XK_Greek_omegaaccent: c_uint = 0x7bb; 736 | pub const XK_Greek_ALPHA: c_uint = 0x7c1; 737 | pub const XK_Greek_BETA: c_uint = 0x7c2; 738 | pub const XK_Greek_GAMMA: c_uint = 0x7c3; 739 | pub const XK_Greek_DELTA: c_uint = 0x7c4; 740 | pub const XK_Greek_EPSILON: c_uint = 0x7c5; 741 | pub const XK_Greek_ZETA: c_uint = 0x7c6; 742 | pub const XK_Greek_ETA: c_uint = 0x7c7; 743 | pub const XK_Greek_THETA: c_uint = 0x7c8; 744 | pub const XK_Greek_IOTA: c_uint = 0x7c9; 745 | pub const XK_Greek_KAPPA: c_uint = 0x7ca; 746 | pub const XK_Greek_LAMDA: c_uint = 0x7cb; 747 | pub const XK_Greek_LAMBDA: c_uint = 0x7cb; 748 | pub const XK_Greek_MU: c_uint = 0x7cc; 749 | pub const XK_Greek_NU: c_uint = 0x7cd; 750 | pub const XK_Greek_XI: c_uint = 0x7ce; 751 | pub const XK_Greek_OMICRON: c_uint = 0x7cf; 752 | pub const XK_Greek_PI: c_uint = 0x7d0; 753 | pub const XK_Greek_RHO: c_uint = 0x7d1; 754 | pub const XK_Greek_SIGMA: c_uint = 0x7d2; 755 | pub const XK_Greek_TAU: c_uint = 0x7d4; 756 | pub const XK_Greek_UPSILON: c_uint = 0x7d5; 757 | pub const XK_Greek_PHI: c_uint = 0x7d6; 758 | pub const XK_Greek_CHI: c_uint = 0x7d7; 759 | pub const XK_Greek_PSI: c_uint = 0x7d8; 760 | pub const XK_Greek_OMEGA: c_uint = 0x7d9; 761 | pub const XK_Greek_alpha: c_uint = 0x7e1; 762 | pub const XK_Greek_beta: c_uint = 0x7e2; 763 | pub const XK_Greek_gamma: c_uint = 0x7e3; 764 | pub const XK_Greek_delta: c_uint = 0x7e4; 765 | pub const XK_Greek_epsilon: c_uint = 0x7e5; 766 | pub const XK_Greek_zeta: c_uint = 0x7e6; 767 | pub const XK_Greek_eta: c_uint = 0x7e7; 768 | pub const XK_Greek_theta: c_uint = 0x7e8; 769 | pub const XK_Greek_iota: c_uint = 0x7e9; 770 | pub const XK_Greek_kappa: c_uint = 0x7ea; 771 | pub const XK_Greek_lamda: c_uint = 0x7eb; 772 | pub const XK_Greek_lambda: c_uint = 0x7eb; 773 | pub const XK_Greek_mu: c_uint = 0x7ec; 774 | pub const XK_Greek_nu: c_uint = 0x7ed; 775 | pub const XK_Greek_xi: c_uint = 0x7ee; 776 | pub const XK_Greek_omicron: c_uint = 0x7ef; 777 | pub const XK_Greek_pi: c_uint = 0x7f0; 778 | pub const XK_Greek_rho: c_uint = 0x7f1; 779 | pub const XK_Greek_sigma: c_uint = 0x7f2; 780 | pub const XK_Greek_finalsmallsigma: c_uint = 0x7f3; 781 | pub const XK_Greek_tau: c_uint = 0x7f4; 782 | pub const XK_Greek_upsilon: c_uint = 0x7f5; 783 | pub const XK_Greek_phi: c_uint = 0x7f6; 784 | pub const XK_Greek_chi: c_uint = 0x7f7; 785 | pub const XK_Greek_psi: c_uint = 0x7f8; 786 | pub const XK_Greek_omega: c_uint = 0x7f9; 787 | pub const XK_Greek_switch: c_uint = 0xFF7E; 788 | pub const XK_leftradical: c_uint = 0x8a1; 789 | pub const XK_topleftradical: c_uint = 0x8a2; 790 | pub const XK_horizconnector: c_uint = 0x8a3; 791 | pub const XK_topintegral: c_uint = 0x8a4; 792 | pub const XK_botintegral: c_uint = 0x8a5; 793 | pub const XK_vertconnector: c_uint = 0x8a6; 794 | pub const XK_topleftsqbracket: c_uint = 0x8a7; 795 | pub const XK_botleftsqbracket: c_uint = 0x8a8; 796 | pub const XK_toprightsqbracket: c_uint = 0x8a9; 797 | pub const XK_botrightsqbracket: c_uint = 0x8aa; 798 | pub const XK_topleftparens: c_uint = 0x8ab; 799 | pub const XK_botleftparens: c_uint = 0x8ac; 800 | pub const XK_toprightparens: c_uint = 0x8ad; 801 | pub const XK_botrightparens: c_uint = 0x8ae; 802 | pub const XK_leftmiddlecurlybrace: c_uint = 0x8af; 803 | pub const XK_rightmiddlecurlybrace: c_uint = 0x8b0; 804 | pub const XK_topleftsummation: c_uint = 0x8b1; 805 | pub const XK_botleftsummation: c_uint = 0x8b2; 806 | pub const XK_topvertsummationconnector: c_uint = 0x8b3; 807 | pub const XK_botvertsummationconnector: c_uint = 0x8b4; 808 | pub const XK_toprightsummation: c_uint = 0x8b5; 809 | pub const XK_botrightsummation: c_uint = 0x8b6; 810 | pub const XK_rightmiddlesummation: c_uint = 0x8b7; 811 | pub const XK_lessthanequal: c_uint = 0x8bc; 812 | pub const XK_notequal: c_uint = 0x8bd; 813 | pub const XK_greaterthanequal: c_uint = 0x8be; 814 | pub const XK_integral: c_uint = 0x8bf; 815 | pub const XK_therefore: c_uint = 0x8c0; 816 | pub const XK_variation: c_uint = 0x8c1; 817 | pub const XK_infinity: c_uint = 0x8c2; 818 | pub const XK_nabla: c_uint = 0x8c5; 819 | pub const XK_approximate: c_uint = 0x8c8; 820 | pub const XK_similarequal: c_uint = 0x8c9; 821 | pub const XK_ifonlyif: c_uint = 0x8cd; 822 | pub const XK_implies: c_uint = 0x8ce; 823 | pub const XK_identical: c_uint = 0x8cf; 824 | pub const XK_radical: c_uint = 0x8d6; 825 | pub const XK_includedin: c_uint = 0x8da; 826 | pub const XK_includes: c_uint = 0x8db; 827 | pub const XK_intersection: c_uint = 0x8dc; 828 | pub const XK_union: c_uint = 0x8dd; 829 | pub const XK_logicaland: c_uint = 0x8de; 830 | pub const XK_logicalor: c_uint = 0x8df; 831 | pub const XK_partialderivative: c_uint = 0x8ef; 832 | pub const XK_function: c_uint = 0x8f6; 833 | pub const XK_leftarrow: c_uint = 0x8fb; 834 | pub const XK_uparrow: c_uint = 0x8fc; 835 | pub const XK_rightarrow: c_uint = 0x8fd; 836 | pub const XK_downarrow: c_uint = 0x8fe; 837 | pub const XK_blank: c_uint = 0x9df; 838 | pub const XK_soliddiamond: c_uint = 0x9e0; 839 | pub const XK_checkerboard: c_uint = 0x9e1; 840 | pub const XK_ht: c_uint = 0x9e2; 841 | pub const XK_ff: c_uint = 0x9e3; 842 | pub const XK_cr: c_uint = 0x9e4; 843 | pub const XK_lf: c_uint = 0x9e5; 844 | pub const XK_nl: c_uint = 0x9e8; 845 | pub const XK_vt: c_uint = 0x9e9; 846 | pub const XK_lowrightcorner: c_uint = 0x9ea; 847 | pub const XK_uprightcorner: c_uint = 0x9eb; 848 | pub const XK_upleftcorner: c_uint = 0x9ec; 849 | pub const XK_lowleftcorner: c_uint = 0x9ed; 850 | pub const XK_crossinglines: c_uint = 0x9ee; 851 | pub const XK_horizlinescan1: c_uint = 0x9ef; 852 | pub const XK_horizlinescan3: c_uint = 0x9f0; 853 | pub const XK_horizlinescan5: c_uint = 0x9f1; 854 | pub const XK_horizlinescan7: c_uint = 0x9f2; 855 | pub const XK_horizlinescan9: c_uint = 0x9f3; 856 | pub const XK_leftt: c_uint = 0x9f4; 857 | pub const XK_rightt: c_uint = 0x9f5; 858 | pub const XK_bott: c_uint = 0x9f6; 859 | pub const XK_topt: c_uint = 0x9f7; 860 | pub const XK_vertbar: c_uint = 0x9f8; 861 | pub const XK_emspace: c_uint = 0xaa1; 862 | pub const XK_enspace: c_uint = 0xaa2; 863 | pub const XK_em3space: c_uint = 0xaa3; 864 | pub const XK_em4space: c_uint = 0xaa4; 865 | pub const XK_digitspace: c_uint = 0xaa5; 866 | pub const XK_punctspace: c_uint = 0xaa6; 867 | pub const XK_thinspace: c_uint = 0xaa7; 868 | pub const XK_hairspace: c_uint = 0xaa8; 869 | pub const XK_emdash: c_uint = 0xaa9; 870 | pub const XK_endash: c_uint = 0xaaa; 871 | pub const XK_signifblank: c_uint = 0xaac; 872 | pub const XK_ellipsis: c_uint = 0xaae; 873 | pub const XK_doubbaselinedot: c_uint = 0xaaf; 874 | pub const XK_onethird: c_uint = 0xab0; 875 | pub const XK_twothirds: c_uint = 0xab1; 876 | pub const XK_onefifth: c_uint = 0xab2; 877 | pub const XK_twofifths: c_uint = 0xab3; 878 | pub const XK_threefifths: c_uint = 0xab4; 879 | pub const XK_fourfifths: c_uint = 0xab5; 880 | pub const XK_onesixth: c_uint = 0xab6; 881 | pub const XK_fivesixths: c_uint = 0xab7; 882 | pub const XK_careof: c_uint = 0xab8; 883 | pub const XK_figdash: c_uint = 0xabb; 884 | pub const XK_leftanglebracket: c_uint = 0xabc; 885 | pub const XK_decimalpoint: c_uint = 0xabd; 886 | pub const XK_rightanglebracket: c_uint = 0xabe; 887 | pub const XK_marker: c_uint = 0xabf; 888 | pub const XK_oneeighth: c_uint = 0xac3; 889 | pub const XK_threeeighths: c_uint = 0xac4; 890 | pub const XK_fiveeighths: c_uint = 0xac5; 891 | pub const XK_seveneighths: c_uint = 0xac6; 892 | pub const XK_trademark: c_uint = 0xac9; 893 | pub const XK_signaturemark: c_uint = 0xaca; 894 | pub const XK_trademarkincircle: c_uint = 0xacb; 895 | pub const XK_leftopentriangle: c_uint = 0xacc; 896 | pub const XK_rightopentriangle: c_uint = 0xacd; 897 | pub const XK_emopencircle: c_uint = 0xace; 898 | pub const XK_emopenrectangle: c_uint = 0xacf; 899 | pub const XK_leftsinglequotemark: c_uint = 0xad0; 900 | pub const XK_rightsinglequotemark: c_uint = 0xad1; 901 | pub const XK_leftdoublequotemark: c_uint = 0xad2; 902 | pub const XK_rightdoublequotemark: c_uint = 0xad3; 903 | pub const XK_prescription: c_uint = 0xad4; 904 | pub const XK_minutes: c_uint = 0xad6; 905 | pub const XK_seconds: c_uint = 0xad7; 906 | pub const XK_latincross: c_uint = 0xad9; 907 | pub const XK_hexagram: c_uint = 0xada; 908 | pub const XK_filledrectbullet: c_uint = 0xadb; 909 | pub const XK_filledlefttribullet: c_uint = 0xadc; 910 | pub const XK_filledrighttribullet: c_uint = 0xadd; 911 | pub const XK_emfilledcircle: c_uint = 0xade; 912 | pub const XK_emfilledrect: c_uint = 0xadf; 913 | pub const XK_enopencircbullet: c_uint = 0xae0; 914 | pub const XK_enopensquarebullet: c_uint = 0xae1; 915 | pub const XK_openrectbullet: c_uint = 0xae2; 916 | pub const XK_opentribulletup: c_uint = 0xae3; 917 | pub const XK_opentribulletdown: c_uint = 0xae4; 918 | pub const XK_openstar: c_uint = 0xae5; 919 | pub const XK_enfilledcircbullet: c_uint = 0xae6; 920 | pub const XK_enfilledsqbullet: c_uint = 0xae7; 921 | pub const XK_filledtribulletup: c_uint = 0xae8; 922 | pub const XK_filledtribulletdown: c_uint = 0xae9; 923 | pub const XK_leftpointer: c_uint = 0xaea; 924 | pub const XK_rightpointer: c_uint = 0xaeb; 925 | pub const XK_club: c_uint = 0xaec; 926 | pub const XK_diamond: c_uint = 0xaed; 927 | pub const XK_heart: c_uint = 0xaee; 928 | pub const XK_maltesecross: c_uint = 0xaf0; 929 | pub const XK_dagger: c_uint = 0xaf1; 930 | pub const XK_doubledagger: c_uint = 0xaf2; 931 | pub const XK_checkmark: c_uint = 0xaf3; 932 | pub const XK_ballotcross: c_uint = 0xaf4; 933 | pub const XK_musicalsharp: c_uint = 0xaf5; 934 | pub const XK_musicalflat: c_uint = 0xaf6; 935 | pub const XK_malesymbol: c_uint = 0xaf7; 936 | pub const XK_femalesymbol: c_uint = 0xaf8; 937 | pub const XK_telephone: c_uint = 0xaf9; 938 | pub const XK_telephonerecorder: c_uint = 0xafa; 939 | pub const XK_phonographcopyright: c_uint = 0xafb; 940 | pub const XK_caret: c_uint = 0xafc; 941 | pub const XK_singlelowquotemark: c_uint = 0xafd; 942 | pub const XK_doublelowquotemark: c_uint = 0xafe; 943 | pub const XK_cursor: c_uint = 0xaff; 944 | pub const XK_leftcaret: c_uint = 0xba3; 945 | pub const XK_rightcaret: c_uint = 0xba6; 946 | pub const XK_downcaret: c_uint = 0xba8; 947 | pub const XK_upcaret: c_uint = 0xba9; 948 | pub const XK_overbar: c_uint = 0xbc0; 949 | pub const XK_downtack: c_uint = 0xbc2; 950 | pub const XK_upshoe: c_uint = 0xbc3; 951 | pub const XK_downstile: c_uint = 0xbc4; 952 | pub const XK_underbar: c_uint = 0xbc6; 953 | pub const XK_jot: c_uint = 0xbca; 954 | pub const XK_quad: c_uint = 0xbcc; 955 | pub const XK_uptack: c_uint = 0xbce; 956 | pub const XK_circle: c_uint = 0xbcf; 957 | pub const XK_upstile: c_uint = 0xbd3; 958 | pub const XK_downshoe: c_uint = 0xbd6; 959 | pub const XK_rightshoe: c_uint = 0xbd8; 960 | pub const XK_leftshoe: c_uint = 0xbda; 961 | pub const XK_lefttack: c_uint = 0xbdc; 962 | pub const XK_righttack: c_uint = 0xbfc; 963 | pub const XK_hebrew_doublelowline: c_uint = 0xcdf; 964 | pub const XK_hebrew_aleph: c_uint = 0xce0; 965 | pub const XK_hebrew_bet: c_uint = 0xce1; 966 | pub const XK_hebrew_beth: c_uint = 0xce1; 967 | pub const XK_hebrew_gimel: c_uint = 0xce2; 968 | pub const XK_hebrew_gimmel: c_uint = 0xce2; 969 | pub const XK_hebrew_dalet: c_uint = 0xce3; 970 | pub const XK_hebrew_daleth: c_uint = 0xce3; 971 | pub const XK_hebrew_he: c_uint = 0xce4; 972 | pub const XK_hebrew_waw: c_uint = 0xce5; 973 | pub const XK_hebrew_zain: c_uint = 0xce6; 974 | pub const XK_hebrew_zayin: c_uint = 0xce6; 975 | pub const XK_hebrew_chet: c_uint = 0xce7; 976 | pub const XK_hebrew_het: c_uint = 0xce7; 977 | pub const XK_hebrew_tet: c_uint = 0xce8; 978 | pub const XK_hebrew_teth: c_uint = 0xce8; 979 | pub const XK_hebrew_yod: c_uint = 0xce9; 980 | pub const XK_hebrew_finalkaph: c_uint = 0xcea; 981 | pub const XK_hebrew_kaph: c_uint = 0xceb; 982 | pub const XK_hebrew_lamed: c_uint = 0xcec; 983 | pub const XK_hebrew_finalmem: c_uint = 0xced; 984 | pub const XK_hebrew_mem: c_uint = 0xcee; 985 | pub const XK_hebrew_finalnun: c_uint = 0xcef; 986 | pub const XK_hebrew_nun: c_uint = 0xcf0; 987 | pub const XK_hebrew_samech: c_uint = 0xcf1; 988 | pub const XK_hebrew_samekh: c_uint = 0xcf1; 989 | pub const XK_hebrew_ayin: c_uint = 0xcf2; 990 | pub const XK_hebrew_finalpe: c_uint = 0xcf3; 991 | pub const XK_hebrew_pe: c_uint = 0xcf4; 992 | pub const XK_hebrew_finalzade: c_uint = 0xcf5; 993 | pub const XK_hebrew_finalzadi: c_uint = 0xcf5; 994 | pub const XK_hebrew_zade: c_uint = 0xcf6; 995 | pub const XK_hebrew_zadi: c_uint = 0xcf6; 996 | pub const XK_hebrew_qoph: c_uint = 0xcf7; 997 | pub const XK_hebrew_kuf: c_uint = 0xcf7; 998 | pub const XK_hebrew_resh: c_uint = 0xcf8; 999 | pub const XK_hebrew_shin: c_uint = 0xcf9; 1000 | pub const XK_hebrew_taw: c_uint = 0xcfa; 1001 | pub const XK_hebrew_taf: c_uint = 0xcfa; 1002 | pub const XK_Hebrew_switch: c_uint = 0xFF7E; 1003 | 1004 | pub const XF86XK_ModeLock: c_uint = 0x1008FF01; 1005 | pub const XF86XK_MonBrightnessUp: c_uint = 0x1008FF02; 1006 | pub const XF86XK_MonBrightnessDown: c_uint = 0x1008FF03; 1007 | pub const XF86XK_KbdLightOnOff: c_uint = 0x1008FF04; 1008 | pub const XF86XK_KbdBrightnessUp: c_uint = 0x1008FF05; 1009 | pub const XF86XK_KbdBrightnessDown: c_uint = 0x1008FF06; 1010 | pub const XF86XK_Standby: c_uint = 0x1008FF10; 1011 | pub const XF86XK_AudioLowerVolume: c_uint = 0x1008FF11; 1012 | pub const XF86XK_AudioMute: c_uint = 0x1008FF12; 1013 | pub const XF86XK_AudioRaiseVolume: c_uint = 0x1008FF13; 1014 | pub const XF86XK_AudioPlay: c_uint = 0x1008FF14; 1015 | pub const XF86XK_AudioStop: c_uint = 0x1008FF15; 1016 | pub const XF86XK_AudioPrev: c_uint = 0x1008FF16; 1017 | pub const XF86XK_AudioNext: c_uint = 0x1008FF17; 1018 | pub const XF86XK_HomePage: c_uint = 0x1008FF18; 1019 | pub const XF86XK_Mail: c_uint = 0x1008FF19; 1020 | pub const XF86XK_Start: c_uint = 0x1008FF1A; 1021 | pub const XF86XK_Search: c_uint = 0x1008FF1B; 1022 | pub const XF86XK_AudioRecord: c_uint = 0x1008FF1C; 1023 | pub const XF86XK_Calculator: c_uint = 0x1008FF1D; 1024 | pub const XF86XK_Memo: c_uint = 0x1008FF1E; 1025 | pub const XF86XK_ToDoList: c_uint = 0x1008FF1F; 1026 | pub const XF86XK_Calendar: c_uint = 0x1008FF20; 1027 | pub const XF86XK_PowerDown: c_uint = 0x1008FF21; 1028 | pub const XF86XK_ContrastAdjust: c_uint = 0x1008FF22; 1029 | pub const XF86XK_RockerUp: c_uint = 0x1008FF23; 1030 | pub const XF86XK_RockerDown: c_uint = 0x1008FF24; 1031 | pub const XF86XK_RockerEnter: c_uint = 0x1008FF25; 1032 | pub const XF86XK_Back: c_uint = 0x1008FF26; 1033 | pub const XF86XK_Forward: c_uint = 0x1008FF27; 1034 | pub const XF86XK_Stop: c_uint = 0x1008FF28; 1035 | pub const XF86XK_Refresh: c_uint = 0x1008FF29; 1036 | pub const XF86XK_PowerOff: c_uint = 0x1008FF2A; 1037 | pub const XF86XK_WakeUp: c_uint = 0x1008FF2B; 1038 | pub const XF86XK_Eject: c_uint = 0x1008FF2C; 1039 | pub const XF86XK_ScreenSaver: c_uint = 0x1008FF2D; 1040 | pub const XF86XK_WWW: c_uint = 0x1008FF2E; 1041 | pub const XF86XK_Sleep: c_uint = 0x1008FF2F; 1042 | pub const XF86XK_Favorites: c_uint = 0x1008FF30; 1043 | pub const XF86XK_AudioPause: c_uint = 0x1008FF31; 1044 | pub const XF86XK_AudioMedia: c_uint = 0x1008FF32; 1045 | pub const XF86XK_MyComputer: c_uint = 0x1008FF33; 1046 | pub const XF86XK_VendorHome: c_uint = 0x1008FF34; 1047 | pub const XF86XK_LightBulb: c_uint = 0x1008FF35; 1048 | pub const XF86XK_Shop: c_uint = 0x1008FF36; 1049 | pub const XF86XK_History: c_uint = 0x1008FF37; 1050 | pub const XF86XK_OpenURL: c_uint = 0x1008FF38; 1051 | pub const XF86XK_AddFavorite: c_uint = 0x1008FF39; 1052 | pub const XF86XK_HotLinks: c_uint = 0x1008FF3A; 1053 | pub const XF86XK_BrightnessAdjust: c_uint = 0x1008FF3B; 1054 | pub const XF86XK_Finance: c_uint = 0x1008FF3C; 1055 | pub const XF86XK_Community: c_uint = 0x1008FF3D; 1056 | pub const XF86XK_AudioRewind: c_uint = 0x1008FF3E; 1057 | pub const XF86XK_BackForward: c_uint = 0x1008FF3F; 1058 | pub const XF86XK_Launch0: c_uint = 0x1008FF40; 1059 | pub const XF86XK_Launch1: c_uint = 0x1008FF41; 1060 | pub const XF86XK_Launch2: c_uint = 0x1008FF42; 1061 | pub const XF86XK_Launch3: c_uint = 0x1008FF43; 1062 | pub const XF86XK_Launch4: c_uint = 0x1008FF44; 1063 | pub const XF86XK_Launch5: c_uint = 0x1008FF45; 1064 | pub const XF86XK_Launch6: c_uint = 0x1008FF46; 1065 | pub const XF86XK_Launch7: c_uint = 0x1008FF47; 1066 | pub const XF86XK_Launch8: c_uint = 0x1008FF48; 1067 | pub const XF86XK_Launch9: c_uint = 0x1008FF49; 1068 | pub const XF86XK_LaunchA: c_uint = 0x1008FF4A; 1069 | pub const XF86XK_LaunchB: c_uint = 0x1008FF4B; 1070 | pub const XF86XK_LaunchC: c_uint = 0x1008FF4C; 1071 | pub const XF86XK_LaunchD: c_uint = 0x1008FF4D; 1072 | pub const XF86XK_LaunchE: c_uint = 0x1008FF4E; 1073 | pub const XF86XK_LaunchF: c_uint = 0x1008FF4F; 1074 | pub const XF86XK_ApplicationLeft: c_uint = 0x1008FF50; 1075 | pub const XF86XK_ApplicationRight: c_uint = 0x1008FF51; 1076 | pub const XF86XK_Book: c_uint = 0x1008FF52; 1077 | pub const XF86XK_CD: c_uint = 0x1008FF53; 1078 | pub const XF86XK_Calculater: c_uint = 0x1008FF54; 1079 | pub const XF86XK_Clear: c_uint = 0x1008FF55; 1080 | pub const XF86XK_Close: c_uint = 0x1008FF56; 1081 | pub const XF86XK_Copy: c_uint = 0x1008FF57; 1082 | pub const XF86XK_Cut: c_uint = 0x1008FF58; 1083 | pub const XF86XK_Display: c_uint = 0x1008FF59; 1084 | pub const XF86XK_DOS: c_uint = 0x1008FF5A; 1085 | pub const XF86XK_Documents: c_uint = 0x1008FF5B; 1086 | pub const XF86XK_Excel: c_uint = 0x1008FF5C; 1087 | pub const XF86XK_Explorer: c_uint = 0x1008FF5D; 1088 | pub const XF86XK_Game: c_uint = 0x1008FF5E; 1089 | pub const XF86XK_Go: c_uint = 0x1008FF5F; 1090 | pub const XF86XK_iTouch: c_uint = 0x1008FF60; 1091 | pub const XF86XK_LogOff: c_uint = 0x1008FF61; 1092 | pub const XF86XK_Market: c_uint = 0x1008FF62; 1093 | pub const XF86XK_Meeting: c_uint = 0x1008FF63; 1094 | pub const XF86XK_MenuKB: c_uint = 0x1008FF65; 1095 | pub const XF86XK_MenuPB: c_uint = 0x1008FF66; 1096 | pub const XF86XK_MySites: c_uint = 0x1008FF67; 1097 | pub const XF86XK_New: c_uint = 0x1008FF68; 1098 | pub const XF86XK_News: c_uint = 0x1008FF69; 1099 | pub const XF86XK_OfficeHome: c_uint = 0x1008FF6A; 1100 | pub const XF86XK_Open: c_uint = 0x1008FF6B; 1101 | pub const XF86XK_Option: c_uint = 0x1008FF6C; 1102 | pub const XF86XK_Paste: c_uint = 0x1008FF6D; 1103 | pub const XF86XK_Phone: c_uint = 0x1008FF6E; 1104 | pub const XF86XK_Q: c_uint = 0x1008FF70; 1105 | pub const XF86XK_Reply: c_uint = 0x1008FF72; 1106 | pub const XF86XK_Reload: c_uint = 0x1008FF73; 1107 | pub const XF86XK_RotateWindows: c_uint = 0x1008FF74; 1108 | pub const XF86XK_RotationPB: c_uint = 0x1008FF75; 1109 | pub const XF86XK_RotationKB: c_uint = 0x1008FF76; 1110 | pub const XF86XK_Save: c_uint = 0x1008FF77; 1111 | pub const XF86XK_ScrollUp: c_uint = 0x1008FF78; 1112 | pub const XF86XK_ScrollDown: c_uint = 0x1008FF79; 1113 | pub const XF86XK_ScrollClick: c_uint = 0x1008FF7A; 1114 | pub const XF86XK_Send: c_uint = 0x1008FF7B; 1115 | pub const XF86XK_Spell: c_uint = 0x1008FF7C; 1116 | pub const XF86XK_SplitScreen: c_uint = 0x1008FF7D; 1117 | pub const XF86XK_Support: c_uint = 0x1008FF7E; 1118 | pub const XF86XK_TaskPane: c_uint = 0x1008FF7F; 1119 | pub const XF86XK_Terminal: c_uint = 0x1008FF80; 1120 | pub const XF86XK_Tools: c_uint = 0x1008FF81; 1121 | pub const XF86XK_Travel: c_uint = 0x1008FF82; 1122 | pub const XF86XK_UserPB: c_uint = 0x1008FF84; 1123 | pub const XF86XK_User1KB: c_uint = 0x1008FF85; 1124 | pub const XF86XK_User2KB: c_uint = 0x1008FF86; 1125 | pub const XF86XK_Video: c_uint = 0x1008FF87; 1126 | pub const XF86XK_WheelButton: c_uint = 0x1008FF88; 1127 | pub const XF86XK_Word: c_uint = 0x1008FF89; 1128 | pub const XF86XK_Xfer: c_uint = 0x1008FF8A; 1129 | pub const XF86XK_ZoomIn: c_uint = 0x1008FF8B; 1130 | pub const XF86XK_ZoomOut: c_uint = 0x1008FF8C; 1131 | pub const XF86XK_Away: c_uint = 0x1008FF8D; 1132 | pub const XF86XK_Messenger: c_uint = 0x1008FF8E; 1133 | pub const XF86XK_WebCam: c_uint = 0x1008FF8F; 1134 | pub const XF86XK_MailForward: c_uint = 0x1008FF90; 1135 | pub const XF86XK_Pictures: c_uint = 0x1008FF91; 1136 | pub const XF86XK_Music: c_uint = 0x1008FF92; 1137 | pub const XF86XK_Battery: c_uint = 0x1008FF93; 1138 | pub const XF86XK_Bluetooth: c_uint = 0x1008FF94; 1139 | pub const XF86XK_WLAN: c_uint = 0x1008FF95; 1140 | pub const XF86XK_UWB: c_uint = 0x1008FF96; 1141 | pub const XF86XK_AudioForward: c_uint = 0x1008FF97; 1142 | pub const XF86XK_AudioRepeat: c_uint = 0x1008FF98; 1143 | pub const XF86XK_AudioRandomPlay: c_uint = 0x1008FF99; 1144 | pub const XF86XK_Subtitle: c_uint = 0x1008FF9A; 1145 | pub const XF86XK_AudioCycleTrack: c_uint = 0x1008FF9B; 1146 | pub const XF86XK_CycleAngle: c_uint = 0x1008FF9C; 1147 | pub const XF86XK_FrameBack: c_uint = 0x1008FF9D; 1148 | pub const XF86XK_FrameForward: c_uint = 0x1008FF9E; 1149 | pub const XF86XK_Time: c_uint = 0x1008FF9F; 1150 | pub const XF86XK_Select: c_uint = 0x1008FFA0; 1151 | pub const XF86XK_View: c_uint = 0x1008FFA1; 1152 | pub const XF86XK_TopMenu: c_uint = 0x1008FFA2; 1153 | pub const XF86XK_Red: c_uint = 0x1008FFA3; 1154 | pub const XF86XK_Green: c_uint = 0x1008FFA4; 1155 | pub const XF86XK_Yellow: c_uint = 0x1008FFA5; 1156 | pub const XF86XK_Blue: c_uint = 0x1008FFA6; 1157 | pub const XF86XK_Suspend: c_uint = 0x1008FFA7; 1158 | pub const XF86XK_Hibernate: c_uint = 0x1008FFA8; 1159 | pub const XF86XK_TouchpadToggle: c_uint = 0x1008FFA9; 1160 | pub const XF86XK_TouchpadOn: c_uint = 0x1008FFB0; 1161 | pub const XF86XK_TouchpadOff: c_uint = 0x1008FFB1; 1162 | pub const XF86XK_AudioMicMute: c_uint = 0x1008FFB2; 1163 | pub const XF86XK_Switch_VT_1: c_uint = 0x1008FE01; 1164 | pub const XF86XK_Switch_VT_2: c_uint = 0x1008FE02; 1165 | pub const XF86XK_Switch_VT_3: c_uint = 0x1008FE03; 1166 | pub const XF86XK_Switch_VT_4: c_uint = 0x1008FE04; 1167 | pub const XF86XK_Switch_VT_5: c_uint = 0x1008FE05; 1168 | pub const XF86XK_Switch_VT_6: c_uint = 0x1008FE06; 1169 | pub const XF86XK_Switch_VT_7: c_uint = 0x1008FE07; 1170 | pub const XF86XK_Switch_VT_8: c_uint = 0x1008FE08; 1171 | pub const XF86XK_Switch_VT_9: c_uint = 0x1008FE09; 1172 | pub const XF86XK_Switch_VT_10: c_uint = 0x1008FE0A; 1173 | pub const XF86XK_Switch_VT_11: c_uint = 0x1008FE0B; 1174 | pub const XF86XK_Switch_VT_12: c_uint = 0x1008FE0C; 1175 | pub const XF86XK_Ungrab: c_uint = 0x1008FE20; 1176 | pub const XF86XK_ClearGrab: c_uint = 0x1008FE21; 1177 | pub const XF86XK_Next_VMode: c_uint = 0x1008FE22; 1178 | pub const XF86XK_Prev_VMode: c_uint = 0x1008FE23; 1179 | pub const XF86XK_LogWindowTree: c_uint = 0x1008FE24; 1180 | pub const XF86XK_LogGrabInfo: c_uint = 0x1008FE25; 1181 | 1182 | pub const XK_ISO_Lock: c_uint = 0xfe01; 1183 | pub const XK_ISO_Level2_Latch: c_uint = 0xfe02; 1184 | pub const XK_ISO_Level3_Shift: c_uint = 0xfe03; 1185 | pub const XK_ISO_Level3_Latch: c_uint = 0xfe04; 1186 | pub const XK_ISO_Level3_Lock: c_uint = 0xfe05; 1187 | pub const XK_ISO_Level5_Shift: c_uint = 0xfe11; 1188 | pub const XK_ISO_Level5_Latch: c_uint = 0xfe12; 1189 | pub const XK_ISO_Level5_Lock: c_uint = 0xfe13; 1190 | pub const XK_ISO_Group_Shift: c_uint = 0xff7e; 1191 | pub const XK_ISO_Group_Latch: c_uint = 0xfe06; 1192 | pub const XK_ISO_Group_Lock: c_uint = 0xfe07; 1193 | pub const XK_ISO_Next_Group: c_uint = 0xfe08; 1194 | pub const XK_ISO_Next_Group_Lock: c_uint = 0xfe09; 1195 | pub const XK_ISO_Prev_Group: c_uint = 0xfe0a; 1196 | pub const XK_ISO_Prev_Group_Lock: c_uint = 0xfe0b; 1197 | pub const XK_ISO_First_Group: c_uint = 0xfe0c; 1198 | pub const XK_ISO_First_Group_Lock: c_uint = 0xfe0d; 1199 | pub const XK_ISO_Last_Group: c_uint = 0xfe0e; 1200 | pub const XK_ISO_Last_Group_Lock: c_uint = 0xfe0f; 1201 | 1202 | pub const XK_ISO_Left_Tab: c_uint = 0xfe20; 1203 | pub const XK_ISO_Move_Line_Up: c_uint = 0xfe21; 1204 | pub const XK_ISO_Move_Line_Down: c_uint = 0xfe22; 1205 | pub const XK_ISO_Partial_Line_Up: c_uint = 0xfe23; 1206 | pub const XK_ISO_Partial_Line_Down: c_uint = 0xfe24; 1207 | pub const XK_ISO_Partial_Space_Left: c_uint = 0xfe25; 1208 | pub const XK_ISO_Partial_Space_Right: c_uint = 0xfe26; 1209 | pub const XK_ISO_Set_Margin_Left: c_uint = 0xfe27; 1210 | pub const XK_ISO_Set_Margin_Right: c_uint = 0xfe28; 1211 | pub const XK_ISO_Release_Margin_Left: c_uint = 0xfe29; 1212 | pub const XK_ISO_Release_Margin_Right: c_uint = 0xfe2a; 1213 | pub const XK_ISO_Release_Both_Margins: c_uint = 0xfe2b; 1214 | pub const XK_ISO_Fast_Cursor_Left: c_uint = 0xfe2c; 1215 | pub const XK_ISO_Fast_Cursor_Right: c_uint = 0xfe2d; 1216 | pub const XK_ISO_Fast_Cursor_Up: c_uint = 0xfe2e; 1217 | pub const XK_ISO_Fast_Cursor_Down: c_uint = 0xfe2f; 1218 | pub const XK_ISO_Continuous_Underline: c_uint = 0xfe30; 1219 | pub const XK_ISO_Discontinuous_Underline: c_uint = 0xfe31; 1220 | pub const XK_ISO_Emphasize: c_uint = 0xfe32; 1221 | pub const XK_ISO_Center_Object: c_uint = 0xfe33; 1222 | pub const XK_ISO_Enter: c_uint = 0xfe34; 1223 | 1224 | pub const XK_dead_grave: c_uint = 0xfe50; 1225 | pub const XK_dead_acute: c_uint = 0xfe51; 1226 | pub const XK_dead_circumflex: c_uint = 0xfe52; 1227 | pub const XK_dead_tilde: c_uint = 0xfe53; 1228 | pub const XK_dead_perispomeni: c_uint = 0xfe53; 1229 | pub const XK_dead_macron: c_uint = 0xfe54; 1230 | pub const XK_dead_breve: c_uint = 0xfe55; 1231 | pub const XK_dead_abovedot: c_uint = 0xfe56; 1232 | pub const XK_dead_diaeresis: c_uint = 0xfe57; 1233 | pub const XK_dead_abovering: c_uint = 0xfe58; 1234 | pub const XK_dead_doubleacute: c_uint = 0xfe59; 1235 | pub const XK_dead_caron: c_uint = 0xfe5a; 1236 | pub const XK_dead_cedilla: c_uint = 0xfe5b; 1237 | pub const XK_dead_ogonek: c_uint = 0xfe5c; 1238 | pub const XK_dead_iota: c_uint = 0xfe5d; 1239 | pub const XK_dead_voiced_sound: c_uint = 0xfe5e; 1240 | pub const XK_dead_semivoiced_sound: c_uint = 0xfe5f; 1241 | pub const XK_dead_belowdot: c_uint = 0xfe60; 1242 | pub const XK_dead_hook: c_uint = 0xfe61; 1243 | pub const XK_dead_horn: c_uint = 0xfe62; 1244 | pub const XK_dead_stroke: c_uint = 0xfe63; 1245 | pub const XK_dead_abovecomma: c_uint = 0xfe64; 1246 | pub const XK_dead_psili: c_uint = 0xfe64; 1247 | pub const XK_dead_abovereversedcomma: c_uint = 0xfe65; 1248 | pub const XK_dead_dasia: c_uint = 0xfe65; 1249 | pub const XK_dead_doublegrave: c_uint = 0xfe66; 1250 | pub const XK_dead_belowring: c_uint = 0xfe67; 1251 | pub const XK_dead_belowmacron: c_uint = 0xfe68; 1252 | pub const XK_dead_belowcircumflex: c_uint = 0xfe69; 1253 | pub const XK_dead_belowtilde: c_uint = 0xfe6a; 1254 | pub const XK_dead_belowbreve: c_uint = 0xfe6b; 1255 | pub const XK_dead_belowdiaeresis: c_uint = 0xfe6c; 1256 | pub const XK_dead_invertedbreve: c_uint = 0xfe6d; 1257 | pub const XK_dead_belowcomma: c_uint = 0xfe6e; 1258 | pub const XK_dead_currency: c_uint = 0xfe6f; 1259 | 1260 | pub const XK_dead_lowline: c_uint = 0xfe90; 1261 | pub const XK_dead_aboveverticalline: c_uint = 0xfe91; 1262 | pub const XK_dead_belowverticalline: c_uint = 0xfe92; 1263 | pub const XK_dead_longsolidusoverlay: c_uint = 0xfe93; 1264 | 1265 | pub const XK_dead_a: c_uint = 0xfe80; 1266 | pub const XK_dead_A: c_uint = 0xfe81; 1267 | pub const XK_dead_e: c_uint = 0xfe82; 1268 | pub const XK_dead_E: c_uint = 0xfe83; 1269 | pub const XK_dead_i: c_uint = 0xfe84; 1270 | pub const XK_dead_I: c_uint = 0xfe85; 1271 | pub const XK_dead_o: c_uint = 0xfe86; 1272 | pub const XK_dead_O: c_uint = 0xfe87; 1273 | pub const XK_dead_u: c_uint = 0xfe88; 1274 | pub const XK_dead_U: c_uint = 0xfe89; 1275 | pub const XK_dead_small_schwa: c_uint = 0xfe8a; 1276 | pub const XK_dead_capital_schwa: c_uint = 0xfe8b; 1277 | 1278 | pub const XK_dead_greek: c_uint = 0xfe8c; 1279 | 1280 | pub const XK_First_Virtual_Screen: c_uint = 0xfed0; 1281 | pub const XK_Prev_Virtual_Screen: c_uint = 0xfed1; 1282 | pub const XK_Next_Virtual_Screen: c_uint = 0xfed2; 1283 | pub const XK_Last_Virtual_Screen: c_uint = 0xfed4; 1284 | pub const XK_Terminate_Server: c_uint = 0xfed5; 1285 | 1286 | pub const XK_AccessX_Enable: c_uint = 0xfe70; 1287 | pub const XK_AccessX_Feedback_Enable: c_uint = 0xfe71; 1288 | pub const XK_RepeatKeys_Enable: c_uint = 0xfe72; 1289 | pub const XK_SlowKeys_Enable: c_uint = 0xfe73; 1290 | pub const XK_BounceKeys_Enable: c_uint = 0xfe74; 1291 | pub const XK_StickyKeys_Enable: c_uint = 0xfe75; 1292 | pub const XK_MouseKeys_Enable: c_uint = 0xfe76; 1293 | pub const XK_MouseKeys_Accel_Enable: c_uint = 0xfe77; 1294 | pub const XK_Overlay1_Enable: c_uint = 0xfe78; 1295 | pub const XK_Overlay2_Enable: c_uint = 0xfe79; 1296 | pub const XK_AudibleBell_Enable: c_uint = 0xfe7a; 1297 | 1298 | pub const XK_Pointer_Left: c_uint = 0xfee0; 1299 | pub const XK_Pointer_Right: c_uint = 0xfee1; 1300 | pub const XK_Pointer_Up: c_uint = 0xfee2; 1301 | pub const XK_Pointer_Down: c_uint = 0xfee3; 1302 | pub const XK_Pointer_UpLeft: c_uint = 0xfee4; 1303 | pub const XK_Pointer_UpRight: c_uint = 0xfee5; 1304 | pub const XK_Pointer_DownLeft: c_uint = 0xfee6; 1305 | pub const XK_Pointer_DownRight: c_uint = 0xfee7; 1306 | pub const XK_Pointer_Button_Dflt: c_uint = 0xfee8; 1307 | pub const XK_Pointer_Button1: c_uint = 0xfee9; 1308 | pub const XK_Pointer_Button2: c_uint = 0xfeea; 1309 | pub const XK_Pointer_Button3: c_uint = 0xfeeb; 1310 | pub const XK_Pointer_Button4: c_uint = 0xfeec; 1311 | pub const XK_Pointer_Button5: c_uint = 0xfeed; 1312 | pub const XK_Pointer_DblClick_Dflt: c_uint = 0xfeee; 1313 | pub const XK_Pointer_DblClick1: c_uint = 0xfeef; 1314 | pub const XK_Pointer_DblClick2: c_uint = 0xfef0; 1315 | pub const XK_Pointer_DblClick3: c_uint = 0xfef1; 1316 | pub const XK_Pointer_DblClick4: c_uint = 0xfef2; 1317 | pub const XK_Pointer_DblClick5: c_uint = 0xfef3; 1318 | pub const XK_Pointer_Drag_Dflt: c_uint = 0xfef4; 1319 | pub const XK_Pointer_Drag1: c_uint = 0xfef5; 1320 | pub const XK_Pointer_Drag2: c_uint = 0xfef6; 1321 | pub const XK_Pointer_Drag3: c_uint = 0xfef7; 1322 | pub const XK_Pointer_Drag4: c_uint = 0xfef8; 1323 | pub const XK_Pointer_Drag5: c_uint = 0xfefd; 1324 | 1325 | pub const XK_Pointer_EnableKeys: c_uint = 0xfef9; 1326 | pub const XK_Pointer_Accelerate: c_uint = 0xfefa; 1327 | pub const XK_Pointer_DfltBtnNext: c_uint = 0xfefb; 1328 | pub const XK_Pointer_DfltBtnPrev: c_uint = 0xfefc; 1329 | 1330 | pub const XK_ch: c_uint = 0xfea0; 1331 | pub const XK_Ch: c_uint = 0xfea1; 1332 | pub const XK_CH: c_uint = 0xfea2; 1333 | pub const XK_c_h: c_uint = 0xfea3; 1334 | pub const XK_C_h: c_uint = 0xfea4; 1335 | pub const XK_C_H: c_uint = 0xfea5; 1336 | 1337 | // modifier keys mask 1338 | pub const ShiftMask: c_uint = 0x01; 1339 | pub const LockMask: c_uint = 0x02; 1340 | pub const ControlMask: c_uint = 0x04; 1341 | pub const Mod1Mask: c_uint = 0x08; 1342 | pub const Mod2Mask: c_uint = 0x10; 1343 | pub const Mod3Mask: c_uint = 0x20; 1344 | pub const Mod4Mask: c_uint = 0x40; 1345 | pub const Mod5Mask: c_uint = 0x80; 1346 | 1347 | pub const AnyModifier: c_uint = 1 << 15; 1348 | --------------------------------------------------------------------------------