feat: shortcut key input
This commit is contained in:
parent
52cd2f281c
commit
95180b19e4
9 changed files with 590 additions and 129 deletions
|
|
@ -71,6 +71,7 @@ upower_dbus = { git = "https://github.com/pop-os/dbus-settings-bindings", option
|
|||
bluez-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
|
||||
url = "2.5.7"
|
||||
xkb-data = "0.2.1"
|
||||
xkeysym = { version = "0.2.0", optional = true }
|
||||
zbus = { version = "5.11.0", default-features = false, features = [
|
||||
"tokio",
|
||||
], optional = true }
|
||||
|
|
@ -147,6 +148,8 @@ page-input = [
|
|||
"dep:cosmic-comp-config",
|
||||
"dep:cosmic-settings-config",
|
||||
"dep:udev",
|
||||
"dep:xkeysym",
|
||||
"wayland",
|
||||
]
|
||||
page-legacy-applications = ["dep:cosmic-comp-config"]
|
||||
page-networking = [
|
||||
|
|
|
|||
|
|
@ -2,14 +2,17 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use cosmic::app::ContextDrawer;
|
||||
use cosmic::iced::{Alignment, Length};
|
||||
use cosmic::iced::event::listen_with;
|
||||
use cosmic::iced::keyboard::key::Named;
|
||||
use cosmic::iced::keyboard::{Key, Location, Modifiers};
|
||||
use cosmic::iced::{self, Alignment, Length};
|
||||
use cosmic::widget::{self, button, icon, settings, text};
|
||||
use cosmic::{Apply, Element, Task, theme};
|
||||
use cosmic::{Apply, Element, Task, iced_winit, theme};
|
||||
use cosmic_config::{ConfigGet, ConfigSet};
|
||||
use cosmic_settings_config::shortcuts::{self, Action, Binding, Shortcuts};
|
||||
use cosmic_settings_page as page;
|
||||
use slab::Slab;
|
||||
use slotmap::Key;
|
||||
use slotmap::Key as SlotmapKey;
|
||||
use std::borrow::Cow;
|
||||
use std::str::FromStr;
|
||||
use std::{io, mem};
|
||||
|
|
@ -26,12 +29,18 @@ pub enum ShortcutMessage {
|
|||
ResetBindings,
|
||||
ShowShortcut(usize, String),
|
||||
SubmitBinding(usize),
|
||||
Inhibited(bool),
|
||||
ProtocolUnavailable,
|
||||
ModifiersChanged(Modifiers),
|
||||
KeyReleased(u32, Key, Location),
|
||||
KeyPressed(u32, Key, Location, Modifiers),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ShortcutBinding {
|
||||
pub id: widget::Id,
|
||||
pub binding: Binding,
|
||||
pub pending: Binding,
|
||||
pub input: String,
|
||||
pub is_default: bool,
|
||||
pub is_saved: bool,
|
||||
|
|
@ -67,6 +76,7 @@ impl ShortcutModel {
|
|||
slab.insert(ShortcutBinding {
|
||||
id: widget::Id::unique(),
|
||||
binding: binding.clone(),
|
||||
pending: binding.clone(),
|
||||
input: String::new(),
|
||||
is_default,
|
||||
is_saved: true,
|
||||
|
|
@ -150,6 +160,7 @@ impl Model {
|
|||
pub(super) fn config_add(&self, action: Action, binding: Binding) {
|
||||
let mut shortcuts = self.shortcuts_config();
|
||||
shortcuts.0.insert(binding, action);
|
||||
|
||||
self.shortcuts_config_set(shortcuts);
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +237,7 @@ impl Model {
|
|||
None
|
||||
}
|
||||
|
||||
pub(super) fn on_enter(&mut self) {
|
||||
pub(super) fn on_enter(&mut self) -> cosmic::Task<ShortcutMessage> {
|
||||
let mut shortcuts = self.config.get::<Shortcuts>("defaults").unwrap_or_default();
|
||||
self.defaults = shortcuts.clone();
|
||||
|
||||
|
|
@ -240,6 +251,8 @@ impl Model {
|
|||
self.shortcut_models = (self.actions)(&self.defaults, &shortcuts);
|
||||
self.shortcut_context = None;
|
||||
self.editing = None;
|
||||
|
||||
return Task::none();
|
||||
}
|
||||
|
||||
pub(super) fn on_context_drawer_close(&mut self) {
|
||||
|
|
@ -313,7 +326,10 @@ impl Model {
|
|||
self.editing = Some(binding_id);
|
||||
shortcut.input.clear();
|
||||
|
||||
return widget::text_input::focus(shortcut.id.clone());
|
||||
return Task::batch(vec![
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(true).discard(),
|
||||
widget::text_input::focus(shortcut.id.clone())
|
||||
]);
|
||||
}
|
||||
|
||||
// Create a new input and focus it.
|
||||
|
|
@ -321,16 +337,19 @@ impl Model {
|
|||
self.editing = Some(model.bindings.insert(ShortcutBinding {
|
||||
id: id.clone(),
|
||||
binding: Binding::default(),
|
||||
pending: Binding::default(),
|
||||
input: String::new(),
|
||||
is_default: false,
|
||||
is_saved: false,
|
||||
}));
|
||||
|
||||
return widget::text_input::focus(id);
|
||||
return Task::batch(vec![
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(true).discard(),
|
||||
widget::text_input::focus(id)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutMessage::ApplyReplace => {
|
||||
if let Some((id, new_binding, ..)) = self.replace_dialog.take() {
|
||||
if let Some(short_id) = self.shortcut_context {
|
||||
|
|
@ -368,11 +387,10 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
self.on_enter();
|
||||
_ = self.on_enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutMessage::CancelReplace => {
|
||||
if let Some(((id, _, _, _), short_id)) =
|
||||
self.replace_dialog.take().zip(self.shortcut_context)
|
||||
|
|
@ -385,7 +403,6 @@ impl Model {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutMessage::DeleteBinding(id) => {
|
||||
if let Some(short_id) = self.shortcut_context {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
|
|
@ -398,41 +415,47 @@ impl Model {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutMessage::DeleteShortcut(id) => {
|
||||
let model = self.shortcut_models.remove(id);
|
||||
for (_, shortcut) in model.bindings {
|
||||
self.config_remove(&shortcut.binding);
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutMessage::EditBinding(id, enable) => {
|
||||
if !enable && self.editing == Some(id) {
|
||||
self.editing = None;
|
||||
if let Some(short_id) = self.shortcut_context {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(shortcut) = model.bindings.get_mut(id) {
|
||||
shortcut.pending = shortcut.binding.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Task::batch(vec![
|
||||
cosmic::widget::text_input::focus(self.add_keybindings_button_id.clone()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard()
|
||||
]);
|
||||
}
|
||||
if let Some(short_id) = self.shortcut_context {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(shortcut) = model.bindings.get_mut(id) {
|
||||
if enable {
|
||||
self.editing = Some(id);
|
||||
shortcut.input = shortcut.binding.to_string();
|
||||
return widget::text_input::select_all(shortcut.id.clone());
|
||||
return iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(true).discard();
|
||||
} else if self.editing == Some(id) {
|
||||
self.editing = None;
|
||||
return iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutMessage::InputBinding(id, text) => {
|
||||
if let Some(short_id) = self.shortcut_context {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(shortcut) = model.bindings.get_mut(id) {
|
||||
shortcut.input = text;
|
||||
}
|
||||
}
|
||||
ShortcutMessage::InputBinding(bind_id, ..) => {
|
||||
if self.editing.is_none() {
|
||||
return self.update(ShortcutMessage::EditBinding(bind_id, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Removes all bindings from the active shortcut context, and reloads the shortcuts model.
|
||||
ShortcutMessage::ResetBindings => {
|
||||
if let Some(short_id) = self.shortcut_context {
|
||||
if let Some(model) = self.shortcut_models.get(short_id) {
|
||||
|
|
@ -449,10 +472,9 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
self.on_enter();
|
||||
_ = self.on_enter();
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutMessage::ShowShortcut(id, description) => {
|
||||
self.shortcut_context = Some(id);
|
||||
self.shortcut_title = description;
|
||||
|
|
@ -472,13 +494,162 @@ impl Model {
|
|||
|
||||
return Task::batch(tasks);
|
||||
}
|
||||
ShortcutMessage::SubmitBinding(_) => {}
|
||||
ShortcutMessage::ProtocolUnavailable => {
|
||||
tracing::error!("shortcut inhibit protocol is unavailable");
|
||||
}
|
||||
ShortcutMessage::Inhibited(v) => {
|
||||
panic!("{}", v);
|
||||
}
|
||||
ShortcutMessage::ModifiersChanged(modifiers) => {
|
||||
if let Some((short_id, id)) = self.shortcut_context.zip(self.editing) {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(shortcut) = model.bindings.get_mut(id) {
|
||||
let mut cfg_modifiers =
|
||||
cosmic_settings_config::shortcuts::Modifiers::new();
|
||||
if modifiers.alt() {
|
||||
cfg_modifiers = cfg_modifiers.alt()
|
||||
}
|
||||
if modifiers.control() {
|
||||
cfg_modifiers = cfg_modifiers.ctrl()
|
||||
}
|
||||
if modifiers.shift() {
|
||||
cfg_modifiers = cfg_modifiers.shift()
|
||||
}
|
||||
if modifiers.logo() {
|
||||
cfg_modifiers = cfg_modifiers.logo()
|
||||
}
|
||||
shortcut.pending.modifiers = cfg_modifiers;
|
||||
|
||||
ShortcutMessage::SubmitBinding(id) => return self.submit_binding(id),
|
||||
if shortcut.pending.keycode.is_none() && modifiers.is_empty() {
|
||||
self.editing = None;
|
||||
shortcut.input = String::new();
|
||||
return Task::batch(vec![
|
||||
cosmic::widget::text_input::focus(self.add_keybindings_button_id.clone()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard()
|
||||
]);
|
||||
}
|
||||
shortcut.input = shortcut.pending.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ShortcutMessage::KeyReleased(keycode, _, _) => {
|
||||
if let Some((short_id, id)) = self.shortcut_context.zip(self.editing) {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(shortcut) = model.bindings.get_mut(id) {
|
||||
// if the currently selected shortcut matches, finish selecting shortcut
|
||||
if shortcut.pending.key.is_some()
|
||||
&& shortcut.pending.keycode.is_some_and(|k| k == keycode)
|
||||
{
|
||||
if shortcut.pending.modifiers
|
||||
!= cosmic_settings_config::shortcuts::Modifiers::new()
|
||||
{
|
||||
shortcut.input = shortcut.pending.to_string();
|
||||
// XX for now avoid applying the keycode
|
||||
shortcut.binding.keycode = None;
|
||||
return Task::batch(vec![
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard(),
|
||||
self.submit_binding(id)
|
||||
]);
|
||||
}
|
||||
|
||||
return Task::batch(vec![
|
||||
cosmic::widget::text_input::focus(self.add_keybindings_button_id.clone()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ShortcutMessage::KeyPressed(keycode, unmodified_keysym, location, modifiers) => {
|
||||
if unmodified_keysym == Key::Named(Named::Escape) && modifiers.is_empty() {
|
||||
if let Some((short_id, id)) = self.shortcut_context.zip(self.editing) {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(binding) = model.bindings.get_mut(id) {
|
||||
binding.reset();
|
||||
self.editing = None;
|
||||
return Task::batch(vec![
|
||||
cosmic::widget::text_input::focus(self.add_keybindings_button_id.clone()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Task::none();
|
||||
}
|
||||
if let Some((short_id, id)) = self.shortcut_context.zip(self.editing) {
|
||||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(shortcut) = model.bindings.get_mut(id) {
|
||||
shortcut.pending.keycode = Some(keycode);
|
||||
shortcut.pending.key =
|
||||
iced_winit::platform_specific::wayland::keymap::key_to_keysym(
|
||||
unmodified_keysym,
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
pub(crate) fn subscription(
|
||||
&self,
|
||||
_core: &cosmic::Core,
|
||||
) -> cosmic::iced::Subscription<ShortcutMessage> {
|
||||
if self.editing.is_some() {
|
||||
listen_with(|event, _, _| match event {
|
||||
iced::event::Event::Keyboard(iced::keyboard::Event::KeyPressed {
|
||||
key,
|
||||
physical_key,
|
||||
location,
|
||||
modifiers,
|
||||
..
|
||||
}) => {
|
||||
use cosmic::iced::keyboard::{Key, key::Named};
|
||||
|
||||
if matches!(
|
||||
key,
|
||||
Key::Named(Named::Super | Named::Alt | Named::Control | Named::Shift)
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
cosmic::iced_winit::conversion::physical_to_scancode(physical_key)
|
||||
.map(|code| ShortcutMessage::KeyPressed(code, key, location, modifiers))
|
||||
}
|
||||
iced::event::Event::Keyboard(iced::keyboard::Event::KeyReleased {
|
||||
key,
|
||||
physical_key,
|
||||
location,
|
||||
..
|
||||
}) => {
|
||||
use cosmic::iced::keyboard::{Key, key::Named};
|
||||
|
||||
if matches!(
|
||||
key,
|
||||
Key::Named(Named::Super | Named::Alt | Named::Control | Named::Shift)
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
cosmic::iced_winit::conversion::physical_to_scancode(physical_key)
|
||||
.map(|code| ShortcutMessage::KeyReleased(code, key, location))
|
||||
}
|
||||
iced::event::Event::Keyboard(iced::keyboard::Event::ModifiersChanged(e)) => {
|
||||
Some(ShortcutMessage::ModifiersChanged(e))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
})
|
||||
} else {
|
||||
cosmic::iced::Subscription::none()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn view(&self) -> Element<ShortcutMessage> {
|
||||
self.shortcut_models
|
||||
.iter()
|
||||
|
|
@ -535,7 +706,6 @@ impl Model {
|
|||
if let Some(model) = self.shortcut_models.get_mut(short_id) {
|
||||
if let Some(shortcut) = model.bindings.get_mut(id) {
|
||||
let prev_binding = mem::replace(&mut shortcut.binding, new_binding.clone());
|
||||
|
||||
shortcut.is_saved = true;
|
||||
shortcut.input.clear();
|
||||
|
||||
|
|
@ -544,7 +714,6 @@ impl Model {
|
|||
}
|
||||
|
||||
let action = model.action.clone();
|
||||
|
||||
if shortcut.is_default {
|
||||
self.config_add(Action::Disable, prev_binding);
|
||||
} else {
|
||||
|
|
@ -604,6 +773,7 @@ fn context_drawer<'a>(
|
|||
ShortcutMessage::EditBinding(bind_id, enable)
|
||||
})
|
||||
.select_on_focus(true)
|
||||
.on_focus(ShortcutMessage::EditBinding(bind_id, true))
|
||||
.on_input(move |text| ShortcutMessage::InputBinding(bind_id, text))
|
||||
.on_unfocus(ShortcutMessage::SubmitBinding(bind_id))
|
||||
.on_submit(move |_| ShortcutMessage::SubmitBinding(bind_id))
|
||||
|
|
|
|||
|
|
@ -6,14 +6,17 @@ use std::str::FromStr;
|
|||
use super::{ShortcutBinding, ShortcutMessage, ShortcutModel};
|
||||
|
||||
use cosmic::app::ContextDrawer;
|
||||
use cosmic::iced::keyboard::key::Named;
|
||||
use cosmic::iced::keyboard::{Key, Location, Modifiers};
|
||||
use cosmic::iced::{Alignment, Length};
|
||||
use cosmic::iced_winit;
|
||||
use cosmic::widget::{self, button, icon};
|
||||
use cosmic::{Apply, Element, Task};
|
||||
use cosmic_settings_config::Binding;
|
||||
use cosmic_settings_config::shortcuts::{Action, Shortcuts};
|
||||
use cosmic_settings_page::{self as page, Section, section};
|
||||
use slab::Slab;
|
||||
use slotmap::{Key, SlotMap};
|
||||
use slotmap::{Key as SlotKey, SlotMap};
|
||||
|
||||
pub struct Page {
|
||||
entity: page::Entity,
|
||||
|
|
@ -63,6 +66,9 @@ pub enum Message {
|
|||
Shortcut(ShortcutMessage),
|
||||
/// Open the add shortcut context drawer
|
||||
ShortcutContext,
|
||||
ModifiersChanged(Modifiers),
|
||||
KeyReleased(u32, Key, Location),
|
||||
KeyPressed(u32, Key, Location, Modifiers),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -72,6 +78,7 @@ struct AddShortcut {
|
|||
pub name: String,
|
||||
pub task: String,
|
||||
pub keys: Slab<(String, widget::Id)>,
|
||||
pub binding: Binding,
|
||||
}
|
||||
|
||||
impl AddShortcut {
|
||||
|
|
@ -99,17 +106,19 @@ impl Page {
|
|||
self.add_shortcut.task = text;
|
||||
}
|
||||
|
||||
Message::KeyInput(id, text) => {
|
||||
self.add_shortcut.keys[id].0 = text;
|
||||
}
|
||||
Message::KeyInput(..) => {}
|
||||
|
||||
Message::KeyEditing(id, enable) => {
|
||||
if enable {
|
||||
self.add_shortcut.editing = Some(id)
|
||||
self.add_shortcut.editing = Some(id);
|
||||
return iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(true).discard();
|
||||
} else if self.add_shortcut.editing == Some(id) {
|
||||
let task = self.add_keybinding();
|
||||
self.add_shortcut.editing = None;
|
||||
return task;
|
||||
|
||||
return Task::batch(vec![
|
||||
widget::text_input::focus(widget::Id::unique()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,11 +160,13 @@ impl Page {
|
|||
addable_bindings.push(binding);
|
||||
}
|
||||
|
||||
for binding in addable_bindings {
|
||||
for mut binding in addable_bindings {
|
||||
binding.keycode = None;
|
||||
self.add_shortcut(binding);
|
||||
}
|
||||
|
||||
self.model.on_enter();
|
||||
self.add_shortcut.binding = Default::default();
|
||||
_ = self.model.on_enter();
|
||||
}
|
||||
|
||||
Message::EditCombination => {
|
||||
|
|
@ -164,6 +175,10 @@ impl Page {
|
|||
return Task::batch(vec![
|
||||
widget::text_input::focus(id.clone()),
|
||||
widget::text_input::select_all(id.clone()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
true,
|
||||
)
|
||||
.discard()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -175,12 +190,14 @@ impl Page {
|
|||
}
|
||||
|
||||
Message::ReplaceApply => {
|
||||
if let Some((binding, ..)) = self.replace_dialog.pop() {
|
||||
if let Some((mut binding, ..)) = self.replace_dialog.pop() {
|
||||
self.model.config_remove(&binding);
|
||||
binding.keycode = None;
|
||||
self.add_shortcut(binding);
|
||||
|
||||
if self.replace_dialog.is_empty() {
|
||||
self.model.on_enter();
|
||||
self.add_shortcut = Default::default();
|
||||
_ = self.model.on_enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +205,8 @@ impl Page {
|
|||
Message::ReplaceCancel => {
|
||||
_ = self.replace_dialog.pop();
|
||||
if self.replace_dialog.is_empty() {
|
||||
self.model.on_enter();
|
||||
self.add_shortcut = Default::default();
|
||||
_ = self.model.on_enter();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -207,6 +225,112 @@ impl Page {
|
|||
widget::text_input::focus(self.name_id.clone()),
|
||||
]);
|
||||
}
|
||||
|
||||
Message::ModifiersChanged(modifiers) => {
|
||||
if self.add_shortcut.active {
|
||||
let mut cfg_modifiers = cosmic_settings_config::shortcuts::Modifiers::new();
|
||||
if modifiers.alt() {
|
||||
cfg_modifiers = cfg_modifiers.alt()
|
||||
}
|
||||
if modifiers.control() {
|
||||
cfg_modifiers = cfg_modifiers.ctrl()
|
||||
}
|
||||
if modifiers.shift() {
|
||||
cfg_modifiers = cfg_modifiers.shift()
|
||||
}
|
||||
if modifiers.logo() {
|
||||
cfg_modifiers = cfg_modifiers.logo()
|
||||
}
|
||||
self.add_shortcut.binding.modifiers = cfg_modifiers;
|
||||
|
||||
if self.add_shortcut.binding.keycode.is_none() && modifiers.is_empty() {
|
||||
self.add_shortcut = Default::default();
|
||||
self.add_shortcut = Default::default();
|
||||
_ = self.model.on_enter();
|
||||
|
||||
return Task::batch(vec![
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard()
|
||||
]);
|
||||
}
|
||||
if let Some(k) = self
|
||||
.add_shortcut
|
||||
.keys
|
||||
.get_mut(self.add_shortcut.editing.unwrap())
|
||||
{
|
||||
k.0 = self.add_shortcut.binding.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::KeyReleased(keycode, _, _) => {
|
||||
// if the currently selected shortcut matches, finish selecting shortcut
|
||||
if self.add_shortcut.editing.is_some()
|
||||
&& self.add_shortcut.active
|
||||
&& self.add_shortcut.binding.key.is_some()
|
||||
&& self
|
||||
.add_shortcut
|
||||
.binding
|
||||
.keycode
|
||||
.is_some_and(|k| k == keycode)
|
||||
&& self.add_shortcut.binding.modifiers
|
||||
!= cosmic_settings_config::shortcuts::Modifiers::new()
|
||||
{
|
||||
// XX for now avoid applying the keycode
|
||||
let binding = Binding {
|
||||
modifiers: self.add_shortcut.binding.modifiers.clone(),
|
||||
key: self.add_shortcut.binding.key,
|
||||
keycode: None,
|
||||
description: None,
|
||||
};
|
||||
let Some(k) = self
|
||||
.add_shortcut
|
||||
.keys
|
||||
.get_mut(self.add_shortcut.editing.unwrap())
|
||||
else {
|
||||
return iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard();
|
||||
};
|
||||
k.0 = binding.to_string();
|
||||
|
||||
if self.add_shortcut.name.trim().is_empty()
|
||||
|| self.add_shortcut.task.trim().is_empty()
|
||||
{
|
||||
return Task::batch(vec![
|
||||
widget::text_input::focus(widget::Id::unique()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard(),
|
||||
]);
|
||||
}
|
||||
self.add_shortcut(binding);
|
||||
self.add_shortcut = Default::default();
|
||||
_ = self.model.on_enter();
|
||||
|
||||
return Task::batch(vec![
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Message::KeyPressed(keycode, unmodified_keysym, location, modifiers) => {
|
||||
if unmodified_keysym == Key::Named(Named::Escape) && modifiers.is_empty() {
|
||||
self.add_shortcut.editing = None;
|
||||
return Task::batch(vec![
|
||||
widget::text_input::focus(widget::Id::unique()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(false).discard(),
|
||||
]);
|
||||
}
|
||||
if self.add_shortcut.active {
|
||||
self.add_shortcut.binding.keycode = Some(keycode);
|
||||
self.add_shortcut.binding.key =
|
||||
iced_winit::platform_specific::wayland::keymap::key_to_keysym(
|
||||
unmodified_keysym,
|
||||
location,
|
||||
);
|
||||
if let Some(k) = self
|
||||
.add_shortcut
|
||||
.keys
|
||||
.get_mut(self.add_shortcut.editing.unwrap())
|
||||
{
|
||||
k.0 = self.add_shortcut.binding.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Task::none()
|
||||
|
|
@ -221,7 +345,13 @@ impl Page {
|
|||
|
||||
binding.clear();
|
||||
|
||||
return widget::text_input::focus(id.clone());
|
||||
return Task::batch(vec![
|
||||
widget::text_input::focus(id.clone()),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
true,
|
||||
)
|
||||
.discard(),
|
||||
]);
|
||||
}
|
||||
|
||||
let new_id = widget::Id::unique();
|
||||
|
|
@ -234,6 +364,10 @@ impl Page {
|
|||
Task::batch(vec![
|
||||
widget::text_input::focus(new_id.clone()),
|
||||
widget::text_input::select_all(new_id),
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
true,
|
||||
)
|
||||
.discard(),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -275,6 +409,7 @@ impl Page {
|
|||
self.add_shortcut.editing == Some(id),
|
||||
move |enable| Message::KeyEditing(id, enable),
|
||||
)
|
||||
.on_focus(Message::KeyEditing(id, true))
|
||||
.select_on_focus(true)
|
||||
.padding([0, 12])
|
||||
.on_input(move |input| Message::KeyInput(id, input))
|
||||
|
|
@ -381,13 +516,87 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
}
|
||||
|
||||
fn on_enter(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_enter();
|
||||
self.add_shortcut = Default::default();
|
||||
_ = self.model.on_enter();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_clear();
|
||||
Task::none()
|
||||
_ = self.model.on_clear();
|
||||
iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
false,
|
||||
)
|
||||
.discard()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn subscription(
|
||||
&self,
|
||||
core: &cosmic::Core,
|
||||
) -> cosmic::iced::Subscription<crate::pages::Message> {
|
||||
use cosmic::iced::{self, event::listen_with};
|
||||
|
||||
cosmic::iced::Subscription::batch(vec![
|
||||
if self.add_shortcut.active && self.add_shortcut.editing.is_some() {
|
||||
listen_with(|event, _, _| match event {
|
||||
iced::event::Event::Keyboard(iced::keyboard::Event::KeyPressed {
|
||||
key,
|
||||
physical_key,
|
||||
location,
|
||||
modifiers,
|
||||
..
|
||||
}) => {
|
||||
use cosmic::iced::keyboard::{Key, key::Named};
|
||||
if matches!(
|
||||
key,
|
||||
Key::Named(Named::Super | Named::Alt | Named::Control | Named::Shift)
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
cosmic::iced_winit::conversion::physical_to_scancode(physical_key).map(
|
||||
|code| {
|
||||
crate::pages::Message::CustomShortcuts(Message::KeyPressed(
|
||||
code, key, location, modifiers,
|
||||
))
|
||||
},
|
||||
)
|
||||
}
|
||||
iced::event::Event::Keyboard(iced::keyboard::Event::KeyReleased {
|
||||
key,
|
||||
physical_key,
|
||||
location,
|
||||
..
|
||||
}) => {
|
||||
use cosmic::iced::keyboard::{Key, key::Named};
|
||||
if matches!(
|
||||
key,
|
||||
Key::Named(Named::Super | Named::Alt | Named::Control | Named::Shift)
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
cosmic::iced_winit::conversion::physical_to_scancode(physical_key).map(
|
||||
|code| {
|
||||
crate::pages::Message::CustomShortcuts(Message::KeyReleased(
|
||||
code, key, location,
|
||||
))
|
||||
},
|
||||
)
|
||||
}
|
||||
iced::event::Event::Keyboard(iced::keyboard::Event::ModifiersChanged(e)) => {
|
||||
Some(crate::pages::Message::CustomShortcuts(
|
||||
Message::ModifiersChanged(e),
|
||||
))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
})
|
||||
} else {
|
||||
cosmic::iced::Subscription::none()
|
||||
},
|
||||
self.model
|
||||
.subscription(core)
|
||||
.map(|m| crate::pages::Message::CustomShortcuts(Message::Shortcut(m))),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,6 +615,7 @@ fn bindings(_defaults: &Shortcuts, keybindings: &Shortcuts) -> Slab<ShortcutMode
|
|||
let new_binding = ShortcutBinding {
|
||||
id: widget::Id::unique(),
|
||||
binding: binding.clone(),
|
||||
pending: binding.clone(),
|
||||
input: String::new(),
|
||||
is_default: false,
|
||||
is_saved: true,
|
||||
|
|
|
|||
|
|
@ -64,13 +64,26 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
}
|
||||
|
||||
fn on_enter(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_enter();
|
||||
_ = self.model.on_enter();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_clear();
|
||||
Task::none()
|
||||
_ = self.model.on_clear();
|
||||
cosmic::iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
false,
|
||||
)
|
||||
.discard()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn subscription(
|
||||
&self,
|
||||
core: &cosmic::Core,
|
||||
) -> cosmic::iced::Subscription<crate::pages::Message> {
|
||||
self.model
|
||||
.subscription(core)
|
||||
.map(crate::pages::Message::ManageWindowShortcuts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,13 +64,26 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
}
|
||||
|
||||
fn on_enter(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_enter();
|
||||
_ = self.model.on_enter();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_clear();
|
||||
Task::none()
|
||||
_ = self.model.on_clear();
|
||||
cosmic::iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
false,
|
||||
)
|
||||
.discard()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn subscription(
|
||||
&self,
|
||||
core: &cosmic::Core,
|
||||
) -> cosmic::iced::Subscription<crate::pages::Message> {
|
||||
self.model
|
||||
.subscription(core)
|
||||
.map(crate::pages::Message::MoveWindowShortcuts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,13 +65,26 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
}
|
||||
|
||||
fn on_enter(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_enter();
|
||||
_ = self.model.on_enter();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_clear();
|
||||
Task::none()
|
||||
_ = self.model.on_clear();
|
||||
cosmic::iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
false,
|
||||
)
|
||||
.discard()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn subscription(
|
||||
&self,
|
||||
core: &cosmic::Core,
|
||||
) -> cosmic::iced::Subscription<crate::pages::Message> {
|
||||
self.model
|
||||
.subscription(core)
|
||||
.map(crate::pages::Message::NavShortcuts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,13 +64,26 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
}
|
||||
|
||||
fn on_enter(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_enter();
|
||||
_ = self.model.on_enter();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_clear();
|
||||
Task::none()
|
||||
_ = self.model.on_clear();
|
||||
cosmic::iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
false,
|
||||
)
|
||||
.discard()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn subscription(
|
||||
&self,
|
||||
core: &cosmic::Core,
|
||||
) -> cosmic::iced::Subscription<crate::pages::Message> {
|
||||
self.model
|
||||
.subscription(core)
|
||||
.map(crate::pages::Message::SystemShortcuts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,13 +64,26 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
}
|
||||
|
||||
fn on_enter(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_enter();
|
||||
_ = self.model.on_enter();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
self.model.on_clear();
|
||||
Task::none()
|
||||
_ = self.model.on_clear();
|
||||
cosmic::iced_winit::platform_specific::commands::keyboard_shortcuts_inhibit::inhibit_shortcuts(
|
||||
false,
|
||||
)
|
||||
.discard()
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
fn subscription(
|
||||
&self,
|
||||
core: &cosmic::Core,
|
||||
) -> cosmic::iced::Subscription<crate::pages::Message> {
|
||||
self.model
|
||||
.subscription(core)
|
||||
.map(crate::pages::Message::TilingShortcuts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue