Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ journalctl --user -u wayscriber.service -f
| <kbd>Ctrl+Shift+C</kbd> | Select region → clipboard |
| <kbd>Ctrl+Shift+S</kbd> | Select region → save PNG |
| <kbd>Ctrl+Shift+O</kbd> | Capture active window |
| <kbd>Ctrl+Alt+O</kbd> | Open last capture folder |

Requires `wl-clipboard`, `grim`, `slurp`. Falls back to xdg-desktop-portal if missing.

Expand Down Expand Up @@ -354,6 +355,9 @@ Press <kbd>F1</kbd> or <kbd>F10</kbd> at any time for the in-app cheat sheet.
|--------|-----|
| Undo | <kbd>Ctrl+Z</kbd> |
| Redo | <kbd>Ctrl+Shift+Z</kbd> / <kbd>Ctrl+Y</kbd> |
| Copy selection | <kbd>Ctrl+Alt+C</kbd> |
| Paste selection | <kbd>Ctrl+Alt+V</kbd> |
| Select all | <kbd>Ctrl+A</kbd> |
| Eraser | <kbd>D</kbd> |
| Toggle eraser mode | <kbd>Ctrl+Shift+E</kbd> |
| Clear all | <kbd>E</kbd> |
Expand Down
12 changes: 11 additions & 1 deletion config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,13 @@ redo = ["Ctrl+Shift+Z", "Ctrl+Y"]
# Duplicate currently selected annotations
duplicate_selection = ["Ctrl+D"]

# Copy/paste selected annotations
copy_selection = ["Ctrl+Alt+C"]
paste_selection = ["Ctrl+Alt+V"]

# Select all annotations
select_all = ["Ctrl+A"]

# Reorder selected annotations within the stack
move_selection_to_front = ["]"]
move_selection_to_back = ["["]
Expand All @@ -518,7 +525,7 @@ nudge_selection_right = ["ArrowRight", "Shift+PageDown"]
nudge_selection_up_large = ["PageUp"]
nudge_selection_down_large = ["PageDown"]

# Move selection to edges (left/right by default; top/bottom after a vertical nudge)
# Move selection to horizontal edges (left/right)
move_selection_to_start = ["Home"]
move_selection_to_end = ["End"]

Expand Down Expand Up @@ -596,6 +603,9 @@ capture_file_selection = ["Ctrl+Shift+S"]
capture_clipboard_region = ["Ctrl+6"]
capture_file_region = ["Ctrl+Shift+6"]

# Open the most recent capture folder
open_capture_folder = ["Ctrl+Alt+O"]

# Toggle frozen mode
toggle_frozen_mode = ["Ctrl+Shift+F"]

Expand Down
24 changes: 24 additions & 0 deletions configurator/src/models/keybindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub enum KeybindingField {
EnterStickyNoteMode,
ClearCanvas,
Undo,
CopySelection,
PasteSelection,
SelectAll,
IncreaseThickness,
DecreaseThickness,
SelectPenTool,
Expand Down Expand Up @@ -50,6 +53,7 @@ pub enum KeybindingField {
CaptureFileSelection,
CaptureClipboardRegion,
CaptureFileRegion,
OpenCaptureFolder,
ToggleFrozenMode,
ZoomIn,
ZoomOut,
Expand Down Expand Up @@ -128,6 +132,9 @@ impl KeybindingField {
Self::EnterStickyNoteMode,
Self::ClearCanvas,
Self::Undo,
Self::CopySelection,
Self::PasteSelection,
Self::SelectAll,
Self::IncreaseThickness,
Self::DecreaseThickness,
Self::SelectPenTool,
Expand Down Expand Up @@ -158,6 +165,7 @@ impl KeybindingField {
Self::CaptureFileSelection,
Self::CaptureClipboardRegion,
Self::CaptureFileRegion,
Self::OpenCaptureFolder,
Self::ToggleFrozenMode,
Self::ZoomIn,
Self::ZoomOut,
Expand Down Expand Up @@ -189,6 +197,9 @@ impl KeybindingField {
Self::EnterStickyNoteMode => "Enter sticky note mode",
Self::ClearCanvas => "Clear canvas",
Self::Undo => "Undo",
Self::CopySelection => "Copy selection",
Self::PasteSelection => "Paste selection",
Self::SelectAll => "Select all",
Self::IncreaseThickness => "Increase thickness",
Self::DecreaseThickness => "Decrease thickness",
Self::SelectPenTool => "Select pen tool",
Expand Down Expand Up @@ -219,6 +230,7 @@ impl KeybindingField {
Self::CaptureFileSelection => "File selection",
Self::CaptureClipboardRegion => "Clipboard region",
Self::CaptureFileRegion => "File region",
Self::OpenCaptureFolder => "Open capture folder",
Self::ToggleFrozenMode => "Toggle freeze",
Self::ZoomIn => "Zoom in",
Self::ZoomOut => "Zoom out",
Expand Down Expand Up @@ -250,6 +262,9 @@ impl KeybindingField {
Self::EnterStickyNoteMode => "enter_sticky_note_mode",
Self::ClearCanvas => "clear_canvas",
Self::Undo => "undo",
Self::CopySelection => "copy_selection",
Self::PasteSelection => "paste_selection",
Self::SelectAll => "select_all",
Self::IncreaseThickness => "increase_thickness",
Self::DecreaseThickness => "decrease_thickness",
Self::SelectPenTool => "select_pen_tool",
Expand Down Expand Up @@ -280,6 +295,7 @@ impl KeybindingField {
Self::CaptureFileSelection => "capture_file_selection",
Self::CaptureClipboardRegion => "capture_clipboard_region",
Self::CaptureFileRegion => "capture_file_region",
Self::OpenCaptureFolder => "open_capture_folder",
Self::ToggleFrozenMode => "toggle_frozen_mode",
Self::ZoomIn => "zoom_in",
Self::ZoomOut => "zoom_out",
Expand Down Expand Up @@ -311,6 +327,9 @@ impl KeybindingField {
Self::EnterStickyNoteMode => &config.enter_sticky_note_mode,
Self::ClearCanvas => &config.clear_canvas,
Self::Undo => &config.undo,
Self::CopySelection => &config.copy_selection,
Self::PasteSelection => &config.paste_selection,
Self::SelectAll => &config.select_all,
Self::IncreaseThickness => &config.increase_thickness,
Self::DecreaseThickness => &config.decrease_thickness,
Self::SelectPenTool => &config.select_pen_tool,
Expand Down Expand Up @@ -341,6 +360,7 @@ impl KeybindingField {
Self::CaptureFileSelection => &config.capture_file_selection,
Self::CaptureClipboardRegion => &config.capture_clipboard_region,
Self::CaptureFileRegion => &config.capture_file_region,
Self::OpenCaptureFolder => &config.open_capture_folder,
Self::ToggleFrozenMode => &config.toggle_frozen_mode,
Self::ZoomIn => &config.zoom_in,
Self::ZoomOut => &config.zoom_out,
Expand Down Expand Up @@ -372,6 +392,9 @@ impl KeybindingField {
Self::EnterStickyNoteMode => config.enter_sticky_note_mode = value,
Self::ClearCanvas => config.clear_canvas = value,
Self::Undo => config.undo = value,
Self::CopySelection => config.copy_selection = value,
Self::PasteSelection => config.paste_selection = value,
Self::SelectAll => config.select_all = value,
Self::IncreaseThickness => config.increase_thickness = value,
Self::DecreaseThickness => config.decrease_thickness = value,
Self::SelectPenTool => config.select_pen_tool = value,
Expand Down Expand Up @@ -402,6 +425,7 @@ impl KeybindingField {
Self::CaptureFileSelection => config.capture_file_selection = value,
Self::CaptureClipboardRegion => config.capture_clipboard_region = value,
Self::CaptureFileRegion => config.capture_file_region = value,
Self::OpenCaptureFolder => config.open_capture_folder = value,
Self::ToggleFrozenMode => config.toggle_frozen_mode = value,
Self::ZoomIn => config.zoom_in = value,
Self::ZoomOut => config.zoom_out = value,
Expand Down
16 changes: 14 additions & 2 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,13 @@ redo = ["Ctrl+Shift+Z", "Ctrl+Y"]
# Duplicate current selection
duplicate_selection = ["Ctrl+D"]

# Copy/paste selection
copy_selection = ["Ctrl+Alt+C"]
paste_selection = ["Ctrl+Alt+V"]

# Select all annotations
select_all = ["Ctrl+A"]

# Nudge selection (hold Shift for a larger step)
nudge_selection_up = ["ArrowUp"]
nudge_selection_down = ["ArrowDown"]
Expand All @@ -519,7 +526,7 @@ nudge_selection_right = ["ArrowRight", "Shift+PageDown"]
nudge_selection_up_large = ["PageUp"]
nudge_selection_down_large = ["PageDown"]

# Move selection to edges (left/right by default; top/bottom after a vertical nudge)
# Move selection to horizontal edges (left/right)
move_selection_to_start = ["Home"]
move_selection_to_end = ["End"]

Expand Down Expand Up @@ -584,6 +591,9 @@ capture_file_selection = ["Ctrl+Shift+S"]
capture_clipboard_region = ["Ctrl+6"]
capture_file_region = ["Ctrl+Shift+6"]

# Open the most recent capture folder
open_capture_folder = ["Ctrl+Alt+O"]

# Toggle frozen mode
toggle_frozen_mode = ["Ctrl+Shift+F"]

Expand Down Expand Up @@ -673,7 +683,9 @@ clear_canvas = ["X"]
- Duplicate keybindings across actions will be detected and reported at startup

**Defaults:**
All defaults match the original hardcoded keybindings to maintain compatibility.
Defaults match the original hardcoded keybindings where possible. Copy/paste selection uses
<kbd>Ctrl+Alt+C</kbd>/<kbd>Ctrl+Alt+V</kbd>, so the clipboard-selection capture shortcut
defaults to <kbd>Ctrl+Shift+C</kbd> to avoid conflicts.

## Creating Your Configuration

Expand Down
12 changes: 12 additions & 0 deletions src/backend/wayland/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,18 @@ impl WaylandBackend {
message_parts.join(" • ")
};

let open_folder_binding = state
.config
.keybindings
.open_capture_folder
.first()
.map(|binding| binding.as_str());
state.input_state.set_capture_feedback(
result.saved_path.as_deref(),
result.copied_to_clipboard,
open_folder_binding,
);

notification::send_notification_async(
&state.tokio_handle,
"Screenshot Captured".to_string(),
Expand Down
64 changes: 64 additions & 0 deletions src/config/keybindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub enum Action {
UndoAllDelayed,
RedoAllDelayed,
DuplicateSelection,
CopySelection,
PasteSelection,
SelectAll,
MoveSelectionToFront,
MoveSelectionToBack,
NudgeSelectionUp,
Expand Down Expand Up @@ -93,6 +96,7 @@ pub enum Action {
CaptureFileSelection,
CaptureClipboardRegion,
CaptureFileRegion,
OpenCaptureFolder,
ToggleFrozenMode,
ZoomIn,
ZoomOut,
Expand Down Expand Up @@ -246,6 +250,15 @@ pub struct KeybindingsConfig {
#[serde(default = "default_duplicate_selection")]
pub duplicate_selection: Vec<String>,

#[serde(default = "default_copy_selection")]
pub copy_selection: Vec<String>,

#[serde(default = "default_paste_selection")]
pub paste_selection: Vec<String>,

#[serde(default = "default_select_all")]
pub select_all: Vec<String>,

#[serde(default = "default_move_selection_to_front")]
pub move_selection_to_front: Vec<String>,

Expand Down Expand Up @@ -411,6 +424,9 @@ pub struct KeybindingsConfig {
#[serde(default = "default_capture_file_region")]
pub capture_file_region: Vec<String>,

#[serde(default = "default_open_capture_folder")]
pub open_capture_folder: Vec<String>,

#[serde(default = "default_toggle_frozen_mode")]
pub toggle_frozen_mode: Vec<String>,

Expand Down Expand Up @@ -475,6 +491,9 @@ impl Default for KeybindingsConfig {
undo_all_delayed: Vec::new(),
redo_all_delayed: Vec::new(),
duplicate_selection: default_duplicate_selection(),
copy_selection: default_copy_selection(),
paste_selection: default_paste_selection(),
select_all: default_select_all(),
move_selection_to_front: default_move_selection_to_front(),
move_selection_to_back: default_move_selection_to_back(),
nudge_selection_up: default_nudge_selection_up(),
Expand Down Expand Up @@ -531,6 +550,7 @@ impl Default for KeybindingsConfig {
capture_file_selection: default_capture_file_selection(),
capture_clipboard_region: default_capture_clipboard_region(),
capture_file_region: default_capture_file_region(),
open_capture_folder: default_open_capture_folder(),
toggle_frozen_mode: default_toggle_frozen_mode(),
zoom_in: default_zoom_in(),
zoom_out: default_zoom_out(),
Expand Down Expand Up @@ -617,6 +637,18 @@ impl KeybindingsConfig {
insert_binding(binding_str, Action::DuplicateSelection)?;
}

for binding_str in &self.copy_selection {
insert_binding(binding_str, Action::CopySelection)?;
}

for binding_str in &self.paste_selection {
insert_binding(binding_str, Action::PasteSelection)?;
}

for binding_str in &self.select_all {
insert_binding(binding_str, Action::SelectAll)?;
}

for binding_str in &self.move_selection_to_front {
insert_binding(binding_str, Action::MoveSelectionToFront)?;
}
Expand Down Expand Up @@ -863,6 +895,10 @@ impl KeybindingsConfig {
insert_binding(binding_str, Action::CaptureFileRegion)?;
}

for binding_str in &self.open_capture_folder {
insert_binding(binding_str, Action::OpenCaptureFolder)?;
}

for binding_str in &self.toggle_frozen_mode {
insert_binding(binding_str, Action::ToggleFrozenMode)?;
}
Expand Down Expand Up @@ -969,6 +1005,18 @@ fn default_duplicate_selection() -> Vec<String> {
vec!["Ctrl+D".to_string()]
}

fn default_copy_selection() -> Vec<String> {
vec!["Ctrl+Alt+C".to_string()]
}

fn default_paste_selection() -> Vec<String> {
vec!["Ctrl+Alt+V".to_string()]
}

fn default_select_all() -> Vec<String> {
vec!["Ctrl+A".to_string()]
}

fn default_move_selection_to_front() -> Vec<String> {
vec!["]".to_string()]
}
Expand Down Expand Up @@ -1193,6 +1241,10 @@ fn default_capture_file_region() -> Vec<String> {
vec!["Ctrl+Shift+6".to_string()]
}

fn default_open_capture_folder() -> Vec<String> {
vec!["Ctrl+Alt+O".to_string()]
}

fn default_toggle_frozen_mode() -> Vec<String> {
vec!["Ctrl+Shift+F".to_string()]
}
Expand Down Expand Up @@ -1391,6 +1443,18 @@ mod tests {
let move_back = KeyBinding::parse("[").unwrap();
assert_eq!(map.get(&move_back), Some(&Action::MoveSelectionToBack));

let copy_selection = KeyBinding::parse("Ctrl+Alt+C").unwrap();
assert_eq!(map.get(&copy_selection), Some(&Action::CopySelection));

let capture_selection = KeyBinding::parse("Ctrl+Shift+C").unwrap();
assert_eq!(
map.get(&capture_selection),
Some(&Action::CaptureClipboardSelection)
);

let select_all = KeyBinding::parse("Ctrl+A").unwrap();
assert_eq!(map.get(&select_all), Some(&Action::SelectAll));

let toggle_highlight = KeyBinding::parse("Ctrl+Shift+H").unwrap();
assert_eq!(
map.get(&toggle_highlight),
Expand Down
Loading