Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from objc to objc2 #99

Merged
merged 1 commit into from
Sep 8, 2024
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
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
Loading