diff --git a/Changelog b/Changelog index 2695f2fab6..ce5f0319b1 100644 --- a/Changelog +++ b/Changelog @@ -111,6 +111,7 @@ MPlayer (1.0) * change GUI dependency from libpng to libavcodec * ability to change subtitle size during playback * ability to turn loop on/off during playback + * Apple Remote support rc1: "Codename intentionally left blank" October 22, 2006 diff --git a/configure b/configure index d2e177e587..4135543581 100755 --- a/configure +++ b/configure @@ -237,6 +237,7 @@ Optional features: --enable-lirc enable LIRC (remote control) support [autodetect] --enable-lircc enable LIRCCD (LIRC client daemon) input [autodetect] --enable-joystick enable joystick support [disable] + --enable-apple-remote enable Apple Remote input (Mac OS X only) [autodetect] --disable-vm disable X video mode extensions [autodetect] --disable-xf86keysym disable support for multimedia keys [autodetect] --enable-radio enable radio interface [disable] @@ -615,6 +616,7 @@ _x264=auto _libnut=auto _lirc=auto _lircc=auto +_apple_remote=auto _gui=no _gtk1=no _termcap=auto @@ -1030,6 +1032,8 @@ for ac_option do --disable-lirc) _lirc=no ;; --enable-lircc) _lircc=yes ;; --disable-lircc) _lircc=no ;; + --enable-apple-remote) _apple_remote=yes ;; + --disable-apple-remote) _apple_remote=no ;; --enable-gui) _gui=yes ;; --disable-gui) _gui=no ;; --enable-gtk1) _gtk1=yes ;; @@ -3571,6 +3575,44 @@ else fi echores "$_macosx_bundle" +echocheck "Apple Remote" +if test "$_apple_remote" = auto ; then + _apple_remote=no + cat > $TMPC < +#include +int main (int argc, const char * argv[]) +{ + io_iterator_t hidObjectIterator = (io_iterator_t)NULL; + CFMutableDictionaryRef hidMatchDictionary; + IOReturn ioReturnValue; + + // Set up a matching dictionary to search the I/O Registry by class. + // name for all HID class devices + hidMatchDictionary = IOServiceMatching("AppleIRController"); + + // Now search I/O Registry for matching devices. + ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, + hidMatchDictionary, &hidObjectIterator); + + // If search is unsuccessful, return nonzero. + if (ioReturnValue != kIOReturnSuccess || + !IOIteratorIsValid(hidObjectIterator)) { + return 1; + } + return 0; +} +EOF + cc_check -framework IOKit && tmp_run && _apple_remote=yes +fi +if test "$_apple_remote" = yes ; then + _def_apple_remote='#define HAVE_APPLE_REMOTE 1' + _ld_extra="$_ld_extra -framework IOKit" +else + _def_apple_remote='#undef HAVE_APPLE_REMOTE' +fi +echores "$_apple_remote" + fi #if darwin @@ -7524,6 +7566,7 @@ ALSA1X = $_alsa1x # input/demuxer/codecs JOYSTICK = $_joystick LIRC = $_lirc +APPLE_REMOTE = $_apple_remote TV = $_tv TV_V4L = $_tv_v4l TV_V4L1 = $_tv_v4l1 @@ -7909,6 +7952,9 @@ $_def_threads /* LIRC (remote control, see www.lirc.org) support: */ $_def_lirc +/* Apple Remote (remote control, see http://docs.info.apple.com/article.html?artnum=302504) support: */ +$_def_apple_remote + /* Support for maemo (http://www.maemo.org) */ $_def_maemo diff --git a/etc/input.conf b/etc/input.conf index c34eb7e1f6..3094d7dec6 100644 --- a/etc/input.conf +++ b/etc/input.conf @@ -99,6 +99,21 @@ JOY_BTN1 osd JOY_BTN2 volume 1 JOY_BTN3 volume -1 +## +## Apple Remote section +## + +AR_PLAY 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 osd +AR_MENU_HOLD mute +AR_VUP volume 1 +AR_VDOWN volume -1 + ## ## OSD Menu movement keys ## diff --git a/help/help_mp-cs.h b/help/help_mp-cs.h index e8cbf4243e..608fd59661 100644 --- a/help/help_mp-cs.h +++ b/help/help_mp-cs.h @@ -1294,6 +1294,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Nelze inicializovat vstupní joystick\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Nelze stat %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Nelze otevřít %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Nelze inicializovat vstupní Apple Remote.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-de.h b/help/help_mp-de.h index e76dc042cd..d96f36da7b 100644 --- a/help/help_mp-de.h +++ b/help/help_mp-de.h @@ -1348,6 +1348,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Konnte Joystick nicht initialisieren.\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Stat auf Datei '%s' fehlgeschlagen: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Konnte Datei '%s' nicht öffnen: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Konnte Apple Remote Fernbedienung nicht initialisieren.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-en.h b/help/help_mp-en.h index 2aa41ffcd7..e4af6a7f44 100644 --- a/help/help_mp-en.h +++ b/help/help_mp-en.h @@ -1314,6 +1314,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Can't init input joystick\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Can't stat %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Can't open %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Can't init Apple Remote.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-es.h b/help/help_mp-es.h index 3b3e3b06e7..db041baff1 100644 --- a/help/help_mp-es.h +++ b/help/help_mp-es.h @@ -1289,6 +1289,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "No se puede inicializar la entrada del joystick\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "No se puede obtener el estado %s: %s" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "No se puede abrir %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "No se puede inicializar la entrada del Apple Remote.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-fr.h b/help/help_mp-fr.h index a465b76578..6a0fddd95c 100644 --- a/help/help_mp-fr.h +++ b/help/help_mp-fr.h @@ -1286,6 +1286,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Impossible d'initier manette entrée\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Impossible lire %s : %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Impossible ouvrir %s : %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Impossible d'initier télécommande Apple Remote.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-hu.h b/help/help_mp-hu.h index eb4ebe7f94..d0ca7d9862 100644 --- a/help/help_mp-hu.h +++ b/help/help_mp-hu.h @@ -1313,6 +1313,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "A bemeneti borkormány inicializálása nem sikerült\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Nem stat-olható %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Nem nyitható meg %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Apple Remote inicializálása nem sikerült.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-it.h b/help/help_mp-it.h index 63c1a64ff3..92ec685310 100644 --- a/help/help_mp-it.h +++ b/help/help_mp-it.h @@ -1315,6 +1315,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Impossibile inizializzare i controlli del joystick\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Impossibile fare stat di %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Impossibile aprire %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Impossibile inizializzare i Apple Remote.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-pl.h b/help/help_mp-pl.h index 28f0e92a11..79e40fd14c 100644 --- a/help/help_mp-pl.h +++ b/help/help_mp-pl.h @@ -1218,6 +1218,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Nie mogę zainicjować dżojstika\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Nie moge podać statystyk %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Nie moge otworzyć %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Nie mogę zainicjować Apple Remote.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-ru.h b/help/help_mp-ru.h index 669aa15a25..88a90f2e14 100644 --- a/help/help_mp-ru.h +++ b/help/help_mp-ru.h @@ -1425,6 +1425,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Не могу инициализировать джойстик ввода\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "Не могу выполнить stat %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "Не могу выполнить open %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Не могу инициализировать Пульт ДУ Apple Remote.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-tr.h b/help/help_mp-tr.h index 5abc4f6ba3..7ae478d5fd 100644 --- a/help/help_mp-tr.h +++ b/help/help_mp-tr.h @@ -1209,6 +1209,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "Kumanda kolu girdisi açılamıyor\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile " %s sabitlenemiyor: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "%s açılamıyor: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "Apple Remote açılamıyor.\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-zh_CN.h b/help/help_mp-zh_CN.h index 81562c188a..681749715f 100644 --- a/help/help_mp-zh_CN.h +++ b/help/help_mp-zh_CN.h @@ -1308,6 +1308,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "不能初始华输入法操纵杆\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "不能统计(stat) %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "打不开 %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "不能初始化 Apple Remote 遥控器。\n" // ========================== LIBMPDEMUX =================================== diff --git a/help/help_mp-zh_TW.h b/help/help_mp-zh_TW.h index cbead817c4..fd963635e0 100644 --- a/help/help_mp-zh_TW.h +++ b/help/help_mp-zh_TW.h @@ -1294,6 +1294,7 @@ static char help_text[]= #define MSGTR_INPUT_INPUT_ErrCantInitJoystick "不能初始華輸入法操縱杆\n" #define MSGTR_INPUT_INPUT_ErrCantStatFile "不能統計(stat) %s: %s\n" #define MSGTR_INPUT_INPUT_ErrCantOpenFile "打不開 %s: %s\n" +#define MSGTR_INPUT_INPUT_ErrCantInitAppleRemote "不能初始化 Apple Remote 遙控器。\n" // ========================== LIBMPDEMUX =================================== diff --git a/input/Makefile b/input/Makefile index 993c81605c..3b4d085581 100644 --- a/input/Makefile +++ b/input/Makefile @@ -3,6 +3,7 @@ include ../config.mak LIBNAME_MPLAYER = libinput.a SRCS_MPLAYER = input.c +SRCS_MPLAYER-$(APPLE_REMOTE) += ar.c SRCS_MPLAYER-$(JOYSTICK) += joystick.c SRCS_MPLAYER-$(LIRC) += lirc.c diff --git a/input/ar.c b/input/ar.c new file mode 100644 index 0000000000..96c5161953 --- /dev/null +++ b/input/ar.c @@ -0,0 +1,469 @@ +/* + * Apple Remote input interface + * + * Copyright (C) 2007 Zoltan Ponekker + * + * (modified a bit by Ulion ) + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MPlayer; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include +#include + +#include "input.h" +#include "ar.h" + +extern int slave_mode; + +extern const double NSAppKitVersionNumber; + +typedef struct cookie_keycode_map { + char *cookies; + int seq_len; + int keycode; +} cookie_keycode_map_t; + +/* On tiger, 5 always follows 6; on leopard, 18 always follows 19. + * On leopard, there seems to be no cookie value of 5 or 6. + * Following is the shortened cookie sequence list + * keycode cookies_on_tiger cookies_on_leopard *down_state + * AR_PREV_HOLD 14+6+3+2 31+19+3+2 yes + * AR_NEXT_HOLD 14+6+4+2 31+19+4+2 yes + * AR_MENU_HOLD 14+6+14+6 31+19+31+19 + * AR_VUP 14+12+11+6 31+29+28+19 yes + * AR_VDOWN 14+13+11+6 31+30+28+19 yes + * AR_MENU 14+7+6+14+7+6 31+20+19+31+20+19 + * AR_PLAY 14+8+6+14+8+6 31+21+19+31+21+19 + * AR_NEXT 14+9+6+14+9+6 31+22+19+31+22+19 + * AR_PREV 14+10+6+14+10+6 31+23+19+31+23+19 + * AR_PLAY_HOLD 18+14+6+18+14+6 35+31+19+35+31+19 + * + * *down_state: A button with this feature has a pressed event and + * a released event, with which we can trace the state of the button. + * A button without this feature will only return one release event. + * + * hidden keys currently not implemented: + * hold for 5 secs + * MENU_NEXT_HOLD 15+14+6+15+14+6 + * MENU_PREV_HOLD 16+14+6+16+14+6 + * MENU_VUP_HOLD 20+14+6+20+14+6 + * MENU_VDOWN_HOLD 19+14+6+19+14+6 + * + * It seems that pressing 'menu' and 'play' on the Apple Remote for + * 5 seconds will trigger the make-pair function of the remote. + * MENU_PLAY_HOLD 21+15+14+6+15+14+6 + */ + +static const cookie_keycode_map_t ar_codes_tiger[] = { + { "\x0E\x06\x03\x02", 4, AR_PREV_HOLD }, + { "\x0E\x06\x04\x02", 4, AR_NEXT_HOLD }, + { "\x0E\x06\x0E\x06", 4, AR_MENU_HOLD }, + { "\x0E\x0C\x0B\x06", 4, AR_VUP }, + { "\x0E\x0D\x0B\x06", 4, AR_VDOWN }, + { "\x0E\x07\x06\x0E\x07\x06", 6, AR_MENU }, + { "\x0E\x08\x06\x0E\x08\x06", 6, AR_PLAY }, + { "\x0E\x09\x06\x0E\x09\x06", 6, AR_NEXT }, + { "\x0E\x0A\x06\x0E\x0A\x06", 6, AR_PREV }, + { "\x12\x0E\x06\x12\x0E\x06", 6, AR_PLAY_HOLD }, + { NULL, 0, MP_INPUT_NOTHING }, +}; + +static const cookie_keycode_map_t ar_codes_leopard[] = { + { "\x1F\x13\x03\x02", 4, AR_PREV_HOLD }, + { "\x1F\x13\x04\x02", 4, AR_NEXT_HOLD }, + { "\x1F\x13\x1F\x13", 4, AR_MENU_HOLD }, + { "\x1F\x1D\x1C\x13", 4, AR_VUP }, + { "\x1F\x1E\x1C\x13", 4, AR_VDOWN }, + { "\x1F\x14\x13\x1F\x14\x13", 6, AR_MENU }, + { "\x1F\x15\x13\x1F\x15\x13", 6, AR_PLAY }, + { "\x1F\x16\x13\x1F\x16\x13", 6, AR_NEXT }, + { "\x1F\x17\x13\x1F\x17\x13", 6, AR_PREV }, + { "\x23\x1F\x13\x23\x1F\x13", 6, AR_PLAY_HOLD }, + { NULL, 0, MP_INPUT_NOTHING }, +}; + +static int is_leopard; +static const cookie_keycode_map_t *ar_codes; + +static IOHIDQueueInterface **queue; +static IOHIDDeviceInterface **hidDeviceInterface = NULL; +static int inited = 0; +static int hidDeviceIsOpen; + +/* Maximum number of elements in queue before oldest elements + in queue begin to be lost. Set to 16 to hold at least 2 events. */ +static const int MAX_QUEUE_SIZE = 16; + + +static int FindHIDDevices(mach_port_t masterPort, + io_iterator_t *hidObjectIterator) +{ + CFMutableDictionaryRef hidMatchDictionary; + IOReturn ioReturnValue; + + // Set up a matching dictionary to search the I/O Registry + // by class name for all HID class devices. + hidMatchDictionary = IOServiceMatching("AppleIRController"); + + // Now search I/O Registry for matching devices. + ioReturnValue = IOServiceGetMatchingServices(masterPort, + hidMatchDictionary, + hidObjectIterator); + + // If search is unsuccessful, print message and hang. + if (ioReturnValue != kIOReturnSuccess || + !IOIteratorIsValid(*hidObjectIterator)) { + return -1; + } + return 0; +} + +static int getHIDCookies(IOHIDDeviceInterface122 **handle, + IOHIDElementCookie **cookies, + int *nr_cookies) +{ + CFTypeRef object; + long number; + CFArrayRef elements; + CFDictionaryRef element; + CFIndex i; + + *nr_cookies = 0; + + if (!handle || !(*handle)) + return -1; + + // Copy all elements, since we're grabbing most of the elements + // for this device anyway, and thus, it's faster to iterate them + // ourselves. When grabbing only one or two elements, a matching + // dictionary should be passed in here instead of NULL. + if (((*handle)->copyMatchingElements(handle, NULL, &elements)) != kIOReturnSuccess) + return -1; + + // No elements, still a valid result. + if (CFArrayGetCount(elements)==0) + return 0; + + *cookies = calloc(CFArrayGetCount(elements), sizeof(IOHIDElementCookie)); + if (*cookies == NULL) + return -1; + + for (i=0; iQueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), + (LPVOID)hidDeviceInterface) != S_OK + || *hidDeviceInterface == NULL || **hidDeviceInterface == NULL) { + (*plugInInterface)->Release(plugInInterface); + return -1; + } + + (*plugInInterface)->Release(plugInInterface); + + return 0; +} + +int mp_input_ar_init(void) +{ + io_iterator_t hidObjectIterator; + io_object_t hidDevice; + int i; + IOHIDElementCookie *cookies = NULL; + int nr_cookies = 0; + + if (inited) + mp_input_ar_close(-1); + + if (floor(NSAppKitVersionNumber) <= 824 /* NSAppKitVersionNumber10_4 */) { + ar_codes = &ar_codes_tiger[0]; + is_leopard = 0; + } + else { + ar_codes = &ar_codes_leopard[0]; + is_leopard = 1; + } + + if (FindHIDDevices(kIOMasterPortDefault, &hidObjectIterator)) + return -1; + + // Multiple controls could be found, we only use the first usable one. + while ((hidDevice = IOIteratorNext(hidObjectIterator))) { + if (CreateHIDDeviceInterface(hidDevice, &hidDeviceInterface) < 0) { + hidDeviceInterface = NULL; + IOObjectRelease(hidDevice); + continue; + } + if (getHIDCookies((IOHIDDeviceInterface122 **)hidDeviceInterface, + &cookies, + &nr_cookies) < 0) { + (*hidDeviceInterface)->Release(hidDeviceInterface); + hidDeviceInterface = NULL; + IOObjectRelease(hidDevice); + continue; + } + IOObjectRelease(hidDevice); + break; + } + if (hidDeviceInterface == NULL) + goto mp_input_ar_init_error; + + // Open the device. + if ((*hidDeviceInterface)->open(hidDeviceInterface, + kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) + goto mp_input_ar_init_error; + hidDeviceIsOpen = 1; + + if ((queue = (*hidDeviceInterface)->allocQueue(hidDeviceInterface)) == NULL + || *queue == NULL) + goto mp_input_ar_init_error; + + // Create the queue. + (*queue)->create(queue, 0, MAX_QUEUE_SIZE); + + // Add elements to the queue to make the queue work + // on tiger. It's a sequence from 1 to 21, + // maybe it's the range of cookie values. + for (i = 0;i < nr_cookies;i++) + (*queue)->addElement(queue, cookies[i], 0); + + // not used anymore + if (cookies != NULL) + free(cookies); + + // Start data delivery to the queue. + (*queue)->start(queue); + + // not useful anymore + IOObjectRelease(hidObjectIterator); + + inited = 1; + return 0; + +mp_input_ar_init_error: + if (cookies != NULL) + free(cookies); + if (hidDeviceInterface != NULL) { + if (*hidDeviceInterface != NULL) { + (*hidDeviceInterface)->close(hidDeviceInterface); + (*hidDeviceInterface)->Release(hidDeviceInterface); + } + hidDeviceInterface = NULL; + } + IOObjectRelease(hidObjectIterator); + return -1; +} + +int is_mplayer_front() +{ + ProcessSerialNumber myProc, frProc; + Boolean sameProc; + pid_t parentPID; + + if (GetFrontProcess(&frProc) == noErr + && GetCurrentProcess(&myProc) == noErr + && SameProcess(&frProc, &myProc, &sameProc) == noErr) { + if (sameProc) + return 1; + // If MPlayer is running in slave mode, also check parent process. + if (slave_mode && GetProcessPID(&frProc, &parentPID) == noErr) + return parentPID==getppid(); + } + return 0; +} + +int mp_input_ar_read(int fd) +{ + int i, down = 0; + int ret = MP_INPUT_NOTHING; + AbsoluteTime zeroTime = {0,0}; + IOHIDEventStruct event; + static int prev_event = 0; + IOReturn result = kIOReturnSuccess; + + const cookie_keycode_map_t *ar_code; + int cookie_nr = 0; + char cookie_queue[MAX_QUEUE_SIZE]; + int value_queue[MAX_QUEUE_SIZE]; + + if (inited == 0) + return MP_INPUT_NOTHING; + + while ((result = (*queue)->getNextEvent(queue, &event, zeroTime, 0)) == kIOReturnSuccess) { +#ifdef TEST + printf(" - event cookie: %d, value: %d, long value: %d\n", + (int)event.elementCookie, (int)event.value, (int)event.longValue); +#endif + // Shorten cookie sequence by removing cookies value 5 and 18, + // since 5 always follows 6 (on tiger), 18 follows 19 (on leopard). + if ((int)event.elementCookie == 5 + || ((int)event.elementCookie == 18 && is_leopard)) + continue; + // Check valid cookie range. + if ((int)event.elementCookie > 35 || (int)event.elementCookie < 2) { + cookie_nr = 0; + continue; + } + cookie_queue[cookie_nr] = (char)(int)event.elementCookie; + value_queue[cookie_nr++] = event.value; + // 4 cookies are necessary to make up a valid sequence. + if (cookie_nr>=4) { + // Find matching sequence. + ar_code = ar_codes; + while (ar_code->cookies != NULL && + (cookie_nr < ar_code->seq_len || + 0 != memcmp(ar_code->cookies, + &cookie_queue[cookie_nr-ar_code->seq_len], + ar_code->seq_len))) + ++ar_code; + if (ar_code->cookies != NULL) { + ret = ar_code->keycode; + switch (ret) { + // For these 4 keys, the remote can keep a hold state. + case AR_VUP: + case AR_VDOWN: + case AR_NEXT_HOLD: + case AR_PREV_HOLD: + for (i = cookie_nr-ar_code->seq_len; i < cookie_nr; ++i) { + if (value_queue[i]) { + down = MP_KEY_DOWN; + break; + } + } + break; + default: + down = 0; + } + } + } + } + + if (!is_mplayer_front()) { + if (hidDeviceIsOpen) { + (*hidDeviceInterface)->close(hidDeviceInterface); + hidDeviceIsOpen = 0; + + // read out all pending events + while (result == kIOReturnSuccess) + result = (*queue)->getNextEvent(queue, &event, zeroTime, 0); + } + return MP_INPUT_NOTHING; + } + // If we are switched from running as a foreground process to a + // background process and back again, re-open the device to make + // sure we are not affected by the system or other applications + // using the Apple Remote. + else if (!hidDeviceIsOpen) { + if ((*hidDeviceInterface)->open(hidDeviceInterface, + kIOHIDOptionsTypeSeizeDevice) == kIOReturnSuccess) + hidDeviceIsOpen = 1; + } + + if (ret > 0) + prev_event = ret; + return ret | down; +} + +void mp_input_ar_close(int fd) +{ + if (inited == 0) + return; + + // Close the device. + (*hidDeviceInterface)->close(hidDeviceInterface); + + // Stop data delivery to queue. + (*queue)->stop(queue); + // Dispose of queue. + (*queue)->dispose(queue); + // Release the queue we allocated. + (*queue)->Release(queue); + + // Release the interface. + (*hidDeviceInterface)->Release(hidDeviceInterface); + + inited = 0; +} + +#ifdef TEST +int main(void) +{ + int ret; + + if (mp_input_ar_init() < 0) { + printf("Unable to initialize Apple Remote.\n"); + return 1; + } + + while (1) { + switch ((ret = mp_input_ar_read(0)) & ~MP_KEY_DOWN) { + case AR_PLAY: printf(" - AR_PLAY."); break; + case AR_PLAY_HOLD: printf(" - AR_PLAY_HOLD."); break; + case AR_NEXT: printf(" - AR_NEXT."); break; + case AR_NEXT_HOLD: printf(" - AR_NEXT_HOLD."); break; + case AR_PREV: printf(" - AR_PREV."); break; + case AR_PREV_HOLD: printf(" - AR_PREV_HOLD."); break; + case AR_MENU: printf(" - AR_MENU."); break; + case AR_MENU_HOLD: printf(" - AR_MENU_HOLD."); break; + case AR_VUP: printf(" - AR_VUP."); break; + case AR_VDOWN: printf(" - AR_VDOWN."); break; + } + if ((ret > 0 )&&(ret & MP_KEY_DOWN)) + printf(" [hold]"); + if (ret > 0) + printf("\n"); + } + + mp_input_ar_close(0); + return 0; +} +#endif diff --git a/input/ar.h b/input/ar.h new file mode 100644 index 0000000000..c6b7c4d5b9 --- /dev/null +++ b/input/ar.h @@ -0,0 +1,42 @@ +/* + * Apple Remote input interface + * + * Copyright (C) 2007 Zoltan Ponekker + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MPlayer; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INPUT_AR_H +#define INPUT_AR_H + +#define AR_BASE 0x500 +#define AR_PLAY (AR_BASE + 0) +#define AR_PLAY_HOLD (AR_BASE + 1) +#define AR_NEXT (AR_BASE + 2) +#define AR_NEXT_HOLD (AR_BASE + 3) +#define AR_PREV (AR_BASE + 4) +#define AR_PREV_HOLD (AR_BASE + 5) +#define AR_MENU (AR_BASE + 6) +#define AR_MENU_HOLD (AR_BASE + 7) +#define AR_VUP (AR_BASE + 8) +#define AR_VDOWN (AR_BASE + 9) + +int mp_input_ar_init(void); +int mp_input_ar_read(int fd); +void mp_input_ar_close(int fd); + +#endif /* INPUT_AR_H */ diff --git a/input/input.c b/input/input.c index affe926c9c..a14fe75edf 100644 --- a/input/input.c +++ b/input/input.c @@ -35,6 +35,8 @@ #include #endif +#include "ar.h" + /// This array defines all known commands. /// The first field is an id used to recognize the command without too many strcmp. /// The second is obviously the command name. @@ -283,6 +285,17 @@ static mp_key_name_t key_names[] = { { JOY_BTN8, "JOY_BTN8" }, { JOY_BTN9, "JOY_BTN9" }, + { AR_PLAY, "AR_PLAY" }, + { AR_PLAY_HOLD, "AR_PLAY_HOLD" }, + { AR_NEXT, "AR_NEXT" }, + { AR_NEXT_HOLD, "AR_NEXT_HOLD" }, + { AR_PREV, "AR_PREV" }, + { AR_PREV_HOLD, "AR_PREV_HOLD" }, + { AR_MENU, "AR_MENU" }, + { AR_MENU_HOLD, "AR_MENU_HOLD" }, + { AR_VUP, "AR_VUP" }, + { AR_VDOWN, "AR_VDOWN" }, + { KEY_POWER, "POWER" }, { KEY_MENU, "MENU" }, { KEY_PLAY, "PLAY" }, @@ -408,6 +421,18 @@ static mp_cmd_bind_t def_cmd_binds[] = { { { JOY_BTN1, 0 }, "osd" }, { { JOY_BTN2, 0 }, "volume 1"}, { { JOY_BTN3, 0 }, "volume -1"}, +#endif +#ifdef HAVE_APPLE_REMOTE + { { AR_PLAY, 0}, "pause" }, + { { AR_PLAY_HOLD, 0}, "quit" }, + { { AR_NEXT, 0 }, "seek 30" }, + { { AR_NEXT_HOLD, 0 }, "seek 120" }, + { { AR_PREV, 0 }, "seek -10" }, + { { AR_PREV_HOLD, 0 }, "seek -120" }, + { { AR_MENU, 0 }, "osd" }, + { { AR_MENU_HOLD, 0 }, "mute" }, + { { AR_VUP, 0 }, "volume 1"}, + { { AR_VDOWN, 0 }, "volume -1"}, #endif { { 'T', 0 }, "vo_ontop" }, { { 'f', 0 }, "vo_fullscreen" }, @@ -525,6 +550,9 @@ static unsigned int ar_delay = 100, ar_rate = 8, last_ar = 0; static int use_joystick = 1, use_lirc = 1, use_lircc = 1; static char* config_file = "input.conf"; +/* Apple Remote */ +static int use_ar = 1; + static char* js_dev = NULL; static char* in_file = NULL; @@ -553,6 +581,8 @@ static m_option_t mp_input_opts[] = { { "lirc", &use_lirc, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL }, { "nolircc", &use_lircc, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL }, { "lircc", &use_lircc, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL }, + { "noar", &use_ar, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL }, + { "ar", &use_ar, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL }, { NULL, NULL, 0, 0, 0, 0, NULL} }; @@ -1728,6 +1758,15 @@ mp_input_init(int use_gui) { } #endif +#ifdef HAVE_APPLE_REMOTE + if(use_ar) { + if(mp_input_ar_init() < 0) + mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrCantInitAppleRemote); + else + mp_input_add_key_fd(-1,0,mp_input_ar_read,mp_input_ar_close); + } +#endif + if(in_file) { struct stat st; if(stat(in_file,&st))