]> Dogcows Code - chaz/openbox/blob - openbox/keyboard.c
add actions for key/mouse bindings etc
[chaz/openbox] / openbox / keyboard.c
1 #include "focus.h"
2 #include "openbox.h"
3 #include "keyboard.h"
4 #include "clientwrap.h"
5
6 #include <Python.h>
7 #include <glib.h>
8 #ifdef HAVE_STRING_H
9 # include <string.h>
10 #endif
11
12 typedef struct KeyBindingTree {
13 guint state;
14 guint key;
15 GList *keylist;
16 PyObject *func;
17
18 /* the next binding in the tree at the same level */
19 struct KeyBindingTree *next_sibling;
20 /* the first child of this binding (next binding in a chained sequence).*/
21 struct KeyBindingTree *first_child;
22 } KeyBindingTree;
23
24
25 static KeyBindingTree *firstnode, *curpos;
26 static guint reset_key, reset_state;
27 static gboolean grabbed, user_grabbed;
28 static PyObject *grab_func;
29
30 /***************************************************************************
31
32 Define the type 'KeyboardData'
33
34 ***************************************************************************/
35
36 typedef struct KeyboardData {
37 PyObject_HEAD
38 PyObject *keychain;
39 guint state;
40 guint keycode;
41 gboolean press;
42 } KeyboardData;
43
44 staticforward PyTypeObject KeyboardDataType;
45
46 /***************************************************************************
47
48 Type methods/struct
49
50 ***************************************************************************/
51
52 static PyObject *keybdata_new(PyObject *keychain, guint state,
53 guint keycode, gboolean press)
54 {
55 KeyboardData *data = PyObject_New(KeyboardData, &KeyboardDataType);
56 data->keychain = keychain;
57 Py_INCREF(keychain);
58 data->state = state;
59 data->keycode = keycode;
60 data->press = press;
61 return (PyObject*) data;
62 }
63
64 static void keybdata_dealloc(KeyboardData *self)
65 {
66 Py_DECREF(self->keychain);
67 PyObject_Del((PyObject*)self);
68 }
69
70 static PyObject *keybdata_getattr(KeyboardData *self, char *name)
71 {
72 if (!strcmp(name, "keychain")) {
73 Py_INCREF(self->keychain);
74 return self->keychain;
75 } else if (!strcmp(name, "state"))
76 return PyInt_FromLong(self->state);
77 else if (!strcmp(name, "keycode"))
78 return PyInt_FromLong(self->keycode);
79 else if (!strcmp(name, "press"))
80 return PyInt_FromLong(!!self->press);
81
82 PyErr_Format(PyExc_AttributeError, "no such attribute '%s'", name);
83 return NULL;
84 }
85
86 static PyTypeObject KeyboardDataType = {
87 PyObject_HEAD_INIT(NULL)
88 0,
89 "KeyboardData",
90 sizeof(KeyboardData),
91 0,
92 (destructor) keybdata_dealloc, /*tp_dealloc*/
93 0, /*tp_print*/
94 (getattrfunc) keybdata_getattr, /*tp_getattr*/
95 0, /*tp_setattr*/
96 0, /*tp_compare*/
97 0, /*tp_repr*/
98 0, /*tp_as_number*/
99 0, /*tp_as_sequence*/
100 0, /*tp_as_mapping*/
101 0, /*tp_hash */
102 };
103
104 /***************************************************************************/
105
106
107
108 static gboolean grab_keyboard(gboolean grab)
109 {
110 gboolean ret = TRUE;
111
112 g_message("grab_keyboard(%s). grabbed: %d", (grab?"True":"False"),grabbed);
113
114 user_grabbed = grab;
115 if (!grabbed) {
116 if (grab)
117 ret = XGrabKeyboard(ob_display, ob_root, 0, GrabModeAsync,
118 GrabModeAsync, CurrentTime) == GrabSuccess;
119 else
120 XUngrabKeyboard(ob_display, CurrentTime);
121 }
122 return ret;
123 }
124
125 /***************************************************************************
126
127 Define the type 'Keyboard'
128
129 ***************************************************************************/
130
131 #define IS_KEYBOARD(v) ((v)->ob_type == &KeyboardType)
132 #define CHECK_KEYBOARD(self, funcname) { \
133 if (!IS_KEYBOARD(self)) { \
134 PyErr_SetString(PyExc_TypeError, \
135 "descriptor '" funcname "' requires a 'Keyboard' " \
136 "object"); \
137 return NULL; \
138 } \
139 }
140
141 typedef struct Keyboard {
142 PyObject_HEAD
143 } Keyboard;
144
145 staticforward PyTypeObject KeyboardType;
146
147
148 static PyObject *keyb_clearBinds(Keyboard *self, PyObject *args)
149 {
150 CHECK_KEYBOARD(self, "clearBinds");
151 if (!PyArg_ParseTuple(args, ":clearBinds"))
152 return NULL;
153 clearall();
154 Py_INCREF(Py_None);
155 return Py_None;
156 }
157
158 static PyObject *keyb_grab(Keyboard *self, PyObject *args)
159 {
160 PyObject *func;
161
162 CHECK_KEYBOARD(self, "grab");
163 if (!PyArg_ParseTuple(args, "O:grab", &func))
164 return NULL;
165 if (!PyCallable_Check(func)) {
166 PyErr_SetString(PyExc_ValueError, "expected a callable object");
167 return NULL;
168 }
169 if (!grab_keyboard(TRUE)) {
170 PyErr_SetString(PyExc_RuntimeError, "failed to grab keyboard");
171 return NULL;
172 }
173 grab_func = func;
174 Py_INCREF(grab_func);
175 Py_INCREF(Py_None);
176 return Py_None;
177 }
178
179 static PyObject *keyb_ungrab(Keyboard *self, PyObject *args)
180 {
181 CHECK_KEYBOARD(self, "ungrab");
182 if (!PyArg_ParseTuple(args, ":ungrab"))
183 return NULL;
184 grab_keyboard(FALSE);
185 Py_XDECREF(grab_func);
186 grab_func = NULL;
187 Py_INCREF(Py_None);
188 return Py_None;
189 }
190
191 #define METH(n, d) {#n, (PyCFunction)keyb_##n, METH_VARARGS, #d}
192
193 static PyMethodDef KeyboardMethods[] = {
194 METH(bind,
195 "bind(keychain, func)\n\n"
196 "Binds a key-chain to a function. The keychain is a tuple of strings "
197 "which define a chain of key presses. Each member of the tuple has "
198 "the format [Modifier-]...[Key]. Modifiers can be 'mod1', 'mod2', "
199 "'mod3', 'mod4', 'mod5', 'control', and 'shift'. The keys on your "
200 "keyboard that are bound to each of these modifiers can be found by "
201 "running 'xmodmap'. The Key can be any valid key definition. Key "
202 "definitions can be found by running 'xev', pressing the key while "
203 "its window is focused, and watching its output. Here are some "
204 "examples of valid keychains: ('a'), ('F7'), ('control-a', 'd'), "
205 "('control-mod1-x', 'control-mod4-g'), ('F1', 'space'). The func "
206 "must have a definition similar to 'def func(keydata, client)'. A "
207 "keychain cannot be bound to more than one function."),
208 METH(clearBinds,
209 "clearBinds()\n\n"
210 "Removes all bindings that were previously made by bind()."),
211 METH(grab,
212 "grab(func)\n\n"
213 "Grabs the entire keyboard, causing all possible keyboard events to "
214 "be passed to the given function. CAUTION: Be sure when you grab() "
215 "that you also have an ungrab() that will execute, or you will not "
216 "be able to type until you restart Openbox. The func must have a "
217 "definition similar to 'def func(keydata)'. The keyboard cannot be "
218 "grabbed if it is already grabbed."),
219 METH(ungrab,
220 "ungrab()\n\n"
221 "Ungrabs the keyboard. The keyboard cannot be ungrabbed if it is not "
222 "grabbed."),
223 { NULL, NULL, 0, NULL }
224 };
225
226 /***************************************************************************
227
228 Type methods/struct
229
230 ***************************************************************************/
231
232 static void keyb_dealloc(PyObject *self)
233 {
234 PyObject_Del(self);
235 }
236
237 static PyTypeObject KeyboardType = {
238 PyObject_HEAD_INIT(NULL)
239 0,
240 "Keyboard",
241 sizeof(Keyboard),
242 0,
243 (destructor) keyb_dealloc, /*tp_dealloc*/
244 0, /*tp_print*/
245 0, /*tp_getattr*/
246 0, /*tp_setattr*/
247 0, /*tp_compare*/
248 0, /*tp_repr*/
249 0, /*tp_as_number*/
250 0, /*tp_as_sequence*/
251 0, /*tp_as_mapping*/
252 0, /*tp_hash */
253 };
254
255 /**************************************************************************/
256
257 void keyboard_startup()
258 {
259 PyObject *input, *inputdict, *ptr;
260 gboolean b;
261
262 curpos = firstnode = NULL;
263 grabbed = user_grabbed = FALSE;
264
265 b = translate("C-G", &reset_state, &reset_key);
266 g_assert(b);
267
268 KeyboardType.ob_type = &PyType_Type;
269 KeyboardType.tp_methods = KeyboardMethods;
270 PyType_Ready(&KeyboardType);
271 PyType_Ready(&KeyboardDataType);
272
273 /* get the input module/dict */
274 input = PyImport_ImportModule("input"); /* new */
275 g_assert(input != NULL);
276 inputdict = PyModule_GetDict(input); /* borrowed */
277 g_assert(inputdict != NULL);
278
279 /* add a Keyboard instance to the input module */
280 ptr = (PyObject*) PyObject_New(Keyboard, &KeyboardType);
281 PyDict_SetItemString(inputdict, "Keyboard", ptr);
282 Py_DECREF(ptr);
283
284 Py_DECREF(input);
285 }
286
287 void keyboard_shutdown()
288 {
289 if (grabbed || user_grabbed) {
290 grabbed = FALSE;
291 grab_keyboard(FALSE);
292 }
293 grab_keys(FALSE);
294 destroytree(firstnode);
295 firstnode = NULL;
296 }
297
This page took 0.046225 seconds and 5 git commands to generate.