From a2c53aba27bd9615e2d3a739ba126d7cd0afece1 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Wed, 5 Feb 2025 08:18:44 +0000 Subject: [PATCH 01/21] click test, osk test --- docs/window-likes/audio-player.md | 2 +- docs/window-likes/onscreen-keyboard.md | 1 + src/essential/mod.rs | 1 + src/essential/onscreen_keyboard.rs | 47 ++++++++++++++++ src/keyboard.rs | 22 -------- src/lib.rs | 1 - src/messages.rs | 4 +- src/utils.rs | 21 ++++++++ src/window_manager.rs | 74 ++++++++++++++++++-------- 9 files changed, 126 insertions(+), 47 deletions(-) create mode 100644 docs/window-likes/onscreen-keyboard.md create mode 100644 src/essential/onscreen_keyboard.rs delete mode 100644 src/keyboard.rs diff --git a/docs/window-likes/audio-player.md b/docs/window-likes/audio-player.md index 8e1ea32..0bde4e6 100644 --- a/docs/window-likes/audio-player.md +++ b/docs/window-likes/audio-player.md @@ -1,4 +1,4 @@ -Audio player with playlist and folder support. +Audio player with playlist and folder support. Requires the dev version of `alsa` lib. ## Commands diff --git a/docs/window-likes/onscreen-keyboard.md b/docs/window-likes/onscreen-keyboard.md new file mode 100644 index 0000000..8113684 --- /dev/null +++ b/docs/window-likes/onscreen-keyboard.md @@ -0,0 +1 @@ +This is primarily intended for mobile users. diff --git a/src/essential/mod.rs b/src/essential/mod.rs index 0800750..e594dcb 100644 --- a/src/essential/mod.rs +++ b/src/essential/mod.rs @@ -3,6 +3,7 @@ pub mod taskbar; pub mod lock_screen; pub mod workspace_indicator; pub mod start_menu; +pub mod onscreen_keyboard; pub mod about; pub mod help; diff --git a/src/essential/onscreen_keyboard.rs b/src/essential/onscreen_keyboard.rs new file mode 100644 index 0000000..536a6cc --- /dev/null +++ b/src/essential/onscreen_keyboard.rs @@ -0,0 +1,47 @@ +use std::vec; +use std::vec::Vec; + +use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use crate::messages::{ WindowMessage, WindowMessageResponse }; +use crate::framebuffer::Dimensions; +use crate::themes::ThemeInfo; + +#[derive(Default)] +pub struct OnscreenKeyboard { + dimensions: Dimensions, + // +} + +impl WindowLike for OnscreenKeyboard { + fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse { + match message { + WindowMessage::Init(dimensions) => { + self.dimensions = dimensions; + WindowMessageResponse::JustRedraw + }, + // + _ => WindowMessageResponse::DoNothing, + } + } + + fn draw(&self, theme_info: &ThemeInfo) -> Vec { + let mut instructions = vec![DrawInstructions::Rect([0, 0], self.dimensions, theme_info.background)]; + // + instructions + } + // + fn subtype(&self) -> WindowLikeType { + WindowLikeType::OnscreenKeyboard + } + + fn ideal_dimensions(&self, dimensions: Dimensions) -> Dimensions { + [dimensions[0] - 175, 250] + } +} + +impl OnscreenKeyboard { + pub fn new() -> Self { + Self::default() + } +} + diff --git a/src/keyboard.rs b/src/keyboard.rs deleted file mode 100644 index 6834d76..0000000 --- a/src/keyboard.rs +++ /dev/null @@ -1,22 +0,0 @@ -use termion::event::Key; - -#[derive(Clone, Debug, PartialEq)] -pub enum KeyChar { - Press(char), - Alt(char), - Ctrl(char), -} - -//use Linear A for escape, backspace, enter -pub fn key_to_char(key: Key) -> Option { - match key { - Key::Char('\n') => Some(KeyChar::Press('𐘂')), - Key::Char(c) => Some(KeyChar::Press(c)), - Key::Alt(c) => Some(KeyChar::Alt(c)), - Key::Ctrl(c) => Some(KeyChar::Ctrl(c)), - Key::Backspace => Some(KeyChar::Press('𐘁')), - Key::Esc => Some(KeyChar::Press('𐘃')), - _ => None, - } -} - diff --git a/src/lib.rs b/src/lib.rs index 387d654..cb61bd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,5 @@ pub mod utils; pub mod logging; pub mod ipc; mod proxy_window_like; -mod keyboard; mod essential; diff --git a/src/messages.rs b/src/messages.rs index 132ff80..9baf255 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -4,12 +4,12 @@ use std::vec::Vec; use serde::{ Deserialize, Serialize }; -use crate::keyboard::KeyChar; use crate::framebuffer::Dimensions; -use crate::window_manager::WindowLike; +use crate::window_manager::{ WindowLike, KeyChar }; pub enum WindowManagerMessage { KeyChar(KeyChar), + Click(u16, u16), // } diff --git a/src/utils.rs b/src/utils.rs index 8e62417..de6e36a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,26 @@ use std::path::PathBuf; +use termion::event::Key; + +use crate::window_manager::KeyChar; + +//use Linear A for escape, backspace, enter +pub fn key_to_char(key: Key) -> Option { + match key { + Key::Char('\n') => Some(KeyChar::Press('𐘂')), + Key::Char(c) => Some(KeyChar::Press(c)), + Key::Alt(c) => Some(KeyChar::Alt(c)), + Key::Ctrl(c) => Some(KeyChar::Ctrl(c)), + Key::Backspace => Some(KeyChar::Press('𐘁')), + Key::Esc => Some(KeyChar::Press('𐘃')), + _ => None, + } +} + +pub fn min(one: usize, two: usize) -> usize { + if one > two { two } else { one } +} + pub trait Substring { fn substring(&self, start: usize, end: usize) -> &str; fn remove(&self, index: usize, len: usize) -> String; diff --git a/src/window_manager.rs b/src/window_manager.rs index f4a9d97..231a4ec 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -8,14 +8,15 @@ use std::process::exit; use std::cell::RefCell; use linux_framebuffer::Framebuffer; -use termion::input::TermRead; +use termion::input::{ MouseTerminal, TermRead }; use termion::raw::IntoRawMode; use termion::cursor; +use termion::event::{ Event, MouseEvent }; use serde::{ Deserialize, Serialize }; use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor }; use crate::themes::{ ThemeInfo, Themes, get_theme_info }; -use crate::keyboard::{ KeyChar, key_to_char }; +use crate::utils::{ min, key_to_char }; use crate::messages::*; use crate::proxy_window_like::ProxyWindowLike; use crate::essential::desktop_background::DesktopBackground; @@ -25,6 +26,7 @@ use crate::essential::workspace_indicator::WorkspaceIndicator; use crate::essential::start_menu::StartMenu; use crate::essential::about::About; use crate::essential::help::Help; +use crate::essential::onscreen_keyboard::OnscreenKeyboard; //use crate::logging::log; pub const TASKBAR_HEIGHT: usize = 38; @@ -45,31 +47,43 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { wm.draw(None, false); let stdin = stdin().lock(); - let mut stdout = stdout().into_raw_mode().unwrap(); + let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap()); write!(stdout, "{}", cursor::Hide).unwrap(); stdout.flush().unwrap(); - - for c in stdin.keys() { - if let Some(kc) = key_to_char(c.unwrap()) { - //do not allow exit when locked unless debugging - //if kc == KeyChar::Alt('E') { - if kc == KeyChar::Alt('E') && !wm.locked { - write!(stdout, "{}", cursor::Show).unwrap(); - stdout.suspend_raw_mode().unwrap(); - exit(0); - } else { - wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())); - } - } + for e in stdin.events() { + match e.unwrap() { + Event::Key(c) => { + if let Some(kc) = key_to_char(c) { + //do not allow exit when locked unless debugging + //if kc == KeyChar::Alt('E') { + if kc == KeyChar::Alt('E') && !wm.locked { + write!(stdout, "{}", cursor::Show).unwrap(); + stdout.suspend_raw_mode().unwrap(); + exit(0); + } else { + wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())); + } + } + }, + Event::Mouse(m) => { + if let MouseEvent::Press(_, x, y) = m { + //We don't care what button + //(should also support mobile?) + wm.handle_message(WindowManagerMessage::Click(x, y)); + } + }, + _ => {}, + }; } - - // } -pub fn min(one: usize, two: usize) -> usize { - if one > two { two } else { one } +#[derive(Clone, Debug, PartialEq)] +pub enum KeyChar { + Press(char), + Alt(char), + Ctrl(char), } #[derive(Debug, Serialize, Deserialize)] @@ -89,6 +103,7 @@ pub enum WindowLikeType { Taskbar, StartMenu, WorkspaceIndicator, + OnscreenKeyboard, } pub trait WindowLike { @@ -215,6 +230,7 @@ impl WindowManager { } //if off_only is true, also handle request + //written confusingly but it works I promise fn toggle_start_menu(&mut self, off_only: bool) -> WindowMessageResponse { let start_menu_exists = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::StartMenu).is_some(); if (start_menu_exists && off_only) || !off_only { @@ -518,7 +534,23 @@ impl WindowManager { }, } }, - // + WindowManagerMessage::Click(x, y) => { + //println!("{}, {}", x, y); + if x < 10000 && y < 10000 { + //toggle onscreen keyboard if top left keyboard clicked + let osk_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::OnscreenKeyboard); + if let Some(osk_index) = osk_index { + self.window_infos.remove(osk_index); + } else { + let osk = Box::new(OnscreenKeyboard::new()); + let ideal_dimensions = osk.ideal_dimensions(self.dimensions); + self.add_window_like(osk, [175, self.dimensions[1] - TASKBAR_HEIGHT - 250], Some(ideal_dimensions)); + } + } + //see if in onscreen keyboard, if so send to it after offsetting coords + // + WindowMessageResponse::JustRedraw + }, }; if response != WindowMessageResponse::DoNothing { match response { -- 2.39.5 From 26041e6c5c48deaf5051d38d37aa4f7e3eeda005 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Wed, 5 Feb 2025 16:37:27 +0000 Subject: [PATCH 02/21] actually parse touch? --- src/messages.rs | 2 +- src/window_manager.rs | 118 +++++++++++++++++++++++++++++------------- 2 files changed, 84 insertions(+), 36 deletions(-) diff --git a/src/messages.rs b/src/messages.rs index 9baf255..1c639b9 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -9,7 +9,7 @@ use crate::window_manager::{ WindowLike, KeyChar }; pub enum WindowManagerMessage { KeyChar(KeyChar), - Click(u16, u16), + Touch(u16, u16), // } diff --git a/src/window_manager.rs b/src/window_manager.rs index 231a4ec..7d68a70 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -3,15 +3,19 @@ use std::vec; use std::collections::{ HashMap, VecDeque }; use std::fmt; use std::boxed::Box; -use std::io::{ stdin, stdout, Write }; +use std::io::{ stdin, stdout, BufReader, BufRead, Write }; use std::process::exit; use std::cell::RefCell; +use std::sync::mpsc; +use std::thread; +use std::time::Duration; +use std::env; +use std::process::{ Command, Stdio }; use linux_framebuffer::Framebuffer; -use termion::input::{ MouseTerminal, TermRead }; +use termion::input::TermRead; use termion::raw::IntoRawMode; use termion::cursor; -use termion::event::{ Event, MouseEvent }; use serde::{ Deserialize, Serialize }; use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor }; @@ -33,6 +37,19 @@ pub const TASKBAR_HEIGHT: usize = 38; pub const INDICATOR_HEIGHT: usize = 20; const WINDOW_TOP_HEIGHT: usize = 26; +#[derive(Clone, Debug, PartialEq)] +pub enum KeyChar { + Press(char), + Alt(char), + Ctrl(char), +} + +enum ThreadMessage { + KeyChar(KeyChar), + Touch(u16, u16), + Exit, +} + pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { let dimensions = [framebuffer_info.width, framebuffer_info.height]; @@ -46,46 +63,77 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { wm.draw(None, false); - let stdin = stdin().lock(); - let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap()); + let mut stdout = stdout().into_raw_mode().unwrap(); write!(stdout, "{}", cursor::Hide).unwrap(); stdout.flush().unwrap(); - for e in stdin.events() { - match e.unwrap() { - Event::Key(c) => { - if let Some(kc) = key_to_char(c) { - //do not allow exit when locked unless debugging - //if kc == KeyChar::Alt('E') { - if kc == KeyChar::Alt('E') && !wm.locked { - write!(stdout, "{}", cursor::Show).unwrap(); - stdout.suspend_raw_mode().unwrap(); - exit(0); - } else { - wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())); - } + let (tx, rx) = mpsc::channel(); + + let tx1 = tx.clone(); + + //read key presses + thread::spawn(move || { + let stdin = stdin().lock(); + for c in stdin.keys() { + if let Some(kc) = key_to_char(c.unwrap()) { + //do not allow exit when locked unless debugging + //if kc == KeyChar::Alt('E') { + if kc == KeyChar::Alt('E') { + tx.send(ThreadMessage::Exit).unwrap(); + } else { + tx.send(ThreadMessage::KeyChar(kc)).unwrap(); + } + } + thread::sleep(Duration::from_millis(1)); + } + }); + + let args: Vec<_> = env::args().collect(); + + //read touchscreen presses (hopefully) + thread::spawn(move || { + if args.contains(&"touch".to_string()) { + //spawn evtest, parse it for touch coords + let evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap(); + let mut grep = Command::new("grep").arg(r"'\(ABS_X\|ABS_Y\)), value '").stdin(Stdio::from(evtest.stdout.unwrap())).stdout(Stdio::piped()).spawn().unwrap(); + let reader = BufReader::new(grep.stdout.as_mut().unwrap()); + let mut x: Option = None; + let mut y: Option = None; + for line in reader.lines() { + let line = line.unwrap(); + let value: Vec<_> = line.split("), value ").collect(); + let value = value[value.len() - 1].parse::().unwrap(); + if line.contains(&"ABS_X") { + x = Some(value); + } else { + y = Some(value); + } + if x.is_some() && y.is_some() { + tx1.send(ThreadMessage::Touch(x.unwrap(), y.unwrap())).unwrap(); + x = None; + y = None; + } + thread::sleep(Duration::from_millis(1)); + } + } + }); + + for message in rx { + match message { + ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())), + ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)), + ThreadMessage::Exit => { + if !wm.locked { + write!(stdout, "{}", cursor::Show).unwrap(); + stdout.suspend_raw_mode().unwrap(); + exit(0); } }, - Event::Mouse(m) => { - if let MouseEvent::Press(_, x, y) = m { - //We don't care what button - //(should also support mobile?) - wm.handle_message(WindowManagerMessage::Click(x, y)); - } - }, - _ => {}, }; } } -#[derive(Clone, Debug, PartialEq)] -pub enum KeyChar { - Press(char), - Alt(char), - Ctrl(char), -} - #[derive(Debug, Serialize, Deserialize)] pub enum DrawInstructions { Rect(Point, Dimensions, RGBColor), @@ -534,8 +582,8 @@ impl WindowManager { }, } }, - WindowManagerMessage::Click(x, y) => { - //println!("{}, {}", x, y); + WindowManagerMessage::Touch(x, y) => { + println!("{}, {}", x, y); if x < 10000 && y < 10000 { //toggle onscreen keyboard if top left keyboard clicked let osk_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::OnscreenKeyboard); -- 2.39.5 From d182077e785bbcddc1a6c16d47c01301a711bde9 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:26:41 +0000 Subject: [PATCH 03/21] fix 1 --- src/window_manager.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index 7d68a70..9c164b5 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -95,24 +95,25 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { thread::spawn(move || { if args.contains(&"touch".to_string()) { //spawn evtest, parse it for touch coords - let evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap(); - let mut grep = Command::new("grep").arg(r"'\(ABS_X\|ABS_Y\)), value '").stdin(Stdio::from(evtest.stdout.unwrap())).stdout(Stdio::piped()).spawn().unwrap(); - let reader = BufReader::new(grep.stdout.as_mut().unwrap()); + let mut evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap(); + let reader = BufReader::new(evtest.stdout.as_mut().unwrap()); let mut x: Option = None; let mut y: Option = None; for line in reader.lines() { let line = line.unwrap(); - let value: Vec<_> = line.split("), value ").collect(); - let value = value[value.len() - 1].parse::().unwrap(); - if line.contains(&"ABS_X") { - x = Some(value); - } else { - y = Some(value); - } - if x.is_some() && y.is_some() { - tx1.send(ThreadMessage::Touch(x.unwrap(), y.unwrap())).unwrap(); - x = None; - y = None; + if line.contains(&"ABS_X") || line.contains(&"ABS_Y") { + let value: Vec<_> = line.split("), value ").collect(); + let value = value[value.len() - 1].parse::().unwrap(); + if line.contains(&"ABS_X") { + x = Some(value); + } else { + y = Some(value); + } + if x.is_some() && y.is_some() { + tx1.send(ThreadMessage::Touch(x.unwrap(), y.unwrap())).unwrap(); + x = None; + y = None; + } } thread::sleep(Duration::from_millis(1)); } -- 2.39.5 From cb8d5abdbfcbcc079c0784628e586fedc9df815f Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Fri, 7 Feb 2025 06:31:56 +0000 Subject: [PATCH 04/21] show keyboard keys --- src/components/mod.rs | 2 + src/components/press_button.rs | 67 ++++++++++++++++++++++ src/essential/onscreen_keyboard.rs | 90 +++++++++++++++++++++++++++++- src/messages.rs | 3 +- src/utils.rs | 13 ++++- src/window_manager.rs | 68 +++++++++++++++------- 6 files changed, 217 insertions(+), 26 deletions(-) create mode 100644 src/components/press_button.rs diff --git a/src/components/mod.rs b/src/components/mod.rs index 35b56e9..ed77f9b 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -7,6 +7,7 @@ use crate::window_manager::DrawInstructions; pub mod toggle_button; pub mod highlight_button; pub mod paragraph; +pub mod press_button; pub trait Component { fn handle_message(&mut self, message: WindowMessage) -> Option; @@ -17,6 +18,7 @@ pub trait Component { //focusing for components is purely to give a visual representation fn focusable(&self) -> bool; fn clickable(&self) -> bool; + //fn pressable(&self) -> bool; //touch fn name(&self) -> &String; //should be unique } diff --git a/src/components/press_button.rs b/src/components/press_button.rs new file mode 100644 index 0000000..04b5324 --- /dev/null +++ b/src/components/press_button.rs @@ -0,0 +1,67 @@ +use std::vec; +use std::vec::Vec; + +use crate::components::Component; +use crate::framebuffer::{ Dimensions, Point }; +use crate::themes::ThemeInfo; +use crate::messages::WindowMessage; +use crate::window_manager::{ DrawInstructions }; + +const MONO_WIDTH: u8 = 10; + +pub struct PressButton { + top_left: Point, + size: Dimensions, + text: String, + press_return: T, +} + +impl Component for PressButton { + // + fn handle_message(&mut self, message: WindowMessage) -> Option { + match message { + WindowMessage::Touch(x, y) => { + Some(self.press_return.clone()) + }, + _ => None, + } + } + + fn draw(&self, theme_info: &ThemeInfo) -> Vec { + let half = self.size[0] / 2 - self.text.len() * MONO_WIDTH as usize / 2; + vec![ + DrawInstructions::Rect(self.top_left, [self.size[0], 1], theme_info.border_left_top), + DrawInstructions::Rect(self.top_left, [1, self.size[1]], theme_info.border_left_top), + DrawInstructions::Rect([self.top_left[0], self.top_left[1] + self.size[1]], [self.size[0], 1], theme_info.border_right_bottom), + DrawInstructions::Rect([self.top_left[0] + self.size[0], self.top_left[1]], [1, self.size[1]], theme_info.border_right_bottom), + //assume normal background colour + DrawInstructions::Text([self.top_left[0] + half, self.top_left[1] + 8], vec!["times-new-romono".to_string()], self.text.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)), + ] + } + + //properties + fn focusable(&self) -> bool { + false + } + + fn clickable(&self) -> bool { + false + } + + fn name(&self) -> &String { + //sorry + &self.text + } +} + +impl PressButton { + pub fn new(top_left: Point, size: Dimensions, text: String, press_return: T) -> Self { + Self { + top_left, + size, + text, + press_return, + } + } +} + diff --git a/src/essential/onscreen_keyboard.rs b/src/essential/onscreen_keyboard.rs index 536a6cc..38b6c5d 100644 --- a/src/essential/onscreen_keyboard.rs +++ b/src/essential/onscreen_keyboard.rs @@ -1,15 +1,43 @@ use std::vec; use std::vec::Vec; +use std::collections::HashMap; -use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; +use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType, KeyChar }; use crate::messages::{ WindowMessage, WindowMessageResponse }; use crate::framebuffer::Dimensions; use crate::themes::ThemeInfo; +use crate::components::Component; +use crate::components::press_button::PressButton; + +const padding_y: usize = 15; +const padding_x: usize = 15; +//padding in between keys in the x direction +const key_padding_x: usize = 5; +const key_padding_y: usize = 5; + +#[derive(Default, Eq, PartialEq, Hash)] +enum Board { + #[default] + Regular, + Shift, + Symbols, + SymbolsShift, +} + +#[derive(Clone)] +enum KeyResponse { + Key(char), + Alt, + Ctrl, + SwitchBoard, +} #[derive(Default)] pub struct OnscreenKeyboard { dimensions: Dimensions, - // + components: Vec>>, + alt: bool, + board: Board, } impl WindowLike for OnscreenKeyboard { @@ -17,6 +45,7 @@ impl WindowLike for OnscreenKeyboard { match message { WindowMessage::Init(dimensions) => { self.dimensions = dimensions; + self.set_key_components(); WindowMessageResponse::JustRedraw }, // @@ -26,7 +55,9 @@ impl WindowLike for OnscreenKeyboard { fn draw(&self, theme_info: &ThemeInfo) -> Vec { let mut instructions = vec![DrawInstructions::Rect([0, 0], self.dimensions, theme_info.background)]; - // + for component in &self.components { + instructions.extend(component.draw(theme_info)); + } instructions } // @@ -43,5 +74,58 @@ impl OnscreenKeyboard { pub fn new() -> Self { Self::default() } + + fn set_key_components(&mut self) { + self.components = Vec::new(); + let rows: [HashMap>; 4] = [ + HashMap::from([ + (Board::Regular, vec!['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p']), + (Board::Shift, vec!['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P']), + (Board::Symbols, vec!['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']), + (Board::SymbolsShift, vec![]), //empty + ]), + HashMap::from([ + (Board::Regular, vec!['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l']), + (Board::Shift, vec!['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L']), + (Board::Symbols, vec!['|', '=', '$', '%', '&', '-', '+', '(', ')']), + (Board::SymbolsShift, vec!['`', '@', '#', '^']), + ]), + HashMap::from([ + (Board::Regular, vec!['𐘃', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '𐘁']), //escape and backspace + (Board::Shift, vec!['𐘃', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '𐘁']), //escape and backspace + (Board::Symbols, vec!['~', '*', '"', '\'', ':', ';', '!', '?', '𐘁']), //basckspace + (Board::SymbolsShift, vec!['[', ']', '{', '}', '𐘁']), //backspace + ]), + HashMap::from([ + (Board::Regular, vec!['𐘧', '𐘎', ' ', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter + (Board::Shift, vec!['𐘧', '𐘎', ' ', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter + (Board::Symbols, vec!['𐘧', '𐘎', ',', '_', ' ', '/', '.', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter + (Board::SymbolsShift, vec!['𐘧', '𐘎', '\\', '<', ' ', '>', '𐘾', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), ctrl (special case, not a real key), enter + ]), + ]; + //hardcoded for now + let mut y = padding_y; + let key_height = (self.dimensions[1] - padding_y * 2 - key_padding_y * (rows.len() - 1)) / rows.len(); + let reg_key_width = (self.dimensions[0] - padding_x * 2 - key_padding_x * (10 - 1)) / 10; + for row in rows { + let row_keys = &row[&self.board]; + //centre + let mut x = padding_x + (10 - row_keys.len()) * (reg_key_width + key_padding_x) / 2; + for key in row_keys { + let press_return = if key == &'𐘧' { + KeyResponse::SwitchBoard + } else if key == &'𐘎' { + KeyResponse::Alt + } else if key == &'𐘾' { + KeyResponse::Ctrl + } else { + KeyResponse::Key(*key) + }; + self.components.push(Box::new(PressButton::new([x, y], [reg_key_width, key_height], key.to_string(), press_return))); + x += reg_key_width + key_padding_x; + } + y += key_height + key_padding_y; + } + } } diff --git a/src/messages.rs b/src/messages.rs index 1c639b9..924f06c 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -9,7 +9,7 @@ use crate::window_manager::{ WindowLike, KeyChar }; pub enum WindowManagerMessage { KeyChar(KeyChar), - Touch(u16, u16), + Touch(usize, usize), // } @@ -99,5 +99,6 @@ pub enum WindowMessage { Unfocus, FocusClick, ChangeDimensions(Dimensions), + Touch(usize, usize), //for onscreen keyboard only // } diff --git a/src/utils.rs b/src/utils.rs index de6e36a..ea41e9c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,8 +3,10 @@ use std::path::PathBuf; use termion::event::Key; use crate::window_manager::KeyChar; +use crate::framebuffer::{ Dimensions, Point }; //use Linear A for escape, backspace, enter +//Linear A used only internally in onscreen keyboard: 𐘎 is alt, 𐘧 is switch board, 𐘾 is ctrl pub fn key_to_char(key: Key) -> Option { match key { Key::Char('\n') => Some(KeyChar::Press('𐘂')), @@ -41,7 +43,6 @@ impl Substring for String { break; } byte_end += char_length; - } &self[byte_start..byte_end] } @@ -146,3 +147,13 @@ pub fn is_hex(c: char) -> bool { HEX_CHARS.iter().position(|hc| hc == &c).is_some() } +pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool { + let x = point[0]; + let y = point[1]; + let x2 = top_left[0]; + let y2 = top_left[1]; + let x3 = x2 + size[0]; + let y3 = y2 + size[1]; + x >= x2 && y >= x2 && x <= x3 && y <= y3 +} + diff --git a/src/window_manager.rs b/src/window_manager.rs index 9c164b5..c0db4d6 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -20,7 +20,7 @@ use serde::{ Deserialize, Serialize }; use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor }; use crate::themes::{ ThemeInfo, Themes, get_theme_info }; -use crate::utils::{ min, key_to_char }; +use crate::utils::{ min, key_to_char, point_inside }; use crate::messages::*; use crate::proxy_window_like::ProxyWindowLike; use crate::essential::desktop_background::DesktopBackground; @@ -33,6 +33,8 @@ use crate::essential::help::Help; use crate::essential::onscreen_keyboard::OnscreenKeyboard; //use crate::logging::log; +//todo: a lot of the usize should be changed to u16 + pub const TASKBAR_HEIGHT: usize = 38; pub const INDICATOR_HEIGHT: usize = 20; const WINDOW_TOP_HEIGHT: usize = 26; @@ -46,7 +48,7 @@ pub enum KeyChar { enum ThreadMessage { KeyChar(KeyChar), - Touch(u16, u16), + Touch(usize, usize), Exit, } @@ -90,20 +92,21 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { }); let args: Vec<_> = env::args().collect(); + let touch = args.contains(&"touch".to_string()); //read touchscreen presses (hopefully) thread::spawn(move || { - if args.contains(&"touch".to_string()) { - //spawn evtest, parse it for touch coords + //spawn evtest, parse it for touch coords + if touch { let mut evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap(); let reader = BufReader::new(evtest.stdout.as_mut().unwrap()); - let mut x: Option = None; - let mut y: Option = None; + let mut x: Option = None; + let mut y: Option = None; for line in reader.lines() { let line = line.unwrap(); - if line.contains(&"ABS_X") || line.contains(&"ABS_Y") { + if line.contains(&"ABS_X), value ") || line.contains(&"ABS_Y), value ") { let value: Vec<_> = line.split("), value ").collect(); - let value = value[value.len() - 1].parse::().unwrap(); + let value = value[value.len() - 1].parse::().unwrap(); if line.contains(&"ABS_X") { x = Some(value); } else { @@ -119,6 +122,10 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { } } }); + if touch { + //opens osk + wm.handle_message(WindowManagerMessage::Touch(1, 1)); + } for message in rx { match message { @@ -199,6 +206,7 @@ pub struct WindowManager { writer: RefCell, id_count: usize, window_infos: Vec, + osk: Option, dimensions: Dimensions, theme: Themes, focused_id: usize, @@ -216,6 +224,7 @@ impl WindowManager { writer: RefCell::new(writer), id_count: 0, window_infos: Vec::new(), + osk: None, dimensions, theme: Themes::Standard, focused_id: 0, @@ -233,10 +242,9 @@ impl WindowManager { let dimensions = dimensions.unwrap_or(window_like.ideal_dimensions(self.dimensions)); self.id_count = self.id_count + 1; let id = self.id_count; - self.focused_id = id; window_like.handle_message(WindowMessage::Init(dimensions)); let dimensions = if window_like.subtype() == WindowLikeType::Window { [dimensions[0], dimensions[1] + WINDOW_TOP_HEIGHT] } else { dimensions }; - self.window_infos.push(WindowLikeInfo { + let window_info = WindowLikeInfo { id, window_like, top_left, @@ -247,7 +255,13 @@ impl WindowManager { Workspace::All }, fullscreen: false, - }); + }; + if subtype == WindowLikeType::OnscreenKeyboard { + self.osk = Some(window_info); + } else { + self.focused_id = id; + self.window_infos.push(window_info); + } } fn get_focused_index(&self) -> Option { @@ -585,21 +599,30 @@ impl WindowManager { }, WindowManagerMessage::Touch(x, y) => { println!("{}, {}", x, y); - if x < 10000 && y < 10000 { + if x < 100 && y < 100 { //toggle onscreen keyboard if top left keyboard clicked - let osk_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::OnscreenKeyboard); - if let Some(osk_index) = osk_index { - self.window_infos.remove(osk_index); + if self.osk.is_some() { + self.osk = None; } else { let osk = Box::new(OnscreenKeyboard::new()); let ideal_dimensions = osk.ideal_dimensions(self.dimensions); self.add_window_like(osk, [175, self.dimensions[1] - TASKBAR_HEIGHT - 250], Some(ideal_dimensions)); } + WindowMessageResponse::JustRedraw + } else { + //see if in onscreen keyboard, if so send to it after offsetting coords + if self.osk.is_some() { + let mut osk = self.osk.as_mut().unwrap(); + if point_inside([x, y], osk.top_left, osk.dimensions) { + osk.window_like.handle_message(WindowMessage::Touch(x - osk.top_left[0], y - osk.top_left[1])) + } else { + WindowMessageResponse::DoNothing + } + } else { + WindowMessageResponse::DoNothing + } } - //see if in onscreen keyboard, if so send to it after offsetting coords - // - WindowMessageResponse::JustRedraw - }, + } }; if response != WindowMessageResponse::DoNothing { match response { @@ -686,12 +709,15 @@ impl WindowManager { } //get windows to redraw let redraw_ids = maybe_redraw_ids.unwrap_or(Vec::new()); - let all_in_workspace = self.get_windows_in_workspace(true); + let mut all_in_workspace = self.get_windows_in_workspace(true); + if let Some(osk) = &self.osk { + all_in_workspace.push(osk); + } let maybe_length = all_in_workspace.len(); let redraw_windows = all_in_workspace.iter().filter(|w| { //basically, maybe_redraw_ids was None if redraw_ids.len() > 0 { - redraw_ids.contains(&w.id) + redraw_ids.contains(&w.id) || w.window_like.subtype() == WindowLikeType::OnscreenKeyboard } else { true } -- 2.39.5 From 76daaff0239ddf07731530cbed4e3c18a67f3e0d Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sat, 8 Feb 2025 07:13:24 +0000 Subject: [PATCH 05/21] too funny not to preserve --- src/bin/main.rs | 1 + src/components/press_button.rs | 8 ++- src/essential/onscreen_keyboard.rs | 95 +++++++++++++++++++++++++----- src/framebuffer.rs | 20 ++++++- src/messages.rs | 1 + src/window_manager.rs | 36 +++++++++-- 6 files changed, 135 insertions(+), 26 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 6fa77c6..67942ea 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -12,6 +12,7 @@ fn main() { height: fb.var_screen_info.yres_virtual as usize, bytes_per_pixel, stride: fb.fix_screen_info.line_length as usize / bytes_per_pixel, + old_stride: None, }; init(fb, fb_info); diff --git a/src/components/press_button.rs b/src/components/press_button.rs index 04b5324..c7d1e37 100644 --- a/src/components/press_button.rs +++ b/src/components/press_button.rs @@ -10,8 +10,8 @@ use crate::window_manager::{ DrawInstructions }; const MONO_WIDTH: u8 = 10; pub struct PressButton { - top_left: Point, - size: Dimensions, + pub top_left: Point, + pub size: Dimensions, text: String, press_return: T, } @@ -20,7 +20,9 @@ impl Component for PressButton { // fn handle_message(&mut self, message: WindowMessage) -> Option { match message { - WindowMessage::Touch(x, y) => { + WindowMessage::Touch(_, _) => { + //assume that the parent window-like passed it to us intentionally and checked already + //we can check again, but why? Some(self.press_return.clone()) }, _ => None, diff --git a/src/essential/onscreen_keyboard.rs b/src/essential/onscreen_keyboard.rs index 38b6c5d..fdc51b8 100644 --- a/src/essential/onscreen_keyboard.rs +++ b/src/essential/onscreen_keyboard.rs @@ -3,19 +3,20 @@ use std::vec::Vec; use std::collections::HashMap; use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType, KeyChar }; -use crate::messages::{ WindowMessage, WindowMessageResponse }; +use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest }; use crate::framebuffer::Dimensions; use crate::themes::ThemeInfo; use crate::components::Component; use crate::components::press_button::PressButton; +use crate::utils::point_inside; -const padding_y: usize = 15; -const padding_x: usize = 15; +const PADDING_Y: usize = 15; +const PADDING_X: usize = 15; //padding in between keys in the x direction -const key_padding_x: usize = 5; -const key_padding_y: usize = 5; +const KEY_PADDING_X: usize = 5; +const KEY_PADDING_Y: usize = 5; -#[derive(Default, Eq, PartialEq, Hash)] +#[derive(Clone, Default, Eq, PartialEq, Hash)] enum Board { #[default] Regular, @@ -24,6 +25,17 @@ enum Board { SymbolsShift, } +impl Board { + fn inc(&mut self) -> Self { + match self { + Board::Regular => Board::Shift, + Board::Shift => Board::Symbols, + Board::Symbols => Board::SymbolsShift, + Board::SymbolsShift => Board::Regular, + } + } +} + #[derive(Clone)] enum KeyResponse { Key(char), @@ -32,11 +44,15 @@ enum KeyResponse { SwitchBoard, } +//if alt is true and ctrl is true, only alt will be sent. +//because I don't care about ctrl+alt stuff, and won't use it. +//(and probably not supported by this with a real keyboard anyways) #[derive(Default)] pub struct OnscreenKeyboard { dimensions: Dimensions, components: Vec>>, alt: bool, + ctrl: bool, board: Board, } @@ -48,7 +64,39 @@ impl WindowLike for OnscreenKeyboard { self.set_key_components(); WindowMessageResponse::JustRedraw }, - // + WindowMessage::Touch(x, y) => { + for c in &mut self.components { + if point_inside([x, y], c.top_left, c.size) { + let returned = c.handle_message(WindowMessage::Touch(x, y)); + if let Some(returned) = returned { + return match returned { + KeyResponse::Key(ch) => { + WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(if self.alt { + KeyChar::Alt(ch) + } else if self.ctrl { + KeyChar::Ctrl(ch) + } else { + KeyChar::Press(ch) + })) + }, + KeyResponse::Alt => { + self.alt = !self.alt; + WindowMessageResponse::DoNothing + }, + KeyResponse::Ctrl => { + self.ctrl = !self.ctrl; + WindowMessageResponse::DoNothing + }, + KeyResponse::SwitchBoard => { + self.board = self.board.inc(); + WindowMessageResponse::DoNothing + }, + }; + } + } + } + WindowMessageResponse::DoNothing + }, _ => WindowMessageResponse::DoNothing, } } @@ -60,7 +108,7 @@ impl WindowLike for OnscreenKeyboard { } instructions } - // + fn subtype(&self) -> WindowLikeType { WindowLikeType::OnscreenKeyboard } @@ -93,7 +141,7 @@ impl OnscreenKeyboard { HashMap::from([ (Board::Regular, vec!['𐘃', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '𐘁']), //escape and backspace (Board::Shift, vec!['𐘃', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '𐘁']), //escape and backspace - (Board::Symbols, vec!['~', '*', '"', '\'', ':', ';', '!', '?', '𐘁']), //basckspace + (Board::Symbols, vec!['~', '*', '"', '\'', ':', ';', '!', '?', '𐘁']), //backspace (Board::SymbolsShift, vec!['[', ']', '{', '}', '𐘁']), //backspace ]), HashMap::from([ @@ -101,16 +149,17 @@ impl OnscreenKeyboard { (Board::Shift, vec!['𐘧', '𐘎', ' ', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter (Board::Symbols, vec!['𐘧', '𐘎', ',', '_', ' ', '/', '.', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter (Board::SymbolsShift, vec!['𐘧', '𐘎', '\\', '<', ' ', '>', '𐘾', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), ctrl (special case, not a real key), enter + //ctrl = shimazu ]), ]; //hardcoded for now - let mut y = padding_y; - let key_height = (self.dimensions[1] - padding_y * 2 - key_padding_y * (rows.len() - 1)) / rows.len(); - let reg_key_width = (self.dimensions[0] - padding_x * 2 - key_padding_x * (10 - 1)) / 10; + let mut y = PADDING_Y; + let key_height = (self.dimensions[1] - PADDING_Y * 2 - KEY_PADDING_Y * (rows.len() - 1)) / rows.len(); + let reg_key_width = (self.dimensions[0] - PADDING_X * 2 - KEY_PADDING_X * (10 - 1)) / 10; for row in rows { let row_keys = &row[&self.board]; //centre - let mut x = padding_x + (10 - row_keys.len()) * (reg_key_width + key_padding_x) / 2; + let mut x = PADDING_X + (10 - row_keys.len()) * (reg_key_width + KEY_PADDING_X) / 2; for key in row_keys { let press_return = if key == &'𐘧' { KeyResponse::SwitchBoard @@ -121,10 +170,24 @@ impl OnscreenKeyboard { } else { KeyResponse::Key(*key) }; - self.components.push(Box::new(PressButton::new([x, y], [reg_key_width, key_height], key.to_string(), press_return))); - x += reg_key_width + key_padding_x; + let mut text = key.to_string(); + if text == "𐘧" { + text = "Switch".to_string(); + } else if text == "𐘎" { + text = "Alt".to_string(); + } else if text == "𐘂" { + text = "Enter".to_string(); + } else if text == "𐘁" { + text = "Back".to_string(); + } else if text == "𐘃" { + text = "Esc".to_string(); + } else if text == "𐘾" { + text = "Ctrl".to_string(); + } + self.components.push(Box::new(PressButton::new([x, y], [reg_key_width, key_height], text, press_return))); + x += reg_key_width + KEY_PADDING_X; } - y += key_height + key_padding_y; + y += key_height + KEY_PADDING_Y; } } } diff --git a/src/framebuffer.rs b/src/framebuffer.rs index 15d5ea2..449cca6 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -38,6 +38,7 @@ pub struct FramebufferInfo { pub height: usize, pub bytes_per_pixel: usize, pub stride: usize, + pub old_stride: Option, //used/set only when rotate is true } //currently doesn't check if writing onto next line accidentally @@ -45,6 +46,7 @@ pub struct FramebufferWriter { info: FramebufferInfo, buffer: Vec, saved_buffer: Option>, + rotate_buffer: Option>, } impl FramebufferWriter { @@ -57,10 +59,25 @@ impl FramebufferWriter { self.info.clone() } - pub fn get_buffer(&self) -> &[u8] { + pub fn get_buffer(&mut self) -> &[u8] { &self.buffer } + pub fn get_transposed_buffer(&mut self) -> &[u8] { + let mut output_array = vec![255; self.info.byte_len]; + let row_bytes_len = self.info.stride * self.info.bytes_per_pixel; + let row_bytes_len_transposed = self.info.old_stride.unwrap_or(self.info.height) * self.info.bytes_per_pixel; + for y in 0..self.info.height { + for x in 0..self.info.width { + for i in 0..self.info.bytes_per_pixel { + output_array[x * row_bytes_len_transposed + y * self.info.bytes_per_pixel + i] = self.buffer[y * row_bytes_len + x * self.info.bytes_per_pixel + i]; + } + } + } + self.rotate_buffer = Some(output_array); + &self.rotate_buffer.as_ref().unwrap() + } + pub fn save_buffer(&mut self) { self.saved_buffer = Some(self.buffer.clone()); } @@ -237,6 +254,7 @@ impl Default for FramebufferWriter { info: Default::default(), buffer: Vec::new(), saved_buffer: None, + rotate_buffer: None, } } } diff --git a/src/messages.rs b/src/messages.rs index 924f06c..a86279d 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -31,6 +31,7 @@ pub enum WindowManagerRequest { CloseStartMenu, Unlock, Lock, + DoKeyChar(KeyChar), // } diff --git a/src/window_manager.rs b/src/window_manager.rs index c0db4d6..42ff4f7 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -39,7 +39,7 @@ pub const TASKBAR_HEIGHT: usize = 38; pub const INDICATOR_HEIGHT: usize = 20; const WINDOW_TOP_HEIGHT: usize = 26; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum KeyChar { Press(char), Alt(char), @@ -53,6 +53,23 @@ enum ThreadMessage { } pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { + let args: Vec<_> = env::args().collect(); + + let rotate = args.contains(&"rotate".to_string()); + + let framebuffer_info = if rotate { + FramebufferInfo { + byte_len: framebuffer_info.byte_len, + width: framebuffer_info.height, + height: framebuffer_info.width, + bytes_per_pixel: framebuffer_info.bytes_per_pixel, + stride: framebuffer_info.height, + old_stride: Some(framebuffer_info.stride), + } + } else { + framebuffer_info + }; + let dimensions = [framebuffer_info.width, framebuffer_info.height]; println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT); @@ -61,7 +78,7 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { writer.init(framebuffer_info.clone()); - let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions); + let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions, rotate); wm.draw(None, false); @@ -91,7 +108,6 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { } }); - let args: Vec<_> = env::args().collect(); let touch = args.contains(&"touch".to_string()); //read touchscreen presses (hopefully) @@ -204,6 +220,7 @@ impl fmt::Debug for WindowLikeInfo { pub struct WindowManager { writer: RefCell, + rotate: bool, id_count: usize, window_infos: Vec, osk: Option, @@ -219,9 +236,10 @@ pub struct WindowManager { //1 is up, 2 is down impl WindowManager { - pub fn new(writer: FramebufferWriter, framebuffer: Framebuffer, dimensions: Dimensions) -> Self { + pub fn new(writer: FramebufferWriter, framebuffer: Framebuffer, dimensions: Dimensions, rotate: bool) -> Self { let mut wm = WindowManager { writer: RefCell::new(writer), + rotate, id_count: 0, window_infos: Vec::new(), osk: None, @@ -612,7 +630,7 @@ impl WindowManager { } else { //see if in onscreen keyboard, if so send to it after offsetting coords if self.osk.is_some() { - let mut osk = self.osk.as_mut().unwrap(); + let osk = self.osk.as_mut().unwrap(); if point_inside([x, y], osk.top_left, osk.dimensions) { osk.window_like.handle_message(WindowMessage::Touch(x - osk.top_left[0], y - osk.top_left[1])) } else { @@ -692,6 +710,9 @@ impl WindowManager { WindowManagerRequest::ClipboardCopy(content) => { self.clipboard = Some(content); }, + WindowManagerRequest::DoKeyChar(kc) => { + self.handle_message(WindowManagerMessage::KeyChar(kc)); + }, }; } @@ -804,6 +825,9 @@ impl WindowManager { self.writer.borrow_mut().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer()); w_index += 1; } - self.framebuffer.write_frame(self.writer.borrow().get_buffer()); + //could probably figure out a way to do borrow() when self.rotate is false but does it matter? + let mut writer_borrow = self.writer.borrow_mut(); + let frame = if self.rotate { writer_borrow.get_transposed_buffer() } else { writer_borrow.get_buffer() }; + self.framebuffer.write_frame(frame); } } -- 2.39.5 From 45b24aa9ccf7b6f6072a95731405da70d146955d Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sat, 8 Feb 2025 07:21:01 +0000 Subject: [PATCH 06/21] fix --- src/framebuffer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framebuffer.rs b/src/framebuffer.rs index 449cca6..73187af 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -70,7 +70,7 @@ impl FramebufferWriter { for y in 0..self.info.height { for x in 0..self.info.width { for i in 0..self.info.bytes_per_pixel { - output_array[x * row_bytes_len_transposed + y * self.info.bytes_per_pixel + i] = self.buffer[y * row_bytes_len + x * self.info.bytes_per_pixel + i]; + output_array[(self.info.width - x - 1) * row_bytes_len_transposed + y * self.info.bytes_per_pixel + i] = self.buffer[y * row_bytes_len + x * self.info.bytes_per_pixel + i]; } } } -- 2.39.5 From 1e4fdeb36377f8cca4238bc2b8ab81ef0dd14627 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:03:32 +0000 Subject: [PATCH 07/21] remove a print --- src/window_manager.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index 42ff4f7..305d727 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -616,7 +616,6 @@ impl WindowManager { } }, WindowManagerMessage::Touch(x, y) => { - println!("{}, {}", x, y); if x < 100 && y < 100 { //toggle onscreen keyboard if top left keyboard clicked if self.osk.is_some() { -- 2.39.5 From 130df4168aa478b70fd33b2349e849e4cf03b733 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:17:27 +0000 Subject: [PATCH 08/21] clear screen --- src/window_manager.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index 305d727..4e9f2c2 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -15,7 +15,7 @@ use std::process::{ Command, Stdio }; use linux_framebuffer::Framebuffer; use termion::input::TermRead; use termion::raw::IntoRawMode; -use termion::cursor; +use termion::{ clear, cursor }; use serde::{ Deserialize, Serialize }; use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor }; @@ -84,6 +84,8 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { let mut stdout = stdout().into_raw_mode().unwrap(); + write!(stdout, "{}", clear::All).unwrap(); + write!(stdout, "{}", cursor::Hide).unwrap(); stdout.flush().unwrap(); -- 2.39.5 From bcda14399cf790dd545ee62b3dea3041f9d5e6a9 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:25:31 +0000 Subject: [PATCH 09/21] touch coords fix? --- src/window_manager.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index 4e9f2c2..33c7bb1 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -131,7 +131,11 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { y = Some(value); } if x.is_some() && y.is_some() { - tx1.send(ThreadMessage::Touch(x.unwrap(), y.unwrap())).unwrap(); + if rotate { + tx1.send(ThreadMessage::Touch(y.unwrap(), x.unwrap())).unwrap(); + } else { + tx1.send(ThreadMessage::Touch(dimensions[0] - x.unwrap(), y.unwrap())).unwrap(); + } x = None; y = None; } -- 2.39.5 From c69e89c200950158ba6f206c82d8777824b92971 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:49:32 +0000 Subject: [PATCH 10/21] real fix? --- src/window_manager.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index 33c7bb1..6026cbc 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -132,9 +132,9 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { } if x.is_some() && y.is_some() { if rotate { - tx1.send(ThreadMessage::Touch(y.unwrap(), x.unwrap())).unwrap(); + tx1.send(ThreadMessage::Touch(y.unwrap(), dimensions[1] - x.unwrap())).unwrap(); } else { - tx1.send(ThreadMessage::Touch(dimensions[0] - x.unwrap(), y.unwrap())).unwrap(); + tx1.send(ThreadMessage::Touch(x.unwrap(), y.unwrap())).unwrap(); } x = None; y = None; -- 2.39.5 From bd267cd0cbf68d8a9264033c46eda7931d614f68 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sat, 8 Feb 2025 19:13:06 +0000 Subject: [PATCH 11/21] fix --- src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.rs b/src/utils.rs index ea41e9c..11504ad 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -154,6 +154,6 @@ pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool { let y2 = top_left[1]; let x3 = x2 + size[0]; let y3 = y2 + size[1]; - x >= x2 && y >= x2 && x <= x3 && y <= y3 + x >= x2 && y >= y2 && x <= x3 && y <= y3 } -- 2.39.5 From 84040fda1477d923b489563f1c4b38ca60102643 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:22:45 +0000 Subject: [PATCH 12/21] better debug print --- src/messages.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/messages.rs b/src/messages.rs index a86279d..3dcbb38 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -24,7 +24,7 @@ impl PartialEq for WindowBox { } */ -#[derive(PartialEq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum WindowManagerRequest { OpenWindow(String), ClipboardCopy(String), @@ -35,12 +35,6 @@ pub enum WindowManagerRequest { // } -impl fmt::Debug for WindowManagerRequest{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "WindowManagerRequest lmao") - } -} - #[derive(PartialEq, Debug, Serialize, Deserialize)] pub enum WindowMessageResponse { Request(WindowManagerRequest), -- 2.39.5 From a5489d67e6d88ddca3d5b14e04a154f862058a71 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:22:55 +0000 Subject: [PATCH 13/21] different approach --- src/window_manager.rs | 582 +++++++++++++++++++++--------------------- 1 file changed, 288 insertions(+), 294 deletions(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index 6026cbc..8cf0636 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -351,302 +351,298 @@ impl WindowManager { pub fn handle_message(&mut self, message: WindowManagerMessage) { let mut use_saved_buffer = false; let mut redraw_ids = None; - let response: WindowMessageResponse = match message { - WindowManagerMessage::KeyChar(key_char) => { - //check if is special key (key releases are guaranteed to be special keys) - //eg: ctrl, alt, command/windows, shift, or caps lock - match key_char { - KeyChar::Alt(c) => { - let mut press_response = WindowMessageResponse::DoNothing; - if !self.locked { - //keyboard shortcut - let shortcuts = HashMap::from([ - //alt+e is terminate program (ctrl+c) - ('s', ShortcutType::StartMenu), - ('[', ShortcutType::FocusPrevWindow), - (']', ShortcutType::FocusNextWindow), - ('q', ShortcutType::QuitWindow), - ('c', ShortcutType::CenterWindow), - ('f', ShortcutType::FullscreenWindow), - ('w', ShortcutType::HalfWidthWindow), - ('C', ShortcutType::ClipboardCopy), - ('P', ShortcutType::ClipboardPaste(String::new())), - //move window a small amount - ('h', ShortcutType::MoveWindow(Direction::Left)), - ('j', ShortcutType::MoveWindow(Direction::Down)), - ('k', ShortcutType::MoveWindow(Direction::Up)), - ('l', ShortcutType::MoveWindow(Direction::Right)), - //move window to edges - ('H', ShortcutType::MoveWindowToEdge(Direction::Left)), - ('J', ShortcutType::MoveWindowToEdge(Direction::Down)), - ('K', ShortcutType::MoveWindowToEdge(Direction::Up)), - ('L', ShortcutType::MoveWindowToEdge(Direction::Right)), - // - //no 10th workspace - ('1', ShortcutType::SwitchWorkspace(0)), - ('2', ShortcutType::SwitchWorkspace(1)), - ('3', ShortcutType::SwitchWorkspace(2)), - ('4', ShortcutType::SwitchWorkspace(3)), - ('5', ShortcutType::SwitchWorkspace(4)), - ('6', ShortcutType::SwitchWorkspace(5)), - ('7', ShortcutType::SwitchWorkspace(6)), - ('8', ShortcutType::SwitchWorkspace(7)), - ('9', ShortcutType::SwitchWorkspace(8)), - //shfit + num key - ('!', ShortcutType::MoveWindowToWorkspace(0)), - ('@', ShortcutType::MoveWindowToWorkspace(1)), - ('#', ShortcutType::MoveWindowToWorkspace(2)), - ('$', ShortcutType::MoveWindowToWorkspace(3)), - ('%', ShortcutType::MoveWindowToWorkspace(4)), - ('^', ShortcutType::MoveWindowToWorkspace(5)), - ('&', ShortcutType::MoveWindowToWorkspace(6)), - ('*', ShortcutType::MoveWindowToWorkspace(7)), - ('(', ShortcutType::MoveWindowToWorkspace(8)), - // - ]); - if let Some(shortcut) = shortcuts.get(&c) { - match shortcut { - &ShortcutType::StartMenu => { - //send to taskbar - press_response = self.toggle_start_menu(false); - if press_response != WindowMessageResponse::Request(WindowManagerRequest::CloseStartMenu) { - //only thing that needs to be redrawed is the start menu and taskbar - let start_menu_id = self.id_count + 1; - let taskbar_id = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::Taskbar).unwrap().id; - redraw_ids = Some(vec![start_menu_id, taskbar_id]); - } - }, - &ShortcutType::MoveWindow(direction) | &ShortcutType::MoveWindowToEdge(direction) => { - if let Some(focused_index) = self.get_focused_index() { - let focused_info = &self.window_infos[focused_index]; - if focused_info.window_like.subtype() == WindowLikeType::Window && !focused_info.fullscreen { - let delta = 15; - let window_x = self.window_infos[focused_index].top_left[0]; - let window_y = self.window_infos[focused_index].top_left[1]; - let mut changed = true; - if direction == Direction::Left { - if window_x == 0 { - changed = false; - } else if window_x < delta || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[0] = 0; - } else { - self.window_infos[focused_index].top_left[0] -= delta; - } - } else if direction == Direction::Down { - let max_y = self.dimensions[1] - TASKBAR_HEIGHT - focused_info.dimensions[1]; - if window_y == max_y { - changed = false; - } else if window_y > (max_y - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[1] = max_y; - } else { - self.window_infos[focused_index].top_left[1] += delta; - } - } else if direction == Direction::Up { - let min_y = INDICATOR_HEIGHT; - if window_y == min_y { - changed = false; - } else if window_y < (min_y + delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[1] = min_y; - } else { - self.window_infos[focused_index].top_left[1] -= delta; - } - } else if direction == Direction::Right { - let max_x = self.dimensions[0] - focused_info.dimensions[0]; - if window_x == max_x { - changed = false; - } else if window_x > (max_x - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[0] = max_x; - } else { - self.window_infos[focused_index].top_left[0] += delta; - } - } - if changed { - press_response = WindowMessageResponse::JustRedraw; - //avoid drawing everything under the moving window, much more efficient - use_saved_buffer = true; - redraw_ids = Some(vec![self.focused_id]); - } - } - } - }, - &ShortcutType::SwitchWorkspace(workspace) => { - if self.current_workspace != workspace { - //close start menu if open - self.toggle_start_menu(true); - self.current_workspace = workspace; - //send to desktop background - let desktop_background_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::DesktopBackground).unwrap(); - self.window_infos[desktop_background_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); - //send to workspace indicator - let indicator_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::WorkspaceIndicator).unwrap(); - self.focused_id = self.window_infos[indicator_index].id; - self.window_infos[indicator_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); - self.taskbar_update_windows(); - press_response = WindowMessageResponse::JustRedraw; - } - }, - &ShortcutType::MoveWindowToWorkspace(workspace) => { - if self.current_workspace != workspace { - if let Some(focused_index) = self.get_focused_index() { - if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window { - self.window_infos[focused_index].workspace = Workspace::Workspace(workspace); - self.taskbar_update_windows(); - press_response = WindowMessageResponse::JustRedraw; - } - } - } - }, - &ShortcutType::FocusPrevWindow | &ShortcutType::FocusNextWindow => { - let current_index = self.get_focused_index().unwrap_or(0); - let mut new_focus_index = current_index; - loop { - if shortcut == &ShortcutType::FocusPrevWindow { - if new_focus_index == 0 { - new_focus_index = self.window_infos.len() - 1; - } else { - new_focus_index -= 1; - } - } else { - new_focus_index += 1; - if new_focus_index == self.window_infos.len() { - new_focus_index = 0; - } - } - if self.window_infos[new_focus_index].window_like.subtype() == WindowLikeType::Window && self.window_infos[new_focus_index].workspace == Workspace::Workspace(self.current_workspace) { - //switch focus to this - self.focused_id = self.window_infos[new_focus_index].id; - //elevate it to the top - self.move_index_to_top(new_focus_index); - self.taskbar_update_windows(); - press_response = WindowMessageResponse::JustRedraw; - break; - } else if new_focus_index == current_index { - break; //did a full loop, found no windows - } - } - }, - &ShortcutType::QuitWindow => { - if let Some(focused_index) = self.get_focused_index() { - if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window { - self.window_infos.remove(focused_index); - self.taskbar_update_windows(); - press_response = WindowMessageResponse::JustRedraw; - } - } - }, - &ShortcutType::CenterWindow => { - if let Some(focused_index) = self.get_focused_index() { - let window_dimensions = &self.window_infos[focused_index].dimensions; - self.window_infos[focused_index].top_left = [self.dimensions[0] / 2 - window_dimensions[0] / 2, self.dimensions[1] / 2 - window_dimensions[1] / 2]; - use_saved_buffer = true; - press_response = WindowMessageResponse::JustRedraw; - } - }, - &ShortcutType::FullscreenWindow => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { - //toggle fullscreen - self.window_infos[focused_index].fullscreen ^= true; - //todo: send message to window about resize - let new_dimensions; - if self.window_infos[focused_index].fullscreen { - new_dimensions = [self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]; - self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; - redraw_ids = Some(vec![self.window_infos[focused_index].id]); - } else { - new_dimensions = self.window_infos[focused_index].dimensions; - } - self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); - press_response = WindowMessageResponse::JustRedraw; - } - } - }, - &ShortcutType::HalfWidthWindow => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { - self.window_infos[focused_index].fullscreen = false; - //full height, half width - self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; - let new_dimensions = [self.dimensions[0] / 2, self.dimensions[1] - INDICATOR_HEIGHT - TASKBAR_HEIGHT]; - self.window_infos[focused_index].dimensions = new_dimensions; - self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); - press_response = WindowMessageResponse::JustRedraw; - } - } - }, - &ShortcutType::ClipboardCopy => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window { - press_response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardCopy)); - } - } - }, - &ShortcutType::ClipboardPaste(_) => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window && self.clipboard.is_some() { - press_response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardPaste(self.clipboard.clone().unwrap()))); - } - } - }, - }; - } - } - press_response - }, - KeyChar::Press(c) | KeyChar::Ctrl(c) => { - let mut press_response = WindowMessageResponse::DoNothing; - //send to focused window - if let Some(focused_index) = self.get_focused_index() { - press_response = self.window_infos[focused_index].window_like.handle_message(if key_char == KeyChar::Press(c) { - WindowMessage::KeyPress(KeyPress { - key: c, - }) - } else { - WindowMessage::CtrlKeyPress(KeyPress { - key: c, - }) - }); - //at most, only the focused window needs to be redrawed - redraw_ids = Some(vec![self.window_infos[focused_index].id]); - //requests can result in window openings and closings, etc - if press_response != WindowMessageResponse::JustRedraw { - redraw_ids = None; - } - } - press_response - }, - } - }, - WindowManagerMessage::Touch(x, y) => { - if x < 100 && y < 100 { - //toggle onscreen keyboard if top left keyboard clicked - if self.osk.is_some() { - self.osk = None; - } else { - let osk = Box::new(OnscreenKeyboard::new()); - let ideal_dimensions = osk.ideal_dimensions(self.dimensions); - self.add_window_like(osk, [175, self.dimensions[1] - TASKBAR_HEIGHT - 250], Some(ideal_dimensions)); - } - WindowMessageResponse::JustRedraw + let mut response: WindowMessageResponse = WindowMessageResponse::DoNothing; + let mut message = message; + if let WindowManagerMessage::Touch(x, y) = message { + if x < 100 && y < 100 { + //toggle onscreen keyboard if top left keyboard clicked + if self.osk.is_some() { + self.osk = None; } else { - //see if in onscreen keyboard, if so send to it after offsetting coords - if self.osk.is_some() { - let osk = self.osk.as_mut().unwrap(); - if point_inside([x, y], osk.top_left, osk.dimensions) { - osk.window_like.handle_message(WindowMessage::Touch(x - osk.top_left[0], y - osk.top_left[1])) - } else { - WindowMessageResponse::DoNothing + let osk = Box::new(OnscreenKeyboard::new()); + let ideal_dimensions = osk.ideal_dimensions(self.dimensions); + self.add_window_like(osk, [175, self.dimensions[1] - TASKBAR_HEIGHT - 250], Some(ideal_dimensions)); + } + response = WindowMessageResponse::JustRedraw + } else { + //see if in onscreen keyboard, if so send to it after offsetting coords + if self.osk.is_some() { + let osk = self.osk.as_mut().unwrap(); + if point_inside([x, y], osk.top_left, osk.dimensions) { + let osk_resp = osk.window_like.handle_message(WindowMessage::Touch(x - osk.top_left[0], y - osk.top_left[1])); + //change to a WindowManagerMessage::KeyChar + if let WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(kc)) = osk_resp { + message = WindowManagerMessage::KeyChar(kc); } - } else { - WindowMessageResponse::DoNothing } } } - }; + } + if let WindowManagerMessage::KeyChar(key_char) = message { + //check if is special key (key releases are guaranteed to be special keys) + //eg: ctrl, alt, command/windows, shift, or caps lock + match key_char { + KeyChar::Alt(c) => { + if !self.locked { + //keyboard shortcut + let shortcuts = HashMap::from([ + //alt+e is terminate program (ctrl+c) + ('s', ShortcutType::StartMenu), + ('[', ShortcutType::FocusPrevWindow), + (']', ShortcutType::FocusNextWindow), + ('q', ShortcutType::QuitWindow), + ('c', ShortcutType::CenterWindow), + ('f', ShortcutType::FullscreenWindow), + ('w', ShortcutType::HalfWidthWindow), + ('C', ShortcutType::ClipboardCopy), + ('P', ShortcutType::ClipboardPaste(String::new())), + //move window a small amount + ('h', ShortcutType::MoveWindow(Direction::Left)), + ('j', ShortcutType::MoveWindow(Direction::Down)), + ('k', ShortcutType::MoveWindow(Direction::Up)), + ('l', ShortcutType::MoveWindow(Direction::Right)), + //move window to edges + ('H', ShortcutType::MoveWindowToEdge(Direction::Left)), + ('J', ShortcutType::MoveWindowToEdge(Direction::Down)), + ('K', ShortcutType::MoveWindowToEdge(Direction::Up)), + ('L', ShortcutType::MoveWindowToEdge(Direction::Right)), + // + //no 10th workspace + ('1', ShortcutType::SwitchWorkspace(0)), + ('2', ShortcutType::SwitchWorkspace(1)), + ('3', ShortcutType::SwitchWorkspace(2)), + ('4', ShortcutType::SwitchWorkspace(3)), + ('5', ShortcutType::SwitchWorkspace(4)), + ('6', ShortcutType::SwitchWorkspace(5)), + ('7', ShortcutType::SwitchWorkspace(6)), + ('8', ShortcutType::SwitchWorkspace(7)), + ('9', ShortcutType::SwitchWorkspace(8)), + //shfit + num key + ('!', ShortcutType::MoveWindowToWorkspace(0)), + ('@', ShortcutType::MoveWindowToWorkspace(1)), + ('#', ShortcutType::MoveWindowToWorkspace(2)), + ('$', ShortcutType::MoveWindowToWorkspace(3)), + ('%', ShortcutType::MoveWindowToWorkspace(4)), + ('^', ShortcutType::MoveWindowToWorkspace(5)), + ('&', ShortcutType::MoveWindowToWorkspace(6)), + ('*', ShortcutType::MoveWindowToWorkspace(7)), + ('(', ShortcutType::MoveWindowToWorkspace(8)), + // + ]); + if let Some(shortcut) = shortcuts.get(&c) { + match shortcut { + &ShortcutType::StartMenu => { + //send to taskbar + response = self.toggle_start_menu(false); + if response != WindowMessageResponse::Request(WindowManagerRequest::CloseStartMenu) { + //only thing that needs to be redrawed is the start menu and taskbar + let start_menu_id = self.id_count + 1; + let taskbar_id = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::Taskbar).unwrap().id; + redraw_ids = Some(vec![start_menu_id, taskbar_id]); + } + }, + &ShortcutType::MoveWindow(direction) | &ShortcutType::MoveWindowToEdge(direction) => { + if let Some(focused_index) = self.get_focused_index() { + let focused_info = &self.window_infos[focused_index]; + if focused_info.window_like.subtype() == WindowLikeType::Window && !focused_info.fullscreen { + let delta = 15; + let window_x = self.window_infos[focused_index].top_left[0]; + let window_y = self.window_infos[focused_index].top_left[1]; + let mut changed = true; + if direction == Direction::Left { + if window_x == 0 { + changed = false; + } else if window_x < delta || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[0] = 0; + } else { + self.window_infos[focused_index].top_left[0] -= delta; + } + } else if direction == Direction::Down { + let max_y = self.dimensions[1] - TASKBAR_HEIGHT - focused_info.dimensions[1]; + if window_y == max_y { + changed = false; + } else if window_y > (max_y - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[1] = max_y; + } else { + self.window_infos[focused_index].top_left[1] += delta; + } + } else if direction == Direction::Up { + let min_y = INDICATOR_HEIGHT; + if window_y == min_y { + changed = false; + } else if window_y < (min_y + delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[1] = min_y; + } else { + self.window_infos[focused_index].top_left[1] -= delta; + } + } else if direction == Direction::Right { + let max_x = self.dimensions[0] - focused_info.dimensions[0]; + if window_x == max_x { + changed = false; + } else if window_x > (max_x - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[0] = max_x; + } else { + self.window_infos[focused_index].top_left[0] += delta; + } + } + if changed { + response = WindowMessageResponse::JustRedraw; + //avoid drawing everything under the moving window, much more efficient + use_saved_buffer = true; + redraw_ids = Some(vec![self.focused_id]); + } + } + } + }, + &ShortcutType::SwitchWorkspace(workspace) => { + if self.current_workspace != workspace { + //close start menu if open + self.toggle_start_menu(true); + self.current_workspace = workspace; + //send to desktop background + let desktop_background_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::DesktopBackground).unwrap(); + self.window_infos[desktop_background_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); + //send to workspace indicator + let indicator_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::WorkspaceIndicator).unwrap(); + self.focused_id = self.window_infos[indicator_index].id; + self.window_infos[indicator_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); + self.taskbar_update_windows(); + response = WindowMessageResponse::JustRedraw; + } + }, + &ShortcutType::MoveWindowToWorkspace(workspace) => { + if self.current_workspace != workspace { + if let Some(focused_index) = self.get_focused_index() { + if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window { + self.window_infos[focused_index].workspace = Workspace::Workspace(workspace); + self.taskbar_update_windows(); + response = WindowMessageResponse::JustRedraw; + } + } + } + }, + &ShortcutType::FocusPrevWindow | &ShortcutType::FocusNextWindow => { + let current_index = self.get_focused_index().unwrap_or(0); + let mut new_focus_index = current_index; + loop { + if shortcut == &ShortcutType::FocusPrevWindow { + if new_focus_index == 0 { + new_focus_index = self.window_infos.len() - 1; + } else { + new_focus_index -= 1; + } + } else { + new_focus_index += 1; + if new_focus_index == self.window_infos.len() { + new_focus_index = 0; + } + } + if self.window_infos[new_focus_index].window_like.subtype() == WindowLikeType::Window && self.window_infos[new_focus_index].workspace == Workspace::Workspace(self.current_workspace) { + //switch focus to this + self.focused_id = self.window_infos[new_focus_index].id; + //elevate it to the top + self.move_index_to_top(new_focus_index); + self.taskbar_update_windows(); + response = WindowMessageResponse::JustRedraw; + break; + } else if new_focus_index == current_index { + break; //did a full loop, found no windows + } + } + }, + &ShortcutType::QuitWindow => { + if let Some(focused_index) = self.get_focused_index() { + if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window { + self.window_infos.remove(focused_index); + self.taskbar_update_windows(); + response = WindowMessageResponse::JustRedraw; + } + } + }, + &ShortcutType::CenterWindow => { + if let Some(focused_index) = self.get_focused_index() { + let window_dimensions = &self.window_infos[focused_index].dimensions; + self.window_infos[focused_index].top_left = [self.dimensions[0] / 2 - window_dimensions[0] / 2, self.dimensions[1] / 2 - window_dimensions[1] / 2]; + use_saved_buffer = true; + response = WindowMessageResponse::JustRedraw; + } + }, + &ShortcutType::FullscreenWindow => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { + //toggle fullscreen + self.window_infos[focused_index].fullscreen ^= true; + //todo: send message to window about resize + let new_dimensions; + if self.window_infos[focused_index].fullscreen { + new_dimensions = [self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]; + self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; + redraw_ids = Some(vec![self.window_infos[focused_index].id]); + } else { + new_dimensions = self.window_infos[focused_index].dimensions; + } + self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); + response = WindowMessageResponse::JustRedraw; + } + } + }, + &ShortcutType::HalfWidthWindow => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { + self.window_infos[focused_index].fullscreen = false; + //full height, half width + self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; + let new_dimensions = [self.dimensions[0] / 2, self.dimensions[1] - INDICATOR_HEIGHT - TASKBAR_HEIGHT]; + self.window_infos[focused_index].dimensions = new_dimensions; + self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); + response = WindowMessageResponse::JustRedraw; + } + } + }, + &ShortcutType::ClipboardCopy => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window { + response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardCopy)); + } + } + }, + &ShortcutType::ClipboardPaste(_) => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window && self.clipboard.is_some() { + response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardPaste(self.clipboard.clone().unwrap()))); + } + } + }, + }; + } + } + }, + KeyChar::Press(c) | KeyChar::Ctrl(c) => { + //send to focused window + if let Some(focused_index) = self.get_focused_index() { + response = self.window_infos[focused_index].window_like.handle_message(if key_char == KeyChar::Press(c) { + WindowMessage::KeyPress(KeyPress { + key: c, + }) + } else { + WindowMessage::CtrlKeyPress(KeyPress { + key: c, + }) + }); + //at most, only the focused window needs to be redrawed + redraw_ids = Some(vec![self.window_infos[focused_index].id]); + //requests can result in window openings and closings, etc + if response != WindowMessageResponse::JustRedraw { + redraw_ids = None; + } + } + }, + } + } if response != WindowMessageResponse::DoNothing { match response { WindowMessageResponse::Request(request) => self.handle_request(request), @@ -715,9 +711,7 @@ impl WindowManager { WindowManagerRequest::ClipboardCopy(content) => { self.clipboard = Some(content); }, - WindowManagerRequest::DoKeyChar(kc) => { - self.handle_message(WindowManagerMessage::KeyChar(kc)); - }, + WindowManagerRequest::DoKeyChar(_) => {}, }; } -- 2.39.5 From 972d4fc425030c54ff759f249ca7a6900f7024ea Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:23:16 +0000 Subject: [PATCH 14/21] Revert "different approach" This reverts commit a5489d67e6d88ddca3d5b14e04a154f862058a71. --- src/window_manager.rs | 548 +++++++++++++++++++++--------------------- 1 file changed, 277 insertions(+), 271 deletions(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index 8cf0636..6026cbc 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -351,298 +351,302 @@ impl WindowManager { pub fn handle_message(&mut self, message: WindowManagerMessage) { let mut use_saved_buffer = false; let mut redraw_ids = None; - let mut response: WindowMessageResponse = WindowMessageResponse::DoNothing; - let mut message = message; - if let WindowManagerMessage::Touch(x, y) = message { - if x < 100 && y < 100 { - //toggle onscreen keyboard if top left keyboard clicked - if self.osk.is_some() { - self.osk = None; - } else { - let osk = Box::new(OnscreenKeyboard::new()); - let ideal_dimensions = osk.ideal_dimensions(self.dimensions); - self.add_window_like(osk, [175, self.dimensions[1] - TASKBAR_HEIGHT - 250], Some(ideal_dimensions)); - } - response = WindowMessageResponse::JustRedraw - } else { - //see if in onscreen keyboard, if so send to it after offsetting coords - if self.osk.is_some() { - let osk = self.osk.as_mut().unwrap(); - if point_inside([x, y], osk.top_left, osk.dimensions) { - let osk_resp = osk.window_like.handle_message(WindowMessage::Touch(x - osk.top_left[0], y - osk.top_left[1])); - //change to a WindowManagerMessage::KeyChar - if let WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(kc)) = osk_resp { - message = WindowManagerMessage::KeyChar(kc); - } - } - } - } - } - if let WindowManagerMessage::KeyChar(key_char) = message { - //check if is special key (key releases are guaranteed to be special keys) - //eg: ctrl, alt, command/windows, shift, or caps lock - match key_char { - KeyChar::Alt(c) => { - if !self.locked { - //keyboard shortcut - let shortcuts = HashMap::from([ - //alt+e is terminate program (ctrl+c) - ('s', ShortcutType::StartMenu), - ('[', ShortcutType::FocusPrevWindow), - (']', ShortcutType::FocusNextWindow), - ('q', ShortcutType::QuitWindow), - ('c', ShortcutType::CenterWindow), - ('f', ShortcutType::FullscreenWindow), - ('w', ShortcutType::HalfWidthWindow), - ('C', ShortcutType::ClipboardCopy), - ('P', ShortcutType::ClipboardPaste(String::new())), - //move window a small amount - ('h', ShortcutType::MoveWindow(Direction::Left)), - ('j', ShortcutType::MoveWindow(Direction::Down)), - ('k', ShortcutType::MoveWindow(Direction::Up)), - ('l', ShortcutType::MoveWindow(Direction::Right)), - //move window to edges - ('H', ShortcutType::MoveWindowToEdge(Direction::Left)), - ('J', ShortcutType::MoveWindowToEdge(Direction::Down)), - ('K', ShortcutType::MoveWindowToEdge(Direction::Up)), - ('L', ShortcutType::MoveWindowToEdge(Direction::Right)), - // - //no 10th workspace - ('1', ShortcutType::SwitchWorkspace(0)), - ('2', ShortcutType::SwitchWorkspace(1)), - ('3', ShortcutType::SwitchWorkspace(2)), - ('4', ShortcutType::SwitchWorkspace(3)), - ('5', ShortcutType::SwitchWorkspace(4)), - ('6', ShortcutType::SwitchWorkspace(5)), - ('7', ShortcutType::SwitchWorkspace(6)), - ('8', ShortcutType::SwitchWorkspace(7)), - ('9', ShortcutType::SwitchWorkspace(8)), - //shfit + num key - ('!', ShortcutType::MoveWindowToWorkspace(0)), - ('@', ShortcutType::MoveWindowToWorkspace(1)), - ('#', ShortcutType::MoveWindowToWorkspace(2)), - ('$', ShortcutType::MoveWindowToWorkspace(3)), - ('%', ShortcutType::MoveWindowToWorkspace(4)), - ('^', ShortcutType::MoveWindowToWorkspace(5)), - ('&', ShortcutType::MoveWindowToWorkspace(6)), - ('*', ShortcutType::MoveWindowToWorkspace(7)), - ('(', ShortcutType::MoveWindowToWorkspace(8)), - // - ]); - if let Some(shortcut) = shortcuts.get(&c) { - match shortcut { - &ShortcutType::StartMenu => { - //send to taskbar - response = self.toggle_start_menu(false); - if response != WindowMessageResponse::Request(WindowManagerRequest::CloseStartMenu) { - //only thing that needs to be redrawed is the start menu and taskbar - let start_menu_id = self.id_count + 1; - let taskbar_id = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::Taskbar).unwrap().id; - redraw_ids = Some(vec![start_menu_id, taskbar_id]); - } - }, - &ShortcutType::MoveWindow(direction) | &ShortcutType::MoveWindowToEdge(direction) => { - if let Some(focused_index) = self.get_focused_index() { - let focused_info = &self.window_infos[focused_index]; - if focused_info.window_like.subtype() == WindowLikeType::Window && !focused_info.fullscreen { - let delta = 15; - let window_x = self.window_infos[focused_index].top_left[0]; - let window_y = self.window_infos[focused_index].top_left[1]; - let mut changed = true; - if direction == Direction::Left { - if window_x == 0 { - changed = false; - } else if window_x < delta || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[0] = 0; - } else { - self.window_infos[focused_index].top_left[0] -= delta; + let response: WindowMessageResponse = match message { + WindowManagerMessage::KeyChar(key_char) => { + //check if is special key (key releases are guaranteed to be special keys) + //eg: ctrl, alt, command/windows, shift, or caps lock + match key_char { + KeyChar::Alt(c) => { + let mut press_response = WindowMessageResponse::DoNothing; + if !self.locked { + //keyboard shortcut + let shortcuts = HashMap::from([ + //alt+e is terminate program (ctrl+c) + ('s', ShortcutType::StartMenu), + ('[', ShortcutType::FocusPrevWindow), + (']', ShortcutType::FocusNextWindow), + ('q', ShortcutType::QuitWindow), + ('c', ShortcutType::CenterWindow), + ('f', ShortcutType::FullscreenWindow), + ('w', ShortcutType::HalfWidthWindow), + ('C', ShortcutType::ClipboardCopy), + ('P', ShortcutType::ClipboardPaste(String::new())), + //move window a small amount + ('h', ShortcutType::MoveWindow(Direction::Left)), + ('j', ShortcutType::MoveWindow(Direction::Down)), + ('k', ShortcutType::MoveWindow(Direction::Up)), + ('l', ShortcutType::MoveWindow(Direction::Right)), + //move window to edges + ('H', ShortcutType::MoveWindowToEdge(Direction::Left)), + ('J', ShortcutType::MoveWindowToEdge(Direction::Down)), + ('K', ShortcutType::MoveWindowToEdge(Direction::Up)), + ('L', ShortcutType::MoveWindowToEdge(Direction::Right)), + // + //no 10th workspace + ('1', ShortcutType::SwitchWorkspace(0)), + ('2', ShortcutType::SwitchWorkspace(1)), + ('3', ShortcutType::SwitchWorkspace(2)), + ('4', ShortcutType::SwitchWorkspace(3)), + ('5', ShortcutType::SwitchWorkspace(4)), + ('6', ShortcutType::SwitchWorkspace(5)), + ('7', ShortcutType::SwitchWorkspace(6)), + ('8', ShortcutType::SwitchWorkspace(7)), + ('9', ShortcutType::SwitchWorkspace(8)), + //shfit + num key + ('!', ShortcutType::MoveWindowToWorkspace(0)), + ('@', ShortcutType::MoveWindowToWorkspace(1)), + ('#', ShortcutType::MoveWindowToWorkspace(2)), + ('$', ShortcutType::MoveWindowToWorkspace(3)), + ('%', ShortcutType::MoveWindowToWorkspace(4)), + ('^', ShortcutType::MoveWindowToWorkspace(5)), + ('&', ShortcutType::MoveWindowToWorkspace(6)), + ('*', ShortcutType::MoveWindowToWorkspace(7)), + ('(', ShortcutType::MoveWindowToWorkspace(8)), + // + ]); + if let Some(shortcut) = shortcuts.get(&c) { + match shortcut { + &ShortcutType::StartMenu => { + //send to taskbar + press_response = self.toggle_start_menu(false); + if press_response != WindowMessageResponse::Request(WindowManagerRequest::CloseStartMenu) { + //only thing that needs to be redrawed is the start menu and taskbar + let start_menu_id = self.id_count + 1; + let taskbar_id = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::Taskbar).unwrap().id; + redraw_ids = Some(vec![start_menu_id, taskbar_id]); + } + }, + &ShortcutType::MoveWindow(direction) | &ShortcutType::MoveWindowToEdge(direction) => { + if let Some(focused_index) = self.get_focused_index() { + let focused_info = &self.window_infos[focused_index]; + if focused_info.window_like.subtype() == WindowLikeType::Window && !focused_info.fullscreen { + let delta = 15; + let window_x = self.window_infos[focused_index].top_left[0]; + let window_y = self.window_infos[focused_index].top_left[1]; + let mut changed = true; + if direction == Direction::Left { + if window_x == 0 { + changed = false; + } else if window_x < delta || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[0] = 0; + } else { + self.window_infos[focused_index].top_left[0] -= delta; + } + } else if direction == Direction::Down { + let max_y = self.dimensions[1] - TASKBAR_HEIGHT - focused_info.dimensions[1]; + if window_y == max_y { + changed = false; + } else if window_y > (max_y - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[1] = max_y; + } else { + self.window_infos[focused_index].top_left[1] += delta; + } + } else if direction == Direction::Up { + let min_y = INDICATOR_HEIGHT; + if window_y == min_y { + changed = false; + } else if window_y < (min_y + delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[1] = min_y; + } else { + self.window_infos[focused_index].top_left[1] -= delta; + } + } else if direction == Direction::Right { + let max_x = self.dimensions[0] - focused_info.dimensions[0]; + if window_x == max_x { + changed = false; + } else if window_x > (max_x - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { + self.window_infos[focused_index].top_left[0] = max_x; + } else { + self.window_infos[focused_index].top_left[0] += delta; + } } - } else if direction == Direction::Down { - let max_y = self.dimensions[1] - TASKBAR_HEIGHT - focused_info.dimensions[1]; - if window_y == max_y { - changed = false; - } else if window_y > (max_y - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[1] = max_y; - } else { - self.window_infos[focused_index].top_left[1] += delta; + if changed { + press_response = WindowMessageResponse::JustRedraw; + //avoid drawing everything under the moving window, much more efficient + use_saved_buffer = true; + redraw_ids = Some(vec![self.focused_id]); } - } else if direction == Direction::Up { - let min_y = INDICATOR_HEIGHT; - if window_y == min_y { - changed = false; - } else if window_y < (min_y + delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[1] = min_y; - } else { - self.window_infos[focused_index].top_left[1] -= delta; - } - } else if direction == Direction::Right { - let max_x = self.dimensions[0] - focused_info.dimensions[0]; - if window_x == max_x { - changed = false; - } else if window_x > (max_x - delta) || shortcut == &ShortcutType::MoveWindowToEdge(direction) { - self.window_infos[focused_index].top_left[0] = max_x; - } else { - self.window_infos[focused_index].top_left[0] += delta; - } - } - if changed { - response = WindowMessageResponse::JustRedraw; - //avoid drawing everything under the moving window, much more efficient - use_saved_buffer = true; - redraw_ids = Some(vec![self.focused_id]); } } - } - }, - &ShortcutType::SwitchWorkspace(workspace) => { - if self.current_workspace != workspace { - //close start menu if open - self.toggle_start_menu(true); - self.current_workspace = workspace; - //send to desktop background - let desktop_background_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::DesktopBackground).unwrap(); - self.window_infos[desktop_background_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); - //send to workspace indicator - let indicator_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::WorkspaceIndicator).unwrap(); - self.focused_id = self.window_infos[indicator_index].id; - self.window_infos[indicator_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); - self.taskbar_update_windows(); - response = WindowMessageResponse::JustRedraw; - } - }, - &ShortcutType::MoveWindowToWorkspace(workspace) => { - if self.current_workspace != workspace { + }, + &ShortcutType::SwitchWorkspace(workspace) => { + if self.current_workspace != workspace { + //close start menu if open + self.toggle_start_menu(true); + self.current_workspace = workspace; + //send to desktop background + let desktop_background_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::DesktopBackground).unwrap(); + self.window_infos[desktop_background_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); + //send to workspace indicator + let indicator_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::WorkspaceIndicator).unwrap(); + self.focused_id = self.window_infos[indicator_index].id; + self.window_infos[indicator_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace))); + self.taskbar_update_windows(); + press_response = WindowMessageResponse::JustRedraw; + } + }, + &ShortcutType::MoveWindowToWorkspace(workspace) => { + if self.current_workspace != workspace { + if let Some(focused_index) = self.get_focused_index() { + if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window { + self.window_infos[focused_index].workspace = Workspace::Workspace(workspace); + self.taskbar_update_windows(); + press_response = WindowMessageResponse::JustRedraw; + } + } + } + }, + &ShortcutType::FocusPrevWindow | &ShortcutType::FocusNextWindow => { + let current_index = self.get_focused_index().unwrap_or(0); + let mut new_focus_index = current_index; + loop { + if shortcut == &ShortcutType::FocusPrevWindow { + if new_focus_index == 0 { + new_focus_index = self.window_infos.len() - 1; + } else { + new_focus_index -= 1; + } + } else { + new_focus_index += 1; + if new_focus_index == self.window_infos.len() { + new_focus_index = 0; + } + } + if self.window_infos[new_focus_index].window_like.subtype() == WindowLikeType::Window && self.window_infos[new_focus_index].workspace == Workspace::Workspace(self.current_workspace) { + //switch focus to this + self.focused_id = self.window_infos[new_focus_index].id; + //elevate it to the top + self.move_index_to_top(new_focus_index); + self.taskbar_update_windows(); + press_response = WindowMessageResponse::JustRedraw; + break; + } else if new_focus_index == current_index { + break; //did a full loop, found no windows + } + } + }, + &ShortcutType::QuitWindow => { if let Some(focused_index) = self.get_focused_index() { if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window { - self.window_infos[focused_index].workspace = Workspace::Workspace(workspace); + self.window_infos.remove(focused_index); self.taskbar_update_windows(); - response = WindowMessageResponse::JustRedraw; + press_response = WindowMessageResponse::JustRedraw; } } - } - }, - &ShortcutType::FocusPrevWindow | &ShortcutType::FocusNextWindow => { - let current_index = self.get_focused_index().unwrap_or(0); - let mut new_focus_index = current_index; - loop { - if shortcut == &ShortcutType::FocusPrevWindow { - if new_focus_index == 0 { - new_focus_index = self.window_infos.len() - 1; - } else { - new_focus_index -= 1; - } - } else { - new_focus_index += 1; - if new_focus_index == self.window_infos.len() { - new_focus_index = 0; + }, + &ShortcutType::CenterWindow => { + if let Some(focused_index) = self.get_focused_index() { + let window_dimensions = &self.window_infos[focused_index].dimensions; + self.window_infos[focused_index].top_left = [self.dimensions[0] / 2 - window_dimensions[0] / 2, self.dimensions[1] / 2 - window_dimensions[1] / 2]; + use_saved_buffer = true; + press_response = WindowMessageResponse::JustRedraw; + } + }, + &ShortcutType::FullscreenWindow => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { + //toggle fullscreen + self.window_infos[focused_index].fullscreen ^= true; + //todo: send message to window about resize + let new_dimensions; + if self.window_infos[focused_index].fullscreen { + new_dimensions = [self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]; + self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; + redraw_ids = Some(vec![self.window_infos[focused_index].id]); + } else { + new_dimensions = self.window_infos[focused_index].dimensions; + } + self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); + press_response = WindowMessageResponse::JustRedraw; } } - if self.window_infos[new_focus_index].window_like.subtype() == WindowLikeType::Window && self.window_infos[new_focus_index].workspace == Workspace::Workspace(self.current_workspace) { - //switch focus to this - self.focused_id = self.window_infos[new_focus_index].id; - //elevate it to the top - self.move_index_to_top(new_focus_index); - self.taskbar_update_windows(); - response = WindowMessageResponse::JustRedraw; - break; - } else if new_focus_index == current_index { - break; //did a full loop, found no windows - } - } - }, - &ShortcutType::QuitWindow => { - if let Some(focused_index) = self.get_focused_index() { - if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window { - self.window_infos.remove(focused_index); - self.taskbar_update_windows(); - response = WindowMessageResponse::JustRedraw; - } - } - }, - &ShortcutType::CenterWindow => { - if let Some(focused_index) = self.get_focused_index() { - let window_dimensions = &self.window_infos[focused_index].dimensions; - self.window_infos[focused_index].top_left = [self.dimensions[0] / 2 - window_dimensions[0] / 2, self.dimensions[1] / 2 - window_dimensions[1] / 2]; - use_saved_buffer = true; - response = WindowMessageResponse::JustRedraw; - } - }, - &ShortcutType::FullscreenWindow => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { - //toggle fullscreen - self.window_infos[focused_index].fullscreen ^= true; - //todo: send message to window about resize - let new_dimensions; - if self.window_infos[focused_index].fullscreen { - new_dimensions = [self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]; + }, + &ShortcutType::HalfWidthWindow => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { + self.window_infos[focused_index].fullscreen = false; + //full height, half width self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; - redraw_ids = Some(vec![self.window_infos[focused_index].id]); - } else { - new_dimensions = self.window_infos[focused_index].dimensions; + let new_dimensions = [self.dimensions[0] / 2, self.dimensions[1] - INDICATOR_HEIGHT - TASKBAR_HEIGHT]; + self.window_infos[focused_index].dimensions = new_dimensions; + self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); + press_response = WindowMessageResponse::JustRedraw; } - self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); - response = WindowMessageResponse::JustRedraw; } - } - }, - &ShortcutType::HalfWidthWindow => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { - self.window_infos[focused_index].fullscreen = false; - //full height, half width - self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; - let new_dimensions = [self.dimensions[0] / 2, self.dimensions[1] - INDICATOR_HEIGHT - TASKBAR_HEIGHT]; - self.window_infos[focused_index].dimensions = new_dimensions; - self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT])); - response = WindowMessageResponse::JustRedraw; + }, + &ShortcutType::ClipboardCopy => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window { + press_response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardCopy)); + } } - } - }, - &ShortcutType::ClipboardCopy => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window { - response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardCopy)); + }, + &ShortcutType::ClipboardPaste(_) => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window && self.clipboard.is_some() { + press_response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardPaste(self.clipboard.clone().unwrap()))); + } } - } - }, - &ShortcutType::ClipboardPaste(_) => { - if let Some(focused_index) = self.get_focused_index() { - let window_like = &self.window_infos[focused_index].window_like; - if window_like.subtype() == WindowLikeType::Window && self.clipboard.is_some() { - response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardPaste(self.clipboard.clone().unwrap()))); - } - } - }, - }; + }, + }; + } } + press_response + }, + KeyChar::Press(c) | KeyChar::Ctrl(c) => { + let mut press_response = WindowMessageResponse::DoNothing; + //send to focused window + if let Some(focused_index) = self.get_focused_index() { + press_response = self.window_infos[focused_index].window_like.handle_message(if key_char == KeyChar::Press(c) { + WindowMessage::KeyPress(KeyPress { + key: c, + }) + } else { + WindowMessage::CtrlKeyPress(KeyPress { + key: c, + }) + }); + //at most, only the focused window needs to be redrawed + redraw_ids = Some(vec![self.window_infos[focused_index].id]); + //requests can result in window openings and closings, etc + if press_response != WindowMessageResponse::JustRedraw { + redraw_ids = None; + } + } + press_response + }, + } + }, + WindowManagerMessage::Touch(x, y) => { + if x < 100 && y < 100 { + //toggle onscreen keyboard if top left keyboard clicked + if self.osk.is_some() { + self.osk = None; + } else { + let osk = Box::new(OnscreenKeyboard::new()); + let ideal_dimensions = osk.ideal_dimensions(self.dimensions); + self.add_window_like(osk, [175, self.dimensions[1] - TASKBAR_HEIGHT - 250], Some(ideal_dimensions)); } - }, - KeyChar::Press(c) | KeyChar::Ctrl(c) => { - //send to focused window - if let Some(focused_index) = self.get_focused_index() { - response = self.window_infos[focused_index].window_like.handle_message(if key_char == KeyChar::Press(c) { - WindowMessage::KeyPress(KeyPress { - key: c, - }) + WindowMessageResponse::JustRedraw + } else { + //see if in onscreen keyboard, if so send to it after offsetting coords + if self.osk.is_some() { + let osk = self.osk.as_mut().unwrap(); + if point_inside([x, y], osk.top_left, osk.dimensions) { + osk.window_like.handle_message(WindowMessage::Touch(x - osk.top_left[0], y - osk.top_left[1])) } else { - WindowMessage::CtrlKeyPress(KeyPress { - key: c, - }) - }); - //at most, only the focused window needs to be redrawed - redraw_ids = Some(vec![self.window_infos[focused_index].id]); - //requests can result in window openings and closings, etc - if response != WindowMessageResponse::JustRedraw { - redraw_ids = None; + WindowMessageResponse::DoNothing } + } else { + WindowMessageResponse::DoNothing } - }, + } } - } + }; if response != WindowMessageResponse::DoNothing { match response { WindowMessageResponse::Request(request) => self.handle_request(request), @@ -711,7 +715,9 @@ impl WindowManager { WindowManagerRequest::ClipboardCopy(content) => { self.clipboard = Some(content); }, - WindowManagerRequest::DoKeyChar(_) => {}, + WindowManagerRequest::DoKeyChar(kc) => { + self.handle_message(WindowManagerMessage::KeyChar(kc)); + }, }; } -- 2.39.5 From 2be106e3e61c00f240181dc3ec92776097c14c23 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:31:30 +0000 Subject: [PATCH 15/21] osk not redrawing fix??? --- src/messages.rs | 10 ++++++++++ src/window_manager.rs | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/messages.rs b/src/messages.rs index 3dcbb38..5658bf6 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -42,6 +42,16 @@ pub enum WindowMessageResponse { DoNothing, } +impl WindowMessageResponse { + pub fn is_key_char_request(&self) -> bool { + if let WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(_)) = self { + true + } else { + false + } + } +} + #[derive(Serialize, Deserialize)] pub struct KeyPress { pub key: char, diff --git a/src/window_manager.rs b/src/window_manager.rs index 6026cbc..ea77204 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -648,11 +648,14 @@ impl WindowManager { } }; if response != WindowMessageResponse::DoNothing { + let is_key_char_request = response.is_key_char_request(); match response { WindowMessageResponse::Request(request) => self.handle_request(request), _ => {}, }; - self.draw(redraw_ids, use_saved_buffer); + if !is_key_char_request { + self.draw(redraw_ids, use_saved_buffer); + } } } -- 2.39.5 From 1865b2548c8e022020fd28127d9e483ad03703d6 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 10 Feb 2025 01:22:30 +0000 Subject: [PATCH 16/21] try this --- Cargo.toml | 1 + src/essential/onscreen_keyboard.rs | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9c64742..938185b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ serde = { version = "1", features = ["derive"] } audiotags = "0.5.0" bmp-rust = "0.4.1" dirs = "5.0.1" +uinput = "0.1.3" diff --git a/src/essential/onscreen_keyboard.rs b/src/essential/onscreen_keyboard.rs index fdc51b8..523f76a 100644 --- a/src/essential/onscreen_keyboard.rs +++ b/src/essential/onscreen_keyboard.rs @@ -2,6 +2,9 @@ use std::vec; use std::vec::Vec; use std::collections::HashMap; +use uinput::Device; +use uinput::event::keyboard; + use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType, KeyChar }; use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest }; use crate::framebuffer::Dimensions; @@ -47,13 +50,13 @@ enum KeyResponse { //if alt is true and ctrl is true, only alt will be sent. //because I don't care about ctrl+alt stuff, and won't use it. //(and probably not supported by this with a real keyboard anyways) -#[derive(Default)] pub struct OnscreenKeyboard { dimensions: Dimensions, components: Vec>>, alt: bool, ctrl: bool, board: Board, + device: Device, } impl WindowLike for OnscreenKeyboard { @@ -71,6 +74,12 @@ impl WindowLike for OnscreenKeyboard { if let Some(returned) = returned { return match returned { KeyResponse::Key(ch) => { + //for now just send a random keypress to see if it refreshes the framebuffer + //(with just touch event fb doesn't seem to be written to screen, needs key... or stdin?) + self.device.click(&keyboard::Key::Down).unwrap(); + //sync to indicate the events were at the same time + //(so alt+key, ctrl+key is possible) + self.device.synchronize().unwrap(); WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(if self.alt { KeyChar::Alt(ch) } else if self.ctrl { @@ -120,7 +129,14 @@ impl WindowLike for OnscreenKeyboard { impl OnscreenKeyboard { pub fn new() -> Self { - Self::default() + Self { + dimensions: [0, 0], + components: Vec::new(), + alt: false, + ctrl: false, + board: Board::default(), + device: uinput::default().unwrap().name("uinput").unwrap().event(uinput::event::Keyboard::All).unwrap().create().unwrap(), + } } fn set_key_components(&mut self) { -- 2.39.5 From 5af536d5631457b071529936a33e6e09638939bd Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 10 Feb 2025 02:17:39 +0000 Subject: [PATCH 17/21] own fork of uinput with a fix --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 938185b..91bd01f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,6 @@ audiotags = "0.5.0" bmp-rust = "0.4.1" dirs = "5.0.1" uinput = "0.1.3" + +[patch.crates-io] +uinput = { git = 'https://github.com/stjet/rust-uinput.git' } -- 2.39.5 From 3fc70420d28da1f98c98db0c97fcc6b5d916be65 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 10 Feb 2025 03:21:14 +0000 Subject: [PATCH 18/21] permission --- src/essential/onscreen_keyboard.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/essential/onscreen_keyboard.rs b/src/essential/onscreen_keyboard.rs index 523f76a..e903cd3 100644 --- a/src/essential/onscreen_keyboard.rs +++ b/src/essential/onscreen_keyboard.rs @@ -56,7 +56,7 @@ pub struct OnscreenKeyboard { alt: bool, ctrl: bool, board: Board, - device: Device, + device: Option, } impl WindowLike for OnscreenKeyboard { @@ -74,12 +74,14 @@ impl WindowLike for OnscreenKeyboard { if let Some(returned) = returned { return match returned { KeyResponse::Key(ch) => { - //for now just send a random keypress to see if it refreshes the framebuffer - //(with just touch event fb doesn't seem to be written to screen, needs key... or stdin?) - self.device.click(&keyboard::Key::Down).unwrap(); - //sync to indicate the events were at the same time - //(so alt+key, ctrl+key is possible) - self.device.synchronize().unwrap(); + if let Some(device) = &mut self.device { + //for now just send a random keypress to see if it refreshes the framebuffer + //(with just touch event fb doesn't seem to be written to screen, needs key... or stdin?) + device.click(&keyboard::Key::Down).unwrap(); + //sync to indicate the events were at the same time + //(so alt+key, ctrl+key is possible) + device.synchronize().unwrap(); + } WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(if self.alt { KeyChar::Alt(ch) } else if self.ctrl { @@ -129,13 +131,19 @@ impl WindowLike for OnscreenKeyboard { impl OnscreenKeyboard { pub fn new() -> Self { + let device = if let Ok(builder) = uinput::default() { + Some(builder.name("uinput").unwrap().event(uinput::event::Keyboard::All).unwrap().create().unwrap()) + } else { + println!("could not open uinput"); + None + }; Self { dimensions: [0, 0], components: Vec::new(), alt: false, ctrl: false, board: Board::default(), - device: uinput::default().unwrap().name("uinput").unwrap().event(uinput::event::Keyboard::All).unwrap().create().unwrap(), + device, } } -- 2.39.5 From 5998216b19e8763adf24cb477dcd304c42fa2f89 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 10 Feb 2025 03:56:35 +0000 Subject: [PATCH 19/21] remove prev approach, clear fix, and alt/ctrl toggle fix --- Cargo.toml | 4 ---- src/essential/onscreen_keyboard.rs | 38 ++++++++---------------------- src/window_manager.rs | 5 ++-- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 91bd01f..9c64742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,3 @@ serde = { version = "1", features = ["derive"] } audiotags = "0.5.0" bmp-rust = "0.4.1" dirs = "5.0.1" -uinput = "0.1.3" - -[patch.crates-io] -uinput = { git = 'https://github.com/stjet/rust-uinput.git' } diff --git a/src/essential/onscreen_keyboard.rs b/src/essential/onscreen_keyboard.rs index e903cd3..db15b4d 100644 --- a/src/essential/onscreen_keyboard.rs +++ b/src/essential/onscreen_keyboard.rs @@ -2,9 +2,6 @@ use std::vec; use std::vec::Vec; use std::collections::HashMap; -use uinput::Device; -use uinput::event::keyboard; - use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType, KeyChar }; use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest }; use crate::framebuffer::Dimensions; @@ -13,6 +10,9 @@ use crate::components::Component; use crate::components::press_button::PressButton; use crate::utils::point_inside; +//seems like framebuffer only updates if (real) key is pressed... +//on mobile, volume down button seems to work but is annoying + const PADDING_Y: usize = 15; const PADDING_X: usize = 15; //padding in between keys in the x direction @@ -50,13 +50,13 @@ enum KeyResponse { //if alt is true and ctrl is true, only alt will be sent. //because I don't care about ctrl+alt stuff, and won't use it. //(and probably not supported by this with a real keyboard anyways) +#[derive(Default)] pub struct OnscreenKeyboard { dimensions: Dimensions, components: Vec>>, alt: bool, ctrl: bool, board: Board, - device: Option, } impl WindowLike for OnscreenKeyboard { @@ -74,21 +74,16 @@ impl WindowLike for OnscreenKeyboard { if let Some(returned) = returned { return match returned { KeyResponse::Key(ch) => { - if let Some(device) = &mut self.device { - //for now just send a random keypress to see if it refreshes the framebuffer - //(with just touch event fb doesn't seem to be written to screen, needs key... or stdin?) - device.click(&keyboard::Key::Down).unwrap(); - //sync to indicate the events were at the same time - //(so alt+key, ctrl+key is possible) - device.synchronize().unwrap(); - } - WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(if self.alt { + let kc = if self.alt { + self.alt = false; KeyChar::Alt(ch) } else if self.ctrl { + self.ctrl = false; KeyChar::Ctrl(ch) } else { KeyChar::Press(ch) - })) + }; + WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(kc)) }, KeyResponse::Alt => { self.alt = !self.alt; @@ -131,20 +126,7 @@ impl WindowLike for OnscreenKeyboard { impl OnscreenKeyboard { pub fn new() -> Self { - let device = if let Ok(builder) = uinput::default() { - Some(builder.name("uinput").unwrap().event(uinput::event::Keyboard::All).unwrap().create().unwrap()) - } else { - println!("could not open uinput"); - None - }; - Self { - dimensions: [0, 0], - components: Vec::new(), - alt: false, - ctrl: false, - board: Board::default(), - device, - } + Default::default() } fn set_key_components(&mut self) { diff --git a/src/window_manager.rs b/src/window_manager.rs index ea77204..f9eb121 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -80,15 +80,16 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions, rotate); - wm.draw(None, false); - let mut stdout = stdout().into_raw_mode().unwrap(); write!(stdout, "{}", clear::All).unwrap(); write!(stdout, "{}", cursor::Hide).unwrap(); + stdout.flush().unwrap(); + wm.draw(None, false); + let (tx, rx) = mpsc::channel(); let tx1 = tx.clone(); -- 2.39.5 From 2cee4aed6720ecb1844737f671494ce930aa8bfc Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 10 Feb 2025 04:34:09 +0000 Subject: [PATCH 20/21] add clear if top right --- src/messages.rs | 8 ++++++++ src/window_manager.rs | 22 +++++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/messages.rs b/src/messages.rs index 5658bf6..18ad423 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -107,3 +107,11 @@ pub enum WindowMessage { Touch(usize, usize), //for onscreen keyboard only // } + +pub enum ThreadMessage { + KeyChar(KeyChar), + Touch(usize, usize), + Clear, + Exit, +} + diff --git a/src/window_manager.rs b/src/window_manager.rs index f9eb121..f403f28 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -46,12 +46,6 @@ pub enum KeyChar { Ctrl(char), } -enum ThreadMessage { - KeyChar(KeyChar), - Touch(usize, usize), - Exit, -} - pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { let args: Vec<_> = env::args().collect(); @@ -132,11 +126,17 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { y = Some(value); } if x.is_some() && y.is_some() { - if rotate { - tx1.send(ThreadMessage::Touch(y.unwrap(), dimensions[1] - x.unwrap())).unwrap(); + let (x2, y2) = if rotate { + (y.unwrap(), dimensions[1] - x.unwrap()) } else { - tx1.send(ThreadMessage::Touch(x.unwrap(), y.unwrap())).unwrap(); + (x.unwrap(), y.unwrap()) + }; + //top right, clear + //useful sometimes, I think. + if x2 > dimensions[0] - 100 && y2 < 100 { + tx1.send(ThreadMessage::Clear); } + tx1.send(ThreadMessage::Touch(x2, y2)).unwrap(); x = None; y = None; } @@ -154,6 +154,10 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { match message { ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())), ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)), + ThreadMessage::Clear => { + write!(stdout, "{}", clear::All).unwrap(); + stdout.flush().unwrap(); + }, ThreadMessage::Exit => { if !wm.locked { write!(stdout, "{}", cursor::Show).unwrap(); -- 2.39.5 From 1f394d4068d43e37d64e0bb7beced5e9e49a0c36 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 10 Feb 2025 04:59:39 +0000 Subject: [PATCH 21/21] fix panic for touch --- src/window_manager.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/window_manager.rs b/src/window_manager.rs index f403f28..a651e65 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -134,7 +134,7 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { //top right, clear //useful sometimes, I think. if x2 > dimensions[0] - 100 && y2 < 100 { - tx1.send(ThreadMessage::Clear); + tx1.send(ThreadMessage::Clear).unwrap(); } tx1.send(ThreadMessage::Touch(x2, y2)).unwrap(); x = None; @@ -665,10 +665,14 @@ impl WindowManager { } pub fn handle_request(&mut self, request: WindowManagerRequest) { - let focused_index = self.get_focused_index().unwrap(); - let subtype = self.window_infos[focused_index].window_like.subtype(); + let subtype = if let Some(focused_index) = self.get_focused_index() { + Some(self.window_infos[focused_index].window_like.subtype()) + } else { + None + }; match request { WindowManagerRequest::OpenWindow(w) => { + let subtype = subtype.unwrap(); if subtype != WindowLikeType::Taskbar && subtype != WindowLikeType::StartMenu { return; } @@ -700,6 +704,7 @@ impl WindowManager { self.taskbar_update_windows(); }, WindowManagerRequest::CloseStartMenu => { + let subtype = subtype.unwrap(); if subtype != WindowLikeType::Taskbar && subtype != WindowLikeType::StartMenu { return; } @@ -709,13 +714,13 @@ impl WindowManager { } }, WindowManagerRequest::Unlock => { - if subtype != WindowLikeType::LockScreen { + if subtype.unwrap() != WindowLikeType::LockScreen { return; } self.unlock(); }, WindowManagerRequest::Lock => { - if subtype != WindowLikeType::StartMenu { + if subtype.unwrap() != WindowLikeType::StartMenu { return; } self.lock(); -- 2.39.5