shuttle and transportque reworks, new shdmp, titler font textbox tweak
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / shuttle.C
index 627f162a8d6f0e71a5f65bfbc33940f1fa970208..b3049c5dcd01ddb660e60510e414e3a3fae317e4 100644 (file)
@@ -2,22 +2,33 @@
 // 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 "keys.h"
 #include "linklist.h"
 #include "loadfile.h"
 #include "mainmenu.h"
-#include "mwindow.h"
 #include "shuttle.h"
 #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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
 #include <sys/time.h>
-#include <sys/types.h>
 #include <sys/stat.h>
 
 #include <X11/Xlib.h>
@@ -31,6 +42,7 @@ static Time milliTimeClock()
 }
 
 KeySymMapping KeySymMapping::key_sym_mapping[] = {
+// button keycodes
        { "XK_Button_1", XK_Button_1 },
        { "XK_Button_2", XK_Button_2 },
        { "XK_Button_3", XK_Button_3 },
@@ -42,6 +54,22 @@ KeySymMapping KeySymMapping::key_sym_mapping[] = {
 
 KeySym KeySymMapping::to_keysym(const char *str)
 {
+       if( !strncmp("FWD_",str, 4) ) {
+               float speed = atof(str+4) / SHUTTLE_MAX_SPEED;
+               if( speed > SHUTTLE_MAX_SPEED ) return 0;
+               int key_code = (SKEY_MAX+SKEY_MIN)/2. +
+                       (SKEY_MAX-SKEY_MIN)/2. * speed;
+               if( key_code > SKEY_MAX ) key_code = SKEY_MAX;
+               return key_code;
+       }
+       if( !strncmp("REV_",str, 4) ) {
+               float speed = atof(str+4) / SHUTTLE_MAX_SPEED;
+               if( speed > SHUTTLE_MAX_SPEED ) return 0;
+               int key_code = (SKEY_MAX+SKEY_MIN)/2. -
+                       (SKEY_MAX-SKEY_MIN)/2. * speed;
+               if( key_code < SKEY_MIN ) key_code = SKEY_MIN;
+               return key_code;
+       }
        for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->str; ++ksp )
                if( !strcmp(str, ksp->str) ) return ksp->sym;
        return 0;
@@ -51,6 +79,19 @@ const char *KeySymMapping::to_string(KeySym ks)
 {
        for( KeySymMapping *ksp = &key_sym_mapping[0]; ksp->sym; ++ksp )
                if( ksp->sym == ks ) return ksp->str;
+       if( ks >= SKEY_MIN && ks <= SKEY_MAX ) {
+               double speed = SHUTTLE_MAX_SPEED *
+                       (ks-(SKEY_MAX+SKEY_MIN)/2.) / ((SKEY_MAX-SKEY_MIN)/2.);
+               static char text[BCSTRLEN];
+               sprintf(text, "%s_%0.3f", speed>=0 ? "FWD" : "REV", fabs(speed));
+               char *bp = strchr(text,'.');
+               if( bp ) {
+                       char *cp = bp+strlen(bp);
+                       while( --cp>bp && *cp=='0' ) *cp=0;
+                       if( cp == bp ) *cp = 0;
+               }
+               return text;
+       }
        return 0;
 }
 
@@ -58,18 +99,10 @@ 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, &regex, emsg, sizeof(emsg));
-               fprintf(stderr, "regerror: %s\n", emsg);
-       }
 }
 TransName::~TransName()
 {
        delete [] name;
-       regfree(&regex);
 }
 
 void Translation::init(int def)
@@ -357,9 +390,6 @@ Shuttle::Shuttle(MWindow *mwindow)
        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;
@@ -390,6 +420,7 @@ int Shuttle::send_button(unsigned int button, int press)
        memset(b, 0, sizeof(*b));
        b->type = press ? ButtonPress : ButtonRelease;
        b->time = milliTimeClock();
+       b->send_event = 1;
        b->display = wdw->top_level->display;
        b->root = wdw->top_level->rootwin;
        b->window = win;
@@ -403,15 +434,21 @@ int Shuttle::send_button(unsigned int button, int press)
        wdw->top_level->put_event((XEvent *) b);
        return 0;
 }
-int Shuttle::send_key(KeySym keysym, int press)
+int Shuttle::send_keycode(unsigned int keycode, int press, int send)
 {
-       KeyCode keycode = XKeysymToKeycode(wdw->top_level->display, keysym);
-       if( debug )
-               printf("key: %04x %d\n", (unsigned)keycode, press);
+       if( debug ) {
+               const char *cp = !send ? 0 :
+                       KeySymMapping::to_string(keycode);
+               if( cp )
+                       printf("key: %s %d\n", cp, press);
+               else
+                       printf("key: %04x %d\n", keycode, press);
+       }
        XKeyEvent *k = new XKeyEvent();
        memset(k, 0, sizeof(*k));
        k->type = press ? KeyPress : KeyRelease;
        k->time = milliTimeClock();
+       k->send_event = send;
        k->display = wdw->top_level->display;
        k->root = wdw->top_level->rootwin;
        k->window = win;
@@ -430,7 +467,9 @@ 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);
+               send_keycode((unsigned int)keysym, press, 1);
+//     unsigned int keycode = XKeysymToKeycode(wdw->top_level->display, keysym);
+//     return send_keycode(keycode, press, 0);
 }
 
 
@@ -440,10 +479,10 @@ static Stroke *fetch_stroke(Translation *translation, int kjs, int index)
        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;
+               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-S_7].first; break;
                }
        }
        return ret;
@@ -471,17 +510,15 @@ void Shuttle::key(unsigned short code, unsigned int value)
 }
 
 
-void Shuttle:: shuttle(int value)
+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 ) {
+       if( value != (int)shuttlevalue ) {
                shuttlevalue = value;
-               send_stroke_sequence(KJS_SHUTTLE, value+7);
+               send_stroke_sequence(KJS_SHUTTLE, value);
        }
 }
 
@@ -495,29 +532,14 @@ void Shuttle:: shuttle(int value)
 // 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;
+               int direction = ((value - jogvalue) & 0x80) ? -1 : 1;
+               int index = direction > 0 ? 1 : 0;
                while( jogvalue != value ) {
                        // driver fails to send an event when jogvalue == 0
                        if( jogvalue != 0 ) {
-       send_stroke_sequence(KJS_JOG, direction > 0 ? 1 : 0);
+                               send_stroke_sequence(KJS_JOG, index);
                        }
                        jogvalue = (jogvalue + direction) & 0xff;
                }
@@ -546,6 +568,7 @@ const char *Shuttle::probe()
        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) );
@@ -569,6 +592,14 @@ void Shuttle::stop()
        }
 }
 
+BC_WindowBase *Shuttle::owns(BC_WindowBase *wdw, Window win)
+{
+       if( wdw->win == win ) return wdw;
+       if( (wdw=wdw->top_level)->win == win ) return wdw;
+       for( int i=wdw->popups.size(); --i>=0; )
+               if( wdw->popups[i]->win == win ) return wdw;
+       return 0;
+}
 
 int Shuttle::get_focused_window_translation()
 {
@@ -576,7 +607,7 @@ int Shuttle::get_focused_window_translation()
        Display *dpy = gui->display;
        Window focus = 0;
        int ret = 0, revert = 0;
-       char win_title[BCTEXTLEN];
+       char win_title[BCTEXTLEN];  win_title[0] = 0;
        gui->lock_window("Shuttle::get_focused_window_translation");
        XGetInputFocus(dpy, &focus, &revert);
        if( last_focused != focus ) {
@@ -592,7 +623,7 @@ int Shuttle::get_focused_window_translation()
                        win_title[len] = 0;
                        XFree(list);
                        if( debug )
-                               printf("new focus: %08x\n", (unsigned)focus);
+                               printf("new focus: %08x %s\n", (unsigned)focus, win_title);
                }
                else {
                        last_focused = 0;
@@ -610,13 +641,17 @@ int Shuttle::get_focused_window_translation()
        this->msk = 0;
        BC_WindowBase *wdw = 0;
        int cin = -1;
-       if( (wdw=mwindow->gui) && wdw->win == focus )
+       if( (wdw=owns(mwindow->gui, focus)) != 0 )
                cin = FOCUS_MWINDOW;
-       else if( (wdw=mwindow->awindow->gui) && wdw->win == focus )
+       else if( (wdw=owns(mwindow->awindow->gui, focus)) != 0 )
                cin = FOCUS_AWINDOW;
-       else if( (wdw=mwindow->cwindow->gui) && wdw->win == focus )
+       else if( (wdw=owns(mwindow->cwindow->gui, focus)) != 0 ) {
+               if( mwindow->cwindow->gui->canvas->get_fullscreen() )
+                       wdw = mwindow->cwindow->gui->canvas->get_canvas();
                cin = FOCUS_CWINDOW;
-       else if( (wdw=mwindow->gui->mainmenu->load_file->thread->window) &&
+       }
+       else if( mwindow->gui->mainmenu->load_file->thread->running() &&
+                (wdw=mwindow->gui->mainmenu->load_file->thread->window) != 0 &&
                 wdw->win == focus )
                cin = FOCUS_LOAD;
        else {
@@ -624,7 +659,9 @@ int Shuttle::get_focused_window_translation()
                while( --i >= 0 ) {
                        VWindow *vwdw =  mwindow->vwindows[i];
                        if( !vwdw->is_running() ) continue;
-                       if( (wdw=vwdw->gui) && wdw->win == focus ) {
+                       if( (wdw=owns(vwdw->gui, focus)) != 0 ) {
+                               if( vwdw->gui->canvas->get_fullscreen() )
+                                       wdw = vwdw->gui->canvas->get_canvas();
                                cin = FOCUS_VIEWER;  break;
                        }
                }
@@ -634,7 +671,7 @@ int Shuttle::get_focused_window_translation()
        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,
+       if( XQueryPointer(wdw->top_level->display, focus, &root, &child,
                        &root_x, &root_y, &win_x, &win_y, &mask) ) {
                if( !child ) {
                        if( wdw->active_menubar )
@@ -643,9 +680,11 @@ int Shuttle::get_focused_window_translation()
                                child = wdw->active_popup_menu->win;
                        else if( wdw->active_subwindow )
                                child = wdw->active_subwindow->win;
+                       else
+                               child = wdw->win;
                }
-               if( child )
-                       XGetGeometry(wdw->display, child, &root, &x, &y,
+               else
+                       XGetGeometry(wdw->top_level->display, child, &root, &x, &y,
                                &width, &height, &border_width, &depth);
        }
        wdw->unlock_window();
@@ -662,9 +701,7 @@ int Shuttle::get_focused_window_translation()
                if( tr->is_default ) return 1;
                for( int i=0; i<tr->names.size(); ++i ) {
                        TransName *name = tr->names[i];
-                       if( name->cin != cin ) continue;
-                       if( regexec(&name->regex, win_title, 0, NULL, 0) )
-                               return 1;
+                       if( name->cin == cin ) return 1;
                }
        }
        tr = default_translation;
@@ -684,7 +721,8 @@ void Shuttle::handle_event()
                if( debug )
                        printf("new translation: %s\n", tr->name);
        }
-//fprintf(stderr, "event: (%d, %d, 0x%x)\n", ev.type, ev.code, ev.value);
+//     if( debug )
+//             printf("event: (%d, %d, 0x%x)\n", ev.type, ev.code, ev.value);
        switch( ev.type ) {
        case EVENT_TYPE_DONE:
        case EVENT_TYPE_ACTIVE_KEY:
@@ -804,9 +842,7 @@ int Shuttle::read_config_file()
                                }
                        }
                        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",