1 /* KeyboardShortcuts.c- keyboard shortcut bindings
3 * WPrefs - Window Maker Preferences Program
5 * Copyright (c) 1998-2003 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
23 #include "config.h" /* for HAVE_XCONVERTCASE */
28 #include <X11/keysym.h>
30 typedef struct _Panel {
37 CallbackRec callbacks;
49 WMLabel *instructionsL;
61 #define ICON_FILE "keyshortcuts"
63 /* must be in the same order as the corresponding items in actions list */
64 static char *keyOptions[] = {
90 "NextWorkspaceLayerKey",
91 "PrevWorkspaceLayerKey",
102 "WindowShortcut1Key",
103 "WindowShortcut2Key",
104 "WindowShortcut3Key",
105 "WindowShortcut4Key",
106 "WindowShortcut5Key",
107 "WindowShortcut6Key",
108 "WindowShortcut7Key",
109 "WindowShortcut8Key",
110 "WindowShortcut9Key",
111 "WindowShortcut10Key",
113 #ifdef VIRTUAL_DESKTOP
114 "VirtualEdgeLeftKey",
115 "VirtualEdgeRightKey",
117 "VirtualEdgeDownKey",
127 #endif /* XKB_MODELOCK */
130 #ifndef HAVE_XCONVERTCASE
133 static void XConvertCase(register KeySym sym, KeySym * lower, KeySym * upper)
138 case 0: /* Latin 1 */
139 if ((sym >= XK_A) && (sym <= XK_Z))
140 *lower += (XK_a - XK_A);
141 else if ((sym >= XK_a) && (sym <= XK_z))
142 *upper -= (XK_a - XK_A);
143 else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
144 *lower += (XK_agrave - XK_Agrave);
145 else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
146 *upper -= (XK_agrave - XK_Agrave);
147 else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
148 *lower += (XK_oslash - XK_Ooblique);
149 else if ((sym >= XK_oslash) && (sym <= XK_thorn))
150 *upper -= (XK_oslash - XK_Ooblique);
152 case 1: /* Latin 2 */
153 /* Assume the KeySym is a legal value (ignore discontinuities) */
154 if (sym == XK_Aogonek)
156 else if (sym >= XK_Lstroke && sym <= XK_Sacute)
157 *lower += (XK_lstroke - XK_Lstroke);
158 else if (sym >= XK_Scaron && sym <= XK_Zacute)
159 *lower += (XK_scaron - XK_Scaron);
160 else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
161 *lower += (XK_zcaron - XK_Zcaron);
162 else if (sym == XK_aogonek)
164 else if (sym >= XK_lstroke && sym <= XK_sacute)
165 *upper -= (XK_lstroke - XK_Lstroke);
166 else if (sym >= XK_scaron && sym <= XK_zacute)
167 *upper -= (XK_scaron - XK_Scaron);
168 else if (sym >= XK_zcaron && sym <= XK_zabovedot)
169 *upper -= (XK_zcaron - XK_Zcaron);
170 else if (sym >= XK_Racute && sym <= XK_Tcedilla)
171 *lower += (XK_racute - XK_Racute);
172 else if (sym >= XK_racute && sym <= XK_tcedilla)
173 *upper -= (XK_racute - XK_Racute);
175 case 2: /* Latin 3 */
176 /* Assume the KeySym is a legal value (ignore discontinuities) */
177 if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
178 *lower += (XK_hstroke - XK_Hstroke);
179 else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
180 *lower += (XK_gbreve - XK_Gbreve);
181 else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
182 *upper -= (XK_hstroke - XK_Hstroke);
183 else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
184 *upper -= (XK_gbreve - XK_Gbreve);
185 else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
186 *lower += (XK_cabovedot - XK_Cabovedot);
187 else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
188 *upper -= (XK_cabovedot - XK_Cabovedot);
190 case 3: /* Latin 4 */
191 /* Assume the KeySym is a legal value (ignore discontinuities) */
192 if (sym >= XK_Rcedilla && sym <= XK_Tslash)
193 *lower += (XK_rcedilla - XK_Rcedilla);
194 else if (sym >= XK_rcedilla && sym <= XK_tslash)
195 *upper -= (XK_rcedilla - XK_Rcedilla);
196 else if (sym == XK_ENG)
198 else if (sym == XK_eng)
200 else if (sym >= XK_Amacron && sym <= XK_Umacron)
201 *lower += (XK_amacron - XK_Amacron);
202 else if (sym >= XK_amacron && sym <= XK_umacron)
203 *upper -= (XK_amacron - XK_Amacron);
205 case 6: /* Cyrillic */
206 /* Assume the KeySym is a legal value (ignore discontinuities) */
207 if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
208 *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
209 else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
210 *upper += (XK_Serbian_DJE - XK_Serbian_dje);
211 else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
212 *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
213 else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
214 *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
217 /* Assume the KeySym is a legal value (ignore discontinuities) */
218 if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
219 *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
220 else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
221 sym != XK_Greek_iotaaccentdieresis && sym != XK_Greek_upsilonaccentdieresis)
222 *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
223 else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
224 *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
225 else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && sym != XK_Greek_finalsmallsigma)
226 *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
228 case 0x14: /* Armenian */
229 if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
238 static char *captureShortcut(Display * dpy, _Panel * panel)
241 KeySym ksym, lksym, uksym;
245 while (panel->capturing) {
246 XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
247 WMNextEvent(dpy, &ev);
248 if (ev.type == KeyPress && ev.xkey.keycode != 0) {
249 ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
250 if (!IsModifierKey(ksym)) {
251 XConvertCase(ksym, &lksym, &uksym);
252 key = XKeysymToString(uksym);
254 panel->capturing = 0;
266 if (ev.xkey.state & ControlMask) {
267 strcat(buffer, "Control+");
269 if (ev.xkey.state & ShiftMask) {
270 strcat(buffer, "Shift+");
272 if (ev.xkey.state & Mod1Mask) {
273 strcat(buffer, "Mod1+");
275 if (ev.xkey.state & Mod2Mask) {
276 strcat(buffer, "Mod2+");
278 if (ev.xkey.state & Mod3Mask) {
279 strcat(buffer, "Mod3+");
281 if (ev.xkey.state & Mod4Mask) {
282 strcat(buffer, "Mod4+");
284 if (ev.xkey.state & Mod5Mask) {
285 strcat(buffer, "Mod5+");
289 return wstrdup(buffer);
292 static void captureClick(WMWidget * w, void *data)
294 _Panel *panel = (_Panel *) data;
295 Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
298 if (!panel->capturing) {
299 panel->capturing = 1;
300 WMSetButtonText(w, _("Cancel"));
301 WMSetLabelText(panel->instructionsL,
302 _("Press the desired shortcut key(s) or click Cancel to stop capturing."));
303 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
304 shortcut = captureShortcut(dpy, panel);
306 int row = WMGetListSelectedItemRow(panel->actLs);
308 WMSetTextFieldText(panel->shoT, shortcut);
310 if (panel->shortcuts[row])
311 wfree(panel->shortcuts[row]);
312 panel->shortcuts[row] = shortcut;
314 WMRedisplayWidget(panel->actLs);
320 panel->capturing = 0;
321 WMSetButtonText(w, _("Capture"));
322 WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
323 XUngrabKeyboard(dpy, CurrentTime);
326 static void clearShortcut(WMWidget * w, void *data)
328 _Panel *panel = (_Panel *) data;
329 int row = WMGetListSelectedItemRow(panel->actLs);
331 WMSetTextFieldText(panel->shoT, NULL);
334 if (panel->shortcuts[row])
335 wfree(panel->shortcuts[row]);
336 panel->shortcuts[row] = NULL;
337 WMRedisplayWidget(panel->actLs);
341 static void typedKeys(void *observerData, WMNotification * notification)
343 _Panel *panel = (_Panel *) observerData;
344 int row = WMGetListSelectedItemRow(panel->actLs);
349 if (panel->shortcuts[row])
350 wfree(panel->shortcuts[row]);
351 panel->shortcuts[row] = WMGetTextFieldText(panel->shoT);
352 if (strlen(panel->shortcuts[row]) == 0) {
353 wfree(panel->shortcuts[row]);
354 panel->shortcuts[row] = NULL;
356 WMRedisplayWidget(panel->actLs);
359 static void listClick(WMWidget * w, void *data)
361 _Panel *panel = (_Panel *) data;
362 int row = WMGetListSelectedItemRow(w);
364 WMSetTextFieldText(panel->shoT, panel->shortcuts[row]);
367 static char *trimstr(char *str)
376 while (isspace(p[i]) && i > 0) {
384 static void showData(_Panel * panel)
389 for (i = 0; i < panel->actionCount; i++) {
391 str = GetStringForKey(keyOptions[i]);
392 if (panel->shortcuts[i])
393 wfree(panel->shortcuts[i]);
395 panel->shortcuts[i] = trimstr(str);
397 panel->shortcuts[i] = NULL;
399 if (panel->shortcuts[i] &&
400 (strcasecmp(panel->shortcuts[i], "none") == 0 || strlen(panel->shortcuts[i]) == 0)) {
401 wfree(panel->shortcuts[i]);
402 panel->shortcuts[i] = NULL;
405 WMRedisplayWidget(panel->actLs);
408 static void paintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
410 int width, height, x, y;
411 _Panel *panel = (_Panel *) WMGetHangedData(lPtr);
412 WMScreen *scr = WMWidgetScreen(lPtr);
413 Display *dpy = WMScreenDisplay(scr);
414 WMColor *backColor = (state & WLDSSelected) ? panel->white : panel->gray;
416 width = rect->size.width;
417 height = rect->size.height;
421 XFillRectangle(dpy, d, WMColorGC(backColor), x, y, width, height);
423 if (panel->shortcuts[index]) {
424 WMPixmap *pix = WMGetSystemPixmap(scr, WSICheckMark);
425 WMSize size = WMGetPixmapSize(pix);
427 WMDrawPixmap(pix, d, x + (20 - size.width) / 2, (height - size.height) / 2 + y);
428 WMReleasePixmap(pix);
431 WMDrawString(scr, d, panel->black, panel->font, x + 20, y, text, strlen(text));
434 static void createPanel(Panel * p)
436 _Panel *panel = (_Panel *) p;
437 WMScreen *scr = WMWidgetScreen(panel->parent);
441 panel->capturing = 0;
443 panel->white = WMWhiteColor(scr);
444 panel->black = WMBlackColor(scr);
445 panel->gray = WMGrayColor(scr);
446 panel->font = WMSystemFontOfSize(scr, 12);
448 panel->box = WMCreateBox(panel->parent);
449 WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
451 boldFont = WMBoldSystemFontOfSize(scr, 12);
453 /* **************** Actions **************** */
454 panel->actL = WMCreateLabel(panel->box);
455 WMResizeWidget(panel->actL, 280, 20);
456 WMMoveWidget(panel->actL, 20, 10);
457 WMSetLabelFont(panel->actL, boldFont);
458 WMSetLabelText(panel->actL, _("Actions"));
459 WMSetLabelRelief(panel->actL, WRSunken);
460 WMSetLabelTextAlignment(panel->actL, WACenter);
461 color = WMDarkGrayColor(scr);
462 WMSetWidgetBackgroundColor(panel->actL, color);
463 WMReleaseColor(color);
464 WMSetLabelTextColor(panel->actL, panel->white);
466 panel->actLs = WMCreateList(panel->box);
467 WMResizeWidget(panel->actLs, 280, 190);
468 WMMoveWidget(panel->actLs, 20, 32);
469 WMSetListUserDrawProc(panel->actLs, paintItem);
470 WMHangData(panel->actLs, panel);
472 WMAddListItem(panel->actLs, _("Open applications menu"));
473 WMAddListItem(panel->actLs, _("Open window list menu"));
474 WMAddListItem(panel->actLs, _("Open window commands menu"));
475 WMAddListItem(panel->actLs, _("Hide active application"));
476 WMAddListItem(panel->actLs, _("Hide other applications"));
477 WMAddListItem(panel->actLs, _("Miniaturize active window"));
478 WMAddListItem(panel->actLs, _("Close active window"));
479 WMAddListItem(panel->actLs, _("Maximize active window"));
480 WMAddListItem(panel->actLs, _("Maximize active window vertically"));
481 WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
482 WMAddListItem(panel->actLs, _("Maximize active window left half"));
483 WMAddListItem(panel->actLs, _("Maximize active window right half"));
484 WMAddListItem(panel->actLs, _("Maximus: Tiled maximization "));
485 WMAddListItem(panel->actLs, _("Raise active window"));
486 WMAddListItem(panel->actLs, _("Lower active window"));
487 WMAddListItem(panel->actLs, _("Raise/Lower window under mouse pointer"));
488 WMAddListItem(panel->actLs, _("Shade active window"));
489 WMAddListItem(panel->actLs, _("Move/Resize active window"));
490 WMAddListItem(panel->actLs, _("Select active window"));
491 WMAddListItem(panel->actLs, _("Focus next window"));
492 WMAddListItem(panel->actLs, _("Focus previous window"));
493 WMAddListItem(panel->actLs, _("Focus next group window"));
494 WMAddListItem(panel->actLs, _("Focus previous group window"));
495 WMAddListItem(panel->actLs, _("Switch to next workspace"));
496 WMAddListItem(panel->actLs, _("Switch to previous workspace"));
497 WMAddListItem(panel->actLs, _("Switch to next ten workspaces"));
498 WMAddListItem(panel->actLs, _("Switch to previous ten workspaces"));
499 WMAddListItem(panel->actLs, _("Switch to workspace 1"));
500 WMAddListItem(panel->actLs, _("Switch to workspace 2"));
501 WMAddListItem(panel->actLs, _("Switch to workspace 3"));
502 WMAddListItem(panel->actLs, _("Switch to workspace 4"));
503 WMAddListItem(panel->actLs, _("Switch to workspace 5"));
504 WMAddListItem(panel->actLs, _("Switch to workspace 6"));
505 WMAddListItem(panel->actLs, _("Switch to workspace 7"));
506 WMAddListItem(panel->actLs, _("Switch to workspace 8"));
507 WMAddListItem(panel->actLs, _("Switch to workspace 9"));
508 WMAddListItem(panel->actLs, _("Switch to workspace 10"));
509 WMAddListItem(panel->actLs, _("Shortcut for window 1"));
510 WMAddListItem(panel->actLs, _("Shortcut for window 2"));
511 WMAddListItem(panel->actLs, _("Shortcut for window 3"));
512 WMAddListItem(panel->actLs, _("Shortcut for window 4"));
513 WMAddListItem(panel->actLs, _("Shortcut for window 5"));
514 WMAddListItem(panel->actLs, _("Shortcut for window 6"));
515 WMAddListItem(panel->actLs, _("Shortcut for window 7"));
516 WMAddListItem(panel->actLs, _("Shortcut for window 8"));
517 WMAddListItem(panel->actLs, _("Shortcut for window 9"));
518 WMAddListItem(panel->actLs, _("Shortcut for window 10"));
519 WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor"));
520 #ifdef VIRTUAL_DESKTOP
521 WMAddListItem(panel->actLs, _("Move VirtualDesktop to next left edge"));
522 WMAddListItem(panel->actLs, _("Move VirtualDesktop to next right edge"));
523 WMAddListItem(panel->actLs, _("Move VirtualDesktop to next top edge"));
524 WMAddListItem(panel->actLs, _("Move VirtualDesktop to next bottom edge"));
526 WMAddListItem(panel->actLs, _("Raise/Lower Dock"));
527 WMAddListItem(panel->actLs, _("Raise Clip"));
528 WMAddListItem(panel->actLs, _("Lower Clip"));
529 WMAddListItem(panel->actLs, _("Raise/Lower Clip"));
531 WMAddListItem(panel->actLs, _("Toggle keyboard language"));
532 #endif /* XKB_MODELOCK */
534 WMSetListAction(panel->actLs, listClick, panel);
536 panel->actionCount = WMGetListNumberOfRows(panel->actLs);
537 panel->shortcuts = wmalloc(sizeof(char *) * panel->actionCount);
538 memset(panel->shortcuts, 0, sizeof(char *) * panel->actionCount);
540 /***************** Shortcut ****************/
542 panel->shoF = WMCreateFrame(panel->box);
543 WMResizeWidget(panel->shoF, 190, 210);
544 WMMoveWidget(panel->shoF, 315, 10);
545 WMSetFrameTitle(panel->shoF, _("Shortcut"));
547 panel->shoT = WMCreateTextField(panel->shoF);
548 WMResizeWidget(panel->shoT, 160, 20);
549 WMMoveWidget(panel->shoT, 15, 65);
550 WMAddNotificationObserver(typedKeys, panel, WMTextDidChangeNotification, panel->shoT);
552 panel->cleB = WMCreateCommandButton(panel->shoF);
553 WMResizeWidget(panel->cleB, 75, 24);
554 WMMoveWidget(panel->cleB, 15, 95);
555 WMSetButtonText(panel->cleB, _("Clear"));
556 WMSetButtonAction(panel->cleB, clearShortcut, panel);
558 panel->defB = WMCreateCommandButton(panel->shoF);
559 WMResizeWidget(panel->defB, 75, 24);
560 WMMoveWidget(panel->defB, 100, 95);
561 WMSetButtonText(panel->defB, _("Capture"));
562 WMSetButtonAction(panel->defB, captureClick, panel);
564 panel->instructionsL = WMCreateLabel(panel->shoF);
565 WMResizeWidget(panel->instructionsL, 160, 55);
566 WMMoveWidget(panel->instructionsL, 15, 140);
567 WMSetLabelTextAlignment(panel->instructionsL, WACenter);
568 WMSetLabelWraps(panel->instructionsL, True);
569 WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
571 WMMapSubwidgets(panel->shoF);
573 WMReleaseFont(boldFont);
575 WMRealizeWidget(panel->box);
576 WMMapSubwidgets(panel->box);
581 static void storeData(_Panel * panel)
586 for (i = 0; i < panel->actionCount; i++) {
588 if (panel->shortcuts[i]) {
589 str = trimstr(panel->shortcuts[i]);
590 if (strlen(str) == 0) {
596 SetStringForKey(str, keyOptions[i]);
599 SetStringForKey("None", keyOptions[i]);
604 Panel *InitKeyboardShortcuts(WMScreen * scr, WMWidget * parent)
608 panel = wmalloc(sizeof(_Panel));
609 memset(panel, 0, sizeof(_Panel));
611 panel->sectionName = _("Keyboard Shortcut Preferences");
613 panel->description = _("Change the keyboard shortcuts for actions such\n"
614 "as changing workspaces and opening menus.");
616 panel->parent = parent;
618 panel->callbacks.createWidgets = createPanel;
619 panel->callbacks.updateDomain = storeData;
621 AddSection(panel, ICON_FILE);