Allow to move the current focused child when circulating over brothers (new bindings)
[clfswm.git] / src / clfswm-keys.lisp
blob465cfa1d87d29c25bf65dd13a0eadd2774f75fd4
1 ;;; --------------------------------------------------------------------------
2 ;;; CLFSWM - FullScreen Window Manager
3 ;;;
4 ;;; --------------------------------------------------------------------------
5 ;;; Documentation: Keys functions definition
6 ;;; --------------------------------------------------------------------------
7 ;;;
8 ;;; (C) 2012 Philippe Brochard <pbrochard@common-lisp.net>
9 ;;;
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or
13 ;;; (at your option) any later version.
14 ;;;
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
19 ;;;
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with this program; if not, write to the Free Software
22 ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 ;;;
24 ;;; --------------------------------------------------------------------------
26 (in-package :clfswm)
29 (defparameter *fun-press* #'first)
30 (defparameter *fun-release* #'second)
34 (defun with-capslock ()
35 (pushnew :lock *default-modifiers*))
37 (defun without-capslock ()
38 (setf *default-modifiers* (remove :lock *default-modifiers*)))
40 (defun with-numlock ()
41 (pushnew :mod-2 *default-modifiers*))
43 (defun without-numlock ()
44 (setf *default-modifiers* (remove :mod-2 *default-modifiers*)))
48 ;;; CONFIG - Key mode names
49 (defmacro define-init-hash-table-key (hash-table name)
50 (let ((init-name (create-symbol "init-" (format nil "~A" hash-table))))
51 `(progn
52 (defun ,init-name ()
53 (setf ,hash-table (make-hash-table :test 'equal))
54 (setf (gethash 'name ,hash-table) ,name))
55 (,init-name))))
57 (define-init-hash-table-key *main-keys* "Main mode keys")
58 (define-init-hash-table-key *main-mouse* "Mouse buttons actions in main mode")
59 (define-init-hash-table-key *second-keys* "Second mode keys")
60 (define-init-hash-table-key *second-mouse* "Mouse buttons actions in second mode")
61 (define-init-hash-table-key *info-keys* "Info mode keys")
62 (define-init-hash-table-key *info-mouse* "Mouse buttons actions in info mode")
63 (define-init-hash-table-key *query-keys* "Query mode keys")
65 (define-init-hash-table-key *circulate-keys* "Circulate mode keys")
66 (define-init-hash-table-key *circulate-keys-release* "Circulate mode release keys")
68 (define-init-hash-table-key *expose-keys* "Expose windows mode keys")
69 (define-init-hash-table-key *expose-mouse* "Mouse buttons actions in expose windows mode")
71 (defun unalias-modifiers (list)
72 (dolist (mod *modifier-alias*)
73 (setf list (substitute (second mod) (first mod) list)))
74 list)
76 (defun key->list (key)
77 (list (first key) (modifiers->state (append (unalias-modifiers (rest key))
78 (unalias-modifiers *default-modifiers*)))))
80 (defmacro define-define-key (name hashtable)
81 (let ((name-key-fun (create-symbol "define-" name "-key-fun"))
82 (name-key (create-symbol "define-" name "-key"))
83 (undefine-name-fun (create-symbol "undefine-" name "-key-fun"))
84 (undefine-name (create-symbol "undefine-" name "-key"))
85 (undefine-multi-name (create-symbol "undefine-" name "-multi-keys")))
86 `(progn
87 (defun ,name-key-fun (key function &rest args)
88 "Define a new key, a key is '(char modifier1 modifier2...))"
89 (setf (gethash (key->list key) ,hashtable) (list function args)))
90 (defmacro ,name-key ((key &rest modifiers) function &rest args)
91 `(,',name-key-fun (list ,key ,@modifiers) ,function ,@args))
92 (defun ,undefine-name-fun (key)
93 "Undefine a new key, a key is '(char modifier1 modifier2...))"
94 (remhash (key->list key) ,hashtable))
95 (defmacro ,undefine-name ((key &rest modifiers))
96 `(,',undefine-name-fun (list ,key ,@modifiers)))
97 (defmacro ,undefine-multi-name (&rest keys)
98 `(progn
99 ,@(loop for k in keys
100 collect `(,',undefine-name ,k)))))))
103 (defmacro define-define-mouse (name hashtable)
104 (let ((name-mouse-fun (create-symbol "define-" name "-fun"))
105 (name-mouse (create-symbol "define-" name))
106 (undefine-name (create-symbol "undefine-" name)))
107 `(progn
108 (defun ,name-mouse-fun (button function-press &optional function-release &rest args)
109 "Define a new mouse button action, a button is '(button number '(modifier list))"
110 (setf (gethash (key->list button) ,hashtable) (list function-press function-release args)))
111 (defmacro ,name-mouse ((button &rest modifiers) function-press &optional function-release &rest args)
112 `(,',name-mouse-fun (list ,button ,@modifiers) ,function-press ,function-release ,@args))
113 (defmacro ,undefine-name ((key &rest modifiers))
114 `(remhash (list ,key ,@modifiers) ,',hashtable)))))
118 (define-define-key "main" *main-keys*)
119 (define-define-key "second" *second-keys*)
120 (define-define-key "info" *info-keys*)
121 (define-define-key "query" *query-keys*)
123 (define-define-key "circulate" *circulate-keys*)
124 (define-define-key "circulate-release" *circulate-keys-release*)
126 (define-define-key "expose" *expose-keys*)
128 (define-define-mouse "main-mouse" *main-mouse*)
129 (define-define-mouse "second-mouse" *second-mouse*)
130 (define-define-mouse "info-mouse" *info-mouse*)
131 (define-define-mouse "expose-mouse" *expose-mouse*)
138 (defun add-in-state (state modifier)
139 "Add a modifier in a state"
140 (modifiers->state (append (state->modifiers state) (list modifier))))
142 (defmacro define-ungrab/grab (name function hashtable)
143 `(defun ,name ()
144 (maphash #'(lambda (k v)
145 (declare (ignore v))
146 (when (consp k)
147 (handler-case
148 (let* ((key (first k))
149 (modifiers (second k))
150 (keycode (typecase key
151 (character (multiple-value-list (char->keycode key)))
152 (number key)
153 (string (let* ((keysym (keysym-name->keysym key))
154 (ret-keycode (multiple-value-list
155 (xlib:keysym->keycodes *display* keysym))))
156 (let ((found nil))
157 (dolist (kc ret-keycode)
158 (when (= keysym (xlib:keycode->keysym *display* kc 0))
159 (setf found t)))
160 (unless found
161 (setf modifiers (add-in-state modifiers :shift))))
162 ret-keycode)))))
163 (if keycode
164 (if (consp keycode)
165 (dolist (kc (remove-duplicates keycode))
166 (,function *root* kc :modifiers modifiers))
167 (,function *root* keycode :modifiers modifiers))
168 (format t "~&Grabbing error: Can't find key '~A'~%" key)))
169 (error (c)
170 ;;(declare (ignore c))
171 (format t "~&Grabbing error: Can't grab key '~A' (~A)~%" k c)))
172 (force-output)))
173 ,hashtable)))
175 (define-ungrab/grab grab-main-keys xlib:grab-key *main-keys*)
176 (define-ungrab/grab ungrab-main-keys xlib:ungrab-key *main-keys*)
187 (defun find-key-from-code (hash-table-key code state)
188 "Return the function associated to code/state"
189 (labels ((function-from (key &optional (new-state state))
190 (multiple-value-bind (function foundp)
191 (gethash (list key new-state) hash-table-key)
192 (when (and foundp (first function))
193 function)))
194 (from-code ()
195 (function-from code))
196 (from-char ()
197 (let ((char (keycode->char code state)))
198 (function-from char)))
199 (from-string ()
200 (let ((string (keysym->keysym-name (xlib:keycode->keysym *display* code 0))))
201 (function-from string)))
202 (from-string-shift ()
203 (let* ((modifiers (state->modifiers state))
204 (string (keysym->keysym-name (keycode->keysym code modifiers))))
205 (function-from string)))
206 (from-string-no-shift ()
207 (let* ((modifiers (state->modifiers state))
208 (string (keysym->keysym-name (keycode->keysym code modifiers))))
209 (function-from string (modifiers->state (remove :shift modifiers))))))
210 (or (from-code) (from-char) (from-string) (from-string-shift) (from-string-no-shift))))
214 (defun funcall-key-from-code (hash-table-key code state &rest args)
215 (let ((function (find-key-from-code hash-table-key code state)))
216 (when function
217 (apply (first function) (append args (second function)))
218 t)))
221 (defun funcall-button-from-code (hash-table-key code state window root-x root-y
222 &optional (action *fun-press*) args)
223 (let ((state (modifiers->state (set-difference (state->modifiers state)
224 '(:button-1 :button-2 :button-3 :button-4 :button-5)))))
225 (multiple-value-bind (function foundp)
226 (gethash (list code state) hash-table-key)
227 (if (and foundp (funcall action function))
228 (progn
229 (apply (funcall action function) `(,window ,root-x ,root-y ,@(append args (third function))))
231 nil))))
236 (defun binding-substitute-modifier (to from &optional (hashtables (list *main-keys* *main-mouse*
237 *second-keys* *second-mouse*
238 *info-keys* *info-mouse*
239 *query-keys*
240 *circulate-keys* *circulate-keys-release*
241 *expose-keys* *expose-mouse*)))
242 "Utility to change modifiers after binding definition"
243 (labels ((change (&optional (hashtable *main-keys*) to from)
244 (maphash (lambda (k v)
245 (when (consp k)
246 (let ((state (modifiers->state (substitute to from (state->modifiers (second k))))))
247 (remhash k hashtable)
248 (setf (gethash (list (first k) state) hashtable) v))))
249 hashtable)))
250 (dolist (h hashtables)
251 (change h to from))))
254 (defmacro define-keys ((mode) &body keys)
255 (let ((symbol (create-symbol "DEFINE-" mode "-KEY")))
256 `(progn
257 ,@(loop for k in keys collect `(,symbol ,@k)))))
260 (defun find-associated-key-bindings (function)
261 "Return keys in main and second mode bounds to function"
262 (labels ((key-string (hash)
263 (let ((binding (or (find-in-hash function hash)
264 (search-in-hash function hash))))
265 (when binding
266 (let ((key (first binding))
267 (modifier (and (second binding) (state->modifiers (second binding)))))
268 (with-output-to-string (str)
269 (when key
270 (dolist (mod modifier)
271 (format str "~A-" (cond
272 ((string-equal mod "MOD-1") "M")
273 ((string-equal mod "CONTROL") "C")
274 ((string-equal mod "SHIFT") "S")
275 (t mod))))
276 (format str "~A" key))))))))
277 (let ((main-string (key-string *main-keys*))
278 (second-string (key-string *second-keys*)))
279 (if (or main-string second-string)
280 (if (string-equal main-string second-string)
281 (format nil "[~A]" main-string)
282 (format nil "[~A|~A]" (or main-string "-") (or second-string "-")))
283 ""))))