Skip to content

Commit 11ef5ac

Browse files
authored
Merge pull request #249 from RustCastLabs/better-input-handling
Better input handling
2 parents 1ed5fa3 + 66cb6c7 commit 11ef5ac

9 files changed

Lines changed: 333 additions & 108 deletions

File tree

src/app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::app::apps::{App, AppCommand, ICNS_ICON};
55
use crate::commands::Function;
66
use crate::config::{Config, MainPage, Shelly};
77
use crate::debounce::DebouncePolicy;
8+
use crate::platform::macos::launching::Shortcut;
89
use crate::utils::icns_data_to_handle;
910
use crate::{app::tile::ExtSender, clipboard::ClipBoardContentType};
1011
use iced::time::Duration;
@@ -90,7 +91,7 @@ pub enum Message {
9091
OpenResult(u32),
9192
OpenToSettings,
9293
SearchQueryChanged(String, Id),
93-
KeyPressed(u32),
94+
KeyPressed(Shortcut),
9495
FocusTextInput(Move),
9596
HideWindow(Id),
9697
RunFunction(Function),

src/app/menubar.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::{collections::HashMap, io::Cursor};
44

5-
use global_hotkey::hotkey::{Code, HotKey, Modifiers};
5+
use global_hotkey::hotkey::{Code, Modifiers};
66
use image::{DynamicImage, ImageReader};
77
use log::info;
88
use tray_icon::{
@@ -16,6 +16,7 @@ use tray_icon::{
1616
use crate::{
1717
app::{Message, tile::ExtSender},
1818
config::Config,
19+
platform::macos::launching::Shortcut,
1920
utils::open_url,
2021
};
2122

@@ -39,14 +40,15 @@ pub fn menu_icon(config: Config, sender: ExtSender) -> TrayIcon {
3940
}
4041

4142
pub fn menu_builder(config: Config, sender: ExtSender, update_item: bool) -> Menu {
42-
let hotkey = config.toggle_hotkey.parse::<HotKey>().ok();
43+
let shortcut =
44+
Shortcut::parse(&config.toggle_hotkey).unwrap_or(Shortcut::parse("opt+space").unwrap());
4345

4446
let mut modes = config.modes;
4547
if !modes.contains_key("default") {
4648
modes.insert("Default".to_string(), "default".to_string());
4749
}
4850

49-
init_event_handler(sender, hotkey.map(|x| x.id));
51+
init_event_handler(sender, shortcut);
5052

5153
Menu::with_items(&[
5254
&MenuItem::with_id(
@@ -64,7 +66,7 @@ pub fn menu_builder(config: Config, sender: ExtSender, update_item: bool) -> Men
6466
&open_github_item(),
6567
&PredefinedMenuItem::separator(),
6668
&refresh_item(),
67-
&open_item(hotkey),
69+
&open_item(),
6870
&mode_item(modes),
6971
&PredefinedMenuItem::separator(),
7072
&open_issue_item(),
@@ -86,10 +88,12 @@ fn get_image() -> DynamicImage {
8688
.unwrap()
8789
}
8890

89-
fn init_event_handler(sender: ExtSender, hotkey_id: Option<u32>) {
91+
fn init_event_handler(sender: ExtSender, shortcut: Shortcut) {
9092
let runtime = Runtime::new().unwrap();
93+
let shortcut = shortcut.clone();
9194

9295
MenuEvent::set_event_handler(Some(move |x: MenuEvent| {
96+
let shortcut = shortcut.clone();
9397
let sender = sender.clone();
9498
let sender = sender.0.clone();
9599
info!("Menubar event called: {}", x.id.0);
@@ -107,11 +111,12 @@ fn init_event_handler(sender: ExtSender, hotkey_id: Option<u32>) {
107111
open_url("https://github.com/RustCastLabs/rustcast/issues/new");
108112
}
109113
"show_rustcast" => {
110-
if let Some(hk) = hotkey_id {
111-
runtime.spawn(async move {
112-
sender.clone().try_send(Message::KeyPressed(hk)).unwrap();
113-
});
114-
}
114+
runtime.spawn(async move {
115+
sender
116+
.clone()
117+
.try_send(Message::KeyPressed(shortcut.clone()))
118+
.unwrap();
119+
});
115120
}
116121
"update" => {
117122
open_url("https://github.com/RustCastLabs/rustcast/releases/latest");
@@ -178,13 +183,8 @@ fn mode_item(modes: HashMap<String, String>) -> Submenu {
178183
Submenu::with_items("Modes", true, &items).unwrap()
179184
}
180185

181-
fn open_item(hotkey: Option<HotKey>) -> MenuItem {
182-
MenuItem::with_id(
183-
"show_rustcast",
184-
"Toggle View",
185-
true,
186-
hotkey.map(|hk| Accelerator::new(Some(hk.mods), hk.key)),
187-
)
186+
fn open_item() -> MenuItem {
187+
MenuItem::with_id("show_rustcast", "Toggle View", true, None)
188188
}
189189

190190
fn open_github_item() -> MenuItem {

src/app/pages/settings.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub fn settings_page(config: Config) -> Element<'static, Message> {
4444
.width(Length::Fill)
4545
.style(move |_, _| settings_text_input_item_style(&hotkey_theme))
4646
.into(),
47-
notice_item(theme.clone(), "Requires a restart"),
47+
notice_item(theme.clone(), "Use \"+\" as a seperator"),
4848
]);
4949

5050
let cb_theme = theme.clone();
@@ -56,7 +56,7 @@ pub fn settings_page(config: Config) -> Element<'static, Message> {
5656
.width(Length::Fill)
5757
.style(move |_, _| settings_text_input_item_style(&cb_theme))
5858
.into(),
59-
notice_item(theme.clone(), "Requires a restart"),
59+
notice_item(theme.clone(), "Use \"+\" as a seperator"),
6060
]);
6161

6262
let placeholder_theme = theme.clone();

src/app/tile.rs

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ pub mod update;
55
use crate::app::apps::App;
66
use crate::app::{ArrowKey, Message, Move, Page};
77
use crate::clipboard::ClipBoardContentType;
8-
use crate::config::Config;
8+
use crate::config::{Config, Shelly};
99
use crate::debounce::Debouncer;
1010
use crate::platform::default_app_paths;
11+
use crate::platform::macos::launching::Shortcut;
1112

1213
use arboard::Clipboard;
13-
use global_hotkey::hotkey::HotKey;
14-
use global_hotkey::{GlobalHotKeyEvent, HotKeyState};
1514

1615
use iced::futures::SinkExt;
1716
use iced::futures::channel::mpsc::{Sender, channel};
@@ -190,9 +189,9 @@ pub struct Tile {
190189
/// Stores the toggle [`HotKey`] and the Clipboard [`HotKey`]
191190
#[derive(Clone, Debug)]
192191
pub struct Hotkeys {
193-
pub toggle: HotKey,
194-
pub clipboard_hotkey: HotKey,
195-
pub shells: HashMap<u32, String>,
192+
pub toggle: Shortcut,
193+
pub clipboard_hotkey: Shortcut,
194+
pub shells: HashMap<Shortcut, Shelly>,
196195
}
197196

198197
impl Tile {
@@ -229,7 +228,6 @@ impl Tile {
229228
_ => None,
230229
});
231230
Subscription::batch([
232-
Subscription::run(handle_hotkeys),
233231
Subscription::run(handle_hot_reloading),
234232
keyboard,
235233
Subscription::run(handle_recipient),
@@ -241,37 +239,34 @@ impl Tile {
241239
if let keyboard::Event::KeyPressed { key, modifiers, .. } = event {
242240
match key {
243241
keyboard::Key::Named(Named::ArrowUp) => {
244-
return Some(Message::ChangeFocus(ArrowKey::Up, 1));
242+
Some(Message::ChangeFocus(ArrowKey::Up, 1))
245243
}
246244
keyboard::Key::Named(Named::ArrowLeft) => {
247-
return Some(Message::ChangeFocus(ArrowKey::Left, 1));
245+
Some(Message::ChangeFocus(ArrowKey::Left, 1))
248246
}
249247
keyboard::Key::Named(Named::ArrowRight) => {
250-
return Some(Message::ChangeFocus(ArrowKey::Right, 1));
248+
Some(Message::ChangeFocus(ArrowKey::Right, 1))
251249
}
252250
keyboard::Key::Named(Named::ArrowDown) => {
253-
return Some(Message::ChangeFocus(ArrowKey::Down, 1));
251+
Some(Message::ChangeFocus(ArrowKey::Down, 1))
254252
}
255253
keyboard::Key::Character(chr) => {
256254
if modifiers.command() && chr.to_string() == "r" {
257-
return Some(Message::ReloadConfig);
255+
Some(Message::ReloadConfig)
258256
} else if chr.to_string() == "p" && modifiers.control() {
259-
return Some(Message::ChangeFocus(ArrowKey::Up, 1));
257+
Some(Message::ChangeFocus(ArrowKey::Up, 1))
260258
} else if chr.to_string() == "n" && modifiers.control() {
261-
return Some(Message::ChangeFocus(ArrowKey::Down, 1));
259+
Some(Message::ChangeFocus(ArrowKey::Down, 1))
262260
} else {
263-
return Some(Message::FocusTextInput(Move::Forwards(
264-
chr.to_string(),
265-
)));
261+
Some(Message::FocusTextInput(Move::Forwards(chr.to_string())))
266262
}
267263
}
268-
keyboard::Key::Named(Named::Enter) => return Some(Message::OpenFocused),
264+
keyboard::Key::Named(Named::Enter) => Some(Message::OpenFocused),
269265
keyboard::Key::Named(Named::Backspace) => {
270-
return Some(Message::FocusTextInput(Move::Back));
266+
Some(Message::FocusTextInput(Move::Back))
271267
}
272-
_ => {}
268+
_ => None,
273269
}
274-
None
275270
} else {
276271
None
277272
}
@@ -337,22 +332,6 @@ impl Tile {
337332
}
338333
}
339334

340-
/// This is the subscription function that handles hotkeys, e.g. for hiding / showing the window
341-
fn handle_hotkeys() -> impl futures::Stream<Item = Message> {
342-
stream::channel(100, async |mut output| {
343-
let receiver = GlobalHotKeyEvent::receiver();
344-
loop {
345-
info!("Hotkey received");
346-
if let Ok(event) = receiver.recv()
347-
&& event.state == HotKeyState::Pressed
348-
{
349-
output.try_send(Message::KeyPressed(event.id)).unwrap();
350-
}
351-
tokio::time::sleep(Duration::from_millis(100)).await;
352-
}
353-
})
354-
}
355-
356335
/// This is the subscription function that handles the change in clipboard history
357336
fn handle_clipboard_history() -> impl futures::Stream<Item = Message> {
358337
stream::channel(100, async |mut output| {
@@ -602,7 +581,6 @@ fn handle_recipient() -> impl futures::Stream<Item = Message> {
602581
let abcd = recipient
603582
.try_recv()
604583
.map(async |msg| {
605-
info!("Sending a message");
606584
output.send(msg).await.unwrap();
607585
})
608586
.ok();

src/app/tile/elm.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
use std::collections::HashMap;
55
use std::fs;
66

7-
use global_hotkey::hotkey::HotKey;
87
use iced::border::Radius;
98
use iced::widget::scrollable::{Anchor, Direction, Scrollbar};
109
use iced::widget::text::LineHeight;
@@ -35,7 +34,7 @@ use crate::{
3534
};
3635

3736
/// Initialise the base window
38-
pub fn new(hotkey: HotKey, config: &Config) -> (Tile, Task<Message>) {
37+
pub fn new(hotkeys: Hotkeys, config: &Config) -> (Tile, Task<Message>) {
3938
let (id, open) = window::open(default_settings());
4039
info!("Opening window");
4140

@@ -60,24 +59,6 @@ pub fn new(hotkey: HotKey, config: &Config) -> (Tile, Task<Message>) {
6059
options.par_sort_by_key(|x| x.display_name.len());
6160
let options = AppIndex::from_apps(options);
6261

63-
let mut shells_map = HashMap::new();
64-
for shell in &config.shells {
65-
if let Some(hk_str) = &shell.hotkey
66-
&& let Ok(hk) = hk_str.parse::<HotKey>()
67-
{
68-
shells_map.insert(hk.id, shell.command.clone());
69-
}
70-
}
71-
72-
let hotkeys = Hotkeys {
73-
toggle: hotkey,
74-
clipboard_hotkey: config
75-
.clipboard_hotkey
76-
.parse()
77-
.unwrap_or("SUPER+SHIFT+C".parse().unwrap()),
78-
shells: shells_map,
79-
};
80-
8162
let home = std::env::var("HOME").unwrap_or("/".to_string());
8263

8364
let ranking = toml::from_str(
@@ -94,8 +75,8 @@ pub fn new(hotkey: HotKey, config: &Config) -> (Tile, Task<Message>) {
9475
focus_id: 0,
9576
results: vec![],
9677
options,
97-
emoji_apps: AppIndex::from_apps(App::emoji_apps()),
9878
hotkeys,
79+
emoji_apps: AppIndex::from_apps(App::emoji_apps()),
9980
visible: true,
10081
frontmost: None,
10182
focused: false,

src/app/tile/update.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! This handles the update logic for the tile (AKA rustcast's main window)
22
use std::cmp::min;
3+
use std::collections::HashMap;
34
use std::fs;
45
use std::io::Cursor;
56
use std::thread;
@@ -34,6 +35,8 @@ use crate::commands::Function;
3435
use crate::config::Config;
3536
use crate::config::MainPage;
3637
use crate::debounce::DebouncePolicy;
38+
use crate::platform::macos::launching::Shortcut;
39+
use crate::platform::macos::launching::global_handler;
3740
use crate::platform::macos::{start_at_login, stop_at_login};
3841
use crate::quit::get_open_apps;
3942
use crate::unit_conversion;
@@ -91,6 +94,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
9194

9295
Message::SetSender(sender) => {
9396
tile.sender = Some(sender.clone());
97+
global_handler(sender.clone());
9498
if tile.config.show_trayicon {
9599
tile.tray_icon = Some(menu_icon(tile.config.clone(), sender));
96100
}
@@ -274,6 +278,24 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
274278
Err(_) => return Task::none(),
275279
};
276280

281+
if let Ok(hotkey) = Shortcut::parse(&new_config.clipboard_hotkey) {
282+
tile.hotkeys.clipboard_hotkey = hotkey
283+
}
284+
285+
if let Ok(hotkey) = Shortcut::parse(&new_config.toggle_hotkey) {
286+
tile.hotkeys.toggle = hotkey
287+
}
288+
289+
let mut shell_map = HashMap::new();
290+
291+
for shell in &new_config.shells {
292+
if let Some(hotkey) = shell.hotkey.clone().and_then(|x| Shortcut::parse(&x).ok()) {
293+
shell_map.insert(hotkey, shell.clone());
294+
}
295+
}
296+
297+
tile.hotkeys.shells = shell_map;
298+
277299
let update_apps_task = if tile.config.shells != new_config.shells {
278300
info!("App Update required");
279301
Task::done(Message::UpdateApps)
@@ -303,17 +325,20 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
303325
Task::batch([Task::done(Message::LoadRanking), update_apps_task])
304326
}
305327

306-
Message::KeyPressed(hk_id) => {
307-
if let Some(cmd) = tile.hotkeys.shells.get(&hk_id) {
308-
return Task::done(Message::RunFunction(Function::RunShellCommand(cmd.clone())));
328+
Message::KeyPressed(shortcut) => {
329+
if let Some(cmd) = tile.hotkeys.shells.get(&shortcut) {
330+
return Task::done(Message::RunFunction(Function::RunShellCommand(
331+
cmd.command.clone(),
332+
)));
309333
}
310-
311-
let is_clipboard_hotkey = tile.hotkeys.clipboard_hotkey.id == hk_id;
312-
let is_open_hotkey = hk_id == tile.hotkeys.toggle.id;
334+
let is_clipboard_hotkey = shortcut == tile.hotkeys.clipboard_hotkey;
335+
let is_open_hotkey = shortcut == tile.hotkeys.toggle;
313336

314337
let clipboard_page_task = if is_clipboard_hotkey {
338+
info!("Switching to clipboard page");
315339
Task::done(Message::SwitchToPage(Page::ClipboardHistory))
316340
} else if is_open_hotkey {
341+
info!("Switching to main page");
317342
Task::done(Message::SwitchToPage(Page::Main))
318343
} else {
319344
Task::none()
@@ -485,6 +510,18 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
485510
new_options.par_sort_by_key(|x| x.display_name.len());
486511
tile.options = AppIndex::from_apps(new_options);
487512

513+
let mut shell_map = HashMap::new();
514+
515+
for shell in &tile.config.shells {
516+
if let Some(has_hk) = &shell.hotkey
517+
&& let Some(hotkey) = Shortcut::parse(has_hk).ok()
518+
{
519+
shell_map.insert(hotkey, shell.clone());
520+
}
521+
}
522+
523+
tile.hotkeys.shells = shell_map;
524+
488525
Task::none()
489526
}
490527

0 commit comments

Comments
 (0)