Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

jogshuttle.cc

Go to the documentation of this file.
00001 // $Id: jogshuttle.cc,v 1.22 2007/02/20 06:32:05 ddennedy Exp $
00002 /*
00003  * Copyright (C) 2001 Tomoaki Hayasaka <hayasakas@postman.riken.go.jp>
00004  * Copyright (C) 2001-2007 Dan Dennedy <dan@dennedy.org>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <fcntl.h>
00028 #include <unistd.h>
00029 #include <errno.h>
00030 #include <linux/input.h>
00031 
00032 #include "jogshuttle.h"
00033 #include "preferences.h"
00034 #include "commands.h"
00035 
00036 #include <string>
00037 using std::string;
00038 #include <utility>
00039 using std::pair;
00040 using std::make_pair;
00041 
00042 /* **********************************************************************
00043  
00044 Overview of jogshuttle mapping code.
00045  
00046 Note, this is mostly about the preferences, but I thought it should go in here
00047  
00048 * Knowing all the actions
00049  
00050 When starting, we fill the optionmenus with the choices. These are
00051 also into an array. Array is keyed on _option_index (duplicated),
00052 contains _short_desc, _desc, _action. When we fill the option menu,
00053 the index is maintained/duplicated in the array.
00054  
00055 * Getting the stored or default actions
00056  
00057 Then the preference.cc file needs to read a lot of stuff from the
00058 config file or a default mapping. These are ints that are the codes of
00059 the buttons, and the strings that are the actual actions. 
00060  
00061 These are read into the mappings of buttons, which is a map keyed on a
00062 pair of codes. The codes are (for now) the actual codes as returned
00063 from the events - a future level of abstraction may call for a mapping
00064 from buttons to codes.
00065  
00066 * Changing the mappings - the user changes the optionmenu selections.
00067  
00068 - When the user changes one of the two "buttons", we look up the
00069   action in the JogShuttleMapping map. The action is then located in
00070   the JogShuttleActions array and the right index is set for the
00071   Action optionmenu.
00072  
00073 - Whenever the action optionmenu is changed, we get the action string
00074   from the list of all actions (keyed on index) and stuff this into
00075   the mappings. In other words, changing the action optionmenu,
00076   "saves" this choice.
00077  
00078 * Using the mappings
00079  
00080 The jogshuttle.cc code only needs a mapping from code, code to string,
00081 which it gets from the Preference object.
00082  
00083 * Saving the mappings
00084  
00085 When saving, the stuff the action mapping into the config file.
00086  
00087 ********************************************************************** */
00088 
00089 
00090 extern "C"
00091 {
00092 #include "support.h"
00093     extern struct navigate_control g_nav_ctl;
00094 }
00095 
00097 
00099 void JogShuttle_inputCallback( gpointer data, gint source, GdkInputCondition condition )
00100 {
00101     JogShuttle * js = static_cast<JogShuttle *>( data );
00102     g_return_if_fail( js != NULL );
00103     js->inputCallback( source, condition );
00104 }
00105 
00111 JogShuttle *JogShuttle::_instance = NULL;
00112 
00117 JogShuttle &JogShuttle::getInstance()
00118 {
00119     if ( _instance == NULL )
00120         _instance = new JogShuttle();
00121     return *_instance;
00122 }
00123 
00126 JogShuttle::JogShuttle() :
00127         _callback( NULL ),
00128         input_( -1 ),
00129         monitorTag_( -1 ),
00130         _modifier_code( 0 )
00131 {
00132     _ctrl.device = NULL;
00133     start();
00134 }
00135 
00140 JogShuttle::~JogShuttle()
00141 {
00142     if ( input_ >= 0 )
00143     {
00144         gdk_input_remove( monitorTag_ );
00145         media_ctrl_close(&_ctrl);
00146     }
00147 }
00148 
00154 bool JogShuttle::start()
00155 {
00156     Preferences & prefs = Preferences::getInstance();
00157     
00158     if ( prefs.enableJogShuttle )
00159     {
00160         stop();
00161         media_ctrl_open( &_ctrl );
00162         if ( _ctrl.device ) 
00163         {
00164             monitorTag_ = gdk_input_add( _ctrl.fd, GDK_INPUT_READ,
00165                              JogShuttle_inputCallback,
00166                              ( gpointer ) this );
00167             return true;
00168         }
00169     }
00170     return false;
00171 }
00172 
00175 void JogShuttle::stop()
00176 {
00177     if ( monitorTag_ != -1 )
00178     {
00179         gdk_input_remove( monitorTag_ );
00180         monitorTag_ = -1;
00181     }
00182     if ( _ctrl.device )
00183         media_ctrl_close( &_ctrl );
00184 }
00185 
00192 void JogShuttle::registerCallback( void * user, JogShuttleCallback callback )
00193 {
00194     if ( _callback )
00195         g_warning( "JogShuttle::registerCallback - already registered\n" );
00196     _callback = callback;
00197     _callbackdata = user;
00198 }
00199 
00206 void JogShuttle::deregisterCallback()
00207 {
00208     if ( _callback == NULL )
00209         g_warning( "JogShuttle::deregisterCallback - not registered\n" );
00210     _callback = NULL;
00211 }
00212 
00213 struct media_ctrl_key *JogShuttle::getKeyset()
00214 {
00215     if ( _ctrl.device != NULL ) return _ctrl.device->keys;
00216     else return NULL;
00217 }
00218 
00219 
00220 
00221 
00222 
00223 
00229 void JogShuttle::jog( int offs )
00230 {
00231     gdk_threads_enter();
00232     if ( offs < 0 )
00233         videoBackBy(offs);
00234     else
00235         videoForwardBy(offs);
00236     gdk_threads_leave();
00237 }
00238 
00243 void JogShuttle::shuttle( int angle )
00244 {
00245     /*if ( angle > 0 )
00246         angle--;
00247     if ( angle < 0 )
00248         angle++;
00249     */
00250     gdk_threads_enter();
00251     videoShuttle( angle );
00252     gdk_threads_leave();
00253 }
00254 
00267 void JogShuttle::button( struct media_ctrl_event *ev )
00268 {
00269     /* Figure out what codes to use */
00270     unsigned short first;
00271     unsigned short second;
00272 
00273     /* 
00274         Release may need to clear a modifier key
00275     */
00276     if ( ev->value == KEY_RELEASE && _modifier_code != 0 )
00277     {
00278         _modifier_code = 0;
00279         return;
00280     }
00281 
00282     /* Do a callback or action based command */
00283     if ( _callback != NULL )
00284     {
00285         /* This is a key press - if there are no modifier, make sure that
00286         this is saved */
00287         if ( _modifier_code == 0 )
00288             _modifier_code = ev->index + 1;
00289 
00290         if ( _modifier_code != ev->index + 1 )
00291         {
00292             first = _modifier_code - 1;
00293             second = ev->index + 1;
00294         }
00295         else
00296         {
00297             first = ev->index; /* Same as modifier */
00298             second = 0;
00299         }
00300         _callback( _callbackdata, first, second );
00301     }
00302     else
00303     {
00304         /* This is a key press - if there are no modifier, make sure that
00305         this is saved */
00306         if ( _modifier_code == 0 )
00307             _modifier_code = ev->code;
00308 
00309         if ( _modifier_code != ev->code )
00310         {
00311             first = _modifier_code;
00312             second = ev->code;
00313         }
00314         else
00315         {
00316             first = ev->code; /* Same as modifier */
00317             second = 0;
00318         }
00319         
00320         /* Get the action from the prefs */
00321         string action
00322         = Preferences::getInstance()._JogShuttleMappings[
00323               make_pair( first, second ) ]._action;
00324 
00325         if ( "" != action )
00326         {
00327             gdk_threads_enter();
00328             processCommand( ( char * ) action.c_str() );
00329             gdk_threads_leave();
00330         }
00331     }
00332     return ;
00333 
00334 }
00335 
00336 
00337 
00338 
00344 void JogShuttle::inputCallback( gint source, GdkInputCondition condition )
00345 {
00346     g_return_if_fail( this != NULL );
00347     // g_return_if_fail( input_ >= 0 );
00348     // g_return_if_fail( input_ == source );
00349     if ( condition != GDK_INPUT_READ )
00350         stop();
00351     g_return_if_fail( condition == GDK_INPUT_READ );
00352 
00353     struct media_ctrl_event ev;
00354     
00355     ev.type = MEDIA_CTRL_EVENT_NONE;
00356     media_ctrl_read_event(&_ctrl, &ev);
00357 
00358 
00359     /* We can get four "kinds" of events:
00360 
00361     ev.type == MEDIA_CTRL_EVENT_NONE (0x00)
00362     An event that actually isnt one... Since we read every event
00363     from the input subsystem, we sometimes get double events 
00364     (e.g. the shuttlepro reports its state approx. every second.)
00365     libmediactrl translates these events to none-events.
00366     
00367     
00368     ev.type == MEDIA_CTRL_EVENT_KEY (0x01)
00369     This is a button press. The whole event will be handled in the
00370     button method..
00371 
00372     ev.type == MEDIA_CTRL_EVENT_JOG (0x02)
00373     This event is issued when ever the dial position changes. 
00374     ev.value is the offset to the current jog position.
00375 
00376 
00377     - ev.code == EDIA_CTRL_EVENT_SHUTTLE (0x02) 
00378     the outer wheel ev.value indicates the position, with positive 
00379     values from 0x01 to 0x0f (inclusive) indicating clockwise twist, 
00380     and negative values from -1 to -15 indicating counterclockwise 
00381     twist.  A 0 value is reported. 
00382 
00383 
00384     */
00385 
00386     if ( ev.type == MEDIA_CTRL_EVENT_NONE ) return;
00387 #if 0
00388     printf( "JogShuttle: %02x %02x %02d\n", ev.type, ev.code, ev.value );
00389 #endif
00390 
00391 
00392     if ( ev.type == MEDIA_CTRL_EVENT_JOG ) 
00393     {
00394         this->jog( CLAMP( ev.value, -1, 1 ) );
00395     } 
00396     else if ( ev.type == MEDIA_CTRL_EVENT_SHUTTLE ) 
00397     {
00398         this->shuttle( ev.value );
00399     }
00400     else if ( ev.type == MEDIA_CTRL_EVENT_KEY ) 
00401     {
00402         this->button( &ev );
00403     }
00404     else
00405     {
00406         return;
00407     }
00408 }

Generated on Sun Mar 11 22:11:45 2007 for Kino by  doxygen 1.4.2