X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~yarrgweb/git?p=ypp-sc-tools.db-live.git;a=blobdiff_plain;f=yarrg%2Fpages.c;h=d5385d3bdd71102cf715a1606cf13a8d62881a66;hp=02cacd95bbc5d0f556d99fdcc33ed5470ddf80e5;hb=4dbb6c3acfdb73f76c221ab016a4406a7b4daacb;hpb=7f9df3a472dda7008366c3fdf865adeb3467b66b diff --git a/yarrg/pages.c b/yarrg/pages.c index 02cacd9..d5385d3 100644 --- a/yarrg/pages.c +++ b/yarrg/pages.c @@ -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; colisdef!='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; modentmax_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,10 +286,34 @@ 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, 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; ilen; 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(); @@ -174,6 +330,7 @@ static void send_mouse_1_updown(int x, int y) { } 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(); @@ -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,7 +507,7 @@ static void wait_for_stability(Snapshot **output, " 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); @@ -566,9 +723,9 @@ static void prepare_ypp_client(void) { 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; @@ -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(); +}