diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 23e71b3a2d..59e00130c4 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -59,6 +59,9 @@ Interface changes setting the properties to non-existing tracks may report it as selected track for a small time window, until it's forced back to "no". The exact details how this is handled may change in the future. + - remove old Apple Remote support, including --input-appleremote + - add MediaPlayer support and remove the old Media Key event tap on macOS. + this possibly also re-adds the Apple Remote support --- mpv 0.30.0 --- - add `--d3d11-output-format` to enable explicit selection of a D3D11 swap chain format. diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 323a961804..3d9263ee3f 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -145,9 +145,6 @@ Comments on some symbolic names: ``GAMEPAD_*`` Keys emitted by the SDL gamepad backend. -``AR_*`` - Keys emitted by the OSX-only Apple Remote code. - ``UNMAPPED`` Pseudo-key that matches any unmapped key. (You should probably avoid this if possible, because it might change behavior or get removed in the future.) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index c2fd9136a3..be9177b09a 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -3484,10 +3484,6 @@ Input See `JSON IPC`_ for details. -``--input-appleremote=`` - (OS X only) - Enable/disable Apple Remote support. Enabled by default (except for libmpv). - ``--input-gamepad=`` Enable/disable SDL2 Gamepad support. Disabled by default. diff --git a/DOCS/mplayer-changes.rst b/DOCS/mplayer-changes.rst index 66cacb3205..d00b520279 100644 --- a/DOCS/mplayer-changes.rst +++ b/DOCS/mplayer-changes.rst @@ -144,7 +144,6 @@ Mac OS X * Native OpenGL backend. * Cocoa event loop is independent from MPlayer's event loop, so user actions like accessing menus and live resizing do not block the playback. -* Apple Remote support. * Media Keys support. * VDA support using libavcodec hwaccel API instead of FFmpeg's decoder with up to 2-2.5x reduction in CPU usage. @@ -248,7 +247,7 @@ Command Line Switches ``-msglevel`` ``--msg-level`` (changed semantics) ``-msgmodule`` ``--msg-module`` ``-name`` ``--x11-name`` - ``-noar`` ``--no-input-appleremote`` + ``-noar`` ``(removed; replaced by MediaPlayer framework)`` ``-noautosub`` ``--no-sub-auto`` ``-noconsolecontrols`` ``--no-input-terminal`` ``-nosound`` ``--no-audio`` diff --git a/ci/build-macos.sh b/ci/build-macos.sh index 4984e3ba81..7b6eda7356 100755 --- a/ci/build-macos.sh +++ b/ci/build-macos.sh @@ -19,7 +19,7 @@ PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" pytho --variant="${MPV_VARIANT}" \ --prefix="${MPV_INSTALL_PREFIX}" \ --enable-{gl,iconv,lcms2,libass,libass-osd,libmpv-shared,lua,jpeg,plain-gl,zlib} \ - --enable-{apple-remote,cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl} + --enable-{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl} python3 ./waf build --variant="${MPV_VARIANT}" -j4 diff --git a/etc/builtin.conf b/etc/builtin.conf index a5e174e964..6984d57769 100644 --- a/etc/builtin.conf +++ b/etc/builtin.conf @@ -27,7 +27,6 @@ osc=no input-default-bindings=no input-vo-keyboard=no # OSX/Cocoa global input hooks -input-appleremote=no input-media-keys=no [encoding] diff --git a/etc/input.conf b/etc/input.conf index f60ed51bd4..9c870ea42b 100644 --- a/etc/input.conf +++ b/etc/input.conf @@ -168,22 +168,6 @@ #F8 show_text ${playlist} # show playlist #F9 show_text ${track-list} # show list of audio/sub streams -# Apple Remote section -#AR_PLAY cycle pause -#AR_PLAY_HOLD quit -#AR_CENTER cycle pause -#AR_CENTER_HOLD quit -#AR_NEXT seek 10 -#AR_NEXT_HOLD seek 120 -#AR_PREV seek -10 -#AR_PREV_HOLD seek -120 -#AR_MENU show-progress -#AR_MENU_HOLD cycle mute -#AR_VUP add volume 2 -#AR_VUP_HOLD add chapter 1 -#AR_VDOWN add volume -2 -#AR_VDOWN_HOLD add chapter -1 - # # Legacy bindings (may or may not be removed in the future) # diff --git a/etc/mplayer-input.conf b/etc/mplayer-input.conf index 742913c0fe..2d23e47477 100644 --- a/etc/mplayer-input.conf +++ b/etc/mplayer-input.conf @@ -74,25 +74,6 @@ l cycle tv-channel -1 n cycle tv-norm #b tv_step_chanlist -## -## Apple Remote section -## -## To use OSD menu with Apple Remote, set key AR_MENU to any OSD menu command, -## or just comment out the 'AR_MENU osd' line and uncomment the line after it. -## - -AR_PLAY cycle pause -AR_PLAY_HOLD quit -AR_NEXT seek 30 -AR_NEXT_HOLD seek 120 -AR_PREV seek -10 -AR_PREV_HOLD seek -120 -#AR_MENU menu up -#AR_MENU menu cancel -AR_MENU_HOLD cycle mute -AR_VUP add volume 1 -AR_VDOWN add volume -1 - #? add chapter -1 # skip to previous dvd chapter #? add chapter +1 # next diff --git a/input/input.c b/input/input.c index 084a61a2eb..1bc8e303f6 100644 --- a/input/input.c +++ b/input/input.c @@ -196,14 +196,14 @@ const struct m_sub_options input_config = { OPT_FLAG("input-cursor", enable_mouse_movements, 0), OPT_FLAG("input-vo-keyboard", vo_key_input, 0), OPT_FLAG("input-media-keys", use_media_keys, 0), -#if HAVE_COCOA - OPT_FLAG("input-appleremote", use_appleremote, 0), -#endif #if HAVE_SDL2_GAMEPAD OPT_FLAG("input-gamepad", use_gamepad, 0), #endif OPT_FLAG("window-dragging", allow_win_drag, 0), OPT_REPLACED("input-x11-keyboard", "input-vo-keyboard"), +#if HAVE_COCOA + OPT_REMOVED("input-appleremote", "replaced by MediaPlayer support"), +#endif {0} }, .size = sizeof(struct input_opts), @@ -215,9 +215,6 @@ const struct m_sub_options input_config = { .use_alt_gr = 1, .enable_mouse_movements = 1, .use_media_keys = 1, -#if HAVE_COCOA - .use_appleremote = 1, -#endif .default_bindings = 1, .vo_key_input = 1, .allow_win_drag = 1, @@ -1335,15 +1332,6 @@ static void reload_opts(struct input_ctx *ictx, bool shutdown) #if HAVE_COCOA struct input_opts *opts = ictx->opts; - if (ictx->using_ar != (opts->use_appleremote && !shutdown)) { - ictx->using_ar = !ictx->using_ar; - if (ictx->using_ar) { - cocoa_init_apple_remote(); - } else { - cocoa_uninit_apple_remote(); - } - } - if (ictx->using_cocoa_media_keys != (opts->use_media_keys && !shutdown)) { ictx->using_cocoa_media_keys = !ictx->using_cocoa_media_keys; if (ictx->using_cocoa_media_keys) { diff --git a/input/keycodes.c b/input/keycodes.c index 3d7fd09d11..bcf59c74a1 100644 --- a/input/keycodes.c +++ b/input/keycodes.c @@ -102,21 +102,6 @@ static const struct key_name key_names[] = { { MP_MBTN_MID_DBL, "MBTN_MID_DBL" }, { MP_MBTN_RIGHT_DBL, "MBTN_RIGHT_DBL" }, - { MP_AR_PLAY, "AR_PLAY" }, - { MP_AR_PLAY_HOLD, "AR_PLAY_HOLD" }, - { MP_AR_CENTER, "AR_CENTER" }, - { MP_AR_CENTER_HOLD, "AR_CENTER_HOLD" }, - { MP_AR_NEXT, "AR_NEXT" }, - { MP_AR_NEXT_HOLD, "AR_NEXT_HOLD" }, - { MP_AR_PREV, "AR_PREV" }, - { MP_AR_PREV_HOLD, "AR_PREV_HOLD" }, - { MP_AR_MENU, "AR_MENU" }, - { MP_AR_MENU_HOLD, "AR_MENU_HOLD" }, - { MP_AR_VUP, "AR_VUP" }, - { MP_AR_VUP_HOLD, "AR_VUP_HOLD" }, - { MP_AR_VDOWN, "AR_VDOWN" }, - { MP_AR_VDOWN_HOLD, "AR_VDOWN_HOLD" }, - { MP_KEY_GAMEPAD_ACTION_DOWN, "GAMEPAD_ACTION_DOWN" }, { MP_KEY_GAMEPAD_ACTION_RIGHT, "GAMEPAD_ACTION_RIGHT" }, { MP_KEY_GAMEPAD_ACTION_LEFT, "GAMEPAD_ACTION_LEFT" }, diff --git a/input/keycodes.h b/input/keycodes.h index 65c31b4d61..a75099f2f2 100644 --- a/input/keycodes.h +++ b/input/keycodes.h @@ -141,23 +141,6 @@ #define MP_KEY_MOUSE_BTN_COUNT (MP_MBTN_END - MP_MBTN_BASE) -// Apple Remote input module -#define MP_AR_BASE (MP_KEY_BASE+0xE0) -#define MP_AR_PLAY (MP_AR_BASE + 0) -#define MP_AR_PLAY_HOLD (MP_AR_BASE + 1) -#define MP_AR_CENTER (MP_AR_BASE + 2) -#define MP_AR_CENTER_HOLD (MP_AR_BASE + 3) -#define MP_AR_NEXT (MP_AR_BASE + 4) -#define MP_AR_NEXT_HOLD (MP_AR_BASE + 5) -#define MP_AR_PREV (MP_AR_BASE + 6) -#define MP_AR_PREV_HOLD (MP_AR_BASE + 7) -#define MP_AR_MENU (MP_AR_BASE + 8) -#define MP_AR_MENU_HOLD (MP_AR_BASE + 9) -#define MP_AR_VUP (MP_AR_BASE + 10) -#define MP_AR_VUP_HOLD (MP_AR_BASE + 11) -#define MP_AR_VDOWN (MP_AR_BASE + 12) -#define MP_AR_VDOWN_HOLD (MP_AR_BASE + 13) - /* game controller keys */ #define MP_KEY_GAMEPAD (MP_KEY_BASE+0xF0) #define MP_KEY_GAMEPAD_ACTION_DOWN (MP_KEY_GAMEPAD+0) diff --git a/osdep/ar/HIDRemote.h b/osdep/ar/HIDRemote.h deleted file mode 100644 index 35db408b40..0000000000 --- a/osdep/ar/HIDRemote.h +++ /dev/null @@ -1,378 +0,0 @@ -// -// HIDRemote.h -// HIDRemote V1.2 -// -// Created by Felix Schwarz on 06.04.07. -// Copyright 2007-2011 IOSPIRIT GmbH. All rights reserved. -// -// The latest version of this class is available at -// http://www.iospirit.com/developers/hidremote/ -// -// ** LICENSE ************************************************************************* -// -// Copyright (c) 2007-2011 IOSPIRIT GmbH (http://www.iospirit.com/) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this -// list of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// * Neither the name of IOSPIRIT GmbH nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior -// written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -// ************************************************************************************ - - -// ************************************************************************************ -// ********************************** DOCUMENTATION *********************************** -// ************************************************************************************ -// -// - a reference is available at http://www.iospirit.com/developers/hidremote/reference/ -// - for a guide, please see http://www.iospirit.com/developers/hidremote/guide/ -// -// ************************************************************************************ - - -#import - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma mark -- Enums / Codes -- - -typedef enum -{ - kHIDRemoteModeNone = 0L, - kHIDRemoteModeShared, // Share the remote with others - let's you listen to the remote control events as long as no one has an exclusive lock on it - // (RECOMMENDED ONLY FOR SPECIAL PURPOSES) - - kHIDRemoteModeExclusive, // Try to acquire an exclusive lock on the remote (NOT RECOMMENDED) - - kHIDRemoteModeExclusiveAuto // Try to acquire an exclusive lock on the remote whenever the application has focus. Temporarily release control over the - // remote when another application has focus (RECOMMENDED) -} HIDRemoteMode; - -typedef enum -{ - /* A code reserved for "no button" (needed for tracking) */ - kHIDRemoteButtonCodeNone = 0L, - - /* Standard codes - available for white plastic and aluminum remote */ - kHIDRemoteButtonCodeUp, - kHIDRemoteButtonCodeDown, - kHIDRemoteButtonCodeLeft, - kHIDRemoteButtonCodeRight, - kHIDRemoteButtonCodeCenter, - kHIDRemoteButtonCodeMenu, - - /* Extra codes - Only available for the new aluminum version of the remote */ - kHIDRemoteButtonCodePlay, - - /* Masks */ - kHIDRemoteButtonCodeCodeMask = 0xFFL, - kHIDRemoteButtonCodeHoldMask = (1L << 16L), - kHIDRemoteButtonCodeSpecialMask = (1L << 17L), - kHIDRemoteButtonCodeAluminumMask = (1L << 21L), // PRIVATE - only used internally - - /* Hold button standard codes - available for white plastic and aluminum remote */ - kHIDRemoteButtonCodeUpHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeUp), - kHIDRemoteButtonCodeDownHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeDown), - kHIDRemoteButtonCodeLeftHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeLeft), - kHIDRemoteButtonCodeRightHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeRight), - kHIDRemoteButtonCodeCenterHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeCenter), - kHIDRemoteButtonCodeMenuHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeMenu), - - /* Hold button extra codes - Only available for aluminum version of the remote */ - kHIDRemoteButtonCodePlayHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodePlay), - - /* DEPRECATED codes - compatibility with HIDRemote 1.0 */ - kHIDRemoteButtonCodePlus = kHIDRemoteButtonCodeUp, - kHIDRemoteButtonCodePlusHold = kHIDRemoteButtonCodeUpHold, - kHIDRemoteButtonCodeMinus = kHIDRemoteButtonCodeDown, - kHIDRemoteButtonCodeMinusHold = kHIDRemoteButtonCodeDownHold, - kHIDRemoteButtonCodePlayPause = kHIDRemoteButtonCodeCenter, - kHIDRemoteButtonCodePlayPauseHold = kHIDRemoteButtonCodeCenterHold, - - /* Special purpose codes */ - kHIDRemoteButtonCodeIDChanged = (kHIDRemoteButtonCodeSpecialMask|(1L << 18L)), // (the ID of the connected remote has changed, you can safely ignore this) - #ifdef _HIDREMOTE_EXTENSIONS - #define _HIDREMOTE_EXTENSIONS_SECTION 1 - #include "HIDRemoteAdditions.h" - #undef _HIDREMOTE_EXTENSIONS_SECTION - #endif /* _HIDREMOTE_EXTENSIONS */ -} HIDRemoteButtonCode; - -typedef enum -{ - kHIDRemoteModelUndetermined = 0L, // Assume a white plastic remote - kHIDRemoteModelWhitePlastic, // Signal *likely* to be coming from a white plastic remote - kHIDRemoteModelAluminum // Signal *definitely* coming from an aluminum remote -} HIDRemoteModel; - -typedef enum -{ - kHIDRemoteAluminumRemoteSupportLevelNone = 0L, // This system has no support for the Aluminum Remote at all - kHIDRemoteAluminumRemoteSupportLevelEmulation, // This system possibly has support for the Aluminum Remote (via emulation) - kHIDRemoteAluminumRemoteSupportLevelNative // This system has native support for the Aluminum Remote -} HIDRemoteAluminumRemoteSupportLevel; - -@class HIDRemote; - -#pragma mark -- Delegate protocol (mandatory) -- -@protocol HIDRemoteDelegate - -// Notification of button events -- (void)hidRemote:(HIDRemote *)hidRemote // The instance of HIDRemote sending this - eventWithButton:(HIDRemoteButtonCode)buttonCode // Event for the button specified by code - isPressed:(BOOL)isPressed // The button was pressed (YES) / released (NO) - fromHardwareWithAttributes:(NSMutableDictionary *)attributes; // Information on the device this event comes from - -@optional - -// Notification of ID changes -- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when the user switched to a remote control with a different ID - remoteIDChangedOldID:(SInt32)old - newID:(SInt32)newID - forHardwareWithAttributes:(NSMutableDictionary *)attributes; - -// Notification about hardware additions/removals -- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware was found / added to HIDRemote's pool - foundNewHardwareWithAttributes:(NSMutableDictionary *)attributes; - -- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when initialization of new hardware as requested failed - failedNewHardwareWithError:(NSError *)error; - -- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when hardware was removed from HIDRemote's pool - releasedHardwareWithAttributes:(NSMutableDictionary *)attributes; - -// ### WARNING: Unless you know VERY PRECISELY what you are doing, do not implement any of the delegate methods below. ### - -// Matching of newly found receiver hardware -- (BOOL)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware is inspected - inspectNewHardwareWithService:(io_service_t)service // - prematchResult:(BOOL)prematchResult; // Return YES if HIDRemote should go on with this hardware and try - // to use it, or NO if it should not be pursued further. - -// Exlusive lock lending -- (BOOL)hidRemote:(HIDRemote *)hidRemote - lendExclusiveLockToApplicationWithInfo:(NSDictionary *)applicationInfo; - -- (void)hidRemote:(HIDRemote *)hidRemote - exclusiveLockReleasedByApplicationWithInfo:(NSDictionary *)applicationInfo; - -- (BOOL)hidRemote:(HIDRemote *)hidRemote - shouldRetryExclusiveLockWithInfo:(NSDictionary *)applicationInfo; - -@end - - -#pragma mark -- Actual header file for class -- - -@interface HIDRemote : NSObject -{ - // IOMasterPort - mach_port_t _masterPort; - - // Notification ports - IONotificationPortRef _notifyPort; - CFRunLoopSourceRef _notifyRLSource; - - // Matching iterator - io_iterator_t _matchingServicesIterator; - - // SecureInput notification - io_object_t _secureInputNotification; - - // Service attributes - NSMutableDictionary *_serviceAttribMap; - - // Mode - HIDRemoteMode _mode; - BOOL _autoRecover; - NSTimer *_autoRecoveryTimer; - - // Delegate - NSObject *_delegate; - - // Last seen ID and remote model - SInt32 _lastSeenRemoteID; - HIDRemoteModel _lastSeenModel; - SInt32 _lastSeenModelRemoteID; - - // Unused button codes - NSArray *_unusedButtonCodes; - - // Simulate Plus/Minus Hold - BOOL _simulateHoldEvents; - - // SecureEventInput workaround - BOOL _secureEventInputWorkAround; - UInt64 _lastSecureEventInputPIDSum; - uid_t _lastFrontUserSession; - - // Exclusive lock lending - BOOL _exclusiveLockLending; - BOOL _sendExclusiveResourceReuseNotification; - NSNumber *_waitForReturnByPID; - NSNumber *_returnToPID; - BOOL _isRestarting; - - // Status notifications - BOOL _sendStatusNotifications; - NSString *_pidString; - - // Status - BOOL _applicationIsTerminating; - BOOL _isStopping; - - // Thread safety - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING /* #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if you're running your HIDRemote instance on a background thread (requires OS X 10.5 or later) */ - NSThread *_runOnThread; - #endif -} - -#pragma mark -- PUBLIC: Shared HID Remote -- -+ (HIDRemote *)sharedHIDRemote; - -#pragma mark -- PUBLIC: System Information -- -+ (BOOL)isCandelairInstalled; -+ (BOOL)isCandelairInstallationRequiredForRemoteMode:(HIDRemoteMode)remoteMode; -- (HIDRemoteAluminumRemoteSupportLevel)aluminiumRemoteSystemSupportLevel; - -#pragma mark -- PUBLIC: Interface / API -- -- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode; -- (void)stopRemoteControl; - -- (BOOL)isStarted; -- (HIDRemoteMode)startedInMode; - -- (unsigned)activeRemoteControlCount; - -- (SInt32)lastSeenRemoteControlID; - -- (void)setLastSeenModel:(HIDRemoteModel)aModel; -- (HIDRemoteModel)lastSeenModel; - -- (void)setDelegate:(NSObject *)newDelegate; -- (NSObject *)delegate; - -- (void)setSimulateHoldEvents:(BOOL)newSimulateHoldEvents; -- (BOOL)simulateHoldEvents; - -- (void)setUnusedButtonCodes:(NSArray *)newArrayWithUnusedButtonCodesAsNSNumbers; -- (NSArray *)unusedButtonCodes; - -#pragma mark -- PUBLIC: Expert APIs -- -- (void)setEnableSecureEventInputWorkaround:(BOOL)newEnableSecureEventInputWorkaround; -- (BOOL)enableSecureEventInputWorkaround; - -- (void)setExclusiveLockLendingEnabled:(BOOL)newExclusiveLockLendingEnabled; -- (BOOL)exclusiveLockLendingEnabled; - -- (BOOL)isApplicationTerminating; -- (BOOL)isStopping; - -#pragma mark -- PRIVATE: HID Event handling -- -- (void)_handleButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict; -- (void)_sendButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict; -- (void)_hidEventFor:(io_service_t)hidDevice from:(IOHIDQueueInterface **)interface withResult:(IOReturn)result; - -#pragma mark -- PRIVATE: Service setup and destruction -- -- (BOOL)_prematchService:(io_object_t)service; -- (HIDRemoteButtonCode)buttonCodeForUsage:(unsigned int)usage usagePage:(unsigned int)usagePage; -- (BOOL)_setupService:(io_object_t)service; -- (void)_destructService:(io_object_t)service; - -#pragma mark -- PRIVATE: Distributed notifiations handling -- -- (void)_postStatusWithAction:(NSString *)action; -- (void)_handleNotifications:(NSNotification *)notification; -- (void)_setSendStatusNotifications:(BOOL)doSend; -- (BOOL)_sendStatusNotifications; - -#pragma mark -- PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto -- -- (void)_appStatusChanged:(NSNotification *)notification; -- (void)_delayedAutoRecovery:(NSTimer *)aTimer; - -#pragma mark -- PRIVATE: Notification handling -- -- (void)_serviceMatching:(io_iterator_t)iterator; -- (void)_serviceNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument; -- (void)_updateSessionInformation; -- (void)_secureInputNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument; - -@end - -#pragma mark -- Information attribute keys -- -extern NSString *kHIDRemoteManufacturer; -extern NSString *kHIDRemoteProduct; -extern NSString *kHIDRemoteTransport; - -#pragma mark -- Internal/Expert attribute keys (AKA: don't touch these unless you really, really, REALLY know what you do) -- -extern NSString *kHIDRemoteCFPluginInterface; -extern NSString *kHIDRemoteHIDDeviceInterface; -extern NSString *kHIDRemoteCookieButtonCodeLUT; -extern NSString *kHIDRemoteHIDQueueInterface; -extern NSString *kHIDRemoteServiceNotification; -extern NSString *kHIDRemoteCFRunLoopSource; -extern NSString *kHIDRemoteLastButtonPressed; -extern NSString *kHIDRemoteService; -extern NSString *kHIDRemoteSimulateHoldEventsTimer; -extern NSString *kHIDRemoteSimulateHoldEventsOriginButtonCode; -extern NSString *kHIDRemoteAluminumRemoteSupportLevel; -extern NSString *kHIDRemoteAluminumRemoteSupportOnDemand; - -#pragma mark -- Distributed notifications -- -extern NSString *kHIDRemoteDNHIDRemotePing; -extern NSString *kHIDRemoteDNHIDRemoteRetry; -extern NSString *kHIDRemoteDNHIDRemoteStatus; - -extern NSString *kHIDRemoteDNHIDRemoteRetryGlobalObject; - -#pragma mark -- Distributed notifications userInfo keys and values -- -extern NSString *kHIDRemoteDNStatusHIDRemoteVersionKey; -extern NSString *kHIDRemoteDNStatusPIDKey; -extern NSString *kHIDRemoteDNStatusModeKey; -extern NSString *kHIDRemoteDNStatusUnusedButtonCodesKey; -extern NSString *kHIDRemoteDNStatusRemoteControlCountKey; -extern NSString *kHIDRemoteDNStatusReturnToPIDKey; -extern NSString *kHIDRemoteDNStatusActionKey; -extern NSString *kHIDRemoteDNStatusActionStart; -extern NSString *kHIDRemoteDNStatusActionStop; -extern NSString *kHIDRemoteDNStatusActionUpdate; -extern NSString *kHIDRemoteDNStatusActionNoNeed; - -#pragma mark -- Driver compatibility flags -- -typedef enum -{ - kHIDRemoteCompatibilityFlagsStandardHIDRemoteDevice = 1L, -} HIDRemoteCompatibilityFlags; diff --git a/osdep/ar/HIDRemote.m b/osdep/ar/HIDRemote.m deleted file mode 100644 index 8e6c913d46..0000000000 --- a/osdep/ar/HIDRemote.m +++ /dev/null @@ -1,2033 +0,0 @@ -// -// HIDRemote.m -// HIDRemote V1.2 (27th May 2011) -// -// Created by Felix Schwarz on 06.04.07. -// Copyright 2007-2011 IOSPIRIT GmbH. All rights reserved. -// -// The latest version of this class is available at -// http://www.iospirit.com/developers/hidremote/ -// -// ** LICENSE ************************************************************************* -// -// Copyright (c) 2007-2011 IOSPIRIT GmbH (http://www.iospirit.com/) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list -// of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this -// list of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// * Neither the name of IOSPIRIT GmbH nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior -// written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -// ************************************************************************************ - -// ************************************************************************************ -// ********************************** DOCUMENTATION *********************************** -// ************************************************************************************ -// -// - a reference is available at http://www.iospirit.com/developers/hidremote/reference/ -// - for a guide, please see http://www.iospirit.com/developers/hidremote/guide/ -// -// ************************************************************************************ - -#import "HIDRemote.h" - -// Callback Prototypes -static void HIDEventCallback( void * target, - IOReturn result, - void * refcon, - void * sender); - -static void ServiceMatchingCallback( void *refCon, - io_iterator_t iterator); - -static void ServiceNotificationCallback(void * refCon, - io_service_t service, - natural_t messageType, - void * messageArgument); - -static void SecureInputNotificationCallback( void * refCon, - io_service_t service, - natural_t messageType, - void * messageArgument); - -// Shared HIDRemote instance -static HIDRemote *sHIDRemote = nil; - -@implementation HIDRemote - -#pragma mark -- Init, dealloc & shared instance -- - -+ (HIDRemote *)sharedHIDRemote -{ - if (sHIDRemote==nil) - { - sHIDRemote = [[HIDRemote alloc] init]; - } - - return (sHIDRemote); -} - -- (id)init -{ - if ((self = [super init]) != nil) - { - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING - _runOnThread = [[NSThread currentThread] retain]; - #endif - - // Detect application becoming active/inactive - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appStatusChanged:) name:NSApplicationDidBecomeActiveNotification object:NSApp]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appStatusChanged:) name:NSApplicationWillResignActiveNotification object:NSApp]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appStatusChanged:) name:NSApplicationWillTerminateNotification object:NSApp]; - - // Handle distributed notifications - _pidString = [[NSString alloc] initWithFormat:@"%d", getpid()]; - - [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleNotifications:) name:kHIDRemoteDNHIDRemotePing object:nil]; - [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleNotifications:) name:kHIDRemoteDNHIDRemoteRetry object:kHIDRemoteDNHIDRemoteRetryGlobalObject]; - [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleNotifications:) name:kHIDRemoteDNHIDRemoteRetry object:_pidString]; - - // Enabled by default: simulate hold events for plus/minus - _simulateHoldEvents = YES; - - // Enabled by default: work around for a locking issue introduced with Security Update 2008-004 / 10.4.9 and beyond (credit for finding this workaround goes to Martin Kahr) - _secureEventInputWorkAround = YES; - _secureInputNotification = 0; - - // Initialize instance variables - _lastSeenRemoteID = -1; - _lastSeenModel = kHIDRemoteModelUndetermined; - _unusedButtonCodes = [[NSMutableArray alloc] init]; - _exclusiveLockLending = NO; - _sendExclusiveResourceReuseNotification = YES; - _applicationIsTerminating = NO; - - // Send status notifications - _sendStatusNotifications = YES; - } - - return (self); -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:NSApp]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillResignActiveNotification object:NSApp]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidBecomeActiveNotification object:NSApp]; - - [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemotePing object:nil]; - [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemoteRetry object:kHIDRemoteDNHIDRemoteRetryGlobalObject]; - [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemoteRetry object:_pidString]; - [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:nil object:nil]; /* As demanded by the documentation for -[NSDistributedNotificationCenter removeObserver:name:object:] */ - - [self stopRemoteControl]; - - [self setExclusiveLockLendingEnabled:NO]; - - [self setDelegate:nil]; - - if (_unusedButtonCodes != nil) - { - [_unusedButtonCodes release]; - _unusedButtonCodes = nil; - } - - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING - [_runOnThread release]; - _runOnThread = nil; - #endif - - [_pidString release]; - _pidString = nil; - - [super dealloc]; -} - -#pragma mark -- PUBLIC: System Information -- -+ (BOOL)isCandelairInstalled -{ - mach_port_t masterPort = 0; - kern_return_t kernResult; - io_service_t matchingService = 0; - BOOL isInstalled = NO; - - kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort); - if ((kernResult!=kIOReturnSuccess) || (masterPort==0)) { return(NO); } - - if ((matchingService = IOServiceGetMatchingService(masterPort, IOServiceMatching("IOSPIRITIRController"))) != 0) - { - isInstalled = YES; - IOObjectRelease((io_object_t) matchingService); - } - - mach_port_deallocate(mach_task_self(), masterPort); - - return (isInstalled); -} - -+ (BOOL)isCandelairInstallationRequiredForRemoteMode:(HIDRemoteMode)remoteMode -{ - return (NO); -} - -- (HIDRemoteAluminumRemoteSupportLevel)aluminiumRemoteSystemSupportLevel -{ - HIDRemoteAluminumRemoteSupportLevel supportLevel = kHIDRemoteAluminumRemoteSupportLevelNone; - NSEnumerator *attribDictsEnum; - NSDictionary *hidAttribsDict; - - attribDictsEnum = [_serviceAttribMap objectEnumerator]; - - while ((hidAttribsDict = [attribDictsEnum nextObject]) != nil) - { - NSNumber *deviceSupportLevel; - - if ((deviceSupportLevel = [hidAttribsDict objectForKey:kHIDRemoteAluminumRemoteSupportLevel]) != nil) - { - if ([deviceSupportLevel intValue] > (int)supportLevel) - { - supportLevel = [deviceSupportLevel intValue]; - } - } - } - - return (supportLevel); -} - -#pragma mark -- PUBLIC: Interface / API -- -- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode -{ - if ((_mode == kHIDRemoteModeNone) && (hidRemoteMode != kHIDRemoteModeNone)) - { - kern_return_t kernReturn; - CFMutableDictionaryRef matchDict=NULL; - io_service_t rootService; - - do - { - // Get IOKit master port - kernReturn = IOMasterPort(bootstrap_port, &_masterPort); - if ((kernReturn!=kIOReturnSuccess) || (_masterPort==0)) { break; } - - // Setup notification port - _notifyPort = IONotificationPortCreate(_masterPort); - - if ((_notifyRLSource = IONotificationPortGetRunLoopSource(_notifyPort)) != NULL) - { - CFRunLoopAddSource( CFRunLoopGetCurrent(), - _notifyRLSource, - kCFRunLoopCommonModes); - } - else - { - break; - } - - // Setup SecureInput notification - if ((hidRemoteMode == kHIDRemoteModeExclusive) || (hidRemoteMode == kHIDRemoteModeExclusiveAuto)) - { - if ((rootService = IORegistryEntryFromPath(_masterPort, kIOServicePlane ":/")) != 0) - { - kernReturn = IOServiceAddInterestNotification( _notifyPort, - rootService, - kIOBusyInterest, - SecureInputNotificationCallback, - (void *)self, - &_secureInputNotification); - if (kernReturn != kIOReturnSuccess) { break; } - - [self _updateSessionInformation]; - } - else - { - break; - } - } - - // Setup notification matching dict - matchDict = IOServiceMatching(kIOHIDDeviceKey); - CFRetain(matchDict); - - // Actually add notification - kernReturn = IOServiceAddMatchingNotification( _notifyPort, - kIOFirstMatchNotification, - matchDict, // one reference count consumed by this call - ServiceMatchingCallback, - (void *) self, - &_matchingServicesIterator); - if (kernReturn != kIOReturnSuccess) { break; } - - // Setup serviceAttribMap - _serviceAttribMap = [[NSMutableDictionary alloc] init]; - if (_serviceAttribMap==nil) { break; } - - // Phew .. everything went well! - _mode = hidRemoteMode; - CFRelease(matchDict); - - [self _serviceMatching:_matchingServicesIterator]; - - [self _postStatusWithAction:kHIDRemoteDNStatusActionStart]; - - return (YES); - - }while(0); - - // An error occurred. Do necessary clean up. - if (matchDict!=NULL) - { - CFRelease(matchDict); - matchDict = NULL; - } - - [self stopRemoteControl]; - } - - return (NO); -} - -- (void)stopRemoteControl -{ - UInt32 serviceCount = 0; - - _autoRecover = NO; - _isStopping = YES; - - if (_autoRecoveryTimer!=nil) - { - [_autoRecoveryTimer invalidate]; - [_autoRecoveryTimer release]; - _autoRecoveryTimer = nil; - } - - if (_serviceAttribMap!=nil) - { - NSDictionary *cloneDict = [[NSDictionary alloc] initWithDictionary:_serviceAttribMap]; - - if (cloneDict!=nil) - { - NSEnumerator *mapKeyEnum = [cloneDict keyEnumerator]; - NSNumber *serviceValue; - - while ((serviceValue = [mapKeyEnum nextObject]) != nil) - { - [self _destructService:(io_object_t)[serviceValue unsignedIntValue]]; - serviceCount++; - }; - - [cloneDict release]; - cloneDict = nil; - } - - [_serviceAttribMap release]; - _serviceAttribMap = nil; - } - - if (_matchingServicesIterator!=0) - { - IOObjectRelease((io_object_t) _matchingServicesIterator); - _matchingServicesIterator = 0; - } - - if (_secureInputNotification!=0) - { - IOObjectRelease((io_object_t) _secureInputNotification); - _secureInputNotification = 0; - } - - if (_notifyRLSource!=NULL) - { - CFRunLoopSourceInvalidate(_notifyRLSource); - _notifyRLSource = NULL; - } - - if (_notifyPort!=NULL) - { - IONotificationPortDestroy(_notifyPort); - _notifyPort = NULL; - } - - if (_masterPort!=0) - { - mach_port_deallocate(mach_task_self(), _masterPort); - _masterPort = 0; - } - - if (_returnToPID!=nil) - { - [_returnToPID release]; - _returnToPID = nil; - } - - if (_mode!=kHIDRemoteModeNone) - { - // Post status - [self _postStatusWithAction:kHIDRemoteDNStatusActionStop]; - - if (_sendStatusNotifications) - { - // In case we were not ready to lend it earlier, tell other HIDRemote apps that the resources (if any were used) are now again available for use by other applications - if (((_mode==kHIDRemoteModeExclusive) || (_mode==kHIDRemoteModeExclusiveAuto)) && (_sendExclusiveResourceReuseNotification==YES) && (_exclusiveLockLending==NO) && (serviceCount>0)) - { - _mode = kHIDRemoteModeNone; - - if (!_isRestarting) - { - [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kHIDRemoteDNHIDRemoteRetry - object:kHIDRemoteDNHIDRemoteRetryGlobalObject - userInfo:[NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInt:(unsigned int)getpid()], kHIDRemoteDNStatusPIDKey, - [[NSBundle mainBundle] bundleIdentifier], (NSString *)kCFBundleIdentifierKey, - nil] - deliverImmediately:YES]; - } - } - } - } - - _mode = kHIDRemoteModeNone; - _isStopping = NO; -} - -- (BOOL)isStarted -{ - return (_mode != kHIDRemoteModeNone); -} - -- (HIDRemoteMode)startedInMode -{ - return (_mode); -} - -- (unsigned)activeRemoteControlCount -{ - return ([_serviceAttribMap count]); -} - -- (SInt32)lastSeenRemoteControlID -{ - return (_lastSeenRemoteID); -} - -- (HIDRemoteModel)lastSeenModel -{ - return (_lastSeenModel); -} - -- (void)setLastSeenModel:(HIDRemoteModel)aModel -{ - _lastSeenModel = aModel; -} - -- (void)setSimulateHoldEvents:(BOOL)newSimulateHoldEvents -{ - _simulateHoldEvents = newSimulateHoldEvents; -} - -- (BOOL)simulateHoldEvents -{ - return (_simulateHoldEvents); -} - -- (NSArray *)unusedButtonCodes -{ - return (_unusedButtonCodes); -} - -- (void)setUnusedButtonCodes:(NSArray *)newArrayWithUnusedButtonCodesAsNSNumbers -{ - [newArrayWithUnusedButtonCodesAsNSNumbers retain]; - [_unusedButtonCodes release]; - - _unusedButtonCodes = newArrayWithUnusedButtonCodesAsNSNumbers; - - [self _postStatusWithAction:kHIDRemoteDNStatusActionUpdate]; -} - -- (void)setDelegate:(NSObject *)newDelegate -{ - _delegate = newDelegate; -} - -- (NSObject *)delegate -{ - return (_delegate); -} - -#pragma mark -- PUBLIC: Expert APIs -- -- (void)setEnableSecureEventInputWorkaround:(BOOL)newEnableSecureEventInputWorkaround -{ - _secureEventInputWorkAround = newEnableSecureEventInputWorkaround; -} - -- (BOOL)enableSecureEventInputWorkaround -{ - return (_secureEventInputWorkAround); -} - -- (void)setExclusiveLockLendingEnabled:(BOOL)newExclusiveLockLendingEnabled -{ - if (newExclusiveLockLendingEnabled != _exclusiveLockLending) - { - _exclusiveLockLending = newExclusiveLockLendingEnabled; - - if (_exclusiveLockLending) - { - [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleNotifications:) name:kHIDRemoteDNHIDRemoteStatus object:nil]; - } - else - { - [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemoteStatus object:nil]; - - [_waitForReturnByPID release]; - _waitForReturnByPID = nil; - } - } -} - -- (BOOL)exclusiveLockLendingEnabled -{ - return (_exclusiveLockLending); -} - -- (void)setSendExclusiveResourceReuseNotification:(BOOL)newSendExclusiveResourceReuseNotification -{ - _sendExclusiveResourceReuseNotification = newSendExclusiveResourceReuseNotification; -} - -- (BOOL)sendExclusiveResourceReuseNotification -{ - return (_sendExclusiveResourceReuseNotification); -} - -- (BOOL)isApplicationTerminating -{ - return (_applicationIsTerminating); -} - -- (BOOL)isStopping -{ - return (_isStopping); -} - -#pragma mark -- PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto -- -- (void)_appStatusChanged:(NSNotification *)notification -{ - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING - if ([self respondsToSelector:@selector(performSelector:onThread:withObject:waitUntilDone:)]) // OS X 10.5+ only - { - if ([NSThread currentThread] != _runOnThread) - { - if ([[notification name] isEqual:NSApplicationDidBecomeActiveNotification]) - { - if (!_autoRecover) - { - return; - } - } - - if ([[notification name] isEqual:NSApplicationWillResignActiveNotification]) - { - if (_mode != kHIDRemoteModeExclusiveAuto) - { - return; - } - } - - [self performSelector:@selector(_appStatusChanged:) onThread:_runOnThread withObject:notification waitUntilDone:[[notification name] isEqual:NSApplicationWillTerminateNotification]]; - return; - } - } - #endif - - if (notification!=nil) - { - if (_autoRecoveryTimer!=nil) - { - [_autoRecoveryTimer invalidate]; - [_autoRecoveryTimer release]; - _autoRecoveryTimer = nil; - } - - if ([[notification name] isEqual:NSApplicationDidBecomeActiveNotification]) - { - if (_autoRecover) - { - // Delay autorecover by 0.1 to avoid race conditions - if ((_autoRecoveryTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:0.1] interval:0.1 target:self selector:@selector(_delayedAutoRecovery:) userInfo:nil repeats:NO]) != nil) - { - // Using CFRunLoopAddTimer instead of [[NSRunLoop currentRunLoop] addTimer:.. for consistency with run loop modes. - // The kCFRunLoopCommonModes counterpart NSRunLoopCommonModes is only available in 10.5 and later, whereas this code - // is designed to be also compatible with 10.4. CFRunLoopTimerRef is "toll-free-bridged" with NSTimer since 10.0. - CFRunLoopAddTimer(CFRunLoopGetCurrent(), (CFRunLoopTimerRef)_autoRecoveryTimer, kCFRunLoopCommonModes); - } - } - } - - if ([[notification name] isEqual:NSApplicationWillResignActiveNotification]) - { - if (_mode == kHIDRemoteModeExclusiveAuto) - { - [self stopRemoteControl]; - _autoRecover = YES; - } - } - - if ([[notification name] isEqual:NSApplicationWillTerminateNotification]) - { - _applicationIsTerminating = YES; - - if ([self isStarted]) - { - [self stopRemoteControl]; - } - } - } -} - -- (void)_delayedAutoRecovery:(NSTimer *)aTimer -{ - [_autoRecoveryTimer invalidate]; - [_autoRecoveryTimer release]; - _autoRecoveryTimer = nil; - - if (_autoRecover) - { - [self startRemoteControl:kHIDRemoteModeExclusiveAuto]; - _autoRecover = NO; - } -} - - -#pragma mark -- PRIVATE: Distributed notifiations handling -- -- (void)_postStatusWithAction:(NSString *)action -{ - if (_sendStatusNotifications) - { - [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kHIDRemoteDNHIDRemoteStatus - object:((_pidString!=nil) ? _pidString : [NSString stringWithFormat:@"%d",getpid()]) - userInfo:[NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:1], kHIDRemoteDNStatusHIDRemoteVersionKey, - [NSNumber numberWithUnsignedInt:(unsigned int)getpid()], kHIDRemoteDNStatusPIDKey, - [NSNumber numberWithInt:(int)_mode], kHIDRemoteDNStatusModeKey, - [NSNumber numberWithUnsignedInt:(unsigned int)[self activeRemoteControlCount]], kHIDRemoteDNStatusRemoteControlCountKey, - ((_unusedButtonCodes!=nil) ? _unusedButtonCodes : [NSArray array]), kHIDRemoteDNStatusUnusedButtonCodesKey, - action, kHIDRemoteDNStatusActionKey, - [[NSBundle mainBundle] bundleIdentifier], (NSString *)kCFBundleIdentifierKey, - _returnToPID, kHIDRemoteDNStatusReturnToPIDKey, - nil] - deliverImmediately:YES - ]; - } -} - -- (void)_handleNotifications:(NSNotification *)notification -{ - NSString *notificationName; - - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING - if ([self respondsToSelector:@selector(performSelector:onThread:withObject:waitUntilDone:)]) // OS X 10.5+ only - { - if ([NSThread currentThread] != _runOnThread) - { - [self performSelector:@selector(_handleNotifications:) onThread:_runOnThread withObject:notification waitUntilDone:NO]; - return; - } - } - #endif - - if ((notification!=nil) && ((notificationName = [notification name]) != nil)) - { - if ([notificationName isEqual:kHIDRemoteDNHIDRemotePing]) - { - [self _postStatusWithAction:kHIDRemoteDNStatusActionUpdate]; - } - - if ([notificationName isEqual:kHIDRemoteDNHIDRemoteRetry]) - { - if ([self isStarted]) - { - BOOL retry = YES; - - // Ignore our own global retry broadcasts - if ([[notification object] isEqual:kHIDRemoteDNHIDRemoteRetryGlobalObject]) - { - NSNumber *fromPID; - - if ((fromPID = [[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey]) != nil) - { - if (getpid() == (int)[fromPID unsignedIntValue]) - { - retry = NO; - } - } - } - - if (retry) - { - if (([self delegate] != nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:shouldRetryExclusiveLockWithInfo:)])) - { - retry = [[self delegate] hidRemote:self shouldRetryExclusiveLockWithInfo:[notification userInfo]]; - } - } - - if (retry) - { - HIDRemoteMode restartInMode = _mode; - - if (restartInMode != kHIDRemoteModeNone) - { - _isRestarting = YES; - [self stopRemoteControl]; - - [_returnToPID release]; - _returnToPID = nil; - - [self startRemoteControl:restartInMode]; - _isRestarting = NO; - - if (restartInMode != kHIDRemoteModeShared) - { - _returnToPID = [[[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey] retain]; - } - } - } - else - { - NSNumber *cacheReturnPID = _returnToPID; - - _returnToPID = [[[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey] retain]; - [self _postStatusWithAction:kHIDRemoteDNStatusActionNoNeed]; - [_returnToPID release]; - - _returnToPID = cacheReturnPID; - } - } - } - - if (_exclusiveLockLending) - { - if ([notificationName isEqual:kHIDRemoteDNHIDRemoteStatus]) - { - NSString *action; - - if ((action = [[notification userInfo] objectForKey:kHIDRemoteDNStatusActionKey]) != nil) - { - if ((_mode == kHIDRemoteModeNone) && (_waitForReturnByPID!=nil)) - { - NSNumber *pidNumber, *returnToPIDNumber; - - if ((pidNumber = [[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey]) != nil) - { - returnToPIDNumber = [[notification userInfo] objectForKey:kHIDRemoteDNStatusReturnToPIDKey]; - - if ([action isEqual:kHIDRemoteDNStatusActionStart]) - { - if ([pidNumber isEqual:_waitForReturnByPID]) - { - NSNumber *startMode; - - if ((startMode = [[notification userInfo] objectForKey:kHIDRemoteDNStatusModeKey]) != nil) - { - if ([startMode intValue] == kHIDRemoteModeShared) - { - returnToPIDNumber = [NSNumber numberWithInt:getpid()]; - action = kHIDRemoteDNStatusActionNoNeed; - } - } - } - } - - if (returnToPIDNumber != nil) - { - if ([action isEqual:kHIDRemoteDNStatusActionStop] || [action isEqual:kHIDRemoteDNStatusActionNoNeed]) - { - if ([pidNumber isEqual:_waitForReturnByPID] && ([returnToPIDNumber intValue] == getpid())) - { - [_waitForReturnByPID release]; - _waitForReturnByPID = nil; - - if (([self delegate] != nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:exclusiveLockReleasedByApplicationWithInfo:)])) - { - [[self delegate] hidRemote:self exclusiveLockReleasedByApplicationWithInfo:[notification userInfo]]; - } - else - { - [self startRemoteControl:kHIDRemoteModeExclusive]; - } - } - } - } - } - } - - if (_mode==kHIDRemoteModeExclusive) - { - if ([action isEqual:kHIDRemoteDNStatusActionStart]) - { - NSNumber *originPID = [[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey]; - BOOL lendLock = YES; - - if ([originPID intValue] != getpid()) - { - if (([self delegate] != nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:lendExclusiveLockToApplicationWithInfo:)])) - { - lendLock = [[self delegate] hidRemote:self lendExclusiveLockToApplicationWithInfo:[notification userInfo]]; - } - - if (lendLock) - { - [_waitForReturnByPID release]; - _waitForReturnByPID = [originPID retain]; - - if (_waitForReturnByPID != nil) - { - [self stopRemoteControl]; - - [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kHIDRemoteDNHIDRemoteRetry - object:[NSString stringWithFormat:@"%d", [_waitForReturnByPID intValue]] - userInfo:[NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInt:(unsigned int)getpid()], kHIDRemoteDNStatusPIDKey, - [[NSBundle mainBundle] bundleIdentifier], (NSString *)kCFBundleIdentifierKey, - nil] - deliverImmediately:YES]; - } - } - } - } - } - } - } - } - } -} - -- (void)_setSendStatusNotifications:(BOOL)doSend -{ - _sendStatusNotifications = doSend; -} - -- (BOOL)_sendStatusNotifications -{ - return (_sendStatusNotifications); -} - -#pragma mark -- PRIVATE: Service setup and destruction -- -- (BOOL)_prematchService:(io_object_t)service -{ - BOOL serviceMatches = NO; - NSString *ioClass; - NSNumber *candelairHIDRemoteCompatibilityMask; - - if (service != 0) - { - // IOClass matching - if ((ioClass = (NSString *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service, - CFSTR(kIOClassKey), - kCFAllocatorDefault, - 0)) != nil) - { - // Match on Apple's AppleIRController and old versions of the Remote Buddy IR Controller - if ([ioClass isEqual:@"AppleIRController"] || [ioClass isEqual:@"RBIOKitAIREmu"]) - { - CFTypeRef candelairHIDRemoteCompatibilityDevice; - - serviceMatches = YES; - - if ((candelairHIDRemoteCompatibilityDevice = IORegistryEntryCreateCFProperty((io_registry_entry_t)service, CFSTR("CandelairHIDRemoteCompatibilityDevice"), kCFAllocatorDefault, 0)) != NULL) - { - if (CFEqual(kCFBooleanTrue, candelairHIDRemoteCompatibilityDevice)) - { - serviceMatches = NO; - } - - CFRelease (candelairHIDRemoteCompatibilityDevice); - } - } - - // Match on the virtual IOSPIRIT IR Controller - if ([ioClass isEqual:@"IOSPIRITIRController"]) - { - serviceMatches = YES; - } - - CFRelease((CFTypeRef)ioClass); - } - - // Match on services that claim compatibility with the HID Remote class (Candelair or third-party) by having a property of CandelairHIDRemoteCompatibilityMask = 1 - if ((candelairHIDRemoteCompatibilityMask = (NSNumber *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service, CFSTR("CandelairHIDRemoteCompatibilityMask"), kCFAllocatorDefault, 0)) != nil) - { - if ([candelairHIDRemoteCompatibilityMask isKindOfClass:[NSNumber class]]) - { - if ([candelairHIDRemoteCompatibilityMask unsignedIntValue] & kHIDRemoteCompatibilityFlagsStandardHIDRemoteDevice) - { - serviceMatches = YES; - } - else - { - serviceMatches = NO; - } - } - - CFRelease((CFTypeRef)candelairHIDRemoteCompatibilityMask); - } - } - - if (([self delegate]!=nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:inspectNewHardwareWithService:prematchResult:)])) - { - serviceMatches = [((NSObject *)[self delegate]) hidRemote:self inspectNewHardwareWithService:service prematchResult:serviceMatches]; - } - - return (serviceMatches); -} - -- (HIDRemoteButtonCode)buttonCodeForUsage:(unsigned int)usage usagePage:(unsigned int)usagePage -{ - HIDRemoteButtonCode buttonCode = kHIDRemoteButtonCodeNone; - - switch (usagePage) - { - case kHIDPage_Consumer: - switch (usage) - { - case kHIDUsage_Csmr_MenuPick: - // Aluminum Remote: Center - buttonCode = (kHIDRemoteButtonCodeCenter|kHIDRemoteButtonCodeAluminumMask); - break; - - case kHIDUsage_Csmr_ModeStep: - // Aluminium Remote: Center Hold - buttonCode = (kHIDRemoteButtonCodeCenterHold|kHIDRemoteButtonCodeAluminumMask); - break; - - case kHIDUsage_Csmr_PlayOrPause: - // Aluminum Remote: Play/Pause - buttonCode = (kHIDRemoteButtonCodePlay|kHIDRemoteButtonCodeAluminumMask); - break; - - case kHIDUsage_Csmr_Rewind: - buttonCode = kHIDRemoteButtonCodeLeftHold; - break; - - case kHIDUsage_Csmr_FastForward: - buttonCode = kHIDRemoteButtonCodeRightHold; - break; - - case kHIDUsage_Csmr_Menu: - buttonCode = kHIDRemoteButtonCodeMenuHold; - break; - - case kHIDUsage_Csmr_VolumeIncrement: - buttonCode = kHIDRemoteButtonCodeUp; - break; - - case kHIDUsage_Csmr_VolumeDecrement: - buttonCode = kHIDRemoteButtonCodeDown; - break; - } - break; - - case kHIDPage_GenericDesktop: - switch (usage) - { - case kHIDUsage_GD_SystemAppMenu: - buttonCode = kHIDRemoteButtonCodeMenu; - break; - - case kHIDUsage_GD_SystemMenu: - buttonCode = kHIDRemoteButtonCodeCenter; - break; - - case kHIDUsage_GD_SystemMenuRight: - buttonCode = kHIDRemoteButtonCodeRight; - break; - - case kHIDUsage_GD_SystemMenuLeft: - buttonCode = kHIDRemoteButtonCodeLeft; - break; - - case kHIDUsage_GD_SystemMenuUp: - buttonCode = kHIDRemoteButtonCodeUp; - break; - - case kHIDUsage_GD_SystemMenuDown: - buttonCode = kHIDRemoteButtonCodeDown; - break; - } - break; - - case 0x06: /* Reserved */ - switch (usage) - { - case 0x22: - buttonCode = kHIDRemoteButtonCodeIDChanged; - break; - } - break; - - case 0xFF01: /* Vendor specific */ - switch (usage) - { - case 0x23: - buttonCode = kHIDRemoteButtonCodeCenterHold; - break; - - #ifdef _HIDREMOTE_EXTENSIONS - #define _HIDREMOTE_EXTENSIONS_SECTION 2 - #include "HIDRemoteAdditions.h" - #undef _HIDREMOTE_EXTENSIONS_SECTION - #endif /* _HIDREMOTE_EXTENSIONS */ - } - break; - } - - return (buttonCode); -} - -- (BOOL)_setupService:(io_object_t)service -{ - kern_return_t kernResult; - IOReturn returnCode; - HRESULT hResult; - SInt32 score; - BOOL opened = NO, queueStarted = NO; - IOHIDDeviceInterface122 **hidDeviceInterface = NULL; - IOCFPlugInInterface **cfPluginInterface = NULL; - IOHIDQueueInterface **hidQueueInterface = NULL; - io_object_t serviceNotification = 0; - CFRunLoopSourceRef queueEventSource = NULL; - NSMutableDictionary *hidAttribsDict = nil; - CFArrayRef hidElements = NULL; - NSError *error = nil; - UInt32 errorCode = 0; - - if (![self _prematchService:service]) - { - return (NO); - } - - do - { - // Create a plugin interface .. - kernResult = IOCreatePlugInInterfaceForService( service, - kIOHIDDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, - &cfPluginInterface, - &score); - - if (kernResult != kIOReturnSuccess) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:kernResult userInfo:nil]; - errorCode = 1; - break; - } - - - // .. use it to get the HID interface .. - hResult = (*cfPluginInterface)->QueryInterface( cfPluginInterface, - CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID122), - (LPVOID)&hidDeviceInterface); - - if ((hResult!=S_OK) || (hidDeviceInterface==NULL)) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:hResult userInfo:nil]; - errorCode = 2; - break; - } - - - // .. then open it .. - switch (_mode) - { - case kHIDRemoteModeShared: - hResult = (*hidDeviceInterface)->open(hidDeviceInterface, kIOHIDOptionsTypeNone); - break; - - case kHIDRemoteModeExclusive: - case kHIDRemoteModeExclusiveAuto: - hResult = (*hidDeviceInterface)->open(hidDeviceInterface, kIOHIDOptionsTypeSeizeDevice); - break; - - default: - goto cleanUp; // Ugh! But there are no "double breaks" available in C AFAIK .. - break; - } - - if (hResult!=S_OK) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:hResult userInfo:nil]; - errorCode = 3; - break; - } - - opened = YES; - - // .. query the HID elements .. - returnCode = (*hidDeviceInterface)->copyMatchingElements(hidDeviceInterface, - NULL, - &hidElements); - if ((returnCode != kIOReturnSuccess) || (hidElements==NULL)) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil]; - errorCode = 4; - - break; - } - - // Setup an event queue for HID events! - hidQueueInterface = (*hidDeviceInterface)->allocQueue(hidDeviceInterface); - if (hidQueueInterface == NULL) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil]; - errorCode = 5; - - break; - } - - returnCode = (*hidQueueInterface)->create(hidQueueInterface, 0, 32); - if (returnCode != kIOReturnSuccess) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil]; - errorCode = 6; - - break; - } - - - // Setup of attributes stored for this HID device - hidAttribsDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys: - [NSValue valueWithPointer:(const void *)cfPluginInterface], kHIDRemoteCFPluginInterface, - [NSValue valueWithPointer:(const void *)hidDeviceInterface], kHIDRemoteHIDDeviceInterface, - [NSValue valueWithPointer:(const void *)hidQueueInterface], kHIDRemoteHIDQueueInterface, - nil]; - - { - UInt32 i, hidElementCnt = CFArrayGetCount(hidElements); - NSMutableDictionary *cookieButtonCodeLUT = [[NSMutableDictionary alloc] init]; - NSMutableDictionary *cookieCount = [[NSMutableDictionary alloc] init]; - - if ((cookieButtonCodeLUT==nil) || (cookieCount==nil)) - { - [cookieButtonCodeLUT release]; - cookieButtonCodeLUT = nil; - - [cookieCount release]; - cookieCount = nil; - - error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil]; - errorCode = 7; - - break; - } - - // Analyze the HID elements and find matching elements - for (i=0;iaddElement(hidQueueInterface, - (IOHIDElementCookie) [cookie unsignedIntValue], - 0); - - #ifdef _HIDREMOTE_EXTENSIONS - // Get current Apple Remote ID value - #define _HIDREMOTE_EXTENSIONS_SECTION 7 - #include "HIDRemoteAdditions.h" - #undef _HIDREMOTE_EXTENSIONS_SECTION - #endif /* _HIDREMOTE_EXTENSIONS */ - - [buttonCodeNumber release]; - [pairString release]; - } - } - } - - // Compare number of *unique* matches (thus the cookieCount dictionary) with required minimum - if ([cookieCount count] < 10) - { - [cookieButtonCodeLUT release]; - cookieButtonCodeLUT = nil; - - [cookieCount release]; - cookieCount = nil; - - error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil]; - errorCode = 8; - - break; - } - - [hidAttribsDict setObject:cookieButtonCodeLUT forKey:kHIDRemoteCookieButtonCodeLUT]; - - [cookieButtonCodeLUT release]; - cookieButtonCodeLUT = nil; - - [cookieCount release]; - cookieCount = nil; - } - - // Finish setup of IOHIDQueueInterface with CFRunLoop - returnCode = (*hidQueueInterface)->createAsyncEventSource(hidQueueInterface, &queueEventSource); - if ((returnCode != kIOReturnSuccess) || (queueEventSource == NULL)) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil]; - errorCode = 9; - break; - } - - returnCode = (*hidQueueInterface)->setEventCallout(hidQueueInterface, HIDEventCallback, (void *)((intptr_t)service), (void *)self); - if (returnCode != kIOReturnSuccess) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil]; - errorCode = 10; - break; - } - - CFRunLoopAddSource( CFRunLoopGetCurrent(), - queueEventSource, - kCFRunLoopCommonModes); - [hidAttribsDict setObject:[NSValue valueWithPointer:(const void *)queueEventSource] forKey:kHIDRemoteCFRunLoopSource]; - - returnCode = (*hidQueueInterface)->start(hidQueueInterface); - if (returnCode != kIOReturnSuccess) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil]; - errorCode = 11; - break; - } - - queueStarted = YES; - - // Setup device notifications - returnCode = IOServiceAddInterestNotification( _notifyPort, - service, - kIOGeneralInterest, - ServiceNotificationCallback, - self, - &serviceNotification); - if ((returnCode != kIOReturnSuccess) || (serviceNotification==0)) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil]; - errorCode = 12; - break; - } - - [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)serviceNotification] forKey:kHIDRemoteServiceNotification]; - - // Retain service - if (IOObjectRetain(service) != kIOReturnSuccess) - { - error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil]; - errorCode = 13; - break; - } - - [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)service] forKey:kHIDRemoteService]; - - // Get some (somewhat optional) infos on the device - { - CFStringRef product, manufacturer, transport; - - if ((product = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service, - (CFStringRef) @"Product", - kCFAllocatorDefault, - 0)) != NULL) - { - if (CFGetTypeID(product) == CFStringGetTypeID()) - { - [hidAttribsDict setObject:(NSString *)product forKey:kHIDRemoteProduct]; - } - - CFRelease(product); - } - - if ((manufacturer = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service, - (CFStringRef) @"Manufacturer", - kCFAllocatorDefault, - 0)) != NULL) - { - if (CFGetTypeID(manufacturer) == CFStringGetTypeID()) - { - [hidAttribsDict setObject:(NSString *)manufacturer forKey:kHIDRemoteManufacturer]; - } - - CFRelease(manufacturer); - } - - if ((transport = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service, - (CFStringRef) @"Transport", - kCFAllocatorDefault, - 0)) != NULL) - { - if (CFGetTypeID(transport) == CFStringGetTypeID()) - { - [hidAttribsDict setObject:(NSString *)transport forKey:kHIDRemoteTransport]; - } - - CFRelease(transport); - } - } - - // Determine Aluminum Remote support - { - CFNumberRef aluSupport; - HIDRemoteAluminumRemoteSupportLevel supportLevel = kHIDRemoteAluminumRemoteSupportLevelNone; - - if ((_mode == kHIDRemoteModeExclusive) || (_mode == kHIDRemoteModeExclusiveAuto)) - { - // Determine if this driver offers on-demand support for the Aluminum Remote (only relevant under OS versions < 10.6.2) - if ((aluSupport = IORegistryEntryCreateCFProperty((io_registry_entry_t)service, - (CFStringRef) @"AluminumRemoteSupportLevelOnDemand", - kCFAllocatorDefault, - 0)) != nil) - { - // There is => request the driver to enable it for us - if (IORegistryEntrySetCFProperty((io_registry_entry_t)service, - CFSTR("EnableAluminumRemoteSupportForMe"), - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithLongLong:(long long)getpid()], @"pid", - [NSNumber numberWithLongLong:(long long)getuid()], @"uid", - nil]) == kIOReturnSuccess) - { - if (CFGetTypeID(aluSupport) == CFNumberGetTypeID()) - { - supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(NSNumber *)aluSupport intValue]; - } - - [hidAttribsDict setObject:[NSNumber numberWithBool:YES] forKey:kHIDRemoteAluminumRemoteSupportOnDemand]; - } - - CFRelease(aluSupport); - } - } - - if (supportLevel == kHIDRemoteAluminumRemoteSupportLevelNone) - { - if ((aluSupport = IORegistryEntryCreateCFProperty((io_registry_entry_t)service, - (CFStringRef) @"AluminumRemoteSupportLevel", - kCFAllocatorDefault, - 0)) != nil) - { - if (CFGetTypeID(aluSupport) == CFNumberGetTypeID()) - { - supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(NSNumber *)aluSupport intValue]; - } - - CFRelease(aluSupport); - } - else - { - CFStringRef ioKitClassName; - - if ((ioKitClassName = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service, - CFSTR(kIOClassKey), - kCFAllocatorDefault, - 0)) != nil) - { - if ([(NSString *)ioKitClassName isEqual:@"AppleIRController"]) - { - supportLevel = kHIDRemoteAluminumRemoteSupportLevelNative; - } - - CFRelease(ioKitClassName); - } - } - } - - [hidAttribsDict setObject:(NSNumber *)[NSNumber numberWithInt:(int)supportLevel] forKey:kHIDRemoteAluminumRemoteSupportLevel]; - } - - // Add it to the serviceAttribMap - [_serviceAttribMap setObject:hidAttribsDict forKey:[NSNumber numberWithUnsignedInt:(unsigned int)service]]; - - // And we're done with setup .. - if (([self delegate]!=nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:foundNewHardwareWithAttributes:)])) - { - [((NSObject *)[self delegate]) hidRemote:self foundNewHardwareWithAttributes:hidAttribsDict]; - } - - [hidAttribsDict release]; - hidAttribsDict = nil; - - return(YES); - - }while(0); - - cleanUp: - - if (([self delegate]!=nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:failedNewHardwareWithError:)])) - { - if (error!=nil) - { - error = [NSError errorWithDomain:[error domain] - code:[error code] - userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:errorCode] forKey:@"InternalErrorCode"] - ]; - } - - [((NSObject *)[self delegate]) hidRemote:self failedNewHardwareWithError:error]; - } - - // An error occurred or this device is not of interest .. cleanup .. - if (serviceNotification!=0) - { - IOObjectRelease(serviceNotification); - serviceNotification = 0; - } - - if (queueEventSource!=NULL) - { - CFRunLoopSourceInvalidate(queueEventSource); - queueEventSource=NULL; - } - - if (hidQueueInterface!=NULL) - { - if (queueStarted) - { - (*hidQueueInterface)->stop(hidQueueInterface); - } - (*hidQueueInterface)->dispose(hidQueueInterface); - (*hidQueueInterface)->Release(hidQueueInterface); - hidQueueInterface = NULL; - } - - if (hidAttribsDict!=nil) - { - [hidAttribsDict release]; - hidAttribsDict = nil; - } - - if (hidElements!=NULL) - { - CFRelease(hidElements); - hidElements = NULL; - } - - if (hidDeviceInterface!=NULL) - { - if (opened) - { - (*hidDeviceInterface)->close(hidDeviceInterface); - } - (*hidDeviceInterface)->Release(hidDeviceInterface); - // opened = NO; - hidDeviceInterface = NULL; - } - - if (cfPluginInterface!=NULL) - { - IODestroyPlugInInterface(cfPluginInterface); - cfPluginInterface = NULL; - } - - return (NO); -} - -- (void)_destructService:(io_object_t)service -{ - NSNumber *serviceValue; - NSMutableDictionary *serviceDict = NULL; - - if ((serviceValue = [NSNumber numberWithUnsignedInt:(unsigned int)service]) == nil) - { - return; - } - - serviceDict = [_serviceAttribMap objectForKey:serviceValue]; - - if (serviceDict!=nil) - { - IOHIDDeviceInterface122 **hidDeviceInterface = NULL; - IOCFPlugInInterface **cfPluginInterface = NULL; - IOHIDQueueInterface **hidQueueInterface = NULL; - io_object_t serviceNotification = 0; - CFRunLoopSourceRef queueEventSource = NULL; - io_object_t theService = 0; - NSMutableDictionary *cookieButtonMap = nil; - NSTimer *simulateHoldTimer = nil; - - serviceNotification = (io_object_t) ([serviceDict objectForKey:kHIDRemoteServiceNotification] ? [[serviceDict objectForKey:kHIDRemoteServiceNotification] unsignedIntValue] : 0); - theService = (io_object_t) ([serviceDict objectForKey:kHIDRemoteService] ? [[serviceDict objectForKey:kHIDRemoteService] unsignedIntValue] : 0); - queueEventSource = (CFRunLoopSourceRef) ([serviceDict objectForKey:kHIDRemoteCFRunLoopSource] ? [[serviceDict objectForKey:kHIDRemoteCFRunLoopSource] pointerValue] : NULL); - hidQueueInterface = (IOHIDQueueInterface **) ([serviceDict objectForKey:kHIDRemoteHIDQueueInterface] ? [[serviceDict objectForKey:kHIDRemoteHIDQueueInterface] pointerValue] : NULL); - hidDeviceInterface = (IOHIDDeviceInterface122 **) ([serviceDict objectForKey:kHIDRemoteHIDDeviceInterface] ? [[serviceDict objectForKey:kHIDRemoteHIDDeviceInterface] pointerValue] : NULL); - cfPluginInterface = (IOCFPlugInInterface **) ([serviceDict objectForKey:kHIDRemoteCFPluginInterface] ? [[serviceDict objectForKey:kHIDRemoteCFPluginInterface] pointerValue] : NULL); - cookieButtonMap = (NSMutableDictionary *) [serviceDict objectForKey:kHIDRemoteCookieButtonCodeLUT]; - simulateHoldTimer = (NSTimer *) [serviceDict objectForKey:kHIDRemoteSimulateHoldEventsTimer]; - - [serviceDict retain]; - [_serviceAttribMap removeObjectForKey:serviceValue]; - - if (([serviceDict objectForKey:kHIDRemoteAluminumRemoteSupportOnDemand]!=nil) && [[serviceDict objectForKey:kHIDRemoteAluminumRemoteSupportOnDemand] boolValue] && (theService != 0)) - { - // We previously requested the driver to enable Aluminum Remote support for us. Tell it to turn it off again - now that we no longer need it - IORegistryEntrySetCFProperty( (io_registry_entry_t)theService, - CFSTR("DisableAluminumRemoteSupportForMe"), - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithLongLong:(long long)getpid()], @"pid", - [NSNumber numberWithLongLong:(long long)getuid()], @"uid", - nil]); - } - - if (([self delegate]!=nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:releasedHardwareWithAttributes:)])) - { - [((NSObject *)[self delegate]) hidRemote:self releasedHardwareWithAttributes:serviceDict]; - } - - if (simulateHoldTimer!=nil) - { - [simulateHoldTimer invalidate]; - } - - if (serviceNotification!=0) - { - IOObjectRelease(serviceNotification); - } - - if (queueEventSource!=NULL) - { - CFRunLoopRemoveSource( CFRunLoopGetCurrent(), - queueEventSource, - kCFRunLoopCommonModes); - } - - if ((hidQueueInterface!=NULL) && (cookieButtonMap!=nil)) - { - NSEnumerator *cookieEnum = [cookieButtonMap keyEnumerator]; - NSNumber *cookie; - - while ((cookie = [cookieEnum nextObject]) != nil) - { - if ((*hidQueueInterface)->hasElement(hidQueueInterface, (IOHIDElementCookie) [cookie unsignedIntValue])) - { - (*hidQueueInterface)->removeElement(hidQueueInterface, - (IOHIDElementCookie) [cookie unsignedIntValue]); - } - }; - } - - if (hidQueueInterface!=NULL) - { - (*hidQueueInterface)->stop(hidQueueInterface); - (*hidQueueInterface)->dispose(hidQueueInterface); - (*hidQueueInterface)->Release(hidQueueInterface); - } - - if (hidDeviceInterface!=NULL) - { - (*hidDeviceInterface)->close(hidDeviceInterface); - (*hidDeviceInterface)->Release(hidDeviceInterface); - } - - if (cfPluginInterface!=NULL) - { - IODestroyPlugInInterface(cfPluginInterface); - } - - if (theService!=0) - { - IOObjectRelease(theService); - } - - [serviceDict release]; - } -} - - -#pragma mark -- PRIVATE: HID Event handling -- -- (void)_simulateHoldEvent:(NSTimer *)aTimer -{ - NSMutableDictionary *hidAttribsDict; - NSTimer *shTimer; - NSNumber *shButtonCode; - - if ((hidAttribsDict = (NSMutableDictionary *)[aTimer userInfo]) != nil) - { - if (((shTimer = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsTimer]) != nil) && - ((shButtonCode = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsOriginButtonCode]) != nil)) - { - [shTimer invalidate]; - [hidAttribsDict removeObjectForKey:kHIDRemoteSimulateHoldEventsTimer]; - - [self _sendButtonCode:(((HIDRemoteButtonCode)[shButtonCode unsignedIntValue])|kHIDRemoteButtonCodeHoldMask) isPressed:YES hidAttribsDict:hidAttribsDict]; - } - } -} - -- (void)_handleButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict -{ - switch (buttonCode) - { - case kHIDRemoteButtonCodeIDChanged: - // Do nothing, this is handled separately - break; - - case kHIDRemoteButtonCodeUp: - case kHIDRemoteButtonCodeDown: - if (_simulateHoldEvents) - { - NSTimer *shTimer = nil; - NSNumber *shButtonCode = nil; - - [[hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsTimer] invalidate]; - - if (isPressed) - { - [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:buttonCode] forKey:kHIDRemoteSimulateHoldEventsOriginButtonCode]; - - if ((shTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:0.7] interval:0.1 target:self selector:@selector(_simulateHoldEvent:) userInfo:hidAttribsDict repeats:NO]) != nil) - { - [hidAttribsDict setObject:shTimer forKey:kHIDRemoteSimulateHoldEventsTimer]; - - // Using CFRunLoopAddTimer instead of [[NSRunLoop currentRunLoop] addTimer:.. for consistency with run loop modes. - // The kCFRunLoopCommonModes counterpart NSRunLoopCommonModes is only available in 10.5 and later, whereas this code - // is designed to be also compatible with 10.4. CFRunLoopTimerRef is "toll-free-bridged" with NSTimer since 10.0. - CFRunLoopAddTimer(CFRunLoopGetCurrent(), (CFRunLoopTimerRef)shTimer, kCFRunLoopCommonModes); - - [shTimer release]; - - break; - } - } - else - { - shTimer = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsTimer]; - shButtonCode = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsOriginButtonCode]; - - if ((shTimer!=nil) && (shButtonCode!=nil)) - { - [self _sendButtonCode:(HIDRemoteButtonCode)[shButtonCode unsignedIntValue] isPressed:YES hidAttribsDict:hidAttribsDict]; - [self _sendButtonCode:(HIDRemoteButtonCode)[shButtonCode unsignedIntValue] isPressed:NO hidAttribsDict:hidAttribsDict]; - } - else - { - if (shButtonCode!=nil) - { - [self _sendButtonCode:(((HIDRemoteButtonCode)[shButtonCode unsignedIntValue])|kHIDRemoteButtonCodeHoldMask) isPressed:NO hidAttribsDict:hidAttribsDict]; - } - } - } - - [hidAttribsDict removeObjectForKey:kHIDRemoteSimulateHoldEventsTimer]; - [hidAttribsDict removeObjectForKey:kHIDRemoteSimulateHoldEventsOriginButtonCode]; - - break; - } - - default: - [self _sendButtonCode:buttonCode isPressed:isPressed hidAttribsDict:hidAttribsDict]; - break; - } -} - -- (void)_sendButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict -{ - if (([self delegate]!=nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:eventWithButton:isPressed:fromHardwareWithAttributes:)])) - { - switch (buttonCode & (~kHIDRemoteButtonCodeAluminumMask)) - { - case kHIDRemoteButtonCodePlay: - case kHIDRemoteButtonCodeCenter: - if (buttonCode & kHIDRemoteButtonCodeAluminumMask) - { - _lastSeenModel = kHIDRemoteModelAluminum; - _lastSeenModelRemoteID = _lastSeenRemoteID; - } - else - { - switch ((HIDRemoteAluminumRemoteSupportLevel)[[hidAttribsDict objectForKey:kHIDRemoteAluminumRemoteSupportLevel] intValue]) - { - case kHIDRemoteAluminumRemoteSupportLevelNone: - case kHIDRemoteAluminumRemoteSupportLevelEmulation: - // Remote type can't be determined by just the Center button press - break; - - case kHIDRemoteAluminumRemoteSupportLevelNative: - // Remote type can be safely determined by just the Center button press - if (((_lastSeenModel == kHIDRemoteModelAluminum) && (_lastSeenModelRemoteID != _lastSeenRemoteID)) || - (_lastSeenModel == kHIDRemoteModelUndetermined)) - { - _lastSeenModel = kHIDRemoteModelWhitePlastic; - } - break; - } - } - break; - } - - // As soon as we have received a code that's unique to the Aluminum Remote, we can tell kHIDRemoteButtonCodePlayHold and kHIDRemoteButtonCodeCenterHold apart. - // Prior to that, a long press of the new "Play" button will be submitted as a "kHIDRemoteButtonCodeCenterHold", not a "kHIDRemoteButtonCodePlayHold" code. - if ((buttonCode == kHIDRemoteButtonCodeCenterHold) && (_lastSeenModel == kHIDRemoteModelAluminum)) - { - buttonCode = kHIDRemoteButtonCodePlayHold; - } - - [((NSObject *)[self delegate]) hidRemote:self eventWithButton:(buttonCode & (~kHIDRemoteButtonCodeAluminumMask)) isPressed:isPressed fromHardwareWithAttributes:hidAttribsDict]; - } -} - -- (void)_hidEventFor:(io_service_t)hidDevice from:(IOHIDQueueInterface **)interface withResult:(IOReturn)result -{ - NSMutableDictionary *hidAttribsDict = [[[_serviceAttribMap objectForKey:[NSNumber numberWithUnsignedInt:(unsigned int)hidDevice]] retain] autorelease]; - - if (hidAttribsDict!=nil) - { - IOHIDQueueInterface **queueInterface = NULL; - - queueInterface = [[hidAttribsDict objectForKey:kHIDRemoteHIDQueueInterface] pointerValue]; - - if (interface == queueInterface) - { - NSNumber *lastButtonPressedNumber = nil; - HIDRemoteButtonCode lastButtonPressed = kHIDRemoteButtonCodeNone; - NSMutableDictionary *cookieButtonMap = nil; - - cookieButtonMap = [hidAttribsDict objectForKey:kHIDRemoteCookieButtonCodeLUT]; - - if ((lastButtonPressedNumber = [hidAttribsDict objectForKey:kHIDRemoteLastButtonPressed]) != nil) - { - lastButtonPressed = [lastButtonPressedNumber unsignedIntValue]; - } - - while (result == kIOReturnSuccess) - { - IOHIDEventStruct hidEvent; - AbsoluteTime supportedTime = { 0,0 }; - - result = (*queueInterface)->getNextEvent( queueInterface, - &hidEvent, - supportedTime, - 0); - - if (result == kIOReturnSuccess) - { - NSNumber *buttonCodeNumber = [cookieButtonMap objectForKey:[NSNumber numberWithUnsignedInt:(unsigned int) hidEvent.elementCookie]]; - - #ifdef _HIDREMOTE_EXTENSIONS - // Debug logging code - #define _HIDREMOTE_EXTENSIONS_SECTION 5 - #include "HIDRemoteAdditions.h" - #undef _HIDREMOTE_EXTENSIONS_SECTION - #endif /* _HIDREMOTE_EXTENSIONS */ - - if (buttonCodeNumber!=nil) - { - HIDRemoteButtonCode buttonCode = [buttonCodeNumber unsignedIntValue]; - - if (hidEvent.value == 0) - { - if (buttonCode == lastButtonPressed) - { - [self _handleButtonCode:lastButtonPressed isPressed:NO hidAttribsDict:hidAttribsDict]; - lastButtonPressed = kHIDRemoteButtonCodeNone; - } - } - - if (hidEvent.value != 0) - { - if (lastButtonPressed != kHIDRemoteButtonCodeNone) - { - [self _handleButtonCode:lastButtonPressed isPressed:NO hidAttribsDict:hidAttribsDict]; - // lastButtonPressed = kHIDRemoteButtonCodeNone; - } - - if (buttonCode == kHIDRemoteButtonCodeIDChanged) - { - if (([self delegate]!=nil) && - ([[self delegate] respondsToSelector:@selector(hidRemote:remoteIDChangedOldID:newID:forHardwareWithAttributes:)])) - { - [((NSObject *)[self delegate]) hidRemote:self remoteIDChangedOldID:_lastSeenRemoteID newID:hidEvent.value forHardwareWithAttributes:hidAttribsDict]; - } - - _lastSeenRemoteID = hidEvent.value; - _lastSeenModel = kHIDRemoteModelUndetermined; - } - - [self _handleButtonCode:buttonCode isPressed:YES hidAttribsDict:hidAttribsDict]; - lastButtonPressed = buttonCode; - } - } - } - }; - - [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:lastButtonPressed] forKey:kHIDRemoteLastButtonPressed]; - } - - #ifdef _HIDREMOTE_EXTENSIONS - // Debug logging code - #define _HIDREMOTE_EXTENSIONS_SECTION 6 - #include "HIDRemoteAdditions.h" - #undef _HIDREMOTE_EXTENSIONS_SECTION - #endif /* _HIDREMOTE_EXTENSIONS */ - } -} - -#pragma mark -- PRIVATE: Notification handling -- -- (void)_serviceMatching:(io_iterator_t)iterator -{ - io_object_t matchingService = 0; - - while ((matchingService = IOIteratorNext(iterator)) != 0) - { - [self _setupService:matchingService]; - - IOObjectRelease(matchingService); - }; -} - -- (void)_serviceNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument -{ - if (messageType == kIOMessageServiceIsTerminated) - { - [self _destructService:service]; - } -} - -- (void)_updateSessionInformation -{ - NSArray *consoleUsersArray; - io_service_t rootService; - - if (_masterPort==0) { return; } - - if ((rootService = IORegistryGetRootEntry(_masterPort)) != 0) - { - if ((consoleUsersArray = (NSArray *)IORegistryEntryCreateCFProperty((io_registry_entry_t)rootService, CFSTR("IOConsoleUsers"), kCFAllocatorDefault, 0)) != nil) - { - if ([consoleUsersArray isKindOfClass:[NSArray class]]) // Be careful - ensure this really is an array - { - NSEnumerator *consoleUsersEnum; // I *love* Obj-C2's fast enumerators, but we need to stay compatible with 10.4 :-/ - - if ((consoleUsersEnum = [consoleUsersArray objectEnumerator]) != nil) - { - UInt64 secureEventInputPIDSum = 0; - uid_t frontUserSession = 0; - NSDictionary *consoleUserDict; - - while ((consoleUserDict = [consoleUsersEnum nextObject]) != nil) - { - if ([consoleUserDict isKindOfClass:[NSDictionary class]]) // Be careful - ensure this really is a dictionary - { - NSNumber *secureInputPID; - NSNumber *onConsole; - NSNumber *userID; - - if ((secureInputPID = [consoleUserDict objectForKey:@"kCGSSessionSecureInputPID"]) != nil) - { - if ([secureInputPID isKindOfClass:[NSNumber class]]) - { - secureEventInputPIDSum += ((UInt64) [secureInputPID intValue]); - } - } - - if (((onConsole = [consoleUserDict objectForKey:@"kCGSSessionOnConsoleKey"]) != nil) && - ((userID = [consoleUserDict objectForKey:@"kCGSSessionUserIDKey"]) != nil)) - { - if ([onConsole isKindOfClass:[NSNumber class]] && [userID isKindOfClass:[NSNumber class]]) - { - if ([onConsole boolValue]) - { - frontUserSession = (uid_t) [userID intValue]; - } - } - } - } - } - - _lastSecureEventInputPIDSum = secureEventInputPIDSum; - _lastFrontUserSession = frontUserSession; - } - } - - CFRelease((CFTypeRef)consoleUsersArray); - } - - IOObjectRelease((io_object_t) rootService); - } -} - -- (void)_secureInputNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument -{ - if (messageType == kIOMessageServiceBusyStateChange) - { - UInt64 old_lastSecureEventInputPIDSum = _lastSecureEventInputPIDSum; - uid_t old_lastFrontUserSession = _lastFrontUserSession; - - [self _updateSessionInformation]; - - if (((old_lastSecureEventInputPIDSum != _lastSecureEventInputPIDSum) || (old_lastFrontUserSession != _lastFrontUserSession)) && _secureEventInputWorkAround) - { - if ((_mode == kHIDRemoteModeExclusive) || (_mode == kHIDRemoteModeExclusiveAuto)) - { - HIDRemoteMode restartInMode = _mode; - - _isRestarting = YES; - [self stopRemoteControl]; - [self startRemoteControl:restartInMode]; - _isRestarting = NO; - } - } - } -} - -@end - -#pragma mark -- PRIVATE: IOKitLib Callbacks -- - -static void HIDEventCallback( void * target, - IOReturn result, - void * refCon, - void * sender) -{ - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - [hidRemote _hidEventFor:(io_service_t)((intptr_t)target) from:(IOHIDQueueInterface**)sender withResult:(IOReturn)result]; - - [pool release]; -} - - -static void ServiceMatchingCallback( void *refCon, - io_iterator_t iterator) -{ - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - [hidRemote _serviceMatching:iterator]; - - [pool release]; -} - -static void ServiceNotificationCallback(void * refCon, - io_service_t service, - natural_t messageType, - void * messageArgument) -{ - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - [hidRemote _serviceNotificationFor:service - messageType:messageType - messageArgument:messageArgument]; - - [pool release]; -} - -static void SecureInputNotificationCallback( void * refCon, - io_service_t service, - natural_t messageType, - void * messageArgument) -{ - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - [hidRemote _secureInputNotificationFor:service - messageType:messageType - messageArgument:messageArgument]; - - [pool release]; -} - -// Attribute dictionary keys -NSString *kHIDRemoteCFPluginInterface = @"CFPluginInterface"; -NSString *kHIDRemoteHIDDeviceInterface = @"HIDDeviceInterface"; -NSString *kHIDRemoteCookieButtonCodeLUT = @"CookieButtonCodeLUT"; -NSString *kHIDRemoteHIDQueueInterface = @"HIDQueueInterface"; -NSString *kHIDRemoteServiceNotification = @"ServiceNotification"; -NSString *kHIDRemoteCFRunLoopSource = @"CFRunLoopSource"; -NSString *kHIDRemoteLastButtonPressed = @"LastButtonPressed"; -NSString *kHIDRemoteService = @"Service"; -NSString *kHIDRemoteSimulateHoldEventsTimer = @"SimulateHoldEventsTimer"; -NSString *kHIDRemoteSimulateHoldEventsOriginButtonCode = @"SimulateHoldEventsOriginButtonCode"; -NSString *kHIDRemoteAluminumRemoteSupportLevel = @"AluminumRemoteSupportLevel"; -NSString *kHIDRemoteAluminumRemoteSupportOnDemand = @"AluminumRemoteSupportLevelOnDemand"; - -NSString *kHIDRemoteManufacturer = @"Manufacturer"; -NSString *kHIDRemoteProduct = @"Product"; -NSString *kHIDRemoteTransport = @"Transport"; - -// Distributed notifications -NSString *kHIDRemoteDNHIDRemotePing = @"com.candelair.ping"; -NSString *kHIDRemoteDNHIDRemoteRetry = @"com.candelair.retry"; -NSString *kHIDRemoteDNHIDRemoteStatus = @"com.candelair.status"; - -NSString *kHIDRemoteDNHIDRemoteRetryGlobalObject = @"global"; - -// Distributed notifications userInfo keys and values -NSString *kHIDRemoteDNStatusHIDRemoteVersionKey = @"HIDRemoteVersion"; -NSString *kHIDRemoteDNStatusPIDKey = @"PID"; -NSString *kHIDRemoteDNStatusModeKey = @"Mode"; -NSString *kHIDRemoteDNStatusUnusedButtonCodesKey = @"UnusedButtonCodes"; -NSString *kHIDRemoteDNStatusActionKey = @"Action"; -NSString *kHIDRemoteDNStatusRemoteControlCountKey = @"RemoteControlCount"; -NSString *kHIDRemoteDNStatusReturnToPIDKey = @"ReturnToPID"; -NSString *kHIDRemoteDNStatusActionStart = @"start"; -NSString *kHIDRemoteDNStatusActionStop = @"stop"; -NSString *kHIDRemoteDNStatusActionUpdate = @"update"; -NSString *kHIDRemoteDNStatusActionNoNeed = @"noneed"; diff --git a/osdep/macosx_events.h b/osdep/macosx_events.h index 17adaf9ae5..9188c8bee2 100644 --- a/osdep/macosx_events.h +++ b/osdep/macosx_events.h @@ -27,9 +27,6 @@ struct mpv_handle; void cocoa_put_key(int keycode); void cocoa_put_key_with_modifiers(int keycode, int modifiers); -void cocoa_init_apple_remote(void); -void cocoa_uninit_apple_remote(void); - void cocoa_init_media_keys(void); void cocoa_uninit_media_keys(void); diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m index 68956de43e..14aa7063fb 100644 --- a/osdep/macosx_events.m +++ b/osdep/macosx_events.m @@ -50,17 +50,12 @@ BOOL _is_application; NSCondition *_input_lock; CFMachPortRef _mk_tap_port; -#if HAVE_APPLE_REMOTE - HIDRemote *_remote; -#endif } - (BOOL)handleMediaKey:(NSEvent *)event; - (NSEvent *)handleKey:(NSEvent *)event; - (BOOL)setMpvHandle:(struct mpv_handle *)ctx; - (void)readEvents; -- (void)startAppleRemote; -- (void)stopAppleRemote; - (void)startMediaKeys; - (void)restartMediaKeys; - (void)stopMediaKeys; @@ -126,16 +121,6 @@ static int convert_key(unsigned key, unsigned charcode) return charcode; } -void cocoa_init_apple_remote(void) -{ - [[EventsResponder sharedInstance] startAppleRemote]; -} - -void cocoa_uninit_apple_remote(void) -{ - [[EventsResponder sharedInstance] stopAppleRemote]; -} - static int mk_code(NSEvent *event) { return (([event data1] & 0xFFFF0000) >> 16); @@ -352,29 +337,6 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx) } } -- (void)startAppleRemote -{ -#if HAVE_APPLE_REMOTE - dispatch_async(dispatch_get_main_queue(), ^{ - self->_remote = [[HIDRemote alloc] init]; - if (self->_remote) { - [self->_remote setDelegate:self]; - [self->_remote startRemoteControl:kHIDRemoteModeExclusiveAuto]; - } - }); -#endif -} - -- (void)stopAppleRemote -{ -#if HAVE_APPLE_REMOTE - dispatch_async(dispatch_get_main_queue(), ^{ - [self->_remote stopRemoteControl]; - [self->_remote release]; - }); -#endif -} - - (void)restartMediaKeys { if (self->_mk_tap_port) @@ -448,33 +410,6 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx) andMapping:keymapd]; } -- (void)hidRemote:(HIDRemote *)remote - eventWithButton:(HIDRemoteButtonCode)buttonCode - isPressed:(BOOL)isPressed - fromHardwareWithAttributes:(NSMutableDictionary *)attributes -{ - if (!isPressed) return; - - NSDictionary *keymapd = @{ - @(kHIDRemoteButtonCodePlay): @(MP_AR_PLAY), - @(kHIDRemoteButtonCodePlayHold): @(MP_AR_PLAY_HOLD), - @(kHIDRemoteButtonCodeCenter): @(MP_AR_CENTER), - @(kHIDRemoteButtonCodeCenterHold): @(MP_AR_CENTER_HOLD), - @(kHIDRemoteButtonCodeLeft): @(MP_AR_PREV), - @(kHIDRemoteButtonCodeLeftHold): @(MP_AR_PREV_HOLD), - @(kHIDRemoteButtonCodeRight): @(MP_AR_NEXT), - @(kHIDRemoteButtonCodeRightHold): @(MP_AR_NEXT_HOLD), - @(kHIDRemoteButtonCodeMenu): @(MP_AR_MENU), - @(kHIDRemoteButtonCodeMenuHold): @(MP_AR_MENU_HOLD), - @(kHIDRemoteButtonCodeUp): @(MP_AR_VUP), - @(kHIDRemoteButtonCodeUpHold): @(MP_AR_VUP_HOLD), - @(kHIDRemoteButtonCodeDown): @(MP_AR_VDOWN), - @(kHIDRemoteButtonCodeDownHold): @(MP_AR_VDOWN_HOLD), - }; - - [self handleKey:buttonCode withMask:0 andMapping:keymapd]; -} - - (int)mapKeyModifiers:(int)cocoaModifiers { int mask = 0; diff --git a/osdep/macosx_events_objc.h b/osdep/macosx_events_objc.h index 79ace0a909..42f6ee234a 100644 --- a/osdep/macosx_events_objc.h +++ b/osdep/macosx_events_objc.h @@ -18,12 +18,11 @@ */ #import -#import "ar/HIDRemote.h" #include "osdep/macosx_events.h" struct input_ctx; -@interface EventsResponder : NSObject +@interface EventsResponder : NSObject + (EventsResponder *)sharedInstance; - (void)setInputContext:(struct input_ctx *)ctx; diff --git a/wscript b/wscript index 7af97dd894..3aa1376995 100644 --- a/wscript +++ b/wscript @@ -904,11 +904,6 @@ standalone_features = [ 'desc': 'w32 executable', 'deps': 'os-win32 || !(!(os-cygwin))', 'func': check_ctx_vars('WINDRES') - }, { - 'name': '--apple-remote', - 'desc': 'Apple Remote support', - 'deps': 'cocoa', - 'func': check_true }, { 'name': '--macos-touchbar', 'desc': 'macOS Touch Bar support', diff --git a/wscript_build.py b/wscript_build.py index 383e1df6f6..3ad85fd3b5 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -544,7 +544,6 @@ def build(ctx): ( "osdep/android/posix-spawn.c", "android"), ( "osdep/android/strnlen.c", "android"), - ( "osdep/ar/HIDRemote.m", "apple-remote" ), ( "osdep/glob-win.c", "glob-win32" ), ( "osdep/macosx_application.m", "cocoa" ), ( "osdep/macosx_events.m", "cocoa" ),