Skip to content

Commit f865eba

Browse files
authored
disable ctrl+shift+v shortcut on windows (#91)
1 parent 5acf199 commit f865eba

File tree

4 files changed

+101
-13
lines changed

4 files changed

+101
-13
lines changed

crates/kiorg/src/config/mod.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,9 @@ pub fn load_config_with_override(
152152
Err(e) => return Err(ConfigError::TomlError(e, config_path)),
153153
};
154154

155-
// Validate user shortcuts for conflicts
156-
if let Some(ref user_shortcuts) = user_config.shortcuts
157-
&& let Err(conflict_error) = validate_user_shortcuts(user_shortcuts)
158-
{
159-
return Err(ConfigError::ShortcutConflict(conflict_error, config_path));
155+
// Validate user shortcuts
156+
if let Some(ref user_shortcuts) = user_config.shortcuts {
157+
validate_user_shortcuts(user_shortcuts, &config_path)?;
160158
}
161159

162160
if let Some(layout) = &user_config.layout
@@ -219,11 +217,13 @@ pub fn get_kiorg_config_dir(override_path: Option<&PathBuf>) -> PathBuf {
219217
}
220218
}
221219

222-
/// Validate user shortcuts for conflicts
220+
/// Validate user shortcuts for conflicts and reserved keys
223221
/// Returns an error if any shortcut is assigned to multiple different actions
222+
/// or if a reserved shortcut is used.
224223
fn validate_user_shortcuts(
225224
user_shortcuts: &shortcuts::Shortcuts,
226-
) -> Result<(), ShortcutConflictError> {
225+
config_path: &std::path::Path,
226+
) -> Result<(), ConfigError> {
227227
use std::collections::HashMap;
228228

229229
// Create a map from shortcut to actions that use it
@@ -234,6 +234,14 @@ fn validate_user_shortcuts(
234234

235235
for (action, shortcuts_list) in user_shortcuts {
236236
for shortcut in shortcuts_list {
237+
if let Ok(keys) = shortcut.to_shortcut_keys() {
238+
for skey in keys {
239+
if let Err(e) = shortcuts::check_blacklisted_shortcut(&skey) {
240+
return Err(ConfigError::ValueError(e, config_path.to_path_buf()));
241+
}
242+
}
243+
}
244+
237245
// Only add unique actions (don't count duplicates of the same action)
238246
let actions_for_shortcut = shortcut_to_actions.entry(shortcut.clone()).or_default();
239247

@@ -247,11 +255,14 @@ fn validate_user_shortcuts(
247255
for (shortcut, actions) in shortcut_to_actions {
248256
if actions.len() > 1 {
249257
// Found a conflict - return error with the first two conflicting actions
250-
return Err(ShortcutConflictError {
251-
shortcut,
252-
action1: actions[0],
253-
action2: actions[1],
254-
});
258+
return Err(ConfigError::ShortcutConflict(
259+
ShortcutConflictError {
260+
shortcut,
261+
action1: actions[0],
262+
action2: actions[1],
263+
},
264+
config_path.to_path_buf(),
265+
));
255266
}
256267
}
257268

crates/kiorg/src/config/shortcuts.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ pub struct ShortcutKey {
1818
pub modifiers: Modifiers,
1919
}
2020

21+
#[inline]
22+
pub fn check_blacklisted_shortcut(_key: &ShortcutKey) -> Result<(), String> {
23+
#[cfg(target_os = "windows")]
24+
if _key.key == Key::V && _key.modifiers.ctrl && _key.modifiers.shift {
25+
// see: https://github.com/houqp/kiorg/issues/3#issuecomment-3514588299
26+
return Err(
27+
"Shortcut Ctrl+Shift+V is reserved on Windows and cannot be registered".to_string(),
28+
);
29+
}
30+
Ok(())
31+
}
32+
2133
// Result of traversing a key buffer through the shortcut tree
2234
#[derive(Debug, Clone, PartialEq)]
2335
pub enum TraverseResult {
@@ -344,6 +356,8 @@ impl Shortcuts {
344356
let mut current_node = &mut self.shortcut_tree;
345357

346358
for (i, key) in keys.iter().enumerate() {
359+
check_blacklisted_shortcut(key)?;
360+
347361
if i == keys.len() - 1 {
348362
// Last key in sequence - insert the action
349363
match current_node {

crates/kiorg/tests/ui_preview_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ fn test_pdf_page_count_in_preview_content() {
352352
Some(PreviewContent::Pdf(_))
353353
)
354354
},
355-
std::time::Duration::from_secs(2),
355+
std::time::Duration::from_secs(3),
356356
);
357357

358358
match &harness.state().preview_content {

crates/kiorg/tests/ui_shortcuts_test.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,66 @@ key = "d"
404404
panic!("Expected ShortcutConflictError, got: {result:?}");
405405
}
406406
}
407+
#[test]
408+
#[cfg(target_os = "windows")]
409+
fn test_disallow_ctrl_shift_v_config() {
410+
// Create a temporary directory for the config
411+
let config_temp_dir = tempdir().unwrap();
412+
let config_dir = config_temp_dir.path().to_path_buf();
413+
414+
// Create a TOML config file with Ctrl+Shift+V
415+
let toml_content = r#"
416+
# Config with reserved Windows shortcut
417+
[[shortcuts.MoveDown]]
418+
key = "v"
419+
ctrl = true
420+
shift = true
421+
"#;
422+
423+
// Write the config file
424+
create_config_file(&config_dir, toml_content);
425+
426+
// Try to load the config
427+
let result = kiorg::config::load_config_with_override(Some(&config_dir));
428+
429+
// Verify that we got an error and it's a value error mentioning the reservation
430+
assert!(
431+
result.is_err(),
432+
"Should return an error for reserved Windows shortcut"
433+
);
434+
435+
let error_msg = result.unwrap_err().to_string();
436+
assert!(
437+
error_msg.contains("reserved on Windows"),
438+
"Error message should mention it's reserved on Windows, got: {error_msg}"
439+
);
440+
}
441+
442+
#[test]
443+
#[cfg(not(target_os = "windows"))]
444+
fn test_allow_ctrl_shift_v_config_non_windows() {
445+
// Create a temporary directory for the config
446+
let config_temp_dir = tempdir().unwrap();
447+
let config_dir = config_temp_dir.path().to_path_buf();
448+
449+
// Create a TOML config file with Ctrl+Shift+V
450+
let toml_content = r#"
451+
# Config with Ctrl+Shift+V which is allowed on non-Windows
452+
[[shortcuts.MoveDown]]
453+
key = "v"
454+
ctrl = true
455+
shift = true
456+
"#;
457+
458+
// Write the config file
459+
create_config_file(&config_dir, toml_content);
460+
461+
// Try to load the config
462+
let result = kiorg::config::load_config_with_override(Some(&config_dir));
463+
464+
// Verify that it works on non-Windows
465+
assert!(
466+
result.is_ok(),
467+
"Should NOT return an error for Ctrl+Shift+V on non-Windows platforms"
468+
);
469+
}

0 commit comments

Comments
 (0)