【问题标题】:Working with events for processing global hotkeys on Mac OS X在 Mac OS X 上使用事件处理全局热键
【发布时间】:2016-01-17 01:05:05
【问题描述】:

我想要什么:

我有一个程序正在运行。当程序在托盘中并且失焦时,我想设置几个全局快捷方式来向程序发送消息。 “发送消息”是什么意思?好吧,在我的程序中,我想要的只是访问某个标志,这将指示指定密钥对的状态(已触发或未触发)。我会在循环中轮询标志并从那里做出决定。

我发现了什么:

System-wide hotkey for an application

system wide shortcut for Mac OS X

我不明白的地方:

从上面的链接看来,我在注册热键时必须传递一个处理程序。在热键按下时,操作系统调用处理程序。对吗?我不明白的是,如果我的程序正在运行,系统将如何在我的程序中调用处理程序。

【问题讨论】:

  • 看来没人会帮忙...

标签: objective-c macos cocoa event-handling


【解决方案1】:

我认为您的主要问题是您不了解在 Objective C 和 Cocoa 成为规范之前的日子里 Mac 编程是如何完成的。在此之前,大多数编程都是使用 Carbon 在 C(或 C++)中完成的。在 Mac OS (Classic) 和 Mac OS X 之间的过渡期间,此名称用于一个库,该库应该是一组更现代的 API 的“复本”。

您必须了解的另一件事是,您在上面给出的示例中的热键注册必须与 Carbon 事件处理程序的注册配对,当您点击该热键组合时将调用该处理程序。

也就是说,我认为您应该阅读这份关于 Carbon Event Manager 的旧文档:

https://developer.apple.com/legacy/library/documentation/Carbon/Conceptual/Carbon_Event_Manager/CarbonEvents.pdf

并特别注意应该如何注册 Carbon Events。我特别用:

OSStatus  InstallEventHandler(EventTargetRef target,
                              EventHandlerUPP handlerProc,
                              UInt32 numTypes,
                              const EventTypeSpec* typeList,
                              void* userData,
                              EventHandlerRef* handlerRef);

我使用它的方式是制作了一个客观的 C 包装器,我在其中基本上执行以下操作:

这是一个类的一部分,我们称之为 MyOwnEventHandler:

- (EventHandlerRef)handlerRef {

    if ( handlerRef == nil ) {
       NSAssert( InstallEventHandler(GetApplicationEventTarget(),
                                     &EventHandler,
                                      0,
                                      nil,
                                      self,
                                      &handlerRef ) == noErr, @"handlerRef" );
    }

    return handlerRef;
  }

  // this is a Carbon callback that the OS invokes when your app gets
  // a hotkey event that must be handled by you
  OSStatus EventHandler( EventHandlerCallRef inHandler,
                         EventRef inEvent,
                         void* inUserData )
 {
     EventHotKeyID hotKeyID;
     GetEventParameter( inEvent,
                        kEventParamDirectObject,
                        typeEventHotKeyID,
                        nil,
                        sizeof(EventHotKeyID,
                        nil,
                        &hotKeyID ) 

   // use this to get your MyOwnEventHandler object back if need be
   // the reason why we get this is because we passed self in InstallEventHandler
   // in Carbon event callbacks you cannot access self directly
   // because this is a C callback, not an objective C method
    MyOwnEventHandler* handler = (MyOwnEventHandler *)inUserData;

   // handle the hotkey here - I usually store the id of the EventHotKeyID struct
   // in a objective C hotkey object to look up events in an array of registered hotkeys

  return eventNotHandledErr; // return this error for other handlers to handle this event as well
}

// call this objective C wrapper method to register your Carbon Event handler
- (void)registerForGettingHotKeyEvents {
       const EventTypeSpec kHotKeysEvent[] = {{ kEventClassKeyboard,   kEventHotKeyPressed }};
       AddEventTypesToHandler( [self handlerRef], GetEventTypeCount(kHotKeysEvent), kHotKeysEvent );
    }

// call this objective C wrapper method to unregister your Carbon Event handler
- (void)unregisterFromGettingHotKeyEvents {
       const EventTypeSpec kHotKeysEvent[] = {{ kEventClassKeyboard,   kEventHotKeyPressed }};
       RemoveEventTypesFromHandler( [self handlerRef], GetEventTypeCount(kHotKeysEvent), kHotKeysEvent );
    }

我希望这会有所帮助。如果您被困在某个地方,请告诉我,我会尽力帮助您。

【讨论】:

  • 使用 c++ 让我很惊讶,因为我现在实际上正在编写一个 c++ 程序 :) 是否意味着我可以直接调用必要的方法?问题是:我有自己的主循环。事实上,我有一个必须支持的 SMFL 窗口。但是当程序失焦(它变得不可见)时,它不会做任何工作。我还可以在其中的某个地方嵌入 Carbon Event Manager 吗?也许当程序变得不可见时?非常感谢您的回答!
  • 现在 Carbon 事件管理器进入了 Carbon.Framework。因此,添加此框架并通过添加 #include 来包含必要的标头
猜你喜欢
  • 1970-01-01
  • 2011-08-12
  • 1970-01-01
  • 2017-04-04
  • 2011-01-23
  • 1970-01-01
  • 2010-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多