1 /* WMix -- a mixer using the OSS mixer API.
2 * Copyright (C) 2014 Christophe CURIS for the WindowMaker Team
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * mmkeys.c: functions related to grabbing the Multimedia Keys on keyboard
26 #include <X11/Xproto.h>
27 #include <X11/keysym.h>
28 #include <X11/XF86keysym.h>
30 #include "include/common.h"
31 #include "include/config.h"
32 #include "include/mmkeys.h"
35 /* The global configuration */
36 struct multimedia_keys mmkeys
;
38 /* The list of keys we're interrested in */
44 { XF86XK_AudioRaiseVolume
, &mmkeys
.raise_volume
, "AudioRaiseVolume" },
45 { XF86XK_AudioLowerVolume
, &mmkeys
.lower_volume
, "AudioLowerVolume" },
46 { XF86XK_AudioMute
, &mmkeys
.mute
, "AudioMute" }
49 /* The modifiers that should not have impact on the key grabbed */
53 } modifier_symbol
[] = {
54 { XK_Caps_Lock
, "CapsLock" },
55 { XK_Num_Lock
, "NumLock" }
60 unsigned int list
[1 << lengthof(modifier_symbol
)];
63 /* The structure to track grab installation for errors */
64 static struct mmkey_track
{
65 XErrorHandler previous_handler
;
68 unsigned long serial
[1 << lengthof(modifier_symbol
)];
70 } request
[lengthof(key_list
)];
71 } *track_install
= NULL
;
74 static void mmkey_build_modifier_list(Display
*display
, modifier_masks
*result
);
75 static int mmkey_catch_grab_error(Display
*display
, XErrorEvent
*event
);
79 * Grab the multimedia keys on the X server
81 * That basically means that whenever these keys are pressed
82 * the events will be sent to us instead of the application
83 * that has current focus.
85 void mmkey_install(Display
*display
)
87 modifier_masks mod_masks
;
88 struct mmkey_track install_info
;
92 mmkey_build_modifier_list(display
, &mod_masks
);
94 root_window
= DefaultRootWindow(display
);
96 memset(&install_info
, 0, sizeof(install_info
));
97 install_info
.previous_handler
= XSetErrorHandler(mmkey_catch_grab_error
);
98 track_install
= &install_info
;
99 for (i
= 0; i
< lengthof(key_list
); i
++) {
102 key
= XKeysymToKeycode(display
, key_list
[i
].symbol
);
103 *(key_list
[i
].store
) = key
;
108 install_info
.request
[i
].key_name
= key_list
[i
].name
;
109 install_info
.request
[i
].displayed
= False
;
110 for (j
= 0; j
< mod_masks
.count
; j
++) {
111 install_info
.request
[i
].serial
[j
] = NextRequest(display
);
112 XGrabKey(display
, key
, mod_masks
.list
[j
], root_window
,
113 False
, GrabModeAsync
, GrabModeAsync
);
116 printf("Found multimedia key: %s\n", key_list
[i
].name
);
119 /* The grab may fail, so make sure it is reported now */
120 XSync(display
, False
);
121 XSetErrorHandler(install_info
.previous_handler
);
122 track_install
= NULL
;
126 * Build the list of bit-masks for all the modifiers we want to not have impact on our grab
128 static void mmkey_build_modifier_list(Display
*display
, modifier_masks
*result
)
130 XModifierKeymap
*mods
;
131 KeyCode mod_code
[lengthof(modifier_symbol
)];
132 unsigned int mod_mask
[lengthof(modifier_symbol
)];
137 /* Get the bitmask associated with the modifiers */
138 for (i
= 0; i
< lengthof(modifier_symbol
); i
++) {
139 mod_code
[i
] = XKeysymToKeycode(display
, modifier_symbol
[i
].symbol
);
143 mods
= XGetModifierMapping(display
);
144 for (i
= 0; i
< 8; i
++) {
145 for (j
= 0; j
< mods
->max_keypermod
; j
++) {
148 key_mod
= mods
->modifiermap
[i
* mods
->max_keypermod
+ j
];
149 for (k
= 0; k
< lengthof(mod_code
); k
++) {
150 if ((mod_code
[k
] != None
) && (key_mod
== mod_code
[k
]))
151 mod_mask
[k
] |= 1 << i
;
155 XFreeModifiermap(mods
);
157 /* Count the number of modifiers found (and display the list to the user) */
159 strcpy(buffer
, "Found key modifiers: ");
162 for (i
= 0; i
< lengthof(modifier_symbol
); i
++) {
163 if (mod_mask
[i
] != 0) {
164 if (config
.verbose
) {
165 if (nb_modifiers
> 0)
166 strcat(buffer
, ", ");
167 strcat(buffer
, modifier_symbol
[i
].name
);
172 if (config
.verbose
) {
173 if (nb_modifiers
== 0)
174 strcat(buffer
, "None");
178 /* Build the list of possible combinations of modifiers */
179 result
->count
= 1 << nb_modifiers
;
180 for (i
= 0; i
< lengthof(result
->list
); i
++)
181 result
->list
[i
] = 0L;
183 for (i
= 0; i
< lengthof(mod_mask
); i
++) {
184 if (mod_mask
[i
] != 0) {
185 for (j
= 1; j
< result
->count
; j
++)
187 result
->list
[j
] |= mod_mask
[i
];
195 * Callback when X11 reports an error
197 * We only track errors from XGrabKey and display them to user, instead of
198 * letting the default error handler exit
200 static int mmkey_catch_grab_error(Display
*display
, XErrorEvent
*event
)
204 if ((event
->error_code
== BadAccess
) && (event
->request_code
== X_GrabKey
)) {
205 for (i
= 0; i
< lengthof(track_install
->request
); i
++) {
206 for (j
= 0; j
< lengthof(track_install
->request
[i
].serial
); j
++) {
207 if (track_install
->request
[i
].serial
[j
] == 0L)
209 if (event
->serial
== track_install
->request
[i
].serial
[j
]) {
210 if (!track_install
->request
[i
].displayed
) {
211 fprintf(stderr
, "wmix:warning: could not grab key %s, is another application using it?\n",
212 track_install
->request
[i
].key_name
);
213 track_install
->request
[i
].displayed
= True
;
221 /* That's not an XGrabKey known issue, let the default handler manage this */
222 return track_install
->previous_handler(display
, event
);