#!/bin/bash
( ./autogen.sh
- ./configure --with-single-user --with-booby
+ ./configure --with-single-user --with-booby --with-shuttle-usb
make && make install ) 2>&1 | tee log
mv Makefile Makefile.cfg
cp Makefile.devel Makefile
//printf("Canvas::get_scrollbars 5 %d %d\n", get_xscroll(), get_yscroll());
}
+
+void Canvas::update_geometry(EDL *edl, int x, int y, int w, int h)
+{
+ int redraw = 0;
+ if( this->x != x || this->y != y ||
+ this->w != w || this->h != h ) redraw = 1;
+ if( !redraw ) {
+ int vx = x, vy = y, vw = w, vh = h;
+ get_scrollbars(edl, vx, vy, vw, vh);
+ if( vx != view_x || vy != view_y ||
+ vw != view_w || vh != view_h ) redraw = 1;
+ }
+ if( !redraw ) return;
+ reposition_window(edl, x, y, w, y);
+}
+
void Canvas::reposition_window(EDL *edl, int x, int y, int w, int h)
{
this->x = view_x = x; this->y = view_y = y;
canvas_subwindow->flash(0);
}
}
-
-
draw_refresh(0);
}
// passing -1 causes automatic size detection
int canvas_w = -1,
int canvas_h = -1);
+ void update_geometry(EDL *edl, int x, int y, int w, int h);
void reposition_window(EDL *edl, int x, int y, int w, int h);
virtual void reset_translation() {};
virtual void close_source() {};
gui->canvas->update_zoom(mwindow->edl->session->cwindow_xscroll,
mwindow->edl->session->cwindow_yscroll,
mwindow->edl->session->cwindow_zoom);
- gui->canvas->reposition_window(mwindow->edl,
- mwindow->theme->ccanvas_x,
- mwindow->theme->ccanvas_y,
- mwindow->theme->ccanvas_w,
- mwindow->theme->ccanvas_h);
-
-
-
+ gui->canvas->update_geometry(mwindow->edl,
+ mwindow->theme->ccanvas_x, mwindow->theme->ccanvas_y,
+ mwindow->theme->ccanvas_w, mwindow->theme->ccanvas_h);
gui->unlock_window();
-
-
-
-
}
int CWindow::update_position(double position)
track->record = track->play = 0;
}
zwindow->change_source(mixer_edl);
- zwindow->handle_mixer(command, wait_tracking,
+ zwindow->handle_mixer(command, 0,
use_inout, toggle_audio, loop_play, speed);
}
zwindows_lock->unlock();
void MWindow::init_shuttle()
{
#ifdef HAVE_SHUTTLE
- const char *dev_name = Shuttle::probe();
- if( dev_name ) {
+ int ret = Shuttle::probe();
+ if( ret >= 0 ) {
shuttle = new Shuttle(this);
- shuttle->start(dev_name);
+ if( shuttle->read_config_file() > 0 ) {
+ printf("shuttle: bad config file\n");
+ delete shuttle; shuttle = 0;
+ return;
+ }
+ shuttle->start(ret);
}
#endif
}
command->command = STOP;
next_command = new TransportCommand();
next_command->change_type = CHANGE_ALL;
- curr_command = new TransportCommand();
stop_command = new TransportCommand();
stop_command->command = STOP;
+ stop_command->realtime = 1;
+ sent_command = new TransportCommand();
+ sent_command->command = -1;
+ sent_lock = new Mutex("PlaybackEngine::sent");
tracking_lock = new Mutex("PlaybackEngine::tracking_lock");
renderengine_lock = new Mutex("PlaybackEngine::renderengine_lock");
tracking_done = new Condition(1, "PlaybackEngine::tracking_done");
PlaybackEngine::~PlaybackEngine()
{
done = 1;
- transport_stop(0);
+ output_lock->unlock();
Thread::join();
delete preferences;
delete_render_engine();
delete command;
delete next_command;
delete stop_command;
- delete curr_command;
+ delete sent_command;
+ delete sent_lock;
delete input_lock;
delete output_lock;
}
void PlaybackEngine::perform_change()
{
- switch( command->change_type )
- {
+ switch( command->change_type ) {
case CHANGE_ALL:
create_cache();
case CHANGE_EDL:
create_render_engine();
+ break;
case CHANGE_PARAMS:
- if(command->change_type != CHANGE_EDL &&
- (uint32_t)command->change_type != CHANGE_ALL)
- render_engine->get_edl()->synchronize_params(command->get_edl());
+ render_engine->get_edl()->synchronize_params(command->get_edl());
case CHANGE_NONE:
break;
}
while( !done ) {
// Wait for current command to finish
output_lock->lock("PlaybackEngine::run");
-//printf("PlaybackEngine::run 0 %d\n", curr_command->command);
- if( curr_command->command < 0 ) continue;
-// this covers a glitch that occurs when stop is asserted
-// when the render_engine starting, but not initialized
- if( curr_command->command == STOP && render_engine )
- render_engine->interrupt_playback();
- wait_render_engine();
+ if( done ) break;
// Read the new command
- input_lock->lock("PlaybackEngine::run");
- command->copy_from(curr_command);
- curr_command->command = -1;
- input_lock->unlock();
- if( done ) break;
+ sent_lock->lock("PlaybackEngine::run");
+ int command = sent_command->command;
+ if( command >= 0 ) {
+ this->command->copy_from(sent_command);
+//printf("sent command=%d\n", sent_command->command);
+ sent_command->command = -1;
+ if( sent_command->locked )
+ input_lock->unlock();
+ }
+ sent_lock->unlock();
+ if( command < 0 ) continue;
+
+ interrupt_playback(0);
+ wait_render_engine();
+
//printf("PlaybackEngine::run 1 %d\n", command->command);
- switch( command->command ) {
+ switch( command ) {
// Parameter change only
case COMMAND_NONE:
perform_change();
int do_stop = 0, do_resume = 0;
int curr_command = this->command->command;
int curr_single_frame = TransportCommand::single_frame(curr_command);
+ int curr_direction = TransportCommand::get_direction(curr_command);
int curr_audio = this->command->toggle_audio ?
!curr_single_frame : curr_single_frame;
int single_frame = TransportCommand::single_frame(command);
+ int direction = TransportCommand::get_direction(command);
int next_audio = next_command->toggle_audio ? !single_frame : single_frame;
// Dispatch command
// Resume or change direction
switch( curr_command ) {
default:
- transport_stop(wait_tracking);
+ transport_stop(curr_direction != direction ? 1 : 0);
do_resume = 1;
// fall through
case STOP:
int PlaybackEngine::transport_stop(int wait_tracking)
{
- input_lock->lock("PlaybackEngine::transport_stop 1");
- curr_command->copy_from(stop_command);
- interrupt_playback(wait_tracking);
-//printf("send: %d (STOP)\n", STOP);
- input_lock->unlock();
+ interrupt_playback(0);
+ input_lock->lock("PlaybackEngine::transport_stop");
+ sent_lock->lock("PlaybackEngine::transport_stop");
+ sent_command->copy_from(stop_command);
+ sent_command->locked = wait_tracking ? 1 : 0;
+ if( !sent_command->locked )
+ input_lock->unlock();
+ sent_lock->unlock();
output_lock->unlock();
+ if( wait_tracking ) {
+ tracking_done->lock("PlaybackEngine::transport_stop");
+ tracking_done->unlock();
+ }
+//printf("send: %d (STOP) 0\n", STOP);
return 0;
}
int PlaybackEngine::transport_command(int command, int change_type, EDL *new_edl, int use_inout)
{
- input_lock->lock("PlaybackEngine::transport_command 1");
next_command->command = command;
next_command->change_type |= change_type;
if( new_edl ) {
next_command->set_playback_range(new_edl, use_inout,
preferences->forward_render_displacement);
}
- curr_command->copy_from(next_command);
+
+ input_lock->lock("PlaybackEngine::transport_command");
+ next_command->locked =
+ next_command->change_type == CHANGE_NONE ||
+ next_command->change_type == CHANGE_PARAMS ? 0 : 1;
+ sent_lock->lock("PlaybackEngine::transport_command");
+ sent_command->copy_from(next_command);
+ if( !sent_command->locked )
+ input_lock->unlock();
next_command->reset();
+ sent_lock->unlock();
+ output_lock->unlock();
//static const char *types[] = { "NONE",
// "FRAME_FWD", "NORMAL_FWD", "FAST_FWD", "FRAME_REV", "NORMAL_REV", "FAST_REV",
// "STOP", "PAUSE", "SLOW_FWD", "SLOW_REV", "REWIND", "GOTO_END", "CURRENT_FRAME",
// "LAST_FRAME" };
-//printf("send= %d (%s)\n", command, types[command]);
- input_lock->unlock();
- output_lock->unlock();
+//printf("send= %d (%s) %d\n", sent_command->command,
+// types[sent_command->command], sent_command->locked);
return 0;
}
EDL *new_edl=0, int use_inout=0);
Condition *input_lock, *output_lock;
-// active command
- TransportCommand *command;
-// stop, next, queued commands
- TransportCommand *stop_command, *next_command, *curr_command;
+ Mutex *sent_lock;
+// active command, stop command
+ TransportCommand *command, *stop_command;
+// next command under construction, last sent command
+ TransportCommand *next_command, *sent_command;
// Render engine
RenderEngine *render_engine;
{ NULL, 0 }
};
-KeySym KeySymMapping::to_keysym(const char *str)
+int KeySymMapping::get_mask(const char *&str)
+{
+ int mask = 0;
+ while( *str ) {
+ if( !strncmp("Shift-",str,6) ) {
+ mask |= ShiftMask;
+ str += 6; continue;
+ }
+ if( !strncmp("Ctrl-",str,5) ) {
+ mask |= ControlMask;
+ str += 5; continue;
+ }
+ else if( !strncmp("Alt-",str,4) ) {
+ mask |= Mod1Mask;
+ str += 4; continue;
+ }
+ break;
+ }
+ return mask;
+}
+
+SKeySym KeySymMapping::to_keysym(const char *str)
{
if( !strncmp("FWD_",str, 4) ) {
float speed = atof(str+4) / SHUTTLE_MAX_SPEED;
if( key_code < SKEY_MIN ) key_code = SKEY_MIN;
return key_code;
}
+ int mask = get_mask(str);
for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->str; ++ksp )
- if( !strcmp(str, ksp->str) ) return ksp->sym;
+ if( !strcmp(str, ksp->str) )
+ return SKeySym(ksp->sym, mask);
return 0;
}
-const char *KeySymMapping::to_string(KeySym ks)
+const char *KeySymMapping::to_string(SKeySym ks)
{
- for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->sym; ++ksp )
- if( ksp->sym == ks ) return ksp->str;
+ for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->sym.key; ++ksp ) {
+ if( ksp->sym.key == ks.key ) {
+ static char string[BCSTRLEN];
+ char *sp = string, *ep = sp+sizeof(string);
+ if( ks.msk & Mod1Mask ) sp += snprintf(sp, ep-sp, "Alt-");
+ if( ks.msk & ControlMask ) sp += snprintf(sp, ep-sp, "Ctrl-");
+ if( ks.msk & ShiftMask ) sp += snprintf(sp, ep-sp, "Shift-");
+ snprintf(sp, ep-sp, "%s", ksp->str);
+ return string;
+ }
+ }
if( ks >= SKEY_MIN && ks <= SKEY_MAX ) {
double speed = SHUTTLE_MAX_SPEED *
(ks-(SKEY_MAX+SKEY_MIN)/2.) / ((SKEY_MAX-SKEY_MIN)/2.);
for( int i=0; i<NUM_JOGS; ++i ) jog[i].clear();
}
-void Translation::append_stroke(KeySym sym, int press)
+void Translation::append_stroke(SKeySym sym, int press)
{
Stroke *s = pressed_strokes->append();
s->keysym = sym;
s->press = press;
}
-void Translation::add_keysym(KeySym sym, int press_release)
+void Translation::add_keysym(SKeySym sym, int press_release)
{
//printf("add_keysym(0x%x, %d)\n", (int)sym, press_release);
switch( press_release ) {
{
//printf("add_release(%d)\n", all_keys);
modifiers.release(all_keys);
- if( !all_keys ) {
+ if( !all_keys )
pressed_strokes = released_strokes;
- }
if( keysym_down ) {
append_stroke(keysym_down, 0);
keysym_down = 0;
void Translation::add_keystroke(const char *keySymName, int press_release)
{
- KeySym sym;
+ SKeySym sym;
if( is_key && !strncmp(keySymName, "RELEASE", 8) ) {
add_release(0);
fprintf(stderr, "unrecognized KeySym: %s\n", keySymName);
}
-void Translation::add_string(const char *str)
+void Translation::add_string(char *&str)
{
- while( str && *str ) {
- if( *str >= ' ' && *str <= '~' )
- add_keysym((KeySym)(*str), PRESS_RELEASE);
- ++str;
+ int delim = *str++;
+ if( !delim ) return;
+ while( str && *str && *str!=delim ) {
+ if( *str < ' ' || *str > '~' ) continue;
+ int mask = KeySymMapping::get_mask((const char *&)str);
+ if( str[0] == '\\' && str[1] ) ++str;
+ add_keysym(SKeySym(*str++, mask), PRESS_RELEASE);
+ mask = 0;
}
+ if( *str == delim ) ++str;
}
int Translation::start_line(const char *key)
void Translation::print_line(const char *key)
{
if( is_key ) {
- print_strokes(key, "D", pressed_strokes);
- print_strokes(key, "U", released_strokes);
+ print_strokes(key, "D", pressed);
+ print_strokes(key, "U", released);
}
else {
- print_strokes(key, "", pressed_strokes);
+ print_strokes(key, "", pressed);
}
printf("\n");
}
// PRESS_RELEASE -> released, but to be re-pressed if necessary
// RELEASE -> up
-void Modifiers::mark_as_down(KeySym sym, int hold)
+void Modifiers::mark_as_down(SKeySym sym, int hold)
{
Modifiers &modifiers = *this;
for( int i=0; i<size(); ++i ) {
s.press = hold ? HOLD : PRESS;
}
-void Modifiers::mark_as_up(KeySym sym)
+void Modifiers::mark_as_up(SKeySym sym)
{
Modifiers &modifiers = *this;
for( int i=0; i<size(); ++i ) {
Shuttle::Shuttle(MWindow *mwindow)
- : Thread(0, 0, 0)
+ : Thread(1, 0, 0)
{
this->mwindow = mwindow;
wx = wy = 0;
jogvalue = 0xffff;
shuttlevalue = 0xffff;
- dev_name = 0;
+ dev_index = -1;
done = -1;
failed = 0;
first_time = 1;
tr = 0;
+ debug = 0;
+ usb_direct = 0;
+
last_translation = 0;
last_focused = 0;
+#ifdef HAVE_SHUTTLE_USB
+ devsh = 0;
+ claimed = -1;
+ last_jog = 0;
+ last_shuttle = 0;
+ last_btns = 0;
+#endif
+
default_translation = new Translation(this);
config_path = 0;
config_mtime = 0;
wdw->top_level->put_event((XEvent *) b);
return 0;
}
-int Shuttle::send_keycode(unsigned int keycode, int press, int send)
+int Shuttle::send_keycode(unsigned key, unsigned msk, int press, int send)
{
if( debug ) {
const char *cp = !send ? 0 :
- KeySymMapping::to_string(keycode);
+ KeySymMapping::to_string(SKeySym(key, msk));
if( cp )
printf("key: %s %d\n", cp, press);
else
- printf("key: %04x %d\n", keycode, press);
+ printf("key: %04x/%04x %d\n", key, msk, press);
}
XKeyEvent *k = new XKeyEvent();
memset(k, 0, sizeof(*k));
k->x = wx;
k->y = wy;
k->state = msk;
- k->keycode = keycode;
+ k->keycode = key;
k->same_screen = 1;
wdw->top_level->put_event((XEvent *) k);
return 0;
}
-int Shuttle::send_keysym(KeySym keysym, int press)
+int Shuttle::send_keysym(SKeySym keysym, int press)
{
return keysym >= XK_Button_1 && keysym <= XK_Scroll_Down ?
send_button((unsigned int)keysym - XK_Button_0, press) :
- send_keycode((unsigned int)keysym, press, 1);
+ send_keycode(keysym.key, keysym.msk, press, 1);
// unsigned int keycode = XKeysymToKeycode(wdw->top_level->display, keysym);
// return send_keycode(keycode, press, 0);
}
}
}
-const char *Shuttle::probe()
+static const struct shuttle_dev {
+ const char *path;
+ unsigned vendor, product;
+} shuttle_devs[] = {
+ { "/dev/input/by-id/usb-Contour_Design_ShuttleXpress-event-if00",
+ 0x0b33, 0x0020 },
+ { "/dev/input/by-id/usb-Contour_Design_ShuttlePRO_v2-event-if00",
+ 0x0b33, 0x0030 },
+ { "/dev/input/by-id/usb-Contour_Design_ShuttlePro-event-if00",
+ 0x0b33, 0x0030 },
+};
+
+#ifdef HAVE_SHUTTLE_USB
+void Shuttle::usb_probe(int idx)
+{
+ int ret = libusb_init(0);
+ if( ret < 0 ) return;
+ claimed = 0;
+ const struct shuttle_dev *s = &shuttle_devs[idx];
+ devsh = libusb_open_device_with_vid_pid(0, s->vendor, s->product);
+ if( devsh ) {
+ int sh_iface = SHUTTLE_INTERFACE;
+ libusb_detach_kernel_driver(devsh, sh_iface);
+ ret = libusb_claim_interface(devsh, sh_iface);
+ if( ret >= 0 ) claimed = 1;
+ }
+ if( !claimed )
+ usb_done();
+}
+
+void Shuttle::usb_done()
+{
+ if( devsh ) {
+ if( claimed > 0 ) {
+ int sh_iface = SHUTTLE_INTERFACE;
+ libusb_release_interface(devsh, sh_iface);
+ libusb_attach_kernel_driver(devsh, sh_iface);
+ claimed = 0;
+ }
+ libusb_close(devsh);
+ devsh = 0;
+ }
+ if( claimed >= 0 ) {
+ libusb_exit(0);
+ claimed = -1;
+ }
+}
+#endif
+
+int Shuttle::probe()
{
struct stat st;
- static const char *shuttle_devs[] = {
- "/dev/input/by-id/usb-Contour_Design_ShuttleXpress-event-if00",
- "/dev/input/by-id/usb-Contour_Design_ShuttlePRO_v2-event-if00",
- "/dev/input/by-id/usb-Contour_Design_ShuttlePro-event-if00",
- };
int ret = sizeof(shuttle_devs) / sizeof(shuttle_devs[0]);
- while( --ret >= 0 && stat(shuttle_devs[ret] , &st) );
- return ret >= 0 ? shuttle_devs[ret] : 0;
+ while( --ret >= 0 && stat(shuttle_devs[ret].path , &st) );
+ return ret;
}
-void Shuttle::start(const char *dev_name)
+void Shuttle::start(int idx)
{
- this->dev_name = dev_name;
+ this->dev_index = idx;
first_time = 1;
done = 0;
Thread::start();
return 0;
}
-void Shuttle::handle_event()
+int Shuttle::load_translation()
{
- if( read_config_file() > 0 ) {
- done = 1;
- return;
- }
+ if( read_config_file() > 0 )
+ return done = 1;
if( get_focused_window_translation() < 0 )
- return;
+ return 0;
if( last_translation != tr ) {
last_translation = tr;
if( debug )
printf("new translation: %s\n", tr->name);
}
+ return 0;
+}
+
+void Shuttle::handle_event()
+{
+ if( load_translation() ) return;
// if( debug )
// printf("event: (%d, %d, 0x%x)\n", ev.type, ev.code, ev.value);
switch( ev.type ) {
void Shuttle::run()
{
- for( enable_cancel(); !done; sleep(1) ) {
+ if( dev_index < 0 ) return;
+ const char *dev_name = shuttle_devs[dev_index].path;
+
+#ifdef HAVE_SHUTTLE_USB
+ if( usb_direct )
+ usb_probe(dev_index);
+
+ disable_cancel();
+ while( devsh && !done ) {
+ int len = 0;
+ static const int IN_ENDPOINT = 0x81;
+ unsigned char dat[BCSTRLEN];
+ int ret = libusb_interrupt_transfer(devsh,
+ IN_ENDPOINT, dat, sizeof(dat), &len, 100);
+ if( ret != 0 ) {
+ if( ret == LIBUSB_ERROR_TIMEOUT ) continue;
+ printf("shuttle: %s\n %s\n",
+ dev_name, libusb_strerror((libusb_error)ret));
+ sleep(1); continue;
+ }
+ if( load_translation() ) break;
+ if( debug ) {
+ printf("shuttle: ");
+ for( int i=0; i<len; ++i ) printf(" %02x", dat[i]);
+ printf("\n");
+ }
+ if( last_shuttle != dat[0] )
+ shuttle((char)(last_shuttle = dat[0]));
+
+ if( last_jog != dat[1] )
+ jog(last_jog = dat[1]);
+
+ unsigned btns = (dat[4]<<8) | dat[3];
+ unsigned dif = last_btns ^ btns;
+ if( dif ) {
+ last_btns = btns;
+ for( int i=0; i<15; ++i ) {
+ unsigned msk = 1 << i;
+ if( !(dif & msk) ) continue;
+ key(i+EVENT_CODE_KEY1, btns & msk ? 1 : 0);
+ }
+ }
+ }
+ usb_done();
+#endif
+ usb_direct = 0;
+ enable_cancel();
+
+ for( ; !done; sleep(1) ) {
fd = open(dev_name, O_RDONLY);
if( fd < 0 ) {
perror(dev_name);
config_mtime = st.st_mtime;
translations.clear();
debug = 0;
+ usb_direct = 0;
#define ws(ch) (ch==' ' || ch=='\t')
char line[BCTEXTLEN], *cp;
Translation *trans = 0;
if( !strcmp(tok, "DEBUG") ) {
debug = 1; goto skip;
}
+ if( !strcmp(tok, "USB_DIRECT") ) {
+ usb_direct = 1; goto skip;
+ }
key = tok;
if( !trans ) {
fprintf(stderr, "no translation section defining key: %s\n", key);
while( ws(*cp) ) ++cp;
if( !*cp || *cp == '#' || *cp == '\n' ) break;
if( *cp == '"' ) {
- tok = ++cp;
- while( *cp && *cp != '"' && *cp != '\n' ) {
- if( *cp != '\\' ) { ++cp; continue; }
- for( char *bp=cp; *bp; ++bp ) bp[0] = bp[1];
+ while( *cp ) {
+ if( *cp == '"' )
+ trans->add_string(cp);
+ while( ws(*cp) ) ++cp;
+ if( !*cp || *cp == '#' || *cp == '\n' ) break;
+ tok = cp;
+ while( *cp && !ws(*cp) && *cp != '\n' ) ++cp;
+ *cp = 0;
+ SKeySym sym = KeySymMapping::to_keysym(tok);
+ if( !sym ) {
+ fprintf(stderr, "unknown keysym: %s\n", tok);
+ ret = 1; break;
+ }
+ trans->add_keysym(sym, PRESS_RELEASE);
}
- *cp++ = 0;
- trans->add_string(tok);
continue;
}
tok = cp;
#include <linux/input.h>
#include <sys/types.h>
+#ifdef HAVE_SHUTTLE_USB
+#include <libusb-1.0/libusb.h>
+#endif
+
// Copyright 2013 Eric Messick (FixedImagePhoto.com/Contact)
// reworked 2019 for cinelerra-gg by William Morrow (aka goodguy)
#define DELAY CurrentTime
// playback max speed -64x .. 64x
#define SHUTTLE_MAX_SPEED 64.
+#define SHUTTLE_INTERFACE 0
// protocol for events from the shuttlepro HUD device
//
#define FOCUS_VIEWER 4
#define FOCUS_LOAD 5
+class SKeySym {
+public:
+ union {
+ struct { uint32_t key, msk; };
+ uint64_t v;
+ };
+ SKeySym() { v = 0; }
+ SKeySym(int k) { key = k; msk = 0; }
+ SKeySym(unsigned k, unsigned m) { key = k; msk = m; }
+ bool operator ==(SKeySym &ks) { return ks.v == v; }
+ operator int() { return key; }
+};
+
class KeySymMapping {
public:
- static KeySym to_keysym(const char *str);
- static const char *to_string(KeySym ks);
+ static int get_mask(const char *&str);
+ static SKeySym to_keysym(const char *str);
+ static const char *to_string(SKeySym ks);
static KeySymMapping key_sym_mapping[];
+
const char *str;
- KeySym sym;
+ SKeySym sym;
};
class Stroke : public ListItem<Stroke>
{
public:
- KeySym keysym;
+ SKeySym keysym;
int press; // 1:press, 0:release
};
Strokes() {}
~Strokes() {}
void clear() { while( last ) delete last; }
- void add_stroke(KeySym keysym, int press=1) {
+ void add_stroke(SKeySym keysym, int press=1) {
Stroke *s = append();
s->keysym = keysym; s->press = press;
}
Modifiers(Translation *trans) { this->trans = trans; }
~Modifiers() {}
- void mark_as_down(KeySym sym, int hold);
- void mark_as_up(KeySym sym);
+ void mark_as_down(SKeySym sym, int hold);
+ void mark_as_up(SKeySym sym);
void release(int allkeys);
void re_press();
};
~Translation();
void init(int def);
void clear();
- void append_stroke(KeySym sym, int press);
+ void append_stroke(SKeySym sym, int press);
void add_release(int all_keys);
void add_keystroke(const char *keySymName, int press_release);
- void add_keysym(KeySym sym, int press_release);
- void add_string(const char *str);
+ void add_keysym(SKeySym sym, int press_release);
+ void add_string(char *&str);
int start_line(const char *key);
void print_strokes(const char *name, const char *up_dn, Strokes *strokes);
void print_stroke(Stroke *s);
int first_release_stroke;
Strokes *pressed, *released;
Strokes *pressed_strokes, *released_strokes;
- KeySym keysym_down;
+ SKeySym keysym_down;
Strokes key_down[NUM_KEYS];
Strokes key_up[NUM_KEYS];
{
int fd;
unsigned short jogvalue, shuttlevalue;
- const char *dev_name;
+ int dev_index;
+#ifdef HAVE_SHUTTLE_USB
+ struct libusb_device_handle *devsh;
+ void usb_probe(int idx);
+ void usb_done();
+ unsigned last_jog, last_shuttle, last_btns;
+ int claimed;
+#endif
+
Translation *default_translation;
Translations translations;
public:
~Shuttle();
int send_button(unsigned int button, int press);
- int send_keycode(unsigned int keycode, int press, int send);
- int send_keysym(KeySym keysym, int press);
+ int send_keycode(unsigned key, unsigned msk, int press, int send);
+ int send_keysym(SKeySym keysym, int press);
void send_stroke_sequence(int kjs, int index);
void key(unsigned short code, unsigned int value);
void shuttle(int value);
void jog(unsigned int value);
void jogshuttle(unsigned short code, unsigned int value);
- void start(const char *dev_name);
+ void start(int idx);
void stop();
void handle_event();
+ int load_translation();
int get_focused_window_translation();
- static const char *probe();
+ static int probe();
void run();
int read_config_file();
static BC_WindowBase *owns(BC_WindowBase *wdw, Window win);
int failed;
int first_time;
int debug;
+ int usb_direct;
MWindow *mwindow;
Translation *tr, *last_translation;
void TransportCommand::reset()
{
+ command = COMMAND_NONE;
+ change_type = 0;
playbackstart = 0;
start_position = 0;
end_position = 0;
infinite = 0;
realtime = 0;
resume = 0;
+ locked = 0;
toggle_audio = 0;
loop_play = 0;
displacement = 0;
speed = 0;
-// Don't reset the change type for commands which don't perform the change
- if(command != STOP) change_type = 0;
- command = COMMAND_NONE;
}
EDL* TransportCommand::get_edl()
this->playbackstart = command->playbackstart;
this->realtime = command->realtime;
this->resume = command->resume;
+ this->locked = command->locked;
this->toggle_audio = command->toggle_audio;
this->loop_play = command->loop_play;
this->displacement = command->displacement;
void delete_edl();
void new_edl();
- PlaybackEngine *engine;
int command;
int change_type;
// playback range
int displacement;
// Send output to device
int realtime;
+// command must execute
+ int locked;
// Use persistant starting point
int resume;
// reverse audio duty
capture_bitmap = 0;
color_model_selected = 0;
is_cleared = 0;
-
- for( int i = 0; i < SCREENCAP_BORDERS; i++ ) {
- screencap_border[i] = 0;
- }
return 0;
}
device->in_config->h,
device->in_config->screencapture_display);
//printf("VDeviceX11::open_input 2\n");
-
-// create overlay
- device->mwindow->gui->lock_window("VDeviceX11::close_all");
-
- screencap_border[0] = new BC_Popup(device->mwindow->gui,
- device->input_x - SCREENCAP_PIXELS, device->input_y - SCREENCAP_PIXELS,
- device->in_config->w + SCREENCAP_PIXELS * 2, SCREENCAP_PIXELS,
- SCREENCAP_COLOR, 1);
- screencap_border[1] = new BC_Popup(device->mwindow->gui,
- device->input_x - SCREENCAP_PIXELS, device->input_y,
- SCREENCAP_PIXELS, device->in_config->h,
- SCREENCAP_COLOR, 1);
- screencap_border[2] = new BC_Popup(device->mwindow->gui,
- device->input_x - SCREENCAP_PIXELS, device->input_y + device->in_config->h,
- device->in_config->w + SCREENCAP_PIXELS * 2, SCREENCAP_PIXELS,
- SCREENCAP_COLOR, 1);
- screencap_border[3] = new BC_Popup(device->mwindow->gui,
- device->input_x + device->in_config->w, device->input_y,
- SCREENCAP_PIXELS, device->in_config->h,
- SCREENCAP_COLOR, 1);
-usleep(500000); // avoids a bug in gnome-shell 2017/10/19
-
- for( int i=0; i<SCREENCAP_BORDERS; ++i )
- screencap_border[i]->show_window(0);
-
- device->mwindow->gui->flush();
- device->mwindow->gui->unlock_window();
+ capture_bitmap->bars_on(SCREENCAP_PIXELS, SCREENCAP_COLOR,
+ device->input_x, device->input_y,
+ device->in_config->w, device->in_config->h);
return 0;
}
output->unlock_canvas();
}
- if( device->mwindow ) {
- device->mwindow->gui->lock_window("VDeviceX11::close_all");
- for( int i=0; i<SCREENCAP_BORDERS; ++i ) {
- delete screencap_border[i];
- screencap_border[i] = 0;
- }
- device->mwindow->gui->unlock_window();
- }
-
reset_parameters();
return 0;
int VDeviceX11::read_buffer(VFrame *frame)
{
-//printf("VDeviceX11::read_buffer %d colormodel=%d\n", __LINE__, frame->get_color_model());
- device->mwindow->gui->lock_window("VDeviceX11::close_all");
-
- screencap_border[0]->reposition_window(device->input_x - SCREENCAP_PIXELS,
- device->input_y - SCREENCAP_PIXELS);
- screencap_border[1]->reposition_window(device->input_x - SCREENCAP_PIXELS,
- device->input_y);
- screencap_border[2]->reposition_window(device->input_x - SCREENCAP_PIXELS,
- device->input_y + device->in_config->h);
- screencap_border[3]->reposition_window(device->input_x + device->in_config->w,
- device->input_y);
- device->mwindow->gui->flush();
- device->mwindow->gui->unlock_window();
-
+ capture_bitmap->bars_reposition(
+ device->input_x, device->input_y,
+ device->in_config->w, device->in_config->h);
capture_bitmap->capture_frame(frame,
device->input_x, device->input_y, device->do_cursor);
int get_display_colormodel(int file_colormodel);
// windows which overlay the screencap area
-#define SCREENCAP_BORDERS 4
#define SCREENCAP_PIXELS 5
#define SCREENCAP_COLOR GREEN
- BC_Popup *screencap_border[SCREENCAP_BORDERS];
// Bitmap to be written to device
BC_Bitmap *bitmap;
void ZWindow::change_source(EDL *edl)
{
- if( this->edl && edl != this->edl )
+ if( this->edl == edl ) return;
+ if( !edl || !this->edl || this->edl->equivalent_output(edl) >= 0 )
+ zgui->playback_engine->refresh_frame(CHANGE_ALL, edl);
+ if( this->edl )
this->edl->remove_user();
this->edl = edl;
- if( edl != 0 ) {
- zgui->playback_engine->refresh_frame(CHANGE_ALL, edl);
- }
}
void ZWindow::stop_playback(int wait)
CHECK_WITH([commercial],[enable commercial capture],[COMMERCIAL],[yes])
CHECK_WITH([thirdparty],[use thirdparty build],[CIN_3RDPARTY],[yes])
CHECK_WITH([shuttle],[shuttle device],[SHUTTLE],[yes])
+CHECK_WITH([shuttle-usb],[use libusb for shuttle],[SHUTTLE_USB],[no])
if test "x$WANT_LV2" != "xno"; then
GTK2_LIBS=`pkg-config --libs gtk+-2.0`
fi
for v in GL XFT XXF86VM OSS ALSA FIREWIRE DV DVB \
VIDEO4LINUX2 ESOUND PACTL OPENEXR LV2 \
- COMMERCIAL LIBZMPEG SHUTTLE; do
+ COMMERCIAL LIBZMPEG SHUTTLE SHUTTLE_USB; do
eval vv="\$WANT_$v"
if test "x$vv" != "xno"; then
CFG_CFLAGS+=" -DHAVE_$v"
echo " using: with-libzmpeg = $WANT_LIBZMPEG"
echo " using: with-commerical = $WANT_COMMERCIAL"
echo " using: with-shuttle = $WANT_SHUTTLE"
+echo " using: with-shuttle-usb = $WANT_SHUTTLE_USB"
echo ""
echo " using: thirdparty build = $WANT_CIN_3RDPARTY"
echo " using: single-user = $WANT_CINBIN_BUILD"
if test "x$WANT_BOOBY" != "xno"; then
CFG_CFLAGS+=" -DBOOBY"
fi
+if test "x$WANT_SHUTTLE_USB" != "xno"; then
+ EXTRA_LIBS+=' -lusb-1.0'
+fi
# intel lock elision bugs
if test "x$WANT_NOELISION" != "xno"; then
ATTRS{name}=="Contour Design ShuttlePRO v2" MODE="0644"
ATTRS{name}=="Contour Design ShuttleXpress" MODE="0644"
ATTRS{name}=="Contour Design ShuttlePro" MODE="0644"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="0b33", ATTRS{idProduct}=="0020", MODE="0666"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="0b33", ATTRS{idProduct}=="0030", MODE="0666"
data = 0;
use_shm = 1;
+ for( int i=0; i<4; ++i ) border[i] = 0;
+ bar_w = 0; bar_color = 0;
init_window(display_path);
allocate_data();
}
-
BC_Capture::~BC_Capture()
{
+ bars_off();
delete_data();
XCloseDisplay(display);
}
+
int BC_Capture::init_window(const char *display_path)
{
int bits_per_pixel;
if( display_path && display_path[0] == 0 ) display_path = NULL;
if( (display = XOpenDisplay(display_path)) == NULL ) {
- printf(_("cannot connect to X server.\n"));
- if( getenv("DISPLAY") == NULL )
- printf(_("'DISPLAY' environment variable not set.\n"));
- exit(-1);
+ printf(_("cannot connect to X server.\n"));
+ if( getenv("DISPLAY") == NULL )
+ printf(_("'DISPLAY' environment variable not set.\n"));
+ exit(-1);
return 1;
}
server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
char *data = 0;
XImage *ximage;
- ximage = XCreateImage(display,
- vis,
- default_depth,
- ZPixmap,
- 0,
- data,
- 16,
- 16,
- 8,
- 0);
+ ximage = XCreateImage(display, vis, default_depth,
+ ZPixmap, 0, data, 16, 16, 8, 0);
bits_per_pixel = ximage->bits_per_pixel;
XDestroyImage(ximage);
bitmap_color_model = BC_WindowBase::evaluate_color_model(client_byte_order, server_byte_order, bits_per_pixel);
// test shared memory
// This doesn't ensure the X Server is on the local host
- if( use_shm && !XShmQueryExtension(display) ) {
- use_shm = 0;
- }
+ if( use_shm && !XShmQueryExtension(display) )
+ use_shm = 0;
return 0;
}
+Window BC_Capture::bar(int x, int y, int w, int h, int color)
+{
+ unsigned long mask = CWEventMask | CWBackPixel |
+ CWOverrideRedirect | CWSaveUnder;
+ XSetWindowAttributes attr;
+ memset(&attr, 0, sizeof(attr));
+ Screen *scr = XDefaultScreenOfDisplay(display);
+ Window root = RootWindowOfScreen(scr);
+ Visual *vis = DefaultVisualOfScreen(scr);
+ int depth = DefaultDepthOfScreen(scr);
+ attr.background_pixel = color;
+ attr.override_redirect = True;
+ attr.save_under = True;
+ Window win = XCreateWindow(display, root, x,y,w,h, 0,depth,
+ InputOutput, vis, mask, &attr);
+ XMapWindow(display, win);
+ return win;
+}
+
+void BC_Capture::bars_on(int bw, int color, int x, int y, int w, int h)
+{
+ this->bar_w = bw;
+ this->bar_color = color;
+ border[0] = bar(x-bw, y-bw, w+2*bw, bw, color);
+ border[1] = bar(x-bw, y, bw, h, color);
+ border[2] = bar(x-bw, y+h, w+2*bw, bw, color);
+ border[3] = bar(x+w, y, bw, h, color);
+ XFlush(display);
+}
+
+void BC_Capture::bars_off()
+{
+ for( int i=0; i<4; ++i ) {
+ if( !border[i] ) continue;
+ XUnmapWindow(display, border[i]);
+ }
+ for( int i=0; i<4; ++i ) {
+ if( !border[i] ) continue;
+ XDestroyWindow(display, border[i]);
+ border[i] = 0;
+ }
+ XFlush(display);
+}
+
+void BC_Capture::bars_reposition(int x, int y, int w, int h)
+{
+ int bw = this->bar_w;
+ if( border[0] )
+ XMoveResizeWindow(display, border[0], x-bw, y-bw, w+2*bw, bw);
+ if( border[1] )
+ XMoveResizeWindow(display, border[1], x-bw, y, bw, h );
+ if( border[2] )
+ XMoveResizeWindow(display, border[2], x-bw, y+h, w+2*bw, bw);
+ if( border[3] )
+ XMoveResizeWindow(display, border[3], x+w, y, bw, h );
+}
int BC_Capture::allocate_data()
{
// try shared memory
if( !display ) return 1;
- if( use_shm ) {
- ximage = XShmCreateImage(display, vis, default_depth, ZPixmap, (char*)NULL, &shm_info, w, h);
+ if( use_shm ) {
+ ximage = XShmCreateImage(display, vis, default_depth, ZPixmap, (char*)NULL, &shm_info, w, h);
shm_info.shmid = shmget(IPC_PRIVATE, h * ximage->bytes_per_line, IPC_CREAT | 0600);
if( shm_info.shmid == -1 ) {
// Crashes here if remote server.
BC_Resources::error = 0;
XShmAttach(display, &shm_info);
- XSync(display, False);
+ XSync(display, False);
if( BC_Resources::error ) {
XDestroyImage(ximage);
shmdt(shm_info.shmaddr);
int get_w();
int get_h();
+ Window border[4];
+ int bar_w, bar_color;
+ Window bar(int x, int y, int w, int h, int color);
+ void bars_on(int bw, int color, int x, int y, int w, int h);
+ void bars_off();
+ void bars_reposition(int x, int y, int w, int h);
+
int w, h, default_depth;
unsigned char **row_data;
TitleFont::TitleFont(TitleMain *client, TitleWindow *window, int x, int y)
: BC_PopupTextBox(window, &window->fonts, client->config.font,
- x, y, 300, 300, LISTBOX_ICON_LIST)
+ x, y, 340, 300, LISTBOX_ICON_LIST)
{
this->client = client;
this->window = window;
# uncomment to enable diagnostics
#DEBUG
+# uncommet to use direct usb
+#USB_DIRECT
# redefine default, use
# also used for resources,load windows
[Cinelerra]
- K5 XK_KP_0 # Stop
- K9 XK_KP_3 # Play
+# Most useful functions have to be on K5-K9 because Xpress only has 5 keys
+ K5 XK_Home # Beginning
+ K6 XK_KP_3 # Play, or if playing Stop
+ K7 XK_KP_0 # Stop
+ K8 XK_KP_6 # Reverse, or if playing Stop
+ K9 XK_End # End
+
+# K10 "[" # Switch if K14 not working
+# K11 "]" # Switch if K15 not working
+ K10 Alt-XK_Left
+ K11 Alt-XK_Right
K12 XK_Home # Beginning
K13 XK_End # End
K14 "[" # Toggle in
K15 "]" # Toggle out
- K1 "i" # Pro Only - Clip
- K2 "x" # Pro Only - Cut
- K3 "c" # Pro Only - Copy
- K4 "v" # Pro Only - Paste
+ K1 "i" # Clip
+ K2 "x" # Cut
+ K3 "c" # Copy
+ K4 "v" # Paste
S-7 REV_16 # Next 6 are reverse keys
S-6 REV_8 # the number on the end represents speed
S5 FWD_4
S6 FWD_8
S7 FWD_16
-
+
JL XK_KP_4 # Frame reverse
JR XK_KP_1 # Frame forward
[Composer]
- K5 XK_KP_0 # Stop
- K9 XK_KP_3 # Play
+# Most useful functions have to be on K5-K9 because Xpress only has 5 keys
+ K5 XK_Home # Beginning
+ K6 XK_KP_3 # Play, or if playing Stop
+ K7 "f" # Go in or out of Fullscreen mode
+ K8 XK_KP_6 # Reverse, of if playing Stop
+ K9 XK_End # End
+
+ K10 "[" # Temporary until K14 Pro fixed
+ K11 "]" # Temporary until K15 Pro fixed
K12 XK_Home # Beginning
K13 XK_End # End
K14 "[" # Toggle in
K15 "]" # Toggle out
- K1 "i" # Pro Only - Clip
- K2 "x" # Pro Only - Cut
- K3 "c" # Pro Only - Copy
- K4 "v" # Pro Only - Paste
+ K1 "i" # Clip
+ K2 "x" # Cut
+ K3 "c" # Copy
+ K4 "v" # Paste
S-7 REV_16
S-6 REV_8
S5 FWD_4
S6 FWD_8
S7 FWD_16
-
+
JL XK_KP_4 # Frame reverse
JR XK_KP_1 # Frame forward
[Viewer]
- K5 "v" # Splice (Viewer only - button is on Xpress)
- K9 "b" # Overwrite (Viewer only - button is on Xpress)
+# Most useful functions have to be on K6-K9 because Xpress only has 5 keys
+ K5 XK_Home # Beginning
+ K6 XK_KP_3 # Play, or if playing Stop
+ K7 "f" # Go in or out of Fullscreen mode
+ K8 XK_KP_6 # Reverse, or if playing Stop
+ K9 XK_End # End
+
+ K10 "[" # Temporary until K14 Pro fixed
+ K11 "]" # Temporary until K15 Pro fixed
K12 XK_Home # Beginning
K13 XK_End # End
K14 "[" # Toggle in
K15 "]" # Toggle out
- K1 "i" # Pro Only - Clip
- K2 XK_Home # Pro Only - Beginning
- K3 "c" # Pro Only - Copy
- K4 XK_End # Pro Only - End
-
+ K1 "i" # Clip
+ K2 "v" # Splice
+ K3 "c" # Copy
+ K4 "b" # Overwrite
+
S-7 REV_16
S-6 REV_8
S-5 REV_4