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;
}
}
-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, 0);
- XTestFakeKeyEvent(disp, keycode(sym),0, 0);
+ 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 send_mouse_1_updown_here(void) {
check_not_disturbed();
}
static void pgdown_by_mouse(void) {
check_not_disturbed();
+ check_pointer_not_disturbed();
debugf("PAGING Mouse\n");
send_mouse_1_updown_here();
sync_after_input();
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);
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();
" last_input=%f previously=%p `%s'\n",
last_input, previously, doing);
- double max_interval= 5.000;
+ double max_interval= 1.000;
double min_interval= 0.100;
for (;;) {
progress_spinner("%s",doing);
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;
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(¤t,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(¤t);
break;
}
-
- pgdown_by_mouse();
- npages++;
}
progress("finishing with the YPP client...");
send_mouse_1_updown(commod_focuslast_point.x, commod_focuslast_point.y);
debugf("PAGING all done.\n");
progress_log("collected %d screenshots.",npages);
+ check_pager_motion(0,npages);
}
void take_one_screenshot(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();
+}