chiark / gitweb /
Fix up search too long error message - really fix up
[ypp-sc-tools.db-live.git] / yarrg / pages.c
index 2e3edde72d4b3fb68ecd48f20e430cac1739252b..d5385d3bdd71102cf715a1606cf13a8d62881a66 100644 (file)
@@ -55,23 +55,155 @@ static XImage *shmim;
 static XShmSegmentInfo shminfo;
 
 DEBUG_DEFINE_DEBUGF(pages)
+DEBUG_DEFINE_SOME_DEBUGF(keymap,keydebugf)
 
 #define xassert(what)                                  \
   ((what) ? (void)0 :                                  \
    fatal("X11 operation unexpectedly failed."          \
         " %s:%d: %s\n", __FILE__,__LINE__,#what))
 
-static KeyCode keycode(KeySym sym) {
-  return XKeysymToKeycode(disp,sym);
+
+/*---------- keyboard map ----------*/
+
+#define KEYS(EACH_KEY)                         \
+  EACH_KEY(XK_slash)                           \
+  EACH_KEY(XK_w)                               \
+  EACH_KEY(XK_Return)                          \
+  EACH_KEY(XK_Prior)                           \
+  EACH_KEY(XK_Next)
+
+#define MAXMAPCOL 6
+typedef struct {
+  int len;
+  int kc[3];
+} MappedKey;
+
+#define KEY_MAP_DEF(xk) \
+static MappedKey mk_##xk;
+KEYS(KEY_MAP_DEF)
+
+typedef struct {
+  int isdef; /* 'y' if defined; otherwise char indicating why not */
+  int kc;
+} MappedModifier;
+
+static int kc_min, kc_max;
+static MappedModifier mm_shift, mm_modeswitch, mm_isol3shift;
+static KeySym *mapping;
+static int mapwidth;
+
+static void keymap_lookup_modifier(MappedModifier *mm, const char *what,
+                                  KeySym sym, char ifnot) {
+  int kc;
+  keydebugf("KEYMAP modifier lookup %-10s %#lx or '%c' ", what,
+           (unsigned long)sym, ifnot);
+
+  mm->isdef= ifnot;
+  for (kc=kc_min; kc <= kc_max; kc++) {
+    if (mapping[(kc-kc_min)*mapwidth] == sym) {
+      keydebugf(" found kc=%d\n", kc);
+      mm->isdef= 'y';
+      mm->kc= kc;
+      return;
+    }
+  }
+  keydebugf(" none\n");
 }
 
-void screenshot_startup(void) {
-  progress("starting...");
-  disp= XOpenDisplay(0);
-  if (!disp) fatal("Unable to open X11 display.");
-  sysassert(! gettimeofday(&tv_startup,0) );
+static void keymap_lookup_key(MappedKey *mk, KeySym sym, const char *what) {
+  const MappedModifier *shift, *xshift;
+  int col, kc;
+  char cols[MAXMAPCOL+1];
+
+  memset(cols,'.',MAXMAPCOL);
+  cols[MAXMAPCOL]= 0;
+
+  for (col=0; col<mapwidth && col<MAXMAPCOL; col++) {
+    keydebugf("KEYMAP lookup %-10s %#lx col=%d ",
+             what, (unsigned long)sym, col);
+
+#define CHECK_SHIFT(sh) do{                                    \
+      if ((sh) && (sh)->isdef!='y') {                          \
+       cols[col]= (sh)->isdef;                                 \
+        keydebugf("no-modifier " #sh "'%c'\n", (sh)->isdef);   \
+       continue;                                               \
+      }                                                                \
+    }while(0)
+
+    shift= col & 1 ? &mm_shift : 0;
+    CHECK_SHIFT(shift);
+
+    xshift= col >= 4 ? &mm_isol3shift :
+            col >= 2 ? &mm_modeswitch :
+            0;
+    CHECK_SHIFT(xshift);
+
+    for (kc=kc_min; kc <= kc_max; kc++) {
+      if (mapping[(kc-kc_min)*mapwidth + col] == sym)
+       goto found;
+    }
+    cols[col]= '_';
+    keydebugf("not-found\n");
+  }
+  fprintf(stderr,"\n"
+         "Unable to find a key to press to generate %s.\n"
+         "(Technical details: cols:%s sh:%c:%d modesw:%c:%d isol3:%c:%d)\n",
+         what, cols,
+#define SH_DETAILS(sh) mm_##sh.isdef, mm_##sh.kc
+         SH_DETAILS(shift), SH_DETAILS(modeswitch), SH_DETAILS(isol3shift));
+  fatal("Keymap is unsuitable!");
+
+ found:;
+  int *fill= mk->kc;
+  
+  if (xshift) *fill++ = xshift->kc;
+  if (shift)  *fill++ = shift->kc;
+  *fill++ += kc;
+  mk->len= fill - mk->kc;
+  keydebugf("found kc=%d len=%d\n",kc,mk->len);
+}
+
+static void keymap_startup(void) {
+  xassert( XDisplayKeycodes(disp,&kc_min,&kc_max) );
+  keydebugf("KEYMAP keycodes %d..%d\n",kc_min,kc_max);
+
+  xassert( mapping= XGetKeyboardMapping(disp, kc_min, kc_max-kc_min+1,
+                                       &mapwidth) );
+  keydebugf("KEYMAP got keyboard map\n");
+
+  XModifierKeymap *modmap;
+  xassert( modmap= XGetModifierMapping(disp) );
+  keydebugf("KEYMAP got modifier map\n");
+
+  /* find a shift keycode */
+  mm_shift.isdef= 'x';
+  int modent;
+  for (modent=0; modent<modmap->max_keypermod; modent++) {
+    int kc= modmap->modifiermap[modent];
+    keydebugf("KEYMAP modifier #0 key #%d is %d ", modent, kc);
+    if (!kc) { keydebugf("none\n"); continue; }
+    keydebugf("ok\n");
+    mm_shift.kc= kc;
+    mm_shift.isdef= 'y';
+    break;
+  }
+
+  XFreeModifiermap(modmap);
+
+  /* find keycodes for mode_switch (column+=2) and ISO L3 shift (column+=4) */
+  keymap_lookup_modifier(&mm_modeswitch,"modeswitch", XK_Mode_switch,     'm');
+  keymap_lookup_modifier(&mm_isol3shift,"isol3shift", XK_ISO_Level3_Shift,'l');
+  
+#define KEY_MAP_LOOKUP(xk) \
+  keymap_lookup_key(&mk_##xk, xk, #xk);
+  KEYS(KEY_MAP_LOOKUP)
+
+  XFree(mapping);
+  mapping= 0;
 }
 
+#define SEND_KEY(xk) (send_key(&mk_##xk))
+
 /*---------- pager ----------*/
 
 typedef RgbImage Snapshot;
@@ -154,28 +286,53 @@ static void check_not_disturbed(void) {
   }
 }      
 
-static void send_key(KeySym sym) {
+static void check_pointer_not_disturbed(void) {
+  Window got_root, got_child;
+  int got_root_x, got_root_y;
+  int got_win_x, got_win_y;
+  unsigned got_mask;
+
+  int r= XQueryPointer(disp,id, &got_root,&got_child,
+                      &got_root_x, &got_root_y,
+                      &got_win_x, &got_win_y,
+                      &got_mask);
+  if (!r ||
+      got_win_x!=commod_page_point.x ||
+      got_win_y!=commod_page_point.y) {
+    progress("");
+    fprintf(stderr,"\nunexpected mouse position:"
+           " samescreen=%d got=%dx%d want=%dx%d",
+           r, got_win_x,got_win_y,
+           commod_page_point.x,commod_page_point.y);
+    fatal("Mouse pointer moved.");
+  }
+}
+
+static void send_key(MappedKey *mk) {
+  int i;
   check_not_disturbed();
-  XTestFakeKeyEvent(disp, keycode(sym),1, 10);
-  XTestFakeKeyEvent(disp, keycode(sym),0, 10);
+  keydebugf("KEYMAP SEND_KEY len=%d kc=%d\n", mk->len, mk->kc[mk->len-1]);
+  for (i=0; i<mk->len; i++) XTestFakeKeyEvent(disp, mk->kc[i], 1, 0);
+  for (i=mk->len; --i>=0; ) XTestFakeKeyEvent(disp, mk->kc[i], 0, 0);
 }
-static void mouse_1_updown_here(void) {
+static void send_mouse_1_updown_here(void) {
   check_not_disturbed();
-  XTestFakeButtonEvent(disp,1,1, 10);
-  XTestFakeButtonEvent(disp,1,0, 10);
+  XTestFakeButtonEvent(disp,1,1, 0);
+  XTestFakeButtonEvent(disp,1,0, 0);
 }
-static void mouse_1_updown(int x, int y) {
+static void send_mouse_1_updown(int x, int y) {
   check_not_disturbed();
   int screen= XScreenNumberOfScreen(attr.screen);
   int xpos, ypos;
   translate_coords_toroot(x,y, &xpos,&ypos);
   XTestFakeMotionEvent(disp, screen, xpos,ypos, 0);
-  mouse_1_updown_here();
+  send_mouse_1_updown_here();
 }
 static void pgdown_by_mouse(void) {
   check_not_disturbed();
+  check_pointer_not_disturbed();
   debugf("PAGING   Mouse\n");
-  mouse_1_updown_here();
+  send_mouse_1_updown_here();
   sync_after_input();
 }
 
@@ -184,7 +341,7 @@ static int pgupdown;
 static void send_pgup_many(void) {
   int i;
   for (i=0; i<25; i++) {
-    send_key(XK_Prior);
+    SEND_KEY(XK_Prior);
     pgupdown--;
   }
   debugf("PAGING   PageUp x %d\n",i);
@@ -193,7 +350,7 @@ static void send_pgup_many(void) {
 static void send_pgdown_torestore(void) {
   debugf("PAGING   PageDown x %d\n", -pgupdown);
   while (pgupdown < 0) {
-    send_key(XK_Next);
+    SEND_KEY(XK_Next);
     pgupdown++;
   }
   sync_after_input();
@@ -350,12 +507,14 @@ static void wait_for_stability(Snapshot **output,
          "  last_input=%f previously=%p `%s'\n",
          last_input, previously, doing);
 
-  double min_interval= 0.025;
+  double max_interval= 1.000;
+  double min_interval= 0.100;
   for (;;) {
     progress_spinner("%s",doing);
     
     double since_last_input= timestamp() - last_input;
     double this_interval= min_interval - since_last_input;
+    if (this_interval > max_interval) this_interval= max_interval;
 
     if (this_interval >= 0)
       delay(this_interval);
@@ -496,7 +655,7 @@ static void set_focus_commodity(void) {
 
   debugf("PAGING set_focus\n");
 
-  mouse_1_updown(commod_focus_point.x, commod_focus_point.y);
+  send_mouse_1_updown(commod_focus_point.x, commod_focus_point.y);
   sync_after_input();
 
   delay(0.5);
@@ -552,20 +711,21 @@ static void prepare_ypp_client(void) {
   Rect sunshine= find_sunshine_widget();
 
   progress("poking client...");
-  mouse_1_updown((sunshine.tl.x   + sunshine.br.x) / 2,
-                (sunshine.tl.y*9 + sunshine.br.y) / 10);
+  send_mouse_1_updown((sunshine.tl.x   + sunshine.br.x) / 2,
+                     (sunshine.tl.y*9 + sunshine.br.y) / 10);
+  sync_after_input();
 
   free(test);
 
   wait_for_stability(&current,0,0, "checking basic YPP client screen...");
-  mouse_1_updown(250, wheight-10);
-  mouse_1_updown_here();
-  mouse_1_updown_here();
-  XSync(disp,False);
+  send_mouse_1_updown(250, wheight-10);
+  send_mouse_1_updown_here();
+  send_mouse_1_updown_here();
+  sync_after_input();
   check_not_disturbed();
-  send_key(XK_slash);
-  send_key(XK_w);
-  send_key(XK_Return);
+  SEND_KEY(XK_slash);
+  SEND_KEY(XK_w);
+  SEND_KEY(XK_Return);
   sync_after_input();
 
   Snapshot *status=0;
@@ -602,37 +762,34 @@ void take_screenshots(void) {
   for (;;) {
     debugf("page %d paging\n",npages);
 
+    pgdown_by_mouse();
+
     if (!(npages < MAX_PAGES))
       fatal("Paging down seems to generate too many pages - max is %d.",
            MAX_PAGES);
 
     convert_store_page(current);
     free_snapshot(&last); last=current; current=0;
-
     debugf("PAGING page %d converted\n",npages);
+    npages++;
 
     wait_for_stability(&current,last, 0,
                       "page %d collecting    ...",
-                      npages+1);
-
-    if (npages &&  /* first pagedown doesn't do much */
-       identical(current,last)) {
-      npages++;
+                      npages);
+    if (identical(current,last)) {
       free_snapshot(&current);
       break;
     }
-
-    pgdown_by_mouse();
-    npages++;
   }
   progress("finishing with the YPP client...");
-  mouse_1_updown(commod_focuslast_point.x, commod_focuslast_point.y);
+  send_mouse_1_updown(commod_focuslast_point.x, commod_focuslast_point.y);
   sync_after_input();
   send_pgdown_torestore();
   sync_after_input();
 
   debugf("PAGING all done.\n");
   progress_log("collected %d screenshots.",npages);
+  check_pager_motion(0,npages);
 }    
 
 void take_one_screenshot(void) {
@@ -770,3 +927,12 @@ void find_yppclient_window(void) {
          " Use --window-id and/or report this as a fault.\n",
          o_ocean || o_pirate ? "matching ": "");
 }
+
+void screenshot_startup(void) {
+  progress("starting...");
+  disp= XOpenDisplay(0);
+  if (!disp) fatal("Unable to open X11 display.");
+  sysassert(! gettimeofday(&tv_startup,0) );
+
+  keymap_startup();
+}