From Sexy Sloth, 3 Years ago, written in Diff-output.
  1. This patch attempts to fix multiple things in imwheel.
  2.  
  3. This patch is in the public domain.
  4.  
  5. It fixes the issue where imwheel stops working after a while
  6. when the @Exclude option is used, but also attempts to make
  7. other changes that make it work more smoothly. Generating thumb
  8. buttons with imwheel is still not possible, so you need to
  9. use @Exclude. This is one big fat ugly patch because I have
  10. no time to split it up into many. It requires all Debian
  11. patches: https://packages.debian.org/source/jessie/imwheel
  12.  
  13. Sorry for any unnecessary stuff in the patch, it's a bit of
  14. a mess.
  15.  
  16. Fixes:
  17.  
  18. It introduces partial exclude, so you can exclude only
  19. some buttons in apps using: @Exclude=Thumb2,ExtBt7
  20.  
  21. Normal @Exclude is also fixed - somewhat - but imwheel
  22. still grabs button for the wrong window from time to time,
  23. and weirdly enough partial one might work better. Ugh.
  24.  
  25. It should be able to send keys to the window under the mouse
  26. for consistency, but this is not tested.
  27.  
  28. Since both wheels are supported by most apps, you most likely
  29. need (otherwise you'd have to use partial or full @Exclude)
  30. imwheel -b "0 0 0 0 8 9 10"
  31.  
  32. There might be some weird inconsistencies when you're not
  33. using focus following mouse regarding exclude - the windows
  34. get their clicks when your mouse is over them, but imwheel
  35. grabs keys depending on the window in focus. There are
  36. two options that attempt to fix this:
  37.  
  38. The -M option tries to detect the window under the mouse,
  39. but it is not tested well enough. It also switches the
  40. focus after a click, which might be undesired. The -F
  41. option attempts to remedy that, but it is broken at present.
  42.  
  43.  
  44. diff -ru imwheel-1.0.0pre12/imwheel.c imwheel-1.0.0pre12.fixed/imwheel.c
  45. --- imwheel-1.0.0pre12/imwheel.c        2015-09-12 12:29:58.000000000 +0300
  46. +++ imwheel-1.0.0pre12.fixed/imwheel.c  2015-09-12 12:19:22.000000000 +0300
  47. @@ -24,6 +24,7 @@
  48.  #include "cfg.h"
  49.  #include "imwheel.h"
  50.  #include <X11/Xmu/WinUtil.h>
  51. +#include <X11/Xatom.h>
  52.  
  53.  #define HISTORY_LENGTH 3
  54.  #define CONFIG_TIME 4
  55. @@ -40,7 +41,7 @@
  56.  
  57.  /*----------------------------------------------------------------------------*/
  58.  
  59. -char *opts="a:b:c4fgiW:dpDKkRrqh?X:t:vxs:";
  60. +char *opts="a:b:c4fgMFSiW:dpDKkRrqh?X:t:vxs:";
  61.  const struct option options[]=
  62.  { /*{name,                     need/opt_arg,   flag,   val}*/
  63.         {"auto-repeat",         1,                      0,              'a'},
  64. @@ -52,6 +53,9 @@
  65.         {"flip-buttons",        0,                      0,              '4'},
  66.         {"focus",                       0,                      0,              'f'},
  67.         {"focus-events",        0,                      0,              'g'},
  68. +       {"mouse-focus",         0,                      0,              'M'},
  69. +       {"return-focus",        0,                      0,              'F'},
  70. +       //{"send-events",               0,                      0,              'S'}, //broken
  71.         {"help",                        0,                      0,              'h'},
  72.         {"key-defaults",        0,                      0,              'K'},
  73.         {"kill",                        0,                      0,              'k'},
  74. @@ -73,6 +77,9 @@
  75.         {NULL,                          "Swaps buttons 4 and 5 events (same as -b "5 4")"},                             //4
  76.         {NULL,                          "Use event subwindow instead of XGetInputFocus"},                       //f
  77.         {NULL,                          "Disable the use of Focus Events for button grabs"},            //g
  78. +       {NULL,                          "Use mouse position instead of focus (do not use with -g/-f)"},//M
  79. +       {NULL,                          "When using mouse focus, return the focus after action"},//M
  80. +       //{NULL,                                "No focus switch (consistent -M, XSendEvent-ok apps only)"},//S
  81.         {NULL,                          "For this help!  Now you know"},                                                        //h
  82.         {NULL,                          "Use the old key style default actions"},                                       //K
  83.         {NULL,                          "Kills the running imwheel process"},                                           //k
  84. @@ -86,11 +93,16 @@
  85.  int buttonFlip=False, useFifo=False, detach=True, quit=False,
  86.      restart=False, threshhold=0, focusOverride=True, sensitivity=0, transpose=False,
  87.         handleFocusGrab=True, doConfig=False, root_wheeling=False, autodelay=250,
  88. -       keystyledefaults=0;
  89. +       keystyledefaults=0, mouseFocus=False, useSendEvent=False, returnFocus=False;
  90.  int fifofd=-1;
  91.  char *fifoName="/dev/gpmwheel", *displayName=NULL;
  92.  Bool grabbed;
  93.  Atom ATOM_NET_WM_NAME, ATOM_UTF8_STRING, ATOM_WM_NAME, ATOM_STRING;
  94. +int xerror = 0;
  95. +
  96. +
  97. +uint64_t current_excludemask;
  98. +
  99.  
  100.  /*----------------------------------------------------------------------------*/
  101.  
  102. @@ -122,17 +134,30 @@
  103.  
  104.  /*----------------------------------------------------------------------------*/
  105.  
  106. -void grabButtons(Display *d, Window w)
  107. +void grabButtonsCustom(Display *d, Window w, uint64_t exclude_mask)
  108.  {
  109.         int i;
  110.  
  111.         if(useFifo)
  112.                 return;
  113. -       Printf("Grab buttons!n");
  114. +
  115. +       if(grabbed)
  116. +       {
  117. +               if (current_excludemask != exclude_mask)
  118. +                       ungrabButtons(d, w);
  119. +               else
  120. +                       return;
  121. +       }
  122. +
  123. +       Printf("Grab buttons! %llx!n", exclude_mask);
  124.         grabbed=True;
  125. +       current_excludemask=exclude_mask;
  126. +
  127. +       uint64_t mask = ~exclude_mask;
  128. +
  129.         for(i=0;i<buttons_cnt;i++)
  130.         {
  131. -               if(buttons[i])
  132. +               if(buttons[i] && mask & (1 << buttons[i]))
  133.                 {
  134.                         Printf("Grabbing Button %d...n",buttons[i]);
  135.                         XGrabButton(
  136. @@ -150,6 +175,11 @@
  137.         }
  138.  }
  139.  
  140. +void grabButtons(Display *d, Window w)
  141. +{
  142. +       grabButtonsCustom(d, w, 0);
  143. +}
  144. +
  145.  /*----------------------------------------------------------------------------*/
  146.  
  147.  void ungrabButtons(Display *d, Window w)
  148. @@ -161,6 +191,7 @@
  149.         Printf("Ungrab buttons!n");
  150.         XSync(d,False);
  151.         grabbed=False;
  152. +       current_excludemask = ALL_BUTTONS_MASK;
  153.         for(i=0;i<buttons_cnt;i++)
  154.         {
  155.                 if(buttons[i])
  156. @@ -179,6 +210,157 @@
  157.         XSync(d,False);
  158.  }
  159.  
  160. +Bool checkWindow(Display *d, Window win) {
  161. +    //Atom wm_name = XInternAtom(d, "WM_NAME", True);
  162. +    Atom wm_name = XInternAtom(d, "WM_CLASS", True);
  163. +    Atom wm_state = XInternAtom(d, "WM_STATE", True);
  164. +
  165. +    unsigned char *property;
  166. +
  167. +    unsigned long nitems;
  168. +    unsigned long bytes;
  169. +    Atom type;
  170. +    int format, status;
  171. +
  172. +    XWindowAttributes xwa;
  173. +
  174. +    XGetWindowAttributes(d, win, &xwa);
  175. +    if (xwa.class != InputOutput || xwa.map_state != IsViewable) {
  176. +        return False;
  177. +    }
  178. +
  179. +    property = NULL;
  180. +    status = XGetWindowProperty(d, win, wm_name, 0, (~0L),
  181. +                                False, AnyPropertyType, &type,
  182. +                                &format, &nitems, &bytes,
  183. +                                &property);
  184. +    if (property)
  185. +        XFree(property);
  186. +    if (status != Success || !nitems) {
  187. +        return False;
  188. +    }
  189. +
  190. +    property = NULL;
  191. +    status = XGetWindowProperty(d, win, wm_state, 0, (~0L),
  192. +                                    False, AnyPropertyType, &type,
  193. +                                    &format, &nitems, &bytes,
  194. +                                    &property);
  195. +    if (property)
  196. +        XFree(property);
  197. +
  198. +    if (status != Success || !nitems) {
  199. +        XFree(property);
  200. +        return False;
  201. +    }
  202. +
  203. +    return True;
  204. +}
  205. +
  206. +Window getWindowFromChildren(Display *d, Window win) {
  207. +    Window foo, parent;
  208. +    Status status;
  209. +    unsigned int n;
  210. +    int j;
  211. +    Window *wins;
  212. +
  213. +    status = XQueryTree(d, win, &foo, &parent, &wins, &n);
  214. +    if (status == 0) {
  215. +        //Printf("!!!!!!!!!! Window: %d; NO Childrenn");
  216. +        return win;
  217. +    }
  218. +
  219. +    //Printf("!!!!!!!!!! Window: %d; Children: %d, parent: %dn", (int) win, n, (int) parent);
  220. +    for (j = (int) n - 1; j >= 0; j--) {
  221. +        //Printf("!!!!!!!!!! Window: %d -> CHILD %dn", (int) win, (int) wins[j]);
  222. +        XWindowAttributes xwa;
  223. +
  224. +        XGetWindowAttributes(d, wins[j], &xwa);
  225. +        if (xwa.class != InputOutput || xwa.map_state != IsViewable) {
  226. +            wins[j] = None;
  227. +            continue;
  228. +        }
  229. +
  230. +        if (checkWindow(d, wins[j])) {
  231. +            //Printf("!!!!!!!!!! Subwindow is a-OK: %dn", (int) wins[j]);
  232. +            win = wins[j];
  233. +            goto done;
  234. +        }
  235. +    }
  236. +
  237. +    for (j = (int) n - 1; j >= 0; j--) {
  238. +        if (wins[j] == None)
  239. +            continue;
  240. +        Window candidate = getWindowFromChildren(d, wins[j]);
  241. +        if (candidate != None && candidate != wins[j]) {
  242. +            win = candidate;
  243. +            goto done;
  244. +        }
  245. +    }
  246. +
  247. +done:
  248. +    XFree(wins);
  249. +   // Printf("!!!!!!!!!! Final Window: %dn", (int) win);
  250. +    return win;
  251. +}
  252. +
  253. +Window getCursorWindow(Display *d) {
  254. +    Window foo;
  255. +    Window win;
  256. +    Window *roots = NULL;
  257. +    Atom type;
  258. +    unsigned long i;
  259. +    int format, status;
  260. +    unsigned long nroots = 0, nrootsbytes = 0;
  261. +    int bar;
  262. +
  263. +    Atom virt_roots = XInternAtom(d, "_NET_VIRTUAL_ROOTS", True);
  264. +
  265. +    if (virt_roots != None) {
  266. +
  267. +        status = XGetWindowProperty(d, DefaultRootWindow(d),
  268. +                                    virt_roots, 0, (~0L),
  269. +                                    False, XA_WINDOW, &type,
  270. +                                    &format, &nroots, &nrootsbytes,
  271. +                                    (unsigned char**) &roots);
  272. +        if (status != Success) {
  273. +            roots = NULL;
  274. +            nroots = 0;
  275. +        }
  276. +    }
  277. +
  278. +    Window cur_root = DefaultRootWindow(d);
  279. +    int is_still_root = 1;
  280. +    do {
  281. +        do {
  282. +            (void) XQueryPointer(d, cur_root, &foo, &win,
  283. +                                 &bar, &bar, &bar, &bar, &bar);
  284. +
  285. +        } while(win <= 0);
  286. +
  287. +        is_still_root = 0;
  288. +
  289. +        for (i = 0; i < nroots; i++) {
  290. +            //Printf("!!!!!!!! ROOOT CHECK %d ?= %dn", (int) roots[i], win);
  291. +            if (roots[i] == win) {
  292. +                //Printf("!!!!!!!! ROOOT MATCH %d = %dn", (int) roots[i], win);
  293. +                is_still_root = 1;
  294. +                cur_root = win;
  295. +                break;
  296. +            }
  297. +        }
  298. +    } while (is_still_root);
  299. +
  300. +    if (roots)
  301. +        XFree(roots);
  302. +        
  303. +    if (checkWindow(d, win)) {
  304. +        //Printf("!!!!!!!!!! Main window is a-OK: %dn", (int) win);
  305. +        return win;
  306. +    }
  307. +
  308. +    return getWindowFromChildren(d, win);
  309. +}
  310. +
  311.  /*----------------------------------------------------------------------------*/
  312.  
  313.  Display *start(char *display)
  314. @@ -202,6 +384,47 @@
  315.         {
  316.                 grabButtons(d,0);
  317.                 XSelectInput(d,DefaultRootWindow(d),PointerMotionMask);
  318. +
  319. +               if (!mouseFocus) {
  320. +                       Window w, wnew;
  321. +                       int ignored;
  322. +                       const struct timespec retry_period = {0, 10000000};
  323. +                       do {
  324. +                               do {
  325. +                                       XGetInputFocus(d, &w, &ignored);
  326. +                                       if (w == PointerRoot || w == None)
  327. +                                               nanosleep(&retry_period, NULL);
  328. +                               } while (w == PointerRoot || w == None);
  329. +
  330. +                               xerror = 0;
  331. +                               XSelectInput(d, w, FocusChangeMask | StructureNotifyMask);
  332. +                               XGetInputFocus(d, &wnew, &ignored);
  333. +                               if (xerror == BadWindow || wnew != w) {
  334. +                                       nanosleep(&retry_period, NULL);
  335. +                                       Printf("THIS HAPPENED %d, %d !!!!n", (int) (xerror == BadWindow), (int) (wnew != w));
  336. +                               }
  337. +                       } while (xerror == BadWindow || wnew != w);
  338. +               }
  339. +               else {
  340. +                       Window w, wnew, root;
  341. +                       int ig1, ig2, ig3, ig4;
  342. +                       unsigned int ig5;
  343. +                       const struct timespec retry_period = {0, 10000000};
  344. +                       do {
  345. +                               XQueryPointer(d, DefaultRootWindow(d), &root, &w,
  346. +                                             &ig1, &ig2, &ig3, &ig4, &ig5);
  347. +                               //w = getCursorWindow(d);
  348. +                               xerror = 0;
  349. +                               XSelectInput(d, w, LeaveWindowMask | StructureNotifyMask);
  350. +                               XQueryPointer(d, DefaultRootWindow(d), &root, &wnew,
  351. +                                             &ig1, &ig2, &ig3, &ig4, &ig5);
  352. +                               //wnew = getCursorWindow(d);
  353. +                               if (xerror == BadWindow || wnew != w) {
  354. +                                       nanosleep(&retry_period, NULL);
  355. +                                       Printf("THIS HAPPENED %d, %d !!!!n", (int) (xerror == BadWindow), (int) (wnew != w));
  356. +                               }
  357. +                       } while (xerror == BadWindow || wnew != w);
  358. +               }
  359.         }
  360.         return(d);
  361.  }
  362. @@ -319,6 +542,16 @@
  363.                         }
  364.                 }
  365.         }
  366. +
  367. +       if(e->type==DestroyNotify)
  368. +       {
  369. +               Printf("Window destroyed!!!!!!!!!!!!!!!!!!!!n");
  370. +               if (mouseFocus)
  371. +                       e->type = LeaveNotify;
  372. +               else
  373. +                       e->type = FocusOut;
  374. +       }
  375. +
  376.         if(e->type==ButtonPress
  377.            && (isUsedButton(e->xbutton.button) || (!useFifo && grabbed)))
  378.         {
  379. @@ -336,16 +569,65 @@
  380.         else
  381.         {
  382.                 e->xbutton.button=button=0;
  383. -               e->type=None;
  384. +               if (e->type != FocusOut && e->type != LeaveNotify)
  385. +                       e->type=None;
  386.         }
  387. -       if(handleFocusGrab && e->type==FocusOut && (!useFifo && !grabbed))
  388. +       if(handleFocusGrab && e->type==FocusOut && (!useFifo))
  389.         {
  390. +               Window w, wnew;
  391. +               int ignored;
  392. +               const struct timespec retry_period = {0, 10000000};
  393. +
  394.                 // the focus is leaving the @ExcludeŽd window,
  395.                 // so we want to grab the buttons again
  396. -               grabButtons(d,0);
  397. +//             if (!grabbed)
  398. +//                     grabButtons(d,0);
  399.                 // we don't need any further events from that window for now
  400.                 // we asked for events during ungrab...below
  401.                 XSelectInput(d, e->xany.window, NoEventMask);
  402. +               do {
  403. +                       do {
  404. +                               XGetInputFocus(d, &w, &ignored);
  405. +                               if (w == PointerRoot || w == None)
  406. +                                       nanosleep(&retry_period, NULL);
  407. +                       } while (w == PointerRoot || w == None);
  408. +
  409. +                       xerror = 0;
  410. +                       XSelectInput(d, w, FocusChangeMask | StructureNotifyMask);
  411. +                       XGetInputFocus(d, &wnew, &ignored);
  412. +                       if (xerror == BadWindow || wnew != w) {
  413. +                               nanosleep(&retry_period, NULL);
  414. +                               Printf("THIS HAPPENED %d, %d !!!!n", (int) (xerror == BadWindow), (int) (wnew != w));
  415. +                       }
  416. +               } while (xerror == BadWindow || wnew != w);
  417. +
  418. +       }
  419. +       if(handleFocusGrab && mouseFocus && e->type==LeaveNotify && (!useFifo))
  420. +       {
  421. +               Window w, wnew, root;
  422. +               int ig1, ig2, ig3, ig4, ig5;
  423. +               const struct timespec retry_period = {0, 10000000};
  424. +
  425. +//             if (!grabbed)
  426. +//                     grabButtons(d,0);
  427. +               XSelectInput(d, e->xany.window, NoEventMask);
  428. +
  429. +               do {
  430. +                       XQueryPointer(d, DefaultRootWindow(d), &root, &w,
  431. +                                     &ig1, &ig2, &ig3, &ig4, &ig5);
  432. +                       //w = getCursorWindow(d);
  433. +
  434. +                       xerror = 0;
  435. +                       XSelectInput(d, w, LeaveWindowMask | StructureNotifyMask);
  436. +                       XQueryPointer(d, DefaultRootWindow(d), &root, &wnew,
  437. +                                     &ig1, &ig2, &ig3, &ig4, &ig5);
  438. +                       //wnew = getCursorWindow(d);
  439. +                       if (xerror == BadWindow || wnew != w) {
  440. +                               nanosleep(&retry_period, NULL);
  441. +                               Printf("THIS HAPPENED %d, %d !!!!n", (int) (xerror == BadWindow), (int) (wnew != w));
  442. +                       }
  443. +               } while (xerror == BadWindow || wnew != w);
  444. +
  445.         }
  446.         if(e->type==ButtonPress)
  447.                 Printf("getInput: Button=%dn",button);
  448. @@ -412,17 +694,20 @@
  449.         XModifierKeymap *xmk=NULL;
  450.         signed char km[32],button;
  451.         struct WinAction *wap=NULL, *ungrabwap=NULL, *grabwap=NULL;
  452. +       uint64_t new_excludemask = 0;
  453.         Window oldw=0;
  454.         int isdiffwin;
  455.         struct {time_t t; int motion;} history[HISTORY_LENGTH];
  456.  
  457.         XSetErrorHandler((XErrorHandler)nullXError);
  458. +       XSynchronize(d, True);
  459.         if(doConfig)
  460.                 openCfg(d,argv,&xmk);
  461.         memset(history,0,sizeof(history));
  462.         while(True)
  463.         {
  464. -               int i;
  465. +               Window oldFocus;
  466. +               int i, ignored;
  467.                 if(!useFifo || !wap || wap->reps) // auto-repeat kinda eats fifo events :(
  468.                         getInput(d,&e,&xmk,km);
  469.                 if(!e.type)
  470. @@ -430,9 +715,16 @@
  471.                 button=e.xbutton.button;
  472.                 //get current input window & it's name
  473.                 i=CurrentTime;
  474. -               if(focusOverride || !e.xbutton.subwindow) //not up to ICCCM standards
  475. +               if(focusOverride || mouseFocus || !e.xbutton.subwindow) { //not up to ICCCM standards
  476.                         // focusOverride: default is true, so this is the default action
  477. -                       XGetInputFocus(d,&e.xbutton.subwindow,&i);
  478. +                       Window root;
  479. +                       if (!mouseFocus)
  480. +                               XGetInputFocus(d,&e.xbutton.subwindow,&i);
  481. +                       else
  482. +                               //XQueryPointer(d,DefaultRootWindow(d),&root,&e.xbutton.subwindow,&i,&i,&i,&i,&i);
  483. +                               e.xbutton.subwindow = getCursorWindow(d);
  484. +
  485. +               }
  486.                 else
  487.                 { /* pulled from xwininfo */
  488.                         Window root,window=e.xbutton.subwindow;
  489. @@ -476,7 +768,7 @@
  490.                                                         XFree(kids);
  491.                                         }
  492.                                         Printf("w:%p r:%p ew:%p et:%dn",win, root, e.xbutton.subwindow, e.type);
  493. -                               } while(!wname && root!=win && root);
  494. +                               } while(!wname && root!=win && e.xbutton.subwindow!=win && root);
  495.                 }
  496.                 isdiffwin=(e.xbutton.subwindow!=oldw);
  497.                 oldw=e.xbutton.subwindow;
  498. @@ -507,27 +799,33 @@
  499.                                         Printf("class name           ="%s"n",xch.res_class);
  500.                                 }
  501.                                 break;
  502. -               }
  503. +               }      
  504.                 if (!wname) wname = strdup(emptystr);
  505.                 if (!xch.res_name) xch.res_name = strdup(emptystr);
  506.                 if (!xch.res_class) xch.res_class = strdup(emptystr);
  507.                 ungrabwap=0;
  508.                 grabwap=0;
  509. +               new_excludemask=0;
  510.                 if(!useFifo)
  511.                 {
  512. -                       if(isdiffwin || e.type==ButtonPress)
  513. +                       if(isdiffwin || e.type==ButtonPress || e.type == FocusOut || e.type == LeaveNotify)
  514.                         {
  515.                                 ungrabwap=findWA(d,UNGRAB,
  516.                                                 wname,
  517.                                                 xch.res_name,
  518.                                                 xch.res_class,
  519.                                                 NULL,NULL);
  520. -                               if(ungrabwap)
  521. +                               if(ungrabwap && ungrabwap->exclude_mask != ALL_BUTTONS_MASK) {
  522. +                                       new_excludemask = ungrabwap->exclude_mask;
  523. +                                       ungrabwap = 0;
  524. +                               }
  525. +                               if(ungrabwap) {
  526.                                         grabwap=findWA(d,GRAB,
  527.                                                         wname,
  528.                                                         xch.res_name,
  529.                                                         xch.res_class,
  530.                                                         NULL,NULL);
  531. +                               }
  532.                                 if(grabwap)
  533.                                 {
  534.                                         Printf("Action defined for window overrides ungrab commandn");
  535. @@ -541,12 +839,17 @@
  536.                         Printf("grabbed=%dn",grabbed);
  537.                         Printf("e.type=%dn",e.type);
  538.  #endif
  539. -                       if(ungrabwap && grabbed && (e.type==ButtonPress || e.type==FocusIn || !e.type))
  540. +                       if(ungrabwap && grabbed && (e.type==ButtonPress || e.type==FocusIn || e.type == FocusOut || e.type == LeaveNotify || !e.type))
  541.                                 e.type=MotionNotify;
  542.                         // force a regrab try
  543.                         if(!ungrabwap && !grabwap && !grabbed && isdiffwin)
  544.                                 e.type=MotionNotify;
  545. +                       if(new_excludemask != current_excludemask)
  546. +                               e.type=MotionNotify;
  547. +                       if(e.type == FocusOut || e.type == LeaveNotify)
  548. +                               e.type=MotionNotify;
  549.                 }
  550. +               Printf("wname=%s,wid=%dn", wname,e.xbutton.subwindow);
  551.                 switch(e.type) // now we actually do something!
  552.                 {
  553.                         case MotionNotify:
  554. @@ -559,13 +862,13 @@
  555.                                                 if(handleFocusGrab)
  556.                                                 {
  557.                                                         // notify us when the focus leaves this window
  558. -                                                       XSelectInput(d, e.xbutton.subwindow,
  559. -                                                                       FocusChangeMask);
  560. +                                                       //XSelectInput(d, e.xbutton.subwindow,
  561. +                                                       //              FocusChangeMask);
  562.                                                 }
  563.                                         }
  564.                                         else
  565. -                                               if(!grabbed)
  566. -                                                       grabButtons(d,0);
  567. +                                               if(!grabbed || new_excludemask != current_excludemask)
  568. +                                                       grabButtonsCustom(d,0,new_excludemask);
  569.                                 }
  570.                                 break;
  571.                         case ButtonPress:
  572. @@ -618,7 +921,15 @@
  573.  
  574.                                                 snprintf(bstr,9,"Button%-2d",button);
  575.                                                 out[0]=bstr;
  576. +                                               if (mouseFocus && !useSendEvent) {
  577. +                                                       if (returnFocus)
  578. +                                                               XGetInputFocus(d, &oldFocus, &ignored);
  579. +                                                       XSetInputFocus(d,e.xbutton.subwindow,RevertToParent,CurrentTime);
  580. +                                               }
  581. +                                               Printf("Sending event to 0x%xn", (int) e.xbutton.subwindow);
  582.                                                 doWA(d,(XButtonEvent*)&e.xbutton,xmk,km,&wa);
  583. +                                               if (returnFocus && mouseFocus && !useSendEvent)
  584. +                                                       XSetInputFocus(d,oldFocus,RevertToParent,CurrentTime);
  585.                                         }
  586.                                         else
  587.                                         {       /* old key style... */
  588. @@ -647,8 +958,15 @@
  589.                                                
  590.                                                 out[0]=(char*)keys[j][k];
  591.                                                 wa.reps=reps[k];
  592. +                                               if (mouseFocus && !useSendEvent) {
  593. +                                                       if (returnFocus)
  594. +                                                               XGetInputFocus(d, &oldFocus, &ignored);
  595. +                                                       XSetInputFocus(d,e.xbutton.subwindow,RevertToParent,CurrentTime);
  596. +                                               }
  597. +                                               Printf("Sending event to 0x%xn", (int) e.xbutton.subwindow);
  598.                                                 doWA(d,(XButtonEvent*)&e.xbutton,xmk,km,&wa);
  599. -
  600. +                                               if (returnFocus && mouseFocus && !useSendEvent)
  601. +                                                       XSetInputFocus(d,oldFocus,RevertToParent,CurrentTime);
  602.                                                 /* old code...
  603.                                                 int kc=XKeysymToKeycode(d, XStringToKeysym(keys[j][k]));
  604.                                                 Printf("keycode=%dn",kc);
  605. @@ -667,8 +985,17 @@
  606.                                                 */
  607.                                         }
  608.                                 }
  609. -                               else
  610. +                               else {
  611. +                                       if (mouseFocus && !useSendEvent) {
  612. +                                               if (returnFocus)
  613. +                                                       XGetInputFocus(d, &oldFocus, &ignored);
  614. +                                               XSetInputFocus(d,e.xbutton.subwindow,RevertToParent,CurrentTime);
  615. +                                       }
  616. +                                       Printf("Sending event to 0x%xn", (int) e.xbutton.subwindow);
  617.                                         doWA(d,(XButtonEvent*)&e.xbutton,xmk,km,wap);
  618. +                                       if (returnFocus && mouseFocus && !useSendEvent)
  619. +                                               XSetInputFocus(d,oldFocus,RevertToParent,CurrentTime);
  620. +                               }
  621.                                 XTestGrabControl(d,False);
  622.                                 //XQueryPointer(d,DefaultRootWindow(d),&e.xbutton.subwindow,&e.xbutton.subwindow,&i,&i,&i,&i,&i);
  623.                                 //XSetInputFocus(d,e.xbutton.subwindow,RevertToParent,CurrentTime);
  624. @@ -711,7 +1038,7 @@
  625.  {
  626.         signed char errorstr[1024];
  627.  
  628. -       grabbed=False;
  629. +       //grabbed=False;
  630.         Printf("XError: n");
  631.         Printf("tserial      : %lun",e->serial);
  632.         Printf("terror_code  : %un",e->error_code);
  633. @@ -720,6 +1047,7 @@
  634.         Printf("tresourceid  : %lun",e->resourceid);
  635.         XGetErrorText(d,e->error_code,errorstr,1024);
  636.         Printf("terror string: %sn",errorstr);
  637. +       xerror = e->error_code;
  638.         return(0);
  639.  }
  640.  
  641. diff -ru imwheel-1.0.0pre12/imwheel.h imwheel-1.0.0pre12.fixed/imwheel.h
  642. --- imwheel-1.0.0pre12/imwheel.h        2004-08-29 13:22:12.000000000 +0300
  643. +++ imwheel-1.0.0pre12.fixed/imwheel.h  2015-09-12 12:19:22.000000000 +0300
  644. @@ -19,7 +19,8 @@
  645.  extern Bool grabbed;
  646.  extern int buttonFlip, useFifo, detach, quit, restart, threshhold,
  647.                         focusOverride, sensitivity, transpose, handleFocusGrab, doConfig,
  648. -                       root_wheeling, autodelay, keystyledefaults;
  649. +                       root_wheeling, autodelay, keystyledefaults, mouseFocus, useSendEvent,
  650. +                       returnFocus;
  651.  extern int fifofd;
  652.  extern char *fifoName, *displayName;
  653.  extern Stick stick;
  654. diff -ru imwheel-1.0.0pre12/util.c imwheel-1.0.0pre12.fixed/util.c
  655. --- imwheel-1.0.0pre12/util.c   2015-09-12 12:29:58.000000000 +0300
  656. +++ imwheel-1.0.0pre12.fixed/util.c     2015-09-12 12:19:22.000000000 +0300
  657. @@ -284,6 +284,15 @@
  658.                         case 'g':
  659.                                 handleFocusGrab=!handleFocusGrab;
  660.                                 break;
  661. +                       case 'M':
  662. +                               mouseFocus=!mouseFocus;
  663. +                               break;
  664. +                       case 'F':
  665. +                               returnFocus=!returnFocus;
  666. +                               break;
  667. +                       case 'S':
  668. +                               useSendEvent=!useSendEvent;
  669. +                               break;
  670.                         case 'X':
  671.                                 displayName=strdup(optarg);
  672.                                 break;
  673. @@ -490,12 +499,13 @@
  674.  
  675.  void printXEvent(XEvent *e)
  676.  {
  677. +       Printf("====================n");
  678.         Printf("type=%dn",e->type);
  679.         Printf("serial    =%lun",e->xany.serial);
  680.         Printf("send_event=%dn",e->xany.send_event);
  681.         Printf("display   =%pn",e->xany.display);
  682.         Printf("window    =0x%08xn",(unsigned)e->xany.window);
  683. -       if(e->type&(ButtonRelease|ButtonPress))
  684. +       if(e->type == ButtonRelease || e->type == ButtonPress)
  685.         {
  686.                 Printf("root         =0x%08xn",(unsigned)e->xbutton.root);
  687.                 Printf("subwindow    =0x%08xn",(unsigned)e->xbutton.subwindow);
  688. @@ -507,6 +517,18 @@
  689.                 Printf("same_screen  =0x%xn",(unsigned)e->xbutton.same_screen);
  690.                 Printf("n");
  691.         }
  692. +       if(e->type == KeyRelease || e->type == KeyPress)
  693. +       {
  694. +               Printf("root         =0x%08xn",(unsigned)e->xkey.root);
  695. +               Printf("subwindow    =0x%08xn",(unsigned)e->xkey.subwindow);
  696. +               Printf("time         =0x%08xn",(unsigned)e->xkey.time);
  697. +               Printf("     x,y     =%d,%dn",e->xkey.x,e->xkey.y);
  698. +               Printf("x_root,y_root=%d,%dn",e->xkey.x_root,e->xkey.y_root);
  699. +               Printf("state        =0x%xn",(unsigned)e->xkey.state);
  700. +               Printf("keycode      =0x%xn",(unsigned)e->xkey.keycode);
  701. +               Printf("same_screen  =0x%xn",(unsigned)e->xkey.same_screen);
  702. +               Printf("n");
  703. +       }
  704.  }
  705.  
  706.  /*----------------------------------------------------------------------------*/
  707. @@ -871,14 +893,40 @@
  708.                         newwa[num_wa].delayup=0;
  709.                         newwa[num_wa].pri=pri;
  710.                         newwa[num_wa].button=0;
  711. +                       newwa[num_wa].exclude_mask=0;
  712.                         num_wa++;
  713.                         //Get Command (if any)
  714.                         if(line[0]=='@')
  715.                         {
  716.                                 if(!strcasecmp(line+1,"Exclude"))
  717. +                               {
  718. +                                       newwa[num_wa-1].exclude_mask=ALL_BUTTONS_MASK;
  719.                                         newwa[num_wa-1].button=UNGRAB;
  720. +                               }
  721.                                 else if(!strcasecmp(line+1,"Repeat"))
  722.                                         newwa[num_wa-1].button=REPEAT;
  723. +                               else if(!strncasecmp(line+1,"Exclude=",8))
  724. +                               {
  725. +                                       char *arg = line + 9;
  726. +                                       char *tok;
  727. +
  728. +                                       newwa[num_wa-1].exclude_mask=0;
  729. +                                       newwa[num_wa-1].button=UNGRAB;
  730. +
  731. +                                       for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ","))
  732. +                                       {
  733. +                                              
  734. +                                               for(i=0; i<buttons_cnt; i++)
  735. +                                               {
  736. +                                                       if(!strcasecmp(tok,(*button_names)[i]))
  737. +                                                       {
  738. +                                                               if(buttons[i])
  739. +                                                                       newwa[num_wa-1].exclude_mask |= 1 << buttons[i];
  740. +                                                               break;
  741. +                                                       }
  742. +                                               }
  743. +                                       }
  744. +                               }
  745.                                 else if(!strncasecmp(line+1,"Priority=",9))
  746.                                 {
  747.                                         pri=strtol(line+10,NULL,10);
  748. @@ -1367,15 +1415,60 @@
  749.         Printf("doWA:n");
  750.         printWA(wap);
  751.  
  752. +       Bool doSendEvent = False;
  753. +       if (mouseFocus && useSendEvent) {
  754. +               Window focus;
  755. +               int ignored;
  756. +               XGetInputFocus(d, &focus, &ignored);
  757. +               if (focus != e->subwindow)
  758. +                       doSendEvent = True;
  759. +       }
  760. +
  761. +       XButtonEvent xbutev;
  762. +       XKeyEvent xkeyev;
  763. +
  764. +       if (doSendEvent) {
  765. +               xbutev = *e;
  766. +               xbutev.window = e->subwindow;
  767. +               xbutev.subwindow = None;
  768. +
  769. +               xkeyev.display = d;
  770. +               xkeyev.subwindow = e->subwindow;
  771. +               xkeyev.time = CurrentTime;
  772. +               xkeyev.same_screen = True;
  773. +               //xkeyev.window = e->window;
  774. +               xkeyev.window = e->subwindow;
  775. +               //xkeyev.subwindow = e->subwindow;
  776. +               xkeyev.subwindow = None;
  777. +               xkeyev.state = 0;
  778. +       }
  779. +
  780.         if(wap->button==REPEAT)
  781.         {
  782.                 Printf("doWA: button down = %dn",e->button);
  783. -               XTestFakeButtonEvent(d,e->button,True,CurrentTime);
  784. +
  785. +               if (doSendEvent) {
  786. +                       xbutev.time = CurrentTime;
  787. +                       xbutev.type = ButtonPress;
  788. +                       printXEvent((XEvent *) &xbutev);
  789. +                       XSendEvent(d, e->subwindow, True, ButtonPressMask,
  790. +                                  (XEvent *) &xbutev);
  791. +               }
  792. +               else
  793. +                       XTestFakeButtonEvent(d,e->button,True,CurrentTime);
  794.                 XFlush(d);
  795.                 /*Printf("doWA: button delay...n");
  796.                 delay(1000); */
  797.                 Printf("doWA: button up = %dn",e->button);
  798. -               XTestFakeButtonEvent(d,e->button,False,CurrentTime);
  799. +               if (doSendEvent) {
  800. +                       xbutev.time = CurrentTime;
  801. +                       xbutev.type = ButtonRelease;
  802. +                       printXEvent((XEvent *) &xbutev);
  803. +                       XSendEvent(d, e->subwindow, True, ButtonPressMask,
  804. +                                  (XEvent *) &xbutev);
  805. +               }
  806. +               else
  807. +                       XTestFakeButtonEvent(d,e->button,False,CurrentTime);
  808.                 XFlush(d);
  809.                 Printf("doWA: button donen");
  810.                 return;
  811. @@ -1385,13 +1478,19 @@
  812.                 Printf("doWA: UNGRAB cannot be handled here: use @Repeat or resend the Button# in the imwheelrc, i.e. None,Up,Button4n");
  813.                 return;
  814.         }
  815. -      
  816. +
  817. +
  818.         for(rep=0; rep<wap->reps || !wap->reps; rep++)
  819.         {
  820.                 if(wap->reps)
  821.                         Printf("rep=%dn",rep);
  822.                 //XSetInputFocus(d,e->subwindow,RevertToParent,CurrentTime);
  823. -               modMods(d,km,xmk,False,0);
  824. +               if (doSendEvent) {
  825. +                       xkeyev.state = km[0] | km[1] << 8 | km[2] << 16 | km[3] << 24;
  826. +                       xbutev.state = xkeyev.state;
  827. +               }
  828. +               else
  829. +                       modMods(d,km,xmk,False,0);
  830.                 //XSync(d,False); //this seems to cause apps to receive crud at random times!
  831.                 memset(nkm,0,8192);
  832.                 memset(nbm,0,16);
  833. @@ -1402,13 +1501,29 @@
  834.                                 if(wap->out[i][0]!='-')
  835.                                 {
  836.                                         kc=XKeysymToKeycode(d, XStringToKeysym(wap->out[i]));
  837. -                                       XTestFakeKeyEvent(d,kc,True,CurrentTime);
  838. +                                       if (doSendEvent) {
  839. +                                               xkeyev.keycode = kc;
  840. +                                               xkeyev.type = KeyPress;
  841. +                                               printXEvent((XEvent *) &xkeyev);
  842. +                                               XSendEvent(d, e->subwindow, True, KeyPressMask,
  843. +                                                          (XEvent *) &xkeyev);
  844. +                                       }
  845. +                                       else
  846. +                                               XTestFakeKeyEvent(d,kc,True,CurrentTime);
  847.                                         setbit(nkm,kc,True);
  848.                                 }
  849.                                 else
  850.                                 {
  851.                                         kc=XKeysymToKeycode(d, XStringToKeysym(wap->out[i]+1));
  852. -                                       XTestFakeKeyEvent(d,kc,False,CurrentTime);
  853. +                                       if (doSendEvent) {
  854. +                                               xkeyev.keycode = kc;
  855. +                                               xkeyev.type = KeyRelease;
  856. +                                               printXEvent((XEvent *) &xkeyev);
  857. +                                               XSendEvent(d, e->subwindow, True, KeyPressMask,
  858. +                                                          (XEvent *) &xkeyev);
  859. +                                       }
  860. +                                       else
  861. +                                               XTestFakeKeyEvent(d,kc,False,CurrentTime);
  862.                                         setbit(nkm,kc,False);
  863.                                 }
  864.                         }
  865. @@ -1418,14 +1533,32 @@
  866.                                 if(wap->out[i][6]!='-')
  867.                                 {
  868.                                         button=strtoul(wap->out[i]+6,NULL,10);
  869. -                                       XTestFakeButtonEvent(d,button,True,CurrentTime);
  870. +                                       if (doSendEvent) {
  871. +                                               xbutev.time = CurrentTime;
  872. +                                               xbutev.type = ButtonPress;
  873. +                                               xbutev.button = button;
  874. +                                               printXEvent((XEvent *) &xbutev);
  875. +                                               XSendEvent(d, e->subwindow, True, ButtonPressMask,
  876. +                                                          (XEvent *) &xbutev);
  877. +                                       }
  878. +                                       else
  879. +                                               XTestFakeButtonEvent(d,button,True,CurrentTime);
  880.                                         if(button<256)
  881.                                                 setbit(nbm,button,True);
  882.                                 }
  883.                                 else
  884.                                 {
  885.                                         button=strtoul(wap->out[i]+7,NULL,10);
  886. -                                       XTestFakeButtonEvent(d,button,False,CurrentTime);
  887. +                                       if (doSendEvent) {
  888. +                                               xbutev.time = CurrentTime;
  889. +                                               xbutev.type = ButtonRelease;
  890. +                                               xbutev.button = button;
  891. +                                               printXEvent((XEvent *) &xbutev);
  892. +                                               XSendEvent(d, e->subwindow, True, ButtonPressMask,
  893. +                                                          (XEvent *) &xbutev);
  894. +                                       }
  895. +                                       else
  896. +                                               XTestFakeButtonEvent(d,button,False,CurrentTime);
  897.                                         if(button<256)
  898.                                                 setbit(nbm,button,False);
  899.                                 }
  900. @@ -1444,7 +1577,15 @@
  901.                                         kc=XKeysymToKeycode(d, XStringToKeysym(wap->out[i]));
  902.                                         if(getbit(nkm,kc))
  903.                                         {
  904. -                                               XTestFakeKeyEvent(d,kc,False,CurrentTime);
  905. +                                               if (doSendEvent) {
  906. +                                                       xkeyev.keycode = kc;
  907. +                                                       xkeyev.type = KeyRelease;
  908. +                                                       printXEvent((XEvent *) &xkeyev);
  909. +                                                       XSendEvent(d, e->subwindow, True, KeyPressMask,
  910. +                                                                  (XEvent *) &xkeyev);
  911. +                                               }
  912. +                                               else
  913. +                                                       XTestFakeKeyEvent(d,kc,False,CurrentTime);
  914.                                                 setbit(nkm,kc,False);
  915.                                         }
  916.                                 }
  917. @@ -1457,7 +1598,16 @@
  918.                                         button=strtoul(wap->out[i]+6,NULL,10);
  919.                                         if(button>=256 || getbit(nbm,button))
  920.                                         {
  921. -                                               XTestFakeButtonEvent(d,button,False,CurrentTime);
  922. +                                               if (doSendEvent) {
  923. +                                                       xbutev.time = CurrentTime;
  924. +                                                       xbutev.type = ButtonRelease;
  925. +                                                       xbutev.button = button;
  926. +                                                       printXEvent((XEvent *) &xbutev);
  927. +                                                       XSendEvent(d, e->subwindow, True, ButtonPressMask,
  928. +                                                                  (XEvent *) &xbutev);
  929. +                                               }
  930. +                                               else
  931. +                                                       XTestFakeButtonEvent(d,button,False,CurrentTime);
  932.                                                 if(button<256)
  933.                                                         setbit(nbm,button,False);
  934.                                         }
  935. @@ -1467,8 +1617,12 @@
  936.                         }
  937.                 }
  938.                 XSync(d,False);
  939. -               modMods(d,km,xmk,True,0);
  940. -               XSync(d,False);
  941. +
  942. +               if (!doSendEvent) {
  943. +                       modMods(d,km,xmk,True,0);
  944. +                       XSync(d,False);
  945. +               }
  946. +
  947.                 if(wap->delay)
  948.                 {
  949.                         Printf("doWA: nextkey delay=%dn",wap->delay);
  950. diff -ru imwheel-1.0.0pre12/util.h imwheel-1.0.0pre12.fixed/util.h
  951. --- imwheel-1.0.0pre12/util.h   2015-09-12 12:29:58.000000000 +0300
  952. +++ imwheel-1.0.0pre12.fixed/util.h     2015-09-12 12:19:22.000000000 +0300
  953. @@ -7,6 +7,7 @@
  954.  #define UTIL_H
  955.  #include <config.h>
  956.  #include <getopt.h>
  957. +#include <stdint.h>
  958.  
  959.  #define PIDFILE PIDDIR"/imwheel.pid"
  960.  
  961. @@ -24,6 +25,7 @@
  962.         PRIORITY=800
  963.  };
  964.  #define MIN_COMMAND UNGRAB
  965. +#define ALL_BUTTONS_MASK 0xffffffffffffffff
  966.  
  967.  struct Trans
  968.  {
  969. @@ -40,6 +42,7 @@
  970.         int reps;       //number of repetitions
  971.         int delay;      //microsecond delay until next keypress
  972.         int delayup;//microsecond delay while key down
  973. +       uint64_t exclude_mask; // Buttons to ungrab
  974.  };
  975.  
  976.  extern int *buttons;
  977.  
captcha