1 /***************************************************************************
2         xbindkeys : a program to bind keys to commands under X11.
3                            -------------------
4     begin                : Sat Oct 13 14:11:34 CEST 2001
5     copyright            : (C) 2001 by Philippe Brochard
6     email                : hocwp@free.fr
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <X11/Xlib.h>
22 #include <X11/Xutil.h>
23 #include <unistd.h>
24 #include "keys.h"
25 #include "options.h"
26 
27 
28 
29 #define STOP_KEY "q"
30 
31 
32 #define INNER_WINDOW_WIDTH 50
33 #define INNER_WINDOW_HEIGHT 50
34 #define INNER_WINDOW_BORDER 4
35 #define INNER_WINDOW_X 10
36 #define INNER_WINDOW_Y 10
37 #define OUTER_WINDOW_MIN_WIDTH (INNER_WINDOW_WIDTH + \
38 				2 * (INNER_WINDOW_BORDER + INNER_WINDOW_X))
39 #define OUTER_WINDOW_MIN_HEIGHT (INNER_WINDOW_HEIGHT + \
40 				2 * (INNER_WINDOW_BORDER + INNER_WINDOW_Y))
41 #define OUTER_WINDOW_DEF_WIDTH (OUTER_WINDOW_MIN_WIDTH + 200)
42 #define OUTER_WINDOW_DEF_HEIGHT (OUTER_WINDOW_MIN_HEIGHT + 4)
43 #define OUTER_WINDOW_DEF_X 200
44 #define OUTER_WINDOW_DEF_Y 4
45 
46 
47 
48 void
set_sizehints(Display * dpy,XSizeHints * hintp,int min_width,int min_height,int defwidth,int defheight,int defx,int defy)49 set_sizehints (Display * dpy, XSizeHints * hintp, int min_width,
50 	       int min_height, int defwidth, int defheight, int defx,
51 	       int defy)
52 {
53   int geom_result;
54 
55   /* set the size hints, algorithm from xlib xbiff */
56 
57   hintp->width = hintp->min_width = min_width;
58   hintp->height = hintp->min_height = min_height;
59   hintp->flags = PMinSize;
60   hintp->x = hintp->y = 0;
61   geom_result = NoValue;
62   if (geom != NULL)
63     {
64       geom_result = XParseGeometry (geom, &hintp->x, &hintp->y,
65 				    (unsigned int *) &hintp->width,
66 				    (unsigned int *) &hintp->height);
67       if ((geom_result & WidthValue) && (geom_result & HeightValue))
68 	{
69 #define max(a,b) ((a) > (b) ? (a) : (b))
70 	  hintp->width = max (hintp->width, hintp->min_width);
71 	  hintp->height = max (hintp->height, hintp->min_height);
72 	  hintp->flags |= USSize;
73 	}
74       if ((geom_result & XValue) && (geom_result & YValue))
75 	{
76 	  hintp->flags += USPosition;
77 	}
78     }
79   if (!(hintp->flags & USSize))
80     {
81       hintp->width = defwidth;
82       hintp->height = defheight;
83       hintp->flags |= PSize;
84     }
85 
86   if (geom_result & XNegative)
87     {
88       hintp->x = DisplayWidth (dpy, DefaultScreen (dpy)) + hintp->x -
89 	hintp->width;
90     }
91   if (geom_result & YNegative)
92     {
93       hintp->y = DisplayHeight (dpy, DefaultScreen (dpy)) + hintp->y -
94 	hintp->height;
95     }
96 }
97 
98 
99 
100 void
get_key_binding(Display * dpy,char ** argv,int argc)101 get_key_binding (Display * dpy, char **argv, int argc)
102 {
103   XSizeHints hints;
104   int borderwidth = 2;
105   Window w;
106   XSetWindowAttributes attr;
107   unsigned long mask = 0L;
108   int done;
109   char *name = "XBindKey: Hit a key";
110   int screen;
111   Keys_t key;
112   int min_keycode, max_keycode;
113 
114   printf ("Press combination of keys or/and click under the window.\n");
115   printf ("You can use one of the two lines after \"NoCommand\"\n");
116   printf ("in $HOME/.xbindkeysrc to bind a key.\n");
117   if (have_to_get_binding == 2)
118     printf ("\n--- Press \"%s\" to stop. ---\n", STOP_KEY);
119 
120   screen = DefaultScreen (dpy);
121 
122   attr.event_mask = KeyReleaseMask | ButtonReleaseMask;
123 
124   set_sizehints (dpy, &hints, OUTER_WINDOW_MIN_WIDTH, OUTER_WINDOW_MIN_HEIGHT,
125 		 OUTER_WINDOW_DEF_WIDTH, OUTER_WINDOW_DEF_HEIGHT,
126 		 OUTER_WINDOW_DEF_X, OUTER_WINDOW_DEF_Y);
127 
128   attr.background_pixel = WhitePixel (dpy, screen);;
129   attr.border_pixel = BlackPixel (dpy, screen);;
130   mask |= (CWBackPixel | CWBorderPixel | CWEventMask);
131 
132   w = XCreateWindow (dpy, RootWindow (dpy, screen), hints.x, hints.y,
133 		     hints.width, hints.height, borderwidth, 0,
134 		     InputOutput, (Visual *) CopyFromParent, mask, &attr);
135 
136   XSetStandardProperties (dpy, w, name, NULL, (Pixmap) 0, argv, argc, &hints);
137 
138   XMapWindow (dpy, w);
139 
140   XDisplayKeycodes (dpy, &min_keycode, &max_keycode);
141 
142   sleep (1);
143 
144   verbose = 1;
145 
146   for (done = 0; !done;)
147     {
148       XEvent event;
149 
150       XNextEvent (dpy, &event);
151 
152       switch (event.type)
153 	{
154 	case KeyRelease:
155 	  key.type = CODE;
156 	  key.event_type = PRESS;
157 	  key.key.code = event.xkey.keycode;
158 	  key.modifier = event.xkey.state;
159 	  key.command = NULL;
160 
161 	  if (have_to_get_binding == 2)
162 	    {
163 	      print_key (dpy, &key);
164 
165 	      if (event.xkey.keycode ==
166 		  XKeysymToKeycode (dpy, XStringToKeysym (STOP_KEY)))
167 		{
168 		  done = 1;
169 		}
170 	    }
171 	  else
172 	    {
173 	      print_key (dpy, &key);
174 
175 	      done = 1;
176 	    }
177 
178 	  if (event.xkey.keycode < min_keycode
179 	      || event.xkey.keycode > max_keycode)
180 	    {
181 	      fprintf (stderr,
182 		       "Note:\n"
183 		       "  The keycode %d cannot be used, as it's not between the\n"
184 		       "  min(%d) and max(%d) keycode of your keyboard.\n"
185 		       "  Please increase the 'maximum' value in\n"
186 		       "    /usr/X11R6/lib/X11/xkb/keycodes/xfree86,\n"
187 		       "  then restart X.\n",
188 		       event.xkey.keycode, min_keycode, max_keycode);
189 	    }
190 
191 	  break;
192 
193 	case ButtonRelease :
194 	  key.type = BUTTON;
195 	  key.event_type = PRESS;
196 	  key.key.button = event.xbutton.button;
197 	  key.modifier = event.xbutton.state;
198 	  key.command = NULL;
199 
200 	  print_key (dpy, &key);
201 
202 	  if (have_to_get_binding == 1)
203 	    done = 1;
204 	  break;
205 
206 
207 	default:
208 	  break;
209 	}
210     }
211 }
212