From: Good Guy Date: Tue, 29 Jan 2019 19:39:37 +0000 (-0700) Subject: add shuttle dev support, use dflt ff_a/v.png icons, mjpegtools typo patch X-Git-Tag: 2019-08~117 X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=commitdiff_plain;h=2a56d102d9db53017b306f2a61a2382f29a75783 add shuttle dev support, use dflt ff_a/v.png icons, mjpegtools typo patch --- diff --git a/cinelerra-5.1/Makefile.am b/cinelerra-5.1/Makefile.am index a61379cf..603f285e 100644 --- a/cinelerra-5.1/Makefile.am +++ b/cinelerra-5.1/Makefile.am @@ -33,7 +33,7 @@ export mkinstalldirs install_sh inst_sh # install to bin bin_install: install-recursive cp -a COPYING README models Cinelerra_factory expanders.txt \ - ffmpeg msg info tips lv2_blacklist.txt bin/. + shuttlerc ffmpeg msg info tips lv2_blacklist.txt bin/. sed -e 's/\/$(WANT_CIN)/g' < image/cin.desktop \ > "bin/applications/$(WANT_CIN).desktop" cp -a image/cin.svg "bin/pixmaps/$(WANT_CIN)".svg @@ -53,7 +53,7 @@ sys_install: $(CIN_INSTALLS) cd bin; $(inst_sh) "$(DESTDIR)$(bindir)" "$(WANT_CIN)" bdwrite cd bin; $(inst_sh) "$(DESTDIR)$(datadir)/$(WANT_CIN)" \ COPYING README models Cinelerra_factory expanders.txt \ - ffmpeg msg info tips doc + shuttlerc ffmpeg msg info tips doc cd bin/locale; $(inst_sh) "$(DESTDIR)$(localedir)" . cd bin/plugins; $(inst_sh) "$(DESTDIR)$(WANT_PLUGIN_DIR)" . cd bin/applications; $(inst_sh) "$(DESTDIR)$(datadir)/applications" . diff --git a/cinelerra-5.1/cinelerra/Makefile b/cinelerra-5.1/cinelerra/Makefile index 43c66e8f..4c08bbf0 100644 --- a/cinelerra-5.1/cinelerra/Makefile +++ b/cinelerra-5.1/cinelerra/Makefile @@ -271,6 +271,7 @@ OBJS := \ $(OBJDIR)/sharedlocation.o \ $(OBJDIR)/shbtnprefs.o \ $(OBJDIR)/shmemory.o \ + $(OBJDIR)/shuttle.o \ $(OBJDIR)/sighandler.o \ $(OBJDIR)/signalstatus.o \ $(OBJDIR)/splashgui.o \ @@ -582,6 +583,11 @@ $(OBJDIR)/lv2ui.o: lv2ui.C $(OBJDIR)/pluginlv2ui.o $(OBJDIR)/lv2ui.o: $(CXX) `cat $(OBJDIR)/c_flags` $(GTK2_INCS) -DMSGQUAL=$* -c $< -o $@ +$(OBJDIR)/shuttle.o: shuttle.C shuttle_keys.h + $(CXX) `cat $(OBJDIR)/c_flags` -DMSGQUAL=$* -c $< -o $@ +shuttle_keys.h: /usr/include/X11/keysymdef.h + sed < /usr/include/X11/keysymdef.h > shuttle_keys.h -f shuttle.sed + $(OBJDIR)/lv2ui: $(LV2OBJS) @echo $(CXX) \`cat $(OBJDIR)/c_flags\` $^ -o $@ @$(CXX) `cat $(OBJDIR)/c_flags` $^ -o $@ $(LIBS) $(GTK2_LIBS) diff --git a/cinelerra-5.1/cinelerra/awindowgui.C b/cinelerra-5.1/cinelerra/awindowgui.C index a5e4007c..2597f52e 100644 --- a/cinelerra-5.1/cinelerra/awindowgui.C +++ b/cinelerra-5.1/cinelerra/awindowgui.C @@ -1213,14 +1213,6 @@ AWindowGUI::AWindowGUI(MWindow *mwindow, AWindow *awindow) video_vframe = 0; video_icon = 0; label_vframe = 0; label_icon = 0; - atransition_vframe = 0; atransition_icon = 0; - vtransition_vframe = 0; vtransition_icon = 0; - aeffect_vframe = 0; aeffect_icon = 0; - ladspa_vframe = 0; ladspa_icon = 0; - veffect_vframe = 0; veffect_icon = 0; - ff_aud_vframe = 0; ff_aud_icon = 0; - ff_vid_vframe = 0; ff_vid_icon = 0; - aeffect_folder_vframe = 0; aeffect_folder_icon = 0; atransition_folder_vframe = 0; atransition_folder_icon = 0; clip_folder_vframe = 0; clip_folder_icon = 0; diff --git a/cinelerra-5.1/cinelerra/loadfile.C b/cinelerra-5.1/cinelerra/loadfile.C index 2ec06fb4..345456d9 100644 --- a/cinelerra-5.1/cinelerra/loadfile.C +++ b/cinelerra-5.1/cinelerra/loadfile.C @@ -47,6 +47,7 @@ Load::Load(MWindow *mwindow, MainMenu *mainmenu) { this->mwindow = mwindow; this->mainmenu = mainmenu; + this->thread = 0; } Load::~Load() @@ -77,6 +78,7 @@ LoadFileThread::LoadFileThread(MWindow *mwindow, Load *load) { this->mwindow = mwindow; this->load = load; + this->window = 0; } LoadFileThread::~LoadFileThread() diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index 9ad32f61..af743cc7 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -102,6 +102,7 @@ #include "savefile.inc" #include "samplescroll.h" #include "sha1.h" +#include "shuttle.h" #include "sighandler.h" #include "splashgui.h" #include "statusbar.h" @@ -237,6 +238,7 @@ MWindow::MWindow() in_destructor = 0; speed_edl = 0; proxy_beep = 0; + shuttle = 0; } @@ -254,6 +256,7 @@ MWindow::~MWindow() delete proxy_beep; delete create_bd; create_bd = 0; delete create_dvd; create_dvd = 0; + delete shuttle; shuttle = 0; delete batch_render; batch_render = 0; delete render; render = 0; commit_commercial(); @@ -1582,6 +1585,17 @@ void MWindow::init_exportedl() exportedl = new ExportEDL(this); } +void MWindow::init_shuttle() +{ +#ifdef HAVE_SHUTTLE + const char *dev_name = Shuttle::probe(); + if( dev_name ) { + shuttle = new Shuttle(this); + shuttle->start(dev_name); + } +#endif +} + void MWindow::init_brender() { if(preferences->use_brender && !brender) @@ -2620,6 +2634,7 @@ void MWindow::create_objects(int want_gui, init_render(); if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference()); + init_shuttle(); init_brender(); init_exportedl(); init_commercials(); diff --git a/cinelerra-5.1/cinelerra/mwindow.h b/cinelerra-5.1/cinelerra/mwindow.h index ce85ca9f..7950659b 100644 --- a/cinelerra-5.1/cinelerra/mwindow.h +++ b/cinelerra-5.1/cinelerra/mwindow.h @@ -82,6 +82,7 @@ #include "sharedlocation.inc" #include "sighandler.inc" #include "splashgui.inc" +#include "shuttle.inc" #include "theme.inc" #include "thread.h" #include "threadloader.inc" @@ -706,6 +707,7 @@ public: void init_preferences(); void init_signals(); + void init_shuttle(); void init_theme(); void init_compositor(); void init_levelwindow(); @@ -730,6 +732,7 @@ public: int restart_status; int screens; int in_destructor; + Shuttle *shuttle; }; #endif diff --git a/cinelerra-5.1/cinelerra/shuttle.C b/cinelerra-5.1/cinelerra/shuttle.C new file mode 100644 index 00000000..627f162a --- /dev/null +++ b/cinelerra-5.1/cinelerra/shuttle.C @@ -0,0 +1,898 @@ +#ifdef HAVE_SHUTTLE +// Copyright 2013 Eric Messick (FixedImagePhoto.com/Contact) +// reworked 2019 for cinelerra-gg by William Morrow + +// keys.h collides with linux/input_events.h +#define KEYS_H + +#include "arraylist.h" +#include "cstrdup.h" +#include "file.h" +#include "guicast.h" +#include "linklist.h" +#include "loadfile.h" +#include "mainmenu.h" +#include "mwindow.h" +#include "shuttle.h" +#include "thread.h" + +#include +#include +#include + +#include +#include + +static Time milliTimeClock() +{ + struct timeval tv; + gettimeofday(&tv, 0); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} + +KeySymMapping KeySymMapping::key_sym_mapping[] = { + { "XK_Button_1", XK_Button_1 }, + { "XK_Button_2", XK_Button_2 }, + { "XK_Button_3", XK_Button_3 }, + { "XK_Scroll_Up", XK_Scroll_Up }, + { "XK_Scroll_Down", XK_Scroll_Down }, +#include "shuttle_keys.h" + { NULL, 0 } +}; + +KeySym KeySymMapping::to_keysym(const char *str) +{ + for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->str; ++ksp ) + if( !strcmp(str, ksp->str) ) return ksp->sym; + return 0; +} + +const char *KeySymMapping::to_string(KeySym ks) +{ + for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->sym; ++ksp ) + if( ksp->sym == ks ) return ksp->str; + return 0; +} + +TransName::TransName(int cin, const char *nm, const char *re) +{ + this->cin = cin; + this->name = cstrdup(nm); + this->err = regcomp(&this->regex, re, REG_NOSUB); + if( err ) { + fprintf(stderr, "error compiling regex for [%s]: %s\n", name, re); + char emsg[BCTEXTLEN]; + regerror(err, ®ex, emsg, sizeof(emsg)); + fprintf(stderr, "regerror: %s\n", emsg); + } +} +TransName::~TransName() +{ + delete [] name; + regfree(®ex); +} + +void Translation::init(int def) +{ + is_default = def; + is_key = 0; + first_release_stroke = 0; + pressed = 0; + released = 0; + keysym_down = 0; +} + +Translation::Translation(Shuttle *shuttle) + : modifiers(this) +{ // initial default translation + init(1); + this->shuttle = shuttle; + this->name = cstrdup("Default"); + names.append(new TransName(FOCUS_DEFAULT, name, "")); + key_down[K6].add_stroke(XK_Button_1, 1); + key_up[K6].add_stroke(XK_Button_1, 0); + key_down[K7].add_stroke(XK_Button_2, 1); + key_up[K7].add_stroke(XK_Button_2, 0); + key_down[K8].add_stroke(XK_Button_3, 1); + key_up[K8].add_stroke(XK_Button_3, 0); + jog[JL].add_stroke(XK_Scroll_Up, 1); + jog[JL].add_stroke(XK_Scroll_Up, 0); + jog[JR].add_stroke(XK_Scroll_Down, 0); + jog[JR].add_stroke(XK_Scroll_Down, 1); +} + +Translation::Translation(Shuttle *shuttle, const char *name) + : modifiers(this) +{ + init(0); + this->shuttle = shuttle; + this->name = cstrdup(name); +} + +Translation::~Translation() +{ + delete [] name; +} + +void Translation::clear() +{ + names.remove_all_objects(); + init(0); + for( int i=0; iappend(); + s->keysym = sym; + s->press = press; +} + +void Translation::add_keysym(KeySym sym, int press_release) +{ +//printf("add_keysym(0x%x, %d)\n", (int)sym, press_release); + switch( press_release ) { + case PRESS: + append_stroke(sym, 1); + modifiers.mark_as_down(sym, 0); + break; + case RELEASE: + append_stroke(sym, 0); + modifiers.mark_as_up(sym); + break; + case HOLD: + append_stroke(sym, 1); + modifiers.mark_as_down(sym, 1); + break; + case PRESS_RELEASE: + default: + if( first_release_stroke ) { + modifiers.re_press(); + first_release_stroke = 0; + } + if( keysym_down ) { + append_stroke(keysym_down, 0); + } + append_stroke(sym, 1); + keysym_down = sym; + break; + } +} + +void Translation::add_release(int all_keys) +{ +//printf("add_release(%d)\n", all_keys); + modifiers.release(all_keys); + if( !all_keys ) { + pressed_strokes = released_strokes; + } + if( keysym_down ) { + append_stroke(keysym_down, 0); + keysym_down = 0; + } + first_release_stroke = 1; +} + +void Translation::add_keystroke(const char *keySymName, int press_release) +{ + KeySym sym; + + if( is_key && !strncmp(keySymName, "RELEASE", 8) ) { + add_release(0); + return; + } + sym = KeySymMapping::to_keysym(keySymName); + if( sym != 0 ) { + add_keysym(sym, press_release); + } + else + fprintf(stderr, "unrecognized KeySym: %s\n", keySymName); +} + +void Translation::add_string(const char *str) +{ + while( str && *str ) { + if( *str >= ' ' && *str <= '~' ) + add_keysym((KeySym)(*str), PRESS_RELEASE); + ++str; + } +} + +int Translation::start_line(const char *key) +{ + pressed_strokes = 0; + released_strokes = 0; + pressed = released = 0; + is_key = 0; + if( !strcasecmp("JL", key) ) { + pressed = &jog[0]; + } + else if( !strcasecmp("JR", key) ) { + pressed = &jog[1]; + } + else { + char c = 0; int k = -1, n = 0; + if( sscanf(key, "%c%d%n", &c, &k, &n) != 2 ) return 1; + switch( c ) { + case 'K': case 'k': + --k; + if( k >= K1 && k <= K15 ) { + pressed = &key_down[k]; + released = &key_up[k]; + is_key = 1; + } + break; + case 'S': case 's': + if( k >= S_7 && k <= S7 ) { + pressed = &shuttles[k-S_7]; + } + break; + } + if( !pressed ) { + fprintf(stderr, "bad key name: [%s]%s\n", name, key); + return 1; + } + if( pressed->first ) { + fprintf(stderr, "dupl key name: [%s]%s\n", name, key); + return 1; + } + } + pressed_strokes = pressed; + released_strokes = released; + return 0; +} + +void Translation::print_stroke(Stroke *s) +{ + if( !s ) return; + const char *cp = KeySymMapping::to_string(s->keysym); + if( !cp ) { printf("0x%x", (int)s->keysym); cp = "???"; } + printf("%s/%c ", cp, s->press ? 'D' : 'U'); +} + +void Translation::print_strokes(const char *name, const char *up_dn, Strokes *strokes) +{ + printf("%s[%s]: ", name, up_dn); + for( Stroke *s=strokes->first; s; s=s->next ) + print_stroke(s); + printf("\n"); +} + +void Translation::finish_line() +{ +//printf("finish_line()\n"); + if( is_key ) { + add_release(0); + } + add_release(1); +} + +void Translation::print_line(const char *key) +{ + if( is_key ) { + print_strokes(key, "D", pressed_strokes); + print_strokes(key, "U", released_strokes); + } + else { + print_strokes(key, "", pressed_strokes); + } + printf("\n"); +} + +// press values in Modifiers: +// PRESS -> down +// HOLD -> held +// PRESS_RELEASE -> released, but to be re-pressed if necessary +// RELEASE -> up + +void Modifiers::mark_as_down(KeySym sym, int hold) +{ + Modifiers &modifiers = *this; + for( int i=0; iappend_stroke(s.keysym, 0); + s.press = PRESS_RELEASE; + } + else if( allkeys && s.press == HOLD ) { + trans->append_stroke(s.keysym, 0); + s.press = RELEASE; + } + } +} + +void Modifiers::re_press() +{ + Modifiers &modifiers = *this; + for( int i=0; iappend_stroke(s.keysym, 1); + s.press = PRESS; + } + } +} + + +Shuttle::Shuttle(MWindow *mwindow) + : Thread(0, 0, 0) +{ + this->mwindow = mwindow; + + fd = -1; + wdw = 0; + win = 0; + msk = 0; + rx = ry = 0; + wx = wy = 0; + jogvalue = 0xffff; + shuttlevalue = 0xffff; + last_shuttle.tv_sec = 0; + last_shuttle.tv_usec = 0; + need_synthetic_shuttle = 0; + dev_name = 0; + + done = -1; + failed = 0; + first_time = 1; + tr = 0; + last_translation = 0; + last_focused = 0; + + default_translation = new Translation(this); + config_path = 0; + config_mtime = 0; + ev.type = ~0; +} + +Shuttle::~Shuttle() +{ + stop(); + delete default_translation; + delete [] config_path; +} + +int Shuttle::send_button(unsigned int button, int press) +{ + if( debug ) + printf("btn: %u %d\n", button, press); + XButtonEvent *b = new XButtonEvent(); + memset(b, 0, sizeof(*b)); + b->type = press ? ButtonPress : ButtonRelease; + b->time = milliTimeClock(); + b->display = wdw->top_level->display; + b->root = wdw->top_level->rootwin; + b->window = win; + b->x_root = rx; + b->y_root = ry; + b->x = wx; + b->y = wy; + b->state = msk; + b->button = button; + b->same_screen = 1; + wdw->top_level->put_event((XEvent *) b); + return 0; +} +int Shuttle::send_key(KeySym keysym, int press) +{ + KeyCode keycode = XKeysymToKeycode(wdw->top_level->display, keysym); + if( debug ) + printf("key: %04x %d\n", (unsigned)keycode, press); + XKeyEvent *k = new XKeyEvent(); + memset(k, 0, sizeof(*k)); + k->type = press ? KeyPress : KeyRelease; + k->time = milliTimeClock(); + k->display = wdw->top_level->display; + k->root = wdw->top_level->rootwin; + k->window = win; + k->x_root = rx; + k->y_root = ry; + k->x = wx; + k->y = wy; + k->state = msk; + k->keycode = keycode; + k->same_screen = 1; + wdw->top_level->put_event((XEvent *) k); + return 0; +} + +int Shuttle::send_keysym(KeySym keysym, int press) +{ + return keysym >= XK_Button_1 && keysym <= XK_Scroll_Down ? + send_button((unsigned int)keysym - XK_Button_0, press) : + send_key(keysym, press ? True : False); +} + + +static Stroke *fetch_stroke(Translation *translation, int kjs, int index) +{ + Stroke *ret = 0; + if( translation ) { + switch( kjs ) { + default: + case KJS_KEY_DOWN: ret = translation->key_down[index].first; break; + case KJS_KEY_UP: ret = translation->key_up[index].first; break; + case KJS_JOG: ret = translation->jog[index].first; break; + case KJS_SHUTTLE: ret = translation->shuttles[index].first; break; + } + } + return ret; +} + +void Shuttle::send_stroke_sequence(int kjs, int index) +{ + if( !wdw ) return; + Stroke *s = fetch_stroke(tr, kjs, index); + if( !s ) s = fetch_stroke(default_translation, kjs, index); + while( s ) { + send_keysym(s->keysym, s->press); + s = s->next; + } +} + +void Shuttle::key(unsigned short code, unsigned int value) +{ + code -= EVENT_CODE_KEY1; + if( code >= NUM_KEYS ) { + fprintf(stderr, "key(%d, %d) out of range\n", code + EVENT_CODE_KEY1, value); + return; + } + send_stroke_sequence(value ? KJS_KEY_DOWN : KJS_KEY_UP, code); +} + + +void Shuttle:: shuttle(int value) +{ + if( value < S_7 || value > S7 ) { + fprintf(stderr, "shuttle(%d) out of range\n", value); + return; + } + gettimeofday(&last_shuttle, 0); + need_synthetic_shuttle = value != 0; + if( value != shuttlevalue ) { + shuttlevalue = value; + send_stroke_sequence(KJS_SHUTTLE, value+7); + } +} + +// Due to a bug (?) in the way Linux HID handles the ShuttlePro, the +// center position is not reported for the shuttle wheel. Instead, +// a jog event is generated immediately when it returns. We check to +// see if the time since the last shuttle was more than a few ms ago +// and generate a shuttle of 0 if so. +// +// Note, this fails if jogvalue happens to be 0, as we don't see that +// event either! +void Shuttle::jog(unsigned int value) +{ + int direction; + struct timeval now; + struct timeval delta; + + // We should generate a synthetic event for the shuttle going + // to the home position if we have not seen one recently + if( need_synthetic_shuttle ) { + gettimeofday( &now, 0 ); + timersub( &now, &last_shuttle, &delta ); + + if( delta.tv_sec >= 1 || delta.tv_usec >= 5000 ) { + shuttle(0); + need_synthetic_shuttle = 0; + } + } + + if( jogvalue != 0xffff ) { + value = value & 0xff; + direction = ((value - jogvalue) & 0x80) ? -1 : 1; + while( jogvalue != value ) { + // driver fails to send an event when jogvalue == 0 + if( jogvalue != 0 ) { + send_stroke_sequence(KJS_JOG, direction > 0 ? 1 : 0); + } + jogvalue = (jogvalue + direction) & 0xff; + } + } + jogvalue = value; +} + +void Shuttle::jogshuttle(unsigned short code, unsigned int value) +{ + switch( code ) { + case EVENT_CODE_JOG: + jog(value); + break; + case EVENT_CODE_SHUTTLE: + shuttle(value); + break; + default: + fprintf(stderr, "jogshuttle(%d, %d) invalid code\n", code, value); + break; + } +} + +const char *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", + }; + int ret = sizeof(shuttle_devs) / sizeof(shuttle_devs[0]); + while( --ret >= 0 && stat(shuttle_devs[ret] , &st) ); + return ret >= 0 ? shuttle_devs[ret] : 0; +} + +void Shuttle::start(const char *dev_name) +{ + this->dev_name = dev_name; + first_time = 1; + done = 0; + Thread::start(); +} + +void Shuttle::stop() +{ + if( running() && !done ) { + done = 1; + cancel(); + join(); + } +} + + +int Shuttle::get_focused_window_translation() +{ + MWindowGUI *gui = mwindow->gui; + Display *dpy = gui->display; + Window focus = 0; + int ret = 0, revert = 0; + char win_title[BCTEXTLEN]; + gui->lock_window("Shuttle::get_focused_window_translation"); + XGetInputFocus(dpy, &focus, &revert); + if( last_focused != focus ) { + last_focused = focus; + Atom prop = XInternAtom(dpy, "WM_NAME", False); + Atom type; int form; + unsigned long remain, len; + unsigned char *list; + if( XGetWindowProperty(dpy, focus, prop, 0, sizeof(win_title)-1, False, + AnyPropertyType, &type, &form, &len, &remain, &list) == Success ) { + len = len*(form/8) - remain; + memcpy(win_title, list, len); + win_title[len] = 0; + XFree(list); + if( debug ) + printf("new focus: %08x\n", (unsigned)focus); + } + else { + last_focused = 0; + fprintf(stderr, "XGetWindowProperty failed for window 0x%x\n", + (int)focus); + ret = 1; + } + } + gui->unlock_window(); + if( ret ) return -1; + + this->wdw = 0; this->win = 0; + this->wx = 0; this->wy = 0; + this->rx = 0; this->ry = 0; + this->msk = 0; + BC_WindowBase *wdw = 0; + int cin = -1; + if( (wdw=mwindow->gui) && wdw->win == focus ) + cin = FOCUS_MWINDOW; + else if( (wdw=mwindow->awindow->gui) && wdw->win == focus ) + cin = FOCUS_AWINDOW; + else if( (wdw=mwindow->cwindow->gui) && wdw->win == focus ) + cin = FOCUS_CWINDOW; + else if( (wdw=mwindow->gui->mainmenu->load_file->thread->window) && + wdw->win == focus ) + cin = FOCUS_LOAD; + else { + int i = mwindow->vwindows.size(); + while( --i >= 0 ) { + VWindow *vwdw = mwindow->vwindows[i]; + if( !vwdw->is_running() ) continue; + if( (wdw=vwdw->gui) && wdw->win == focus ) { + cin = FOCUS_VIEWER; break; + } + } + } + if( cin < 0 ) return -1; + Window root = 0, child = 0; + int root_x = 0, root_y = 0, win_x = 0, win_y = 0, x = 0, y = 0; + unsigned int mask = 0, width = 0, height = 0, border_width = 0, depth = 0; + wdw->lock_window("Shuttle::get_focused_window_translation 1"); + if( XQueryPointer(wdw->display, focus, &root, &child, + &root_x, &root_y, &win_x, &win_y, &mask) ) { + if( !child ) { + if( wdw->active_menubar ) + child = wdw->active_menubar->win; + else if( wdw->active_popup_menu ) + child = wdw->active_popup_menu->win; + else if( wdw->active_subwindow ) + child = wdw->active_subwindow->win; + } + if( child ) + XGetGeometry(wdw->display, child, &root, &x, &y, + &width, &height, &border_width, &depth); + } + wdw->unlock_window(); + if( !child || !wdw->match_window(child) ) return -1; +// success + this->wdw = wdw; + this->win = child; + this->msk = mask; + this->rx = root_x; + this->ry = root_y; + this->wx = win_x - x; + this->wy = win_y - y; + for( tr=translations.first; tr; tr=tr->next ) { + if( tr->is_default ) return 1; + for( int i=0; inames.size(); ++i ) { + TransName *name = tr->names[i]; + if( name->cin != cin ) continue; + if( regexec(&name->regex, win_title, 0, NULL, 0) ) + return 1; + } + } + tr = default_translation; + return 0; +} + +void Shuttle::handle_event() +{ + if( read_config_file() > 0 ) { + done = 1; + return; + } + if( get_focused_window_translation() < 0 ) + return; + if( last_translation != tr ) { + last_translation = tr; + if( debug ) + printf("new translation: %s\n", tr->name); + } +//fprintf(stderr, "event: (%d, %d, 0x%x)\n", ev.type, ev.code, ev.value); + switch( ev.type ) { + case EVENT_TYPE_DONE: + case EVENT_TYPE_ACTIVE_KEY: + break; + case EVENT_TYPE_KEY: + key(ev.code, ev.value); + break; + case EVENT_TYPE_JOGSHUTTLE: + jogshuttle(ev.code, ev.value); + break; + default: + fprintf(stderr, "handle_event() invalid type code\n"); + break; + } +} + +void Shuttle::run() +{ + for( enable_cancel(); !done; sleep(1) ) { + fd = open(dev_name, O_RDONLY); + if( fd < 0 ) { + perror(dev_name); + if( first_time ) break; + continue; + } + if( !ioctl(fd, EVIOCGRAB, 1) ) { // exclusive access + first_time = 0; + while( !done ) { + int ret = read(fd, &ev, sizeof(ev)); + if( done ) break; + if( ret != sizeof(ev) ) { + if( ret < 0 ) { perror("read event"); break; } + fprintf(stderr, "bad read: %d\n", ret); + break; + } + handle_event(); + } + } + else + perror( "evgrab ioctl" ); + close(fd); + } + done = 2; +} + +int Shuttle::read_config_file() +{ + if( !config_path ) { + const char *env; + config_path = (env=getenv("SHUTTLE_CONFIG_FILE")) != 0 ? cstrdup(env) : + (env=getenv("HOME")) != 0 ? cstrcat(2, env, "/.shuttlerc") : 0; + if( !config_path ) { fprintf(stderr, "no config file\n"); return 1; } + } + struct stat st; + if( stat(config_path, &st) ) { + perror(config_path); + char shuttlerc[BCTEXTLEN]; + snprintf(shuttlerc, sizeof(shuttlerc), "%s/shuttlerc", + File::get_cindat_path()); + if( stat(shuttlerc, &st) ) { + perror(shuttlerc); + return 1; + } + delete [] config_path; + config_path = cstrdup(shuttlerc); + } + if( config_mtime > 0 && + config_mtime == st.st_mtime ) return 0; + FILE *fp = fopen(config_path, "r"); + if( !fp ) { + perror(config_path); + return 1; + } + + config_mtime = st.st_mtime; + translations.clear(); + debug = 0; +#define ws(ch) (ch==' ' || ch=='\t') + char line[BCTEXTLEN], *cp; + Translation *trans = 0; + int no = 0; + int ret = fgets(cp=line,sizeof(line),fp) ? 0 : -1; + if( !ret ) ++no; +// lines + while( !ret ) { +// translation names + while( !ret && *cp == '[' ) { + char *name = ++cp; + while( *cp && *cp != ']' ) ++cp; + *cp++ = 0; + if( !name || !*name ) { ret = 1; break; } + int cin = -1; + if( !strcasecmp("default", name) ) + cin = FOCUS_DEFAULT; + else if( !strcasecmp("cinelerra", name) ) + cin = FOCUS_MWINDOW; + else if( !strcasecmp("resources", name) ) + cin = FOCUS_AWINDOW; + else if( !strcasecmp("composer", name) ) + cin = FOCUS_CWINDOW; + else if( !strcasecmp("viewer", name) ) + cin = FOCUS_VIEWER; + else if( !strcasecmp("load", name) ) + cin = FOCUS_LOAD; + else { + fprintf(stderr, "unknown focus target window: %s\n", + name); + ret = 1; break; + } + if( !trans ) { + if( cin == FOCUS_DEFAULT ) { + trans = default_translation; + trans->clear(); + } + else { + trans = new Translation(this, name); + } + } + while( ws(*cp) ) ++cp; +// regex in TransName constructor + trans->names.append(new TransName(cin, name, cp)); + if( trans->names.last()->err ) { ret = 1; break; } + ret = fgets(cp=line,sizeof(line),fp) ? 0 : 1; + if( ret ) { + fprintf(stderr, "hit eof, no translation def for: %s\n", + trans->names.last()->name); + ret = 1; break; + } + ++no; + } + if( ret ) break; + if( debug && trans ) { + printf("------------------------\n"); + TransNames &names = trans->names; + for( int i=0; iname, tp->cin); + } + } +// rules lines: "tok \n" + while( !ret && *cp != '[' ) { + const char *key = 0, *tok = 0; + while( ws(*cp) ) ++cp; + if( !*cp || *cp == '\n' || *cp == '#' ) goto skip; + tok = cp; + while( *cp && !ws(*cp) && *cp != '\n' ) ++cp; + *cp++ = 0; + if( !strcmp(tok, "DEBUG") ) { + debug = 1; goto skip; + } + key = tok; + if( !trans ) { + fprintf(stderr, "no translation section defining key: %s\n", key); + ret = 1; break; + } + + ret = trans->start_line(key); + while( !ret && *cp && *cp != '\n' ) { + 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]; + } + *cp++ = 0; + trans->add_string(tok); + continue; + } + tok = cp; + while( *cp && !ws(*cp) && *cp!='/' && *cp != '\n' ) ++cp; + int dhu = PRESS_RELEASE; + if( *cp == '/' ) { + *cp++ = 0; + switch( *cp ) { + case 'D': dhu = PRESS; break; + case 'H': dhu = HOLD; break; + case 'U': dhu = RELEASE; break; + default: + fprintf(stderr, "invalid up/down modifier [%s]%s: '%c'\n", + trans->name, tok, *cp); + ret = 1; break; + } + ++cp; + } + else + *cp++ = 0; + trans->add_keystroke(tok, dhu); + } + if( ret ) break; + trans->finish_line(); + if( debug ) + trans->print_line(key); + skip: ret = fgets(cp=line,sizeof(line),fp) ? 0 : -1; + if( !ret ) ++no; + } + if( trans ) { + if( trans != default_translation ) + translations.append(trans); + trans = 0; + } + } + if( ret > 0 ) + fprintf(stderr, "shuttle config err file: %s, line:%d\n", + config_path, no); + + fclose(fp); + return ret; +} +#endif diff --git a/cinelerra-5.1/cinelerra/shuttle.h b/cinelerra-5.1/cinelerra/shuttle.h new file mode 100644 index 00000000..532a5609 --- /dev/null +++ b/cinelerra-5.1/cinelerra/shuttle.h @@ -0,0 +1,248 @@ +#ifndef __SHUTTLE_H__ +#define __SHUTTLE_H__ + +#include "arraylist.h" +#include "bcwindowbase.inc" +#include "linklist.h" +#include "shuttle.inc" +#include "thread.h" + +#include "mwindow.h" +#include "mwindowgui.h" +#include "awindow.h" +#include "awindowgui.h" +#include "cwindow.h" +#include "cwindowgui.h" +#include "vwindow.h" +#include "vwindowgui.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +// Copyright 2013 Eric Messick (FixedImagePhoto.com/Contact) +// reworked 2019 for cinelerra-gg by William Morrow (aka goodguy) + +// delay in ms before processing each XTest event +// CurrentTime means no delay +#define DELAY CurrentTime + +// protocol for events from the shuttlepro HUD device +// +// ev.type values: +#define EVENT_TYPE_DONE 0 +#define EVENT_TYPE_KEY 1 +#define EVENT_TYPE_JOGSHUTTLE 2 +#define EVENT_TYPE_ACTIVE_KEY 4 + +// ev.code when ev.type == KEY +#define EVENT_CODE_KEY1 256 +// KEY2 257, etc... + +enum { K1=0,K2,K3,K4,K5,K6,K7,K8,K9,K10,K11,K12,K13,K14,K15, }; +enum { S_7=-7,S_6,S_5,S_4,S_3,S_2,S_1,S0,S1,S2,S3,S4,S5,S6,S7, }; +enum { JL=0,JR }; + +// ev.value when ev.type == KEY +// 1 -> PRESS; 0 -> RELEASE + +// ev.code when ev.type == JOGSHUTTLE +#define EVENT_CODE_JOG 7 +#define EVENT_CODE_SHUTTLE 8 + +// ev.value when ev.code == JOG +// 8 bit value changing by one for each jog step + +// ev.value when ev.code == SHUTTLE +// -7 .. 7 encoding shuttle position + +// we define these as extra KeySyms to represent mouse events +#define XK_Button_0 0x2000000 // just an offset, not a real button +#define XK_Button_1 0x2000001 +#define XK_Button_2 0x2000002 +#define XK_Button_3 0x2000003 +#define XK_Scroll_Up 0x2000004 +#define XK_Scroll_Down 0x2000005 + +#define PRESS 1 +#define RELEASE 2 +#define PRESS_RELEASE 3 +#define HOLD 4 + +#define NUM_KEYS 15 +#define NUM_SHUTTLES 15 +#define NUM_JOGS 2 + +#define KJS_KEY_DOWN 1 +#define KJS_KEY_UP 2 +#define KJS_SHUTTLE 3 +#define KJS_JOG 4 + +// cinelerra window input targets +#define FOCUS_DEFAULT 0 +#define FOCUS_MWINDOW 1 +#define FOCUS_AWINDOW 2 +#define FOCUS_CWINDOW 3 +#define FOCUS_VIEWER 4 +#define FOCUS_LOAD 5 + +class KeySymMapping { +public: + static KeySym to_keysym(const char *str); + static const char *to_string(KeySym ks); + static KeySymMapping key_sym_mapping[]; + const char *str; + KeySym sym; +}; + +class Stroke : public ListItem +{ +public: + KeySym keysym; + int press; // 1:press, 0:release +}; + +class Strokes : public List +{ +public: + Strokes() {} + ~Strokes() {} + void clear() { while( last ) delete last; } + void add_stroke(KeySym keysym, int press=1) { + Stroke *s = append(); + s->keysym = keysym; s->press = press; + } +}; + +class Modifiers : public ArrayList +{ + Translation *trans; +public: + Modifiers(Translation *trans) { this->trans = trans; } + ~Modifiers() {} + + void mark_as_down(KeySym sym, int hold); + void mark_as_up(KeySym sym); + void release(int allkeys); + void re_press(); +}; + +class TransName +{ +public: + int cin, err; + const char *name; + regex_t regex; + + TransName(int cin, const char *nm, const char *re); + ~TransName(); +}; + +class TransNames : public ArrayList +{ +public: + TransNames() {} + ~TransNames() { remove_all_objects(); } +}; + +class Translation : public ListItem +{ +public: + Translation(Shuttle *shuttle); + Translation(Shuttle *shuttle, const char *name); + ~Translation(); + void init(int def); + void clear(); + void append_stroke(KeySym 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); + int start_line(const char *key); + void print_strokes(const char *name, const char *up_dn, Strokes *strokes); + void print_stroke(Stroke *s); + void finish_line(); + void print_line(const char *key); + + Shuttle *shuttle; + TransNames names; + const char *name; + int is_default, is_key; + int first_release_stroke; + Strokes *pressed, *released; + Strokes *pressed_strokes, *released_strokes; + KeySym keysym_down; + + Strokes key_down[NUM_KEYS]; + Strokes key_up[NUM_KEYS]; + Strokes shuttles[NUM_SHUTTLES]; + Strokes jog[NUM_JOGS]; + Modifiers modifiers; +}; + +class Translations : public List +{ +public: + Translations() {} + ~Translations() {} + void clear() { while( last ) delete last; } +}; + +class Shuttle : public Thread +{ + int fd; + unsigned short jogvalue; + int shuttlevalue; + struct timeval last_shuttle; + int need_synthetic_shuttle; + const char *dev_name; + Translation *default_translation; + Translations translations; +public: + Shuttle(MWindow *mwindow); + ~Shuttle(); + + int send_button(unsigned int button, int press); + int send_key(KeySym keysym, int press); + int send_keysym(KeySym 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 stop(); + void handle_event(); + int get_focused_window_translation(); + static const char *probe(); + void run(); + int read_config_file(); + + int done; + int failed; + int first_time; + int debug; + + MWindow *mwindow; + Translation *tr, *last_translation; + BC_WindowBase *wdw; + Window win; + unsigned msk; + int rx, ry, wx, wy; + Window last_focused; + + const char *config_path; + time_t config_mtime; + input_event ev; +}; + +#endif diff --git a/cinelerra-5.1/cinelerra/shuttle.inc b/cinelerra-5.1/cinelerra/shuttle.inc new file mode 100644 index 00000000..5919e9d2 --- /dev/null +++ b/cinelerra-5.1/cinelerra/shuttle.inc @@ -0,0 +1,12 @@ +#ifndef __SHUTTLE_INC__ +#define __SHUTTLE_INC__ + +class KeySymMapping; +class Stroke; +class Strokes; +class Modifiers; +class Translation; +class Translations; +class Shuttle; + +#endif diff --git a/cinelerra-5.1/cinelerra/shuttle.sed b/cinelerra-5.1/cinelerra/shuttle.sed new file mode 100644 index 00000000..1996b8b6 --- /dev/null +++ b/cinelerra-5.1/cinelerra/shuttle.sed @@ -0,0 +1,5 @@ +/^\#ifdef/p +/^\#endif/p +/^\#define/!d +s/^\#define // +s/^\([^[:space:]]*\).*$/{ "\1", \1 }, / diff --git a/cinelerra-5.1/configure.ac b/cinelerra-5.1/configure.ac index 2ec69211..84081a03 100644 --- a/cinelerra-5.1/configure.ac +++ b/cinelerra-5.1/configure.ac @@ -53,6 +53,7 @@ CHECK_WITH([booby],[window lock trace booby trap],[BOOBY],[no]) CHECK_WITH([libzmpeg],[build libzmpeg],[LIBZMPEG],[yes]) CHECK_WITH([commercial],[enable commercial capture],[COMMERCIAL],[yes]) CHECK_WITH([thirdparty],[use thirdparty build],[CIN_3RDPARTY],[yes]) +CHECK_WITH([shuttle],[shuttle device],[SHUTTLE],[yes]) if test "x$WANT_LV2" != "xno"; then GTK2_LIBS=`pkg-config --libs gtk+-2.0` @@ -807,7 +808,7 @@ if test "x$WANT_CIN_3RDPARTY" != "xno"; then fi for v in GL XFT XXF86VM OSS ALSA FIREWIRE DV DVB \ VIDEO4LINUX2 ESOUND PACTL OPENEXR LV2 \ - COMMERCIAL LIBZMPEG; do + COMMERCIAL LIBZMPEG SHUTTLE; do eval vv="\$WANT_$v" if test "x$vv" != "xno"; then CFG_CFLAGS+=" -DHAVE_$v" @@ -833,6 +834,7 @@ echo " using: with-noelision = $WANT_NOELISION" echo " using: with-booby = $WANT_BOOBY" echo " using: with-libzmpeg = $WANT_LIBZMPEG" echo " using: with-commerical = $WANT_COMMERCIAL" +echo " using: with-shuttle = $WANT_SHUTTLE" echo "" echo " using: thirdparty build = $WANT_CIN_3RDPARTY" echo " using: single-user = $WANT_CINBIN_BUILD" diff --git a/cinelerra-5.1/guicast/bcwindowbase.h b/cinelerra-5.1/guicast/bcwindowbase.h index 84cb0896..b512820d 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.h +++ b/cinelerra-5.1/guicast/bcwindowbase.h @@ -173,6 +173,7 @@ public: friend class BC_Tumbler; friend class BC_Window; friend class BC_WindowEvents; + friend class Shuttle; // Main loop int run_window(); diff --git a/cinelerra-5.1/guicast/bcwindowbase.inc b/cinelerra-5.1/guicast/bcwindowbase.inc index e3f68802..046e7dd8 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.inc +++ b/cinelerra-5.1/guicast/bcwindowbase.inc @@ -25,6 +25,8 @@ class BC_ActiveBitmaps; class BC_WindowBase; class BC_WindowList; +class Shuttle; + #define BCTEXTLEN 1024 #define BCSTRLEN 64 #define KEYPRESSLEN 6 diff --git a/cinelerra-5.1/plugins/theme_blond/data/ff_audio.png b/cinelerra-5.1/plugins/theme_blond/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_blond/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_blond/data/ff_video.png b/cinelerra-5.1/plugins/theme_blond/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_blond/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_blond_cv/data/ff_audio.png b/cinelerra-5.1/plugins/theme_blond_cv/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_blond_cv/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_blond_cv/data/ff_video.png b/cinelerra-5.1/plugins/theme_blond_cv/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_blond_cv/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_blue/data/ff_audio.png b/cinelerra-5.1/plugins/theme_blue/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_blue/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_blue/data/ff_video.png b/cinelerra-5.1/plugins/theme_blue/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_blue/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_blue_dot/data/ff_audio.png b/cinelerra-5.1/plugins/theme_blue_dot/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_blue_dot/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_blue_dot/data/ff_video.png b/cinelerra-5.1/plugins/theme_blue_dot/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_blue_dot/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_bright/data/ff_audio.png b/cinelerra-5.1/plugins/theme_bright/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_bright/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_bright/data/ff_video.png b/cinelerra-5.1/plugins/theme_bright/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_bright/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_hulk/data/ff_audio.png b/cinelerra-5.1/plugins/theme_hulk/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_hulk/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_hulk/data/ff_video.png b/cinelerra-5.1/plugins/theme_hulk/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_hulk/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_pinklady/data/ff_audio.png b/cinelerra-5.1/plugins/theme_pinklady/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_pinklady/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_pinklady/data/ff_video.png b/cinelerra-5.1/plugins/theme_pinklady/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_pinklady/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_suv/data/ff_audio.png b/cinelerra-5.1/plugins/theme_suv/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_suv/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_suv/data/ff_video.png b/cinelerra-5.1/plugins/theme_suv/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_suv/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_unflat/data/ff_audio.png b/cinelerra-5.1/plugins/theme_unflat/data/ff_audio.png deleted file mode 100644 index c62e4073..00000000 Binary files a/cinelerra-5.1/plugins/theme_unflat/data/ff_audio.png and /dev/null differ diff --git a/cinelerra-5.1/plugins/theme_unflat/data/ff_video.png b/cinelerra-5.1/plugins/theme_unflat/data/ff_video.png deleted file mode 100644 index 73c231ba..00000000 Binary files a/cinelerra-5.1/plugins/theme_unflat/data/ff_video.png and /dev/null differ diff --git a/cinelerra-5.1/shuttlerc b/cinelerra-5.1/shuttlerc new file mode 100644 index 00000000..a41ba3c0 --- /dev/null +++ b/cinelerra-5.1/shuttlerc @@ -0,0 +1,92 @@ + +# uncomment to enable diagnostics +#DEBUG + +# redefine default, use +# also used for resources,load windows +[Default] +[Resources] +[Load] + K5 XK_Home + K6 XK_Button_1 + K7 XK_Button_2 + K8 XK_Button_3 + K9 XK_End + JL XK_Scroll_Up + JR XK_Scroll_Down + +[Cinelerra] + + K5 XK_KP_0 # Stop + K9 XK_KP_3 # Play + 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 + + S-3 XK_KP_Add # Fast reverse + S-2 XK_KP_6 # Play reverse + S-1 XK_KP_5 # Slow reverse + S0 XK_KP_0 # Stop + S1 XK_KP_2 # Slow forward + S2 XK_KP_3 # Play forward + S3 XK_KP_Enter # Fast forward + + JL XK_KP_4 # Frame reverse + JR XK_KP_1 # Frame forward + +[Composer] + + K5 XK_KP_0 # Stop + K9 XK_KP_3 # Play + 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 + + S-3 XK_KP_Add # Fast reverse + S-2 XK_KP_6 # Play reverse + S-1 XK_KP_5 # Slow reverse + S0 XK_KP_0 # Stop + S1 XK_KP_2 # Slow forward + S2 XK_KP_3 # Play forward + S3 XK_KP_Enter # Fast forward + + 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) + 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 + + S-3 XK_KP_Add # Fast reverse + S-2 XK_KP_6 # Play reverse + S-1 XK_KP_5 # Slow reverse + S0 XK_KP_0 # Stop + S1 XK_KP_2 # Slow forward + S2 XK_KP_3 # Play forward + S3 XK_KP_Enter # Fast forward + + JL XK_KP_4 # Frame reverse + JR XK_KP_1 # Frame forward + diff --git a/cinelerra-5.1/thirdparty/src/mjpegtools-2.1.0.patch3 b/cinelerra-5.1/thirdparty/src/mjpegtools-2.1.0.patch3 new file mode 100644 index 00000000..93a26400 --- /dev/null +++ b/cinelerra-5.1/thirdparty/src/mjpegtools-2.1.0.patch3 @@ -0,0 +1,14 @@ +--- mjpegtools-2.1.0/utils/videodev_mjpeg.h.orig 2019-01-12 11:13:19.901685543 -0700 ++++ mjpegtools-2.1.0/utils/videodev_mjpeg.h 2019-01-12 11:14:33.325683843 -0700 +@@ -109,6 +109,11 @@ + /* + Private IOCTL to set up for displaying MJPEG + */ ++/* bad spelling, see /usr/include/videodev2.h */ ++#ifndef BASE_VIDIOCPRIVATE ++#define BASE_VIDIOCPRIVATE BASE_VIDIOC_PRIVATE ++#endif ++ + #define MJPIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct mjpeg_params) + #define MJPIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct mjpeg_params) + #define MJPIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct mjpeg_requestbuffers)