From: Ed Rogalsky Date: Sun, 2 Mar 2014 16:56:15 +0000 (+0100) Subject: jogshuttle: decode events with mediactrl X-Git-Url: https://git.sesse.net/?p=kdenlive;a=commitdiff_plain;h=8fd72a344483e436b396a1c288221a6e2f311dde jogshuttle: decode events with mediactrl mediactrl: taken from kino project (Dan Dennedys jogshuttle decoder) this is the first playing version. code cleanup and refactoring has to be done --- diff --git a/src/jogshuttle.cpp b/src/jogshuttle.cpp index 73985e56..00b0c797 100644 --- a/src/jogshuttle.cpp +++ b/src/jogshuttle.cpp @@ -88,35 +88,38 @@ bool ShuttleThread::isWorking() void ShuttleThread::run() { kDebug() << "------- STARTING SHUTTLE: " << m_device; + struct media_ctrl mc; + media_ctrl_open2(&mc, m_device.toUtf8().data()); - /* open file descriptor */ - const int fd = KDE_open((char *) m_device.toUtf8().data(), O_RDONLY); - if (fd < 0) { + /* open file descriptor */ + //const int fd = KDE_open((char *) m_device.toUtf8().data(), O_RDONLY); + if (mc.fd < 0) { perror("Can't open Jog Shuttle FILE DESCRIPTOR"); return; } EV ev[64]; - +#if 0 if (ioctl(fd, EVIOCGRAB, 1) < 0) { fprintf(stderr, "Can't get exclusive access on Jog Shuttle FILE DESCRIPTOR\n"); close(fd); return; } +#endif fd_set readset; struct timeval timeout; int num_warnings = 0, readResult = 0; int result, iof = -1; - +#if 0 /* get fd settings */ if ((iof = fcntl(fd, F_GETFL, 0)) == -1) { fprintf(stderr, "Can't get Jog Shuttle file status\n"); close(fd); return; } - +#endif #if 0 else if (fcntl(fd, F_SETFL, iof | O_NONBLOCK) == -1) { fprintf(stderr, "Can't set Jog Shuttle FILE DESCRIPTOR to O_NONBLOCK and stop thread\n"); @@ -124,19 +127,20 @@ void ShuttleThread::run() return; } #endif + struct media_ctrl_event mev; /* enter thread loop */ while (!stop_me) { /* reset the read set */ FD_ZERO(&readset); - FD_SET(fd, &readset); + FD_SET(mc.fd, &readset); /* reinit the timeout structure */ timeout.tv_sec = 0; timeout.tv_usec = 400000; /* 400 ms */ /* do select in blocked mode and wake up after timeout for eval stop_me */ - result = select(fd+1, &readset, NULL, NULL, &timeout); + result = select(mc.fd+1, &readset, NULL, NULL, &timeout); /* see if there was an error or timeout else process event */ if (result < 0 && errno == EINTR) { @@ -152,9 +156,14 @@ void ShuttleThread::run() /* do nothing. reserved for future purposes */ } else { /* we have input */ - if (FD_ISSET(fd, &readset)) { + if (FD_ISSET(mc.fd, &readset)) { /* read input */ - readResult = read(fd, ev, sizeof(EV) * 64); + mev.type = MEDIA_CTRL_EVENT_NONE; + //readResult = read(fd, ev, sizeof(EV) * 64); + media_ctrl_read_event(&mc, &mev); + /* process event */ + handle_event(mev); +#if 0 if (readResult < 0) { if (num_warnings % 10000 == 0) { /* if device is not available anymore - dead or disconnected */ @@ -185,13 +194,25 @@ void ShuttleThread::run() handle_event(ev[i]); } } +#endif } } } kDebug() << "------- STOPPING SHUTTLE: "; /* close the handle and return thread */ - close(fd); + //close(fd); + media_ctrl_close(&mc); +} + +void ShuttleThread::handle_event(struct media_ctrl_event ev) +{ + if (ev.type == MEDIA_CTRL_EVENT_KEY) + key(ev); + else if (ev.type == MEDIA_CTRL_EVENT_JOG) + jog(ev); + else if (ev.type == MEDIA_CTRL_EVENT_SHUTTLE) + shuttle(ev); } void ShuttleThread::handle_event(EV ev) @@ -209,6 +230,14 @@ void ShuttleThread::handle_event(EV ev) } } +void ShuttleThread::key(struct media_ctrl_event ev) +{ + if (ev.value == KEY_PRESS) { + int code = ev.index + 1; + QApplication::postEvent(m_parent, new QEvent((QEvent::Type)(KEY_EVENT_OFFSET + code))); + } +} + void ShuttleThread::key(unsigned short code, unsigned int value) { if (value == 0) { @@ -226,6 +255,11 @@ void ShuttleThread::key(unsigned short code, unsigned int value) } +void ShuttleThread::shuttle(struct media_ctrl_event ev) +{ + QApplication::postEvent(m_parent, new QEvent((QEvent::Type) (JOG_STOP + (ev.value/2)))); +} + void ShuttleThread::shuttle(int value) { //gettimeofday( &last_shuttle, 0 ); @@ -245,6 +279,14 @@ void ShuttleThread::shuttle(int value) QApplication::postEvent(m_parent, new QEvent((QEvent::Type) (JOG_STOP + value))); } +void ShuttleThread::jog(struct media_ctrl_event ev) +{ + if (ev.value < 0) + QApplication::postEvent(m_parent, new QEvent((QEvent::Type) JOG_BACK1)); + else if (ev.value > 0) + QApplication::postEvent(m_parent, new QEvent((QEvent::Type) JOG_FWD1)); +} + void ShuttleThread::jog(unsigned int value) { // generate a synthetic event for the shuttle going diff --git a/src/jogshuttle.h b/src/jogshuttle.h index d1cf185b..dbcd179e 100644 --- a/src/jogshuttle.h +++ b/src/jogshuttle.h @@ -26,7 +26,8 @@ #include #include - +#include +#include "lib/external/media_ctrl/mediactrl.h" typedef struct input_event EV; @@ -47,9 +48,13 @@ public: private: bool m_isWorking; void handle_event(EV ev); + void handle_event(struct media_ctrl_event ev); + void jog(struct media_ctrl_event ev); void jog(unsigned int value); void shuttle(int value); + void shuttle(struct media_ctrl_event ev); void key(unsigned short code, unsigned int value); + void key(struct media_ctrl_event ev); }; typedef QMap DeviceMap; diff --git a/src/lib/external/CMakeLists.txt b/src/lib/external/CMakeLists.txt index 978e5a69..066bd4dd 100644 --- a/src/lib/external/CMakeLists.txt +++ b/src/lib/external/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(kiss_fft) +add_subdirectory(media_ctrl) set(kdenlive_SRCS ${kdenlive_SRCS} diff --git a/src/lib/external/media_ctrl/CMakeLists.txt b/src/lib/external/media_ctrl/CMakeLists.txt new file mode 100644 index 00000000..6de4a0c1 --- /dev/null +++ b/src/lib/external/media_ctrl/CMakeLists.txt @@ -0,0 +1,18 @@ +set(kdenlive_SRCS + ${kdenlive_SRCS} + lib/external/media_ctrl/mediactrl.h + lib/external/media_ctrl/mediactrl.c + PARENT_SCOPE +) + + +# Create a static library from kiss_fft + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --std=c99") +include_directories( + ${CMAKE_BINARY_DIR} +) +add_library(media_ctrl STATIC + mediactrl.h + mediactrl.c +) diff --git a/src/lib/external/media_ctrl/mediactrl.c b/src/lib/external/media_ctrl/mediactrl.c new file mode 100644 index 00000000..4ca6527b --- /dev/null +++ b/src/lib/external/media_ctrl/mediactrl.c @@ -0,0 +1,444 @@ +/* +* mediactrl.c -- Jog Shuttle device support +* Copyright (C) 2001-2007 Dan Dennedy +* +* This program 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. +* +* This program 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 this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mediactrl.h" + + +static char *_shuttle_name = "Shuttle"; +static char *_jog_name = "Jog"; + +/* + ShuttlePro keys +*/ +static struct media_ctrl_key mc_shuttle_pro_keys[] = { + { 0x100, "Button 1", MEDIA_CTRL_F1 }, + { 0x101, "Button 2", MEDIA_CTRL_F2 }, + { 0x102, "Button 3", MEDIA_CTRL_F3 }, + { 0x103, "Button 4", MEDIA_CTRL_F4 }, + { 0x104, "Button 5", MEDIA_CTRL_B4 }, + { 0x105, "Button 6", MEDIA_CTRL_B2 }, + { 0x106, "Button 7", MEDIA_CTRL_B1 }, + { 0x107, "Button 8", MEDIA_CTRL_B3 }, + { 0x108, "Button 9", MEDIA_CTRL_B5 }, + { 0x109, "Button 10", MEDIA_CTRL_B6 }, + { 0x10a, "Button 11", MEDIA_CTRL_B7 }, + { 0x10b, "Button 12", MEDIA_CTRL_B8 }, + { 0x10c, "Button 13", MEDIA_CTRL_B9 }, + { 0, NULL, 0 } +}; + + +/* + ShuttleXPress keys +*/ +static struct media_ctrl_key _mc_shuttle_xpress_keys[] = { + { 0x104, "Button B4", MEDIA_CTRL_B4 }, + { 0x105, "Button B2", MEDIA_CTRL_B2 }, + { 0x106, "Button B1", MEDIA_CTRL_B1 }, + { 0x107, "Button B3", MEDIA_CTRL_B3 }, + { 0x108, "Button B5", MEDIA_CTRL_B5 }, + { 0, NULL, 0 } +}; + +static struct media_ctrl_key mc_shuttle_xpress_keys[] = { + { 0x104, "Button B1", MEDIA_CTRL_B1}, + { 0x105, "Button B2", MEDIA_CTRL_B2 }, + { 0x106, "Button B3", MEDIA_CTRL_B3 }, + { 0x107, "Button B4", MEDIA_CTRL_B4 }, + { 0x108, "Button B5", MEDIA_CTRL_B5 }, + { 0, NULL, 0 } +}; + + + +/* + JLCooper MCS3 Keys +*/ +static struct media_ctrl_key mc_jlcooper_mcs3_keys[] = { + { 0x107, "F1", MEDIA_CTRL_F1 }, + { 0x101, "F2", MEDIA_CTRL_F2 }, + { 0x105, "F3", MEDIA_CTRL_F3 }, + { 0x102, "F4", MEDIA_CTRL_F4 }, + { 0x103, "F5", MEDIA_CTRL_F5 }, + { 0x104, "F6", MEDIA_CTRL_F6 }, + { 0x10d, "W1", MEDIA_CTRL_B6 }, + { 0x10e, "W2", MEDIA_CTRL_B4 }, + { 0x100, "W3", MEDIA_CTRL_B2 }, + { 0x106, "W4", MEDIA_CTRL_B1 }, + { 0x110, "W5", MEDIA_CTRL_B3 }, + { 0x111, "W6", MEDIA_CTRL_B5 }, + { 0x115, "W7", MEDIA_CTRL_B7 }, + { 0x116, "STICK_LEFT", MEDIA_CTRL_STICK_LEFT }, + { 0x113, "STICK_RIGHT", MEDIA_CTRL_STICK_RIGHT }, + { 0x114, "STICK_UP", MEDIA_CTRL_STICK_UP }, + { 0x112, "STICK_DOWN", MEDIA_CTRL_STICK_DOWN }, + { 0x10f, "Rewind", MEDIA_CTRL_REWIND }, + { 0x108, "Fast Forward", MEDIA_CTRL_FAST_FORWARD }, + { 0x109, "Stop", MEDIA_CTRL_STOP }, + { 0x10a, "Play", MEDIA_CTRL_PLAY }, + { 0x10b, "Record", MEDIA_CTRL_RECORD }, + { 0, NULL, 0 } +}; + + +/* + Griffin PowerMate +*/ +static struct media_ctrl_key mc_powermate_keys[] = { + { BTN_0, "Button", MEDIA_CTRL_B1 }, + { 0, NULL, 0 } +}; + + +/* + X-Keys Jog/Shuttle +*/ +static struct media_ctrl_key mc_x_keys[] = { + { 0x102, "Button L1", MEDIA_CTRL_F1 }, + { 0x103, "Button L2", MEDIA_CTRL_F9 }, + { 0x104, "Button L3", MEDIA_CTRL_B1 }, + { 0x105, "Button L4", MEDIA_CTRL_B3 }, + { 0x106, "Button L5", MEDIA_CTRL_B5 }, + { 0x10a, "Button L6", MEDIA_CTRL_F2 }, + { 0x10b, "Button L7", MEDIA_CTRL_F10 }, + { 0x10c, "Button L8", MEDIA_CTRL_B2 }, + { 0x10d, "Button L9", MEDIA_CTRL_B4 }, + { 0x10e, "Button L10", MEDIA_CTRL_B6 }, + { 0x112, "Button C1", MEDIA_CTRL_F3 }, + { 0x11a, "Button C2", MEDIA_CTRL_F4 }, + { 0x122, "Button C3", MEDIA_CTRL_F5 }, + { 0x12a, "Button C4", MEDIA_CTRL_F6 }, + { 0x113, "Button C5", MEDIA_CTRL_F11 }, + { 0x11b, "Button C6", MEDIA_CTRL_F12 }, + { 0x123, "Button C7", MEDIA_CTRL_F13 }, + { 0x12b, "Button C8", MEDIA_CTRL_F14 }, + { 0x132, "Button R1", MEDIA_CTRL_F7 }, + { 0x133, "Button R2", MEDIA_CTRL_F15 }, + { 0x134, "Button R3", MEDIA_CTRL_B7 }, + { 0x135, "Button R4", MEDIA_CTRL_B9 }, + { 0x136, "Button R5", MEDIA_CTRL_B11 }, + { 0x13a, "Button R6", MEDIA_CTRL_F8 }, + { 0x13b, "Button R7", MEDIA_CTRL_F16 }, + { 0x13c, "Button R8", MEDIA_CTRL_B8 }, + { 0x13d, "Button R9", MEDIA_CTRL_B10 }, + { 0x13e, "Button R10", MEDIA_CTRL_B12 }, + { 0, NULL, 0 } +}; + +struct media_ctrl_key *media_ctrl_get_key(struct media_ctrl *ctrl, int code, int *index) +{ + int i = 0; + struct media_ctrl_key *keys = ctrl->device->keys; + + while ( keys[i].key != 0 ) { + if (keys[i].key == code) { + if (index != NULL) + *index = i; + return &keys[i]; + } + i++; + } + + return NULL; +} + + +void translate_contour_hid_event(struct media_ctrl *ctrl, struct input_event *ev, struct media_ctrl_event *me) +{ + + int lv, cv; + + me->type = 0; + + if (ev->type == EV_REL) { + /* First check the outer dial */ + if (ev->code == REL_WHEEL) { + + cv = (signed int)ev->value; + if (cv == 1 || cv == -1 ) cv = 0; + + + if ( cv == ctrl->lastshu ) return; + ctrl->lastshu = cv; + + if ( cv > 0 ) cv -= 1; + if ( cv < 0) cv += 1; + + //printf("Shuttle: %d\n", cv); + me->type = MEDIA_CTRL_EVENT_SHUTTLE; + me->value = cv*2; + me->name = _shuttle_name; + + } else if (ev->code == REL_DIAL) { + + if ( ctrl->lastval == -1 ) ctrl->lastval = ev->value; + lv = ctrl->lastval; + cv = ev->value; + + if ( lv == cv ) return; + + ctrl->lastval = cv; + + if (cv < 10 && lv > 0xF0) cv +=0x100; + if (lv < 10 && cv > 0xF0) lv +=0x100; + + me->type = MEDIA_CTRL_EVENT_JOG; + me->value = cv-lv; + me->name = _jog_name; + + ctrl->jogpos += me->value; + //printf("Jog: %06ld (%d)\n", ctrl->jogpos, me->value); + } + return; + } else if (ev->type == EV_KEY) { + int index; + struct media_ctrl_key *key = media_ctrl_get_key(ctrl, ev->code, &index); + if ( key == NULL ) return; + + me->type = MEDIA_CTRL_EVENT_KEY; + me->code = key->code; + me->value = ev->value; + me->name = ( char* )key->name; + me->index = index; + + //printf("Key: %04x %02x: %s\n", ev->code, ev->value, key->name); + + } + +} + +void translate_compliant(struct media_ctrl *ctrl, struct input_event *ev, struct media_ctrl_event *me) +{ + me->type = 0; + + // printf("Translate %02x %02x\n", ev->type, ev->code ); + + if (ev->type == EV_REL) { + if (ev->code == REL_DIAL) { + + me->type = MEDIA_CTRL_EVENT_JOG; + me->value = (signed int)ev->value; + me->name = _jog_name; + + ctrl->jogpos += me->value; + //printf("Jog: %06ld (%d)\n", ctrl->jogpos, me->value); + } + return; + } else if (ev->type == EV_ABS) { + // printf("ABS\n" ); + if ( ev->code == 0x1c || ev->code == ABS_THROTTLE ) { + //printf("ABS_MISC\n" ); + me->type = MEDIA_CTRL_EVENT_SHUTTLE; + me->value = (signed int)ev->value; + me->name = _shuttle_name; + + ctrl->shuttlepos = me->value; + //printf("Shuttle: %06d (%d)\n", ctrl->shuttlepos, me->value); + } + } else if (ev->type == EV_KEY) { + int index; + struct media_ctrl_key *key = media_ctrl_get_key(ctrl, ev->code, &index); + if ( key == NULL ) return; + + me->type = MEDIA_CTRL_EVENT_KEY; + me->code = key->code; + me->value = ev->value; + me->name = ( char* )key->name; + me->index = index; + + //printf("Key: %04x %02x: %s\n", ev->code, ev->value, key->name); + + } +} + +struct media_ctrl_device supported_devices[] = { + { 0x0b33, 0x0030, "Contour ShuttlePRO v2", mc_shuttle_pro_keys, translate_contour_hid_event }, + { 0x0b33, 0x0020, "Contour ShuttleXPress", mc_shuttle_xpress_keys, translate_contour_hid_event }, + { 0x0b33, 0x0010, "Contour ShuttlePro", mc_shuttle_pro_keys, translate_contour_hid_event }, + { 0x0b33, 0x0011, "Contour ShuttlePro", mc_shuttle_pro_keys, translate_contour_hid_event }, /* Hercules OEM */ + { 0x05f3, 0x0240, "Contour ShuttlePro", mc_shuttle_pro_keys, translate_contour_hid_event }, + { 0x0760, 0x0001, "JLCooper MCS3", mc_jlcooper_mcs3_keys, translate_compliant }, + { 0x077d, 0x0410, "Griffin PowerMate", mc_powermate_keys, translate_compliant }, + { 0x05f3, 0x0241, "X-Keys Editor", mc_x_keys, translate_contour_hid_event }, + { 0, 0, 0 } +}; + + +void media_ctrl_translate(struct media_ctrl *ctrl, struct input_event *ev, struct media_ctrl_event *me) +{ + if ( ctrl->device ) ctrl->device->translate(ctrl, ev, me); +} + + +void media_ctrl_read_event(struct media_ctrl *ctrl, struct media_ctrl_event *me) +{ + ssize_t n; + struct input_event ev; + + // struct media_ctrl_event me; + + if ( ctrl->fd > 0 ) { + n = read(ctrl->fd, &ev, sizeof(ev)); + } else { + return; + } + + if (n != sizeof(ev)) { + //printf("JogShuttle::inputCallback: read: (%d) %s\n", errno, strerror(errno)); + close(ctrl->fd); + ctrl->fd = 0; + return; + } + + if ( ctrl->device && ctrl->device->translate) + ctrl->device->translate(ctrl, &ev, me); + else + me->type = 0; + + if ( me->type == MEDIA_CTRL_EVENT_JOG ) { + struct timeval timev; + gettimeofday(&timev, NULL); + unsigned long now = (unsigned long)timev.tv_usec + (1000000*(unsigned long)timev.tv_sec); + if ( now < ctrl->last_jog_time + 40000 ) { + //printf("*** Fast Jog %02d %05d ***\n", me->value, now - ctrl->last_jog_time); + ctrl->jogrel = me->value; + me->type = MEDIA_CTRL_EVENT_NONE; + } else { + me->value += ctrl->jogrel; + ctrl->jogrel = 0; + ctrl->last_jog_time = now; + // printf("*** Jog %02d ***\n", me->value); + } + } + + return; + +} + + +int probe_device(struct media_ctrl *mc) +{ + short devinfo[4]; + int i = 0; + + if ( ioctl(mc->fd, EVIOCGID, &devinfo) ) { + perror("evdev ioctl"); + return 0; + } + + do { + if ( supported_devices[i].vendor == devinfo[1] + && supported_devices[i].product == devinfo[2] ) { + + mc->device = &supported_devices[i]; + //printf("Success on /dev/input/event%d: %s\n", mc->eventno, mc->device->name); + // mc->fd = fd; + // mc->translate = mc->device.translate_function; + // mc = malloc(sizeof(struct media_ctrl)); + mc->jogpos = 0; + mc->lastval = -1; + mc->last_jog_time = 0; + return 1; + } else { + //mc->device = NULL; + } + + } while ( supported_devices[++i].vendor != 0 ); + + return 0; +} + + +void media_ctrl_get_device_list() +{ + // TBD +} + + + +void find_first_device(struct media_ctrl *mc) +{ + char buf[256]; + int fd, i; + + for ( i = 0; i < 32; i++ ) { + sprintf(buf, "/dev/input/event%d", i); + fd = open( buf, O_RDONLY ); + if ( fd < 0 ) { + perror(buf); + } else { + mc->fd = fd; + mc->eventno = i; + if( probe_device(mc) ) { + return; + } else { + close(fd); + mc->fd = -1; + } + } + } + return; +} + + +void media_ctrl_close(struct media_ctrl *mc) +{ + if (mc->fd > 0) + close( mc->fd ); + memset( mc, 0, sizeof( struct media_ctrl ) ); +} + + +void media_ctrl_open(struct media_ctrl *mc) +{ + find_first_device(mc); +} + +void media_ctrl_open2(struct media_ctrl *mc, const char *devname) +{ + int fd; + + fd = open( devname, O_RDONLY ); + if ( fd < 0 ) { + perror(devname); + } else { + mc->fd = fd; + //mc->eventno = i; + if( probe_device(mc) ) { + return; + } else { + close(fd); + mc->fd = -1; + } + } +} + diff --git a/src/lib/external/media_ctrl/mediactrl.h b/src/lib/external/media_ctrl/mediactrl.h new file mode 100644 index 00000000..652b4ffe --- /dev/null +++ b/src/lib/external/media_ctrl/mediactrl.h @@ -0,0 +1,156 @@ +/* +* mediactrl.c -- Jog Shuttle device support +* Copyright (C) 2001-2007 Dan Dennedy +* +* This program 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. +* +* This program 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 this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef _MEDIA_CTRL_H +#define _MEDIA_CTRL_H + + +// just to make the code more readable +#define KEY_RELEASE 0x00 +#define KEY_PRESS 0x01 + +// not used yet +#define MEDIA_ST_ACTIVE 0x02 +#define MEDIA_ST_INACTIVE 0x01 + +// media ctrl event types +#define MEDIA_CTRL_EVENT_NONE 0x00 +#define MEDIA_CTRL_EVENT_KEY 0x01 +#define MEDIA_CTRL_EVENT_JOG 0x02 +#define MEDIA_CTRL_EVENT_SHUTTLE 0x03 +#define MEDIA_CTRL_EVENT_STICK 0x04 + +// the disconnect event - not used yet +#define MEDIA_CTRL_DISCONNECT 0x01 + +#define MEDIA_CTRL_SHIFT 0x01 + +#define MEDIA_CTRL_PLAY 0x10 +#define MEDIA_CTRL_PLAY_FWD 0x10 +#define MEDIA_CTRL_REVERSE 0x11 +#define MEDIA_CTRL_PLAY_REV 0x11 +#define MEDIA_CTRL_STOP 0x12 +#define MEDIA_CTRL_PAUSE 0x13 +#define MEDIA_CTRL_NEXT 0x14 +#define MEDIA_CTRL_PREV 0x15 +#define MEDIA_CTRL_RECORD 0x16 +#define MEDIA_CTRL_FAST_FORWARD 0x17 +#define MEDIA_CTRL_REWIND 0x18 + +#define MEDIA_CTRL_STICK_LEFT 0x20 +#define MEDIA_CTRL_STICK_RIGHT 0x21 +#define MEDIA_CTRL_STICK_UP 0x22 +#define MEDIA_CTRL_STICK_DOWN 0x23 + +/* function keys, usually at top of device */ +#define MEDIA_CTRL_F1 0x100 +#define MEDIA_CTRL_F2 0x101 +#define MEDIA_CTRL_F3 0x102 +#define MEDIA_CTRL_F4 0x103 +#define MEDIA_CTRL_F5 0x104 +#define MEDIA_CTRL_F6 0x105 +#define MEDIA_CTRL_F7 0x106 +#define MEDIA_CTRL_F8 0x107 +#define MEDIA_CTRL_F9 0x108 +#define MEDIA_CTRL_F10 0x109 +#define MEDIA_CTRL_F11 0x10a +#define MEDIA_CTRL_F12 0x10b +#define MEDIA_CTRL_F13 0x10c +#define MEDIA_CTRL_F14 0x10d +#define MEDIA_CTRL_F15 0x10e +#define MEDIA_CTRL_F16 0x10f + +#define MEDIA_CTRL_B1 0x110 +#define MEDIA_CTRL_B2 0x111 +#define MEDIA_CTRL_B3 0x112 +#define MEDIA_CTRL_B4 0x113 +#define MEDIA_CTRL_B5 0x114 +#define MEDIA_CTRL_B6 0x115 +#define MEDIA_CTRL_B7 0x116 +#define MEDIA_CTRL_B8 0x117 +#define MEDIA_CTRL_B9 0x118 +#define MEDIA_CTRL_B10 0x119 +#define MEDIA_CTRL_B11 0x11a +#define MEDIA_CTRL_B12 0x11b +#define MEDIA_CTRL_B13 0x11c +#define MEDIA_CTRL_B14 0x11d +#define MEDIA_CTRL_B15 0x11e +#define MEDIA_CTRL_B16 0x11f + +#ifdef __cplusplus +extern "C" { +#endif + +struct media_ctrl_device; + +struct media_ctrl_key { + int key; // internal keycode - do not use + const char *name; + int code; // eventcode + int action; +}; + +struct media_ctrl_event { + struct timeval time; + unsigned short type; + unsigned short code; + char *name; + int value; + unsigned short index; +}; + +struct media_ctrl { + + int fd; + int eventno; + + int status; + + struct media_ctrl_device *device; + + long jogpos; + int shuttlepos; + + int lastval; + int lastshu; + + int jogrel; // accumulate relative values if events come too fast + unsigned long last_jog_time; // last jog event + +}; + +struct media_ctrl_device { + int vendor; + int product; + const char *name; + struct media_ctrl_key *keys; + void (*translate)(struct media_ctrl *ctrl, struct input_event *ev, struct media_ctrl_event *me); +}; + +void media_ctrl_open(struct media_ctrl *); +void media_ctrl_open2(struct media_ctrl *, const char *devname); +void media_ctrl_close(struct media_ctrl *); +void media_ctrl_read_event(struct media_ctrl *, struct media_ctrl_event *); + +struct media_ctrl_key *media_ctrl_get_keys(struct media_ctrl *); + +#ifdef __cplusplus +} +#endif + +#endif