feat: Add support for action modifier keys like ctrl,shift,alt.
This commit is contained in:
@@ -15,7 +15,9 @@ use iced_layershell::settings::{LayerShellSettings, Settings};
|
||||
use iced_layershell::to_layer_message;
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
|
||||
use pikl_core::event::{Action, MenuEvent, Mode, ViewState, VisibleItem};
|
||||
use pikl_core::event::{
|
||||
Action, MenuEvent, ModifiedAction, Modifiers as PiklModifiers, Mode, ViewState, VisibleItem,
|
||||
};
|
||||
|
||||
/// Number of visible items in the list viewport.
|
||||
const VIEWPORT_HEIGHT: u16 = 20;
|
||||
@@ -52,12 +54,12 @@ static BRIDGE_RX: OnceLock<Mutex<Option<mpsc::Receiver<Message>>>> = OnceLock::n
|
||||
|
||||
/// Global slot for the action sender. Moved into the Pikl
|
||||
/// struct during boot (called exactly once by iced).
|
||||
static ACTION_TX: OnceLock<Mutex<Option<mpsc::Sender<Action>>>> = OnceLock::new();
|
||||
static ACTION_TX: OnceLock<Mutex<Option<mpsc::Sender<ModifiedAction>>>> = OnceLock::new();
|
||||
|
||||
/// Top-level GUI state.
|
||||
struct Pikl {
|
||||
/// Channel to send actions into the core engine.
|
||||
action_tx: mpsc::Sender<Action>,
|
||||
action_tx: mpsc::Sender<ModifiedAction>,
|
||||
/// Current view snapshot from core.
|
||||
view_state: Option<ViewState>,
|
||||
/// Local copy of filter text for the text input widget.
|
||||
@@ -82,13 +84,13 @@ struct Pikl {
|
||||
/// runs the iced event loop, and exits when the user
|
||||
/// confirms or cancels.
|
||||
pub fn run(
|
||||
action_tx: mpsc::Sender<Action>,
|
||||
action_tx: mpsc::Sender<ModifiedAction>,
|
||||
event_rx: broadcast::Receiver<MenuEvent>,
|
||||
) -> Result<(), iced_layershell::Error> {
|
||||
// Send initial resize to core so it knows our viewport.
|
||||
let _ = action_tx.blocking_send(Action::Resize {
|
||||
let _ = action_tx.blocking_send(ModifiedAction::new(Action::Resize {
|
||||
height: VIEWPORT_HEIGHT,
|
||||
});
|
||||
}));
|
||||
|
||||
// Bridge: spawn a thread that reads core events and
|
||||
// forwards them as Messages through an mpsc channel.
|
||||
@@ -109,7 +111,7 @@ pub fn run(
|
||||
.get()
|
||||
.and_then(|m| m.lock().unwrap_or_else(|e| e.into_inner()).take())
|
||||
.unwrap_or_else(|| {
|
||||
let (tx, _) = mpsc::channel(1);
|
||||
let (tx, _) = mpsc::channel::<ModifiedAction>(1);
|
||||
tx
|
||||
});
|
||||
let pikl = Pikl {
|
||||
@@ -228,7 +230,7 @@ fn update(state: &mut Pikl, message: Message) -> Task<Message> {
|
||||
let tx = state.action_tx.clone();
|
||||
Task::perform(
|
||||
async move {
|
||||
let _ = tx.send(Action::UpdateFilter(new_text)).await;
|
||||
let _ = tx.send(ModifiedAction::new(Action::UpdateFilter(new_text))).await;
|
||||
},
|
||||
|_| Message::Sent,
|
||||
)
|
||||
@@ -415,6 +417,15 @@ fn core_event_stream() -> impl iced::futures::Stream<Item = Message> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert iced keyboard modifiers to pikl Modifiers.
|
||||
fn iced_modifiers(m: &iced::keyboard::Modifiers) -> PiklModifiers {
|
||||
PiklModifiers {
|
||||
shift: m.shift(),
|
||||
ctrl: m.control(),
|
||||
alt: m.alt(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle a keyboard event and return the appropriate task.
|
||||
fn handle_key(state: &mut Pikl, key: Key, modifiers: Modifiers) -> Task<Message> {
|
||||
let action = match state.mode {
|
||||
@@ -443,9 +454,10 @@ fn handle_key(state: &mut Pikl, key: Key, modifiers: Modifiers) -> Task<Message>
|
||||
};
|
||||
|
||||
let tx = state.action_tx.clone();
|
||||
let mods = iced_modifiers(&modifiers);
|
||||
let send_task = Task::perform(
|
||||
async move {
|
||||
let _ = tx.send(action).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(action, mods)).await;
|
||||
},
|
||||
|_| Message::Sent,
|
||||
);
|
||||
@@ -470,9 +482,10 @@ fn map_insert_key(state: &mut Pikl, key: &Key, modifiers: &Modifiers) -> Option<
|
||||
Key::Named(Named::PageDown) => Some(Action::PageDown(1)),
|
||||
Key::Named(Named::Tab) if state.multi_enabled => {
|
||||
let tx = state.action_tx.clone();
|
||||
let mods = iced_modifiers(modifiers);
|
||||
tokio::spawn(async move {
|
||||
let _ = tx.send(Action::ToggleSelect).await;
|
||||
let _ = tx.send(Action::MoveDown(1)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::ToggleSelect, mods)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::MoveDown(1), mods)).await;
|
||||
});
|
||||
None
|
||||
}
|
||||
@@ -515,9 +528,10 @@ fn map_normal_key(state: &mut Pikl, key: &Key, modifiers: &Modifiers) -> Option<
|
||||
"u" => Some(Action::UndoSelection),
|
||||
" " if state.multi_enabled => {
|
||||
let tx = state.action_tx.clone();
|
||||
let mods = iced_modifiers(modifiers);
|
||||
tokio::spawn(async move {
|
||||
let _ = tx.send(Action::ToggleSelect).await;
|
||||
let _ = tx.send(Action::MoveDown(1)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::ToggleSelect, mods)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::MoveDown(1), mods)).await;
|
||||
});
|
||||
None
|
||||
}
|
||||
@@ -539,9 +553,10 @@ fn map_normal_key(state: &mut Pikl, key: &Key, modifiers: &Modifiers) -> Option<
|
||||
Key::Named(Named::ArrowDown) => Some(Action::MoveDown(1)),
|
||||
Key::Named(Named::Tab) if state.multi_enabled => {
|
||||
let tx = state.action_tx.clone();
|
||||
let mods = iced_modifiers(modifiers);
|
||||
tokio::spawn(async move {
|
||||
let _ = tx.send(Action::ToggleSelect).await;
|
||||
let _ = tx.send(Action::MoveDown(1)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::ToggleSelect, mods)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::MoveDown(1), mods)).await;
|
||||
});
|
||||
None
|
||||
}
|
||||
@@ -580,11 +595,12 @@ fn map_visual_key(state: &mut Pikl, key: &Key, modifiers: &Modifiers) -> Option<
|
||||
let tx = state.action_tx.clone();
|
||||
let start = anchor;
|
||||
let end = vs.cursor;
|
||||
let mods = iced_modifiers(modifiers);
|
||||
tokio::spawn(async move {
|
||||
let _ = tx
|
||||
.send(Action::SelectRange { start, end })
|
||||
.send(ModifiedAction::with_modifiers(Action::SelectRange { start, end }, mods))
|
||||
.await;
|
||||
let _ = tx.send(Action::SetMode(Mode::Normal)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::SetMode(Mode::Normal), mods)).await;
|
||||
});
|
||||
}
|
||||
state.visual_anchor = None;
|
||||
@@ -599,11 +615,12 @@ fn map_visual_key(state: &mut Pikl, key: &Key, modifiers: &Modifiers) -> Option<
|
||||
let tx = state.action_tx.clone();
|
||||
let start = anchor;
|
||||
let end = vs.cursor;
|
||||
let mods = iced_modifiers(modifiers);
|
||||
tokio::spawn(async move {
|
||||
let _ = tx
|
||||
.send(Action::SelectRange { start, end })
|
||||
.send(ModifiedAction::with_modifiers(Action::SelectRange { start, end }, mods))
|
||||
.await;
|
||||
let _ = tx.send(Action::SetMode(Mode::Normal)).await;
|
||||
let _ = tx.send(ModifiedAction::with_modifiers(Action::SetMode(Mode::Normal), mods)).await;
|
||||
});
|
||||
}
|
||||
state.visual_anchor = None;
|
||||
|
||||
Reference in New Issue
Block a user