Skip to content

Commit

Permalink
Migrate from objc to objc2 (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm authored Sep 8, 2024
1 parent cd18ef4 commit 7d15d09
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 57 deletions.
5 changes: 5 additions & 0 deletions .changes/use-objc2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"global-hotkey": patch
---

Use `objc2` internally, leading to slightly better memory- and type-safety.
21 changes: 10 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,39 @@ name = "global-hotkey"
version = "0.6.0"
description = "Global hotkeys for Desktop Applications"
edition = "2021"
keywords = [ "windowing", "global", "global-hotkey", "hotkey" ]
keywords = ["windowing", "global", "global-hotkey", "hotkey"]
license = "Apache-2.0 OR MIT"
readme = "README.md"
repository = "https://github.com/amrbashir/global-hotkey"
documentation = "https://docs.rs/global-hotkey"
categories = [ "gui" ]
categories = ["gui"]

[features]
serde = [ "dep:serde" ]
serde = ["dep:serde"]

[dependencies]
crossbeam-channel = "0.5"
keyboard-types = "0.7"
once_cell = "1"
thiserror = "1"
serde = { version = "1", optional = true, features = [ "derive" ] }
serde = { version = "1", optional = true, features = ["derive"] }

[target."cfg(target_os = \"macos\")".dependencies]
bitflags = "2"
cocoa = "0.26"
objc = "0.2"
[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.5.2"
objc2-app-kit = { version = "0.2.2", features = ["NSEvent"] }

[target."cfg(target_os = \"windows\")".dependencies.windows-sys]
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = "0.59"
features = [
"Win32_UI_WindowsAndMessaging",
"Win32_Foundation",
"Win32_System_SystemServices",
"Win32_Graphics_Gdi",
"Win32_UI_Shell",
"Win32_UI_Input_KeyboardAndMouse"
"Win32_UI_Input_KeyboardAndMouse",
]

[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
x11-dl = "2.21"

[dev-dependencies]
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/macos/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

use std::ffi::{c_long, c_void};

use objc2::encode::{Encode, Encoding, RefEncode};

pub type UInt32 = ::std::os::raw::c_uint;
pub type SInt32 = ::std::os::raw::c_int;
pub type OSStatus = SInt32;
Expand Down Expand Up @@ -199,6 +201,10 @@ macro_rules! CGEventMaskBit {
pub enum CGEvent {}
pub type CGEventRef = *const CGEvent;

unsafe impl RefEncode for CGEvent {
const ENCODING_REF: Encoding = Encoding::Pointer(&Encoding::Struct("__CGEvent", &[]));
}

pub type CGEventTapProxy = *const c_void;
type CGEventTapCallBack = unsafe extern "C" fn(
proxy: CGEventTapProxy,
Expand Down
70 changes: 24 additions & 46 deletions src/platform_impl/macos/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
use bitflags::bitflags;
use cocoa::{
appkit::NSEventType,
base::id,
foundation::{NSInteger, NSUInteger},
};
use keyboard_types::{Code, Modifiers};
use objc::{class, msg_send, sel, sel_impl};
use objc2::{msg_send_id, rc::Retained, ClassType};
use objc2_app_kit::{NSEvent, NSEventModifierFlags, NSEventSubtype, NSEventType};
use std::{
collections::{BTreeMap, HashSet},
ffi::c_void,
Expand Down Expand Up @@ -255,35 +250,6 @@ impl GlobalHotKeyManager {
}
}

bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct NSEventModifierFlags: NSUInteger {
const Shift = 1 << 17;
const Control = 1 << 18;
const Option = 1 << 19;
const Command = 1 << 20;
}
}

impl From<NSEventModifierFlags> for Modifiers {
fn from(mod_flags: NSEventModifierFlags) -> Self {
let mut mods = Modifiers::empty();
if mod_flags.contains(NSEventModifierFlags::Shift) {
mods |= Modifiers::SHIFT;
}
if mod_flags.contains(NSEventModifierFlags::Control) {
mods |= Modifiers::CONTROL;
}
if mod_flags.contains(NSEventModifierFlags::Option) {
mods |= Modifiers::ALT;
}
if mod_flags.contains(NSEventModifierFlags::Command) {
mods |= Modifiers::META;
}
mods
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(non_camel_case_types)]
enum NX_KEYTYPE {
Expand All @@ -294,10 +260,10 @@ enum NX_KEYTYPE {
Rewind = 20,
}

impl TryFrom<i64> for NX_KEYTYPE {
impl TryFrom<isize> for NX_KEYTYPE {
type Error = String;

fn try_from(value: i64) -> Result<Self, Self::Error> {
fn try_from(value: isize) -> Result<Self, Self::Error> {
match value {
16 => Ok(NX_KEYTYPE::Play),
17 => Ok(NX_KEYTYPE::Next),
Expand Down Expand Up @@ -381,25 +347,37 @@ unsafe extern "C" fn media_key_event_callback(
return event;
}

let ns_event: id = msg_send![class!(NSEvent), eventWithCGEvent:event];
let event_type: NSEventType = msg_send![ns_event, type];
let event_subtype: u64 = msg_send![ns_event, subtype];
let ns_event: Retained<NSEvent> = msg_send_id![NSEvent::class(), eventWithCGEvent: event];
let event_type = ns_event.r#type();
let event_subtype = ns_event.subtype();

if event_type == NSEventType::NSSystemDefined && event_subtype == 8 {
if event_type == NSEventType::SystemDefined && event_subtype == NSEventSubtype::ScreenChanged {
// Key
let data_1: NSInteger = msg_send![ns_event, data1];
let data_1 = ns_event.data1();
let nx_keytype = NX_KEYTYPE::try_from((data_1 & 0xFFFF0000) >> 16);
if nx_keytype.is_err() {
return event;
}
let nx_keytype = nx_keytype.unwrap();

// Modifiers
let mods: NSUInteger = msg_send![ns_event, modifierFlags];
let mods = NSEventModifierFlags::from_bits_truncate(mods);
let flags = ns_event.modifierFlags();
let mut mods = Modifiers::empty();
if flags.contains(NSEventModifierFlags::NSEventModifierFlagShift) {
mods |= Modifiers::SHIFT;
}
if flags.contains(NSEventModifierFlags::NSEventModifierFlagControl) {
mods |= Modifiers::CONTROL;
}
if flags.contains(NSEventModifierFlags::NSEventModifierFlagOption) {
mods |= Modifiers::ALT;
}
if flags.contains(NSEventModifierFlags::NSEventModifierFlagCommand) {
mods |= Modifiers::META;
}

// Generate hotkey for matching
let hotkey = HotKey::new(Some(mods.into()), nx_keytype.into());
let hotkey = HotKey::new(Some(mods), nx_keytype.into());

// Prevent Arc been releaded after callback returned
let media_hotkeys = &*(user_info as *const Mutex<HashSet<HotKey>>);
Expand Down

0 comments on commit 7d15d09

Please sign in to comment.