Skip to content

Commit

Permalink
fix: Better hotkey state tracking
Browse files Browse the repository at this point in the history
Previously, the hotkey listener would accept unintended key combinations. For instance, a hotkey of Ctrl+Shift would trigger even if the user pressed Ctrl+Shift+R. This commit fixes this behavior, ensuring the hotkey is only recognized when the exact combination is pressed. Any additional keys will be treated as an incorrect hotkey.
  • Loading branch information
huytd committed Apr 9, 2024
1 parent 2229d77 commit 5c63ccd
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
description = "Bộ gõ tiếng Việt mã nguồn mở đa hệ điều hành Gõ Key"
edition = "2021"
name = "goxkey"
version = "0.2.3"
version = "0.2.4"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down Expand Up @@ -33,4 +33,4 @@ copyright = "Copyright (c) Huy Tran 2023. All rights reserved."
icon = ["icons/icon.icns", "icons/icon.png"]
identifier = "com.goxkey.app"
name = "GoKey"
version = "0.2.3"
version = "0.2.4"
3 changes: 3 additions & 0 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const TONE_DUPLICATE_PATTERNS: [&str; 17] = [
];

pub static mut INPUT_STATE: Lazy<InputState> = Lazy::new(InputState::new);
pub static mut HOTKEY_MODIFIERS: KeyModifier = KeyModifier::MODIFIER_NONE;
pub static mut HOTKEY_MATCHING: bool = false;
pub static mut HOTKEY_MATCHING_CIRCUIT_BREAK: bool = false;

pub const PREDEFINED_CHARS: [char; 47] = [
'a', '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'q', 'w', 'e', 'r', 't',
Expand Down
44 changes: 34 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ mod ui;
use std::thread;

use druid::{AppLauncher, ExtEventSink, Target, WindowDesc};
use input::{rebuild_keyboard_layout_map, INPUT_STATE};
use input::{rebuild_keyboard_layout_map, HOTKEY_MATCHING_CIRCUIT_BREAK, INPUT_STATE};
use log::debug;
use once_cell::sync::OnceCell;
use platform::{
add_app_change_callback, ensure_accessibility_permission, run_event_listener, send_backspace,
send_string, Handle, KeyModifier, PressedKey, KEY_DELETE, KEY_ENTER, KEY_ESCAPE, KEY_SPACE,
KEY_TAB, RAW_KEY_GLOBE,
send_string, EventTapType, Handle, KeyModifier, PressedKey, KEY_DELETE, KEY_ENTER, KEY_ESCAPE,
KEY_SPACE, KEY_TAB, RAW_KEY_GLOBE,
};

use crate::platform::{RAW_ARROW_DOWN, RAW_ARROW_LEFT, RAW_ARROW_RIGHT, RAW_ARROW_UP};
use crate::{
input::{HOTKEY_MATCHING, HOTKEY_MODIFIERS},
platform::{RAW_ARROW_DOWN, RAW_ARROW_LEFT, RAW_ARROW_RIGHT, RAW_ARROW_UP},
};
use ui::{UIDataAdapter, UPDATE_UI};

static UI_EVENT_SINK: OnceCell<ExtEventSink> = OnceCell::new();
Expand Down Expand Up @@ -92,19 +95,40 @@ unsafe fn auto_toggle_vietnamese() {
}
}

fn event_handler(handle: Handle, pressed_key: Option<PressedKey>, modifiers: KeyModifier) -> bool {
fn event_handler(
handle: Handle,
event_type: EventTapType,
pressed_key: Option<PressedKey>,
modifiers: KeyModifier,
) -> bool {
unsafe {
let pressed_key_code = pressed_key.and_then(|p| match p {
PressedKey::Char(c) => Some(c),
_ => None,
});
let is_hotkey_pressed = INPUT_STATE

if event_type == EventTapType::FlagsChanged {
if modifiers.is_empty() {
// Modifier keys are released
if HOTKEY_MATCHING && !HOTKEY_MATCHING_CIRCUIT_BREAK {
toggle_vietnamese();
}
HOTKEY_MODIFIERS = KeyModifier::MODIFIER_NONE;
HOTKEY_MATCHING = false;
HOTKEY_MATCHING_CIRCUIT_BREAK = false;
} else {
HOTKEY_MODIFIERS.set(modifiers, true);
}
}

let is_hotkey_matched = INPUT_STATE
.get_hotkey()
.is_match(modifiers, pressed_key_code);
if is_hotkey_pressed {
toggle_vietnamese();
return true;
.is_match(HOTKEY_MODIFIERS, pressed_key_code);
if HOTKEY_MATCHING && !is_hotkey_matched {
HOTKEY_MATCHING_CIRCUIT_BREAK = true;
}
HOTKEY_MATCHING = is_hotkey_matched;

match pressed_key {
Some(pressed_key) => {
match pressed_key {
Expand Down
33 changes: 24 additions & 9 deletions src/platform/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,25 @@ use self::macos_ext::{
};

use super::{
CallbackFn, KeyModifier, PressedKey, KEY_DELETE, KEY_ENTER, KEY_ESCAPE, KEY_SPACE, KEY_TAB,
CallbackFn, EventTapType, KeyModifier, PressedKey, KEY_DELETE, KEY_ENTER, KEY_ESCAPE,
KEY_SPACE, KEY_TAB,
};

pub const SYMBOL_SHIFT: &str = "⇧";
pub const SYMBOL_CTRL: &str = "⌃";
pub const SYMBOL_SUPER: &str = "⌘";
pub const SYMBOL_ALT: &str = "⌥";

impl From<CGEventType> for EventTapType {
fn from(value: CGEventType) -> Self {
match value {
CGEventType::KeyDown => EventTapType::KeyDown,
CGEventType::FlagsChanged => EventTapType::FlagsChanged,
_ => EventTapType::Other,
}
}
}

static AUTO_LAUNCH: Lazy<AutoLaunch> = Lazy::new(|| {
let app_path = get_current_app_path();
let app_name = Path::new(&app_path)
Expand Down Expand Up @@ -251,29 +262,33 @@ pub fn run_event_listener(callback: &CallbackFn) {
if flags.contains(CGEventFlags::CGEventFlagAlternate) {
modifiers.add_alt();
}
if flags.eq(&CGEventFlags::CGEventFlagNonCoalesced)
|| flags.eq(&CGEventFlags::CGEventFlagNull)
{
modifiers = KeyModifier::MODIFIER_NONE;
}

match event.get_type() {
CGEventType::KeyDown => {
let event_tap_type: EventTapType = EventTapType::from(event.get_type());
match event_tap_type {
EventTapType::KeyDown => {
let source_state_id =
event.get_integer_value_field(EventField::EVENT_SOURCE_STATE_ID);
if source_state_id == 1 {
let key_code = event
.get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE)
as CGKeyCode;

if callback(proxy, get_char(key_code), modifiers) {
if callback(proxy, event_tap_type, get_char(key_code), modifiers) {
// block the key if already processed
return None;
}
}
}
CGEventType::FlagsChanged => {
if !modifiers.is_empty() {
callback(proxy, None, modifiers);
}
EventTapType::FlagsChanged => {
callback(proxy, event_tap_type, None, modifiers);
}
_ => {
callback(proxy, None, KeyModifier::new());
callback(proxy, event_tap_type, None, KeyModifier::new());
}
}
Some(event.to_owned())
Expand Down
10 changes: 9 additions & 1 deletion src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,12 @@ pub enum PressedKey {
Char(char),
Raw(u16),
}
pub type CallbackFn = dyn Fn(os::Handle, Option<PressedKey>, KeyModifier) -> bool;

#[derive(Debug, PartialEq, Eq)]
pub enum EventTapType {
KeyDown,
FlagsChanged,
Other,
}

pub type CallbackFn = dyn Fn(os::Handle, EventTapType, Option<PressedKey>, KeyModifier) -> bool;

0 comments on commit 5c63ccd

Please sign in to comment.