wmix: added function to handle Multimedia keys related to volume
We can handle the keys AudioRaiseVolume, AudioLowerVolume and AudioMute, so we ask the X server to send the key press event for them to us and update the volume appropriately. Signed-off-by: Christophe CURIS <christophe.curis@free.fr>
This commit is contained in:
parent
3e2d8a730a
commit
4379368290
|
@ -2,7 +2,7 @@ CC = gcc
|
|||
CFLAGS = -O3 -W -Wall
|
||||
LDFLAGS = -L/usr/X11R6/lib
|
||||
LIBS = -lXpm -lXext -lX11 -lm
|
||||
OBJECTS = misc.o config.o mixer-oss.o ui_x.o wmix.o
|
||||
OBJECTS = misc.o config.o mixer-oss.o ui_x.o mmkeys.o wmix.o
|
||||
|
||||
# where to install this program (also for packaging stuff)
|
||||
PREFIX = /usr/local
|
||||
|
|
|
@ -33,3 +33,11 @@ typedef unsigned int bool;
|
|||
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
|
||||
|
||||
#define MAX_DOUBLE_CLICK_TIME 0.5
|
||||
|
||||
/*
|
||||
* Get the number of element in a static array
|
||||
*
|
||||
* Do not use on an allocated array, it will not work
|
||||
*/
|
||||
#define lengthof(arr) \
|
||||
((ssize_t)(sizeof( arr ) / sizeof( arr[0] )))
|
||||
|
|
34
wmix/include/mmkeys.h
Normal file
34
wmix/include/mmkeys.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* WMix -- a mixer using the OSS mixer API
|
||||
* Copyright (C)2014 Christophe CURIS for the WindowMaker Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/* include/mmkeys.h: functions related to handling Multimedia keys */
|
||||
|
||||
#ifndef WMIX_MMKEYS_H
|
||||
#define WMIX_MMKEYS_H
|
||||
|
||||
|
||||
/* Global Configuration */
|
||||
extern struct multimedia_keys {
|
||||
KeyCode raise_volume;
|
||||
KeyCode lower_volume;
|
||||
KeyCode mute;
|
||||
} mmkeys;
|
||||
|
||||
/* Grab the multimedia keys */
|
||||
void mmkey_install(Display *display);
|
||||
|
||||
#endif /* WMIX_MMKEYS_H */
|
168
wmix/mmkeys.c
Normal file
168
wmix/mmkeys.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/* WMix -- a mixer using the OSS mixer API.
|
||||
* Copyright (C) 2014 Christophe CURIS for the WindowMaker Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
* mmkeys.c: functions related to grabing the Multimedia Keys on keyboard
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XF86keysym.h>
|
||||
|
||||
#include "include/common.h"
|
||||
#include "include/config.h"
|
||||
#include "include/mmkeys.h"
|
||||
|
||||
|
||||
/* The global configuration */
|
||||
struct multimedia_keys mmkeys;
|
||||
|
||||
/* The list of keys we're interrested in */
|
||||
static const struct {
|
||||
KeySym symbol;
|
||||
KeyCode *store;
|
||||
const char *name;
|
||||
} key_list[] = {
|
||||
{ XF86XK_AudioRaiseVolume, &mmkeys.raise_volume, "AudioRaiseVolume" },
|
||||
{ XF86XK_AudioLowerVolume, &mmkeys.lower_volume, "AudioLowerVolume" },
|
||||
{ XF86XK_AudioMute, &mmkeys.mute, "AudioMute" }
|
||||
};
|
||||
|
||||
/* The modifiers that should not have impact on the key grabbed */
|
||||
static const struct {
|
||||
KeySym symbol;
|
||||
const char *name;
|
||||
} modifier_symbol[] = {
|
||||
{ XK_Caps_Lock, "CapsLock" },
|
||||
{ XK_Num_Lock, "NumLock" }
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int count;
|
||||
unsigned int list[1 << lengthof(modifier_symbol)];
|
||||
} modifier_masks;
|
||||
|
||||
/* Local functions */
|
||||
static void mmkey_build_modifier_list(Display *display, modifier_masks *result);
|
||||
|
||||
|
||||
/*
|
||||
* Grab the multimedia keys on the X server
|
||||
*
|
||||
* That basically means that whenever these keys are pressed
|
||||
* the events will be sent to us instead of the application
|
||||
* that has current focus.
|
||||
*/
|
||||
void mmkey_install(Display *display)
|
||||
{
|
||||
modifier_masks mod_masks;
|
||||
Window root_window;
|
||||
int i, j;
|
||||
|
||||
mmkey_build_modifier_list(display, &mod_masks);
|
||||
|
||||
root_window = DefaultRootWindow(display);
|
||||
|
||||
for (i = 0; i < lengthof(key_list); i++) {
|
||||
KeyCode key;
|
||||
|
||||
key = XKeysymToKeycode(display, key_list[i].symbol);
|
||||
*(key_list[i].store) = key;
|
||||
|
||||
if (key == None)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < mod_masks.count; j++) {
|
||||
XGrabKey(display, key, mod_masks.list[j], root_window,
|
||||
False, GrabModeAsync, GrabModeAsync);
|
||||
}
|
||||
if (config.verbose)
|
||||
printf("Found multimedia key: %s\n", key_list[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the list of bit-masks for all the modifiers we want to not have impact on our grab
|
||||
*/
|
||||
static void mmkey_build_modifier_list(Display *display, modifier_masks *result)
|
||||
{
|
||||
XModifierKeymap *mods;
|
||||
KeyCode mod_code[lengthof(modifier_symbol)];
|
||||
unsigned int mod_mask[lengthof(modifier_symbol)];
|
||||
char buffer[256];
|
||||
int nb_modifiers;
|
||||
int i, j, k;
|
||||
|
||||
/* Get the bitmask associated with the modifiers */
|
||||
for (i = 0; i < lengthof(modifier_symbol); i++) {
|
||||
mod_code[i] = XKeysymToKeycode(display, modifier_symbol[i].symbol);
|
||||
mod_mask[i] = 0L;
|
||||
}
|
||||
|
||||
mods = XGetModifierMapping(display);
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < mods->max_keypermod; j++) {
|
||||
KeyCode key_mod;
|
||||
|
||||
key_mod = mods->modifiermap[i * mods->max_keypermod + j];
|
||||
for (k = 0; k < lengthof(mod_code); k++) {
|
||||
if ((mod_code[k] != None) && (key_mod == mod_code[k]))
|
||||
mod_mask[k] |= 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
XFreeModifiermap(mods);
|
||||
|
||||
/* Count the number of modifiers found (and display the list to the user) */
|
||||
if (config.verbose)
|
||||
strcpy(buffer, "Found key modifiers: ");
|
||||
|
||||
nb_modifiers = 0;
|
||||
for (i = 0; i < lengthof(modifier_symbol); i++) {
|
||||
if (mod_mask[i] != 0) {
|
||||
if (config.verbose) {
|
||||
if (nb_modifiers > 0)
|
||||
strcat(buffer, ", ");
|
||||
strcat(buffer, modifier_symbol[i].name);
|
||||
}
|
||||
nb_modifiers++;
|
||||
}
|
||||
}
|
||||
if (config.verbose) {
|
||||
if (nb_modifiers == 0)
|
||||
strcat(buffer, "None");
|
||||
puts(buffer);
|
||||
}
|
||||
|
||||
/* Build the list of possible combinations of modifiers */
|
||||
result->count = 1 << nb_modifiers;
|
||||
for (i = 0; i < lengthof(result->list); i++)
|
||||
result->list[i] = 0L;
|
||||
k = 1;
|
||||
for (i = 0; i < lengthof(mod_mask); i++) {
|
||||
if (mod_mask[i] != 0) {
|
||||
for (j = 1; j < result->count; j++)
|
||||
if (j & k)
|
||||
result->list[j] |= mod_mask[i];
|
||||
|
||||
k <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,8 @@ Allows toggling record source,
|
|||
muting individual channels, adjusting volume and balance, all in a
|
||||
compact dockapp size, with TV\-like on\-screen\-display for volume levels.
|
||||
.LP
|
||||
Supports mouse wheel to adjust current channel's volume
|
||||
Supports mouse wheel to adjust current channel's volume,
|
||||
supports also the volume control keys on \(lqmultimedia\(rq keyboards
|
||||
and can be controlled remotely with unix signals
|
||||
.IR SIGUSR1 / SIGUSR2
|
||||
to raise/lower the volume.
|
||||
|
@ -144,3 +145,4 @@ It was expanded by Christophe CURIS for the Window Maker Dev Team.
|
|||
.PP
|
||||
wmix was written by Tim, timecop <timecop@japan.co.jp>,
|
||||
with some code by Daniel Richard G. <skunk@mit.edu>
|
||||
and some addition by Christophe CURIS.
|
||||
|
|
37
wmix/wmix.c
37
wmix/wmix.c
|
@ -37,6 +37,7 @@
|
|||
#include "include/mixer.h"
|
||||
#include "include/misc.h"
|
||||
#include "include/ui_x.h"
|
||||
#include "include/mmkeys.h"
|
||||
#include "include/config.h"
|
||||
|
||||
|
||||
|
@ -55,6 +56,7 @@ static int idle_loop;
|
|||
static void signal_catch(int sig);
|
||||
static void button_press_event(XButtonEvent *event);
|
||||
static void button_release_event(XButtonEvent *event);
|
||||
static int key_press_event(XKeyEvent *event);
|
||||
static void motion_event(XMotionEvent *event);
|
||||
|
||||
|
||||
|
@ -91,6 +93,7 @@ int main(int argc, char **argv)
|
|||
dockapp_init(display);
|
||||
new_window("wmix", 64, 64);
|
||||
new_osd(DisplayWidth(display, DefaultScreen(display)) - 200, 60);
|
||||
mmkey_install(display);
|
||||
|
||||
config_release();
|
||||
|
||||
|
@ -116,6 +119,10 @@ int main(int argc, char **argv)
|
|||
if (button_pressed || slider_pressed || (XPending(display) > 0)) {
|
||||
XNextEvent(display, &event);
|
||||
switch (event.type) {
|
||||
case KeyPress:
|
||||
if (key_press_event(&event.xkey))
|
||||
idle_loop = 0;
|
||||
break;
|
||||
case Expose:
|
||||
redraw_window();
|
||||
break;
|
||||
|
@ -276,6 +283,36 @@ static void button_press_event(XButtonEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
static int key_press_event(XKeyEvent *event)
|
||||
{
|
||||
if (event->keycode == mmkeys.raise_volume) {
|
||||
mixer_set_volume_rel(config.scrollstep);
|
||||
if (!osd_mapped())
|
||||
map_osd();
|
||||
if (osd_mapped())
|
||||
update_osd(mixer_get_volume(), false);
|
||||
ui_update();
|
||||
return 1;
|
||||
}
|
||||
if (event->keycode == mmkeys.lower_volume) {
|
||||
mixer_set_volume_rel(-config.scrollstep);
|
||||
if (!osd_mapped())
|
||||
map_osd();
|
||||
if (osd_mapped())
|
||||
update_osd(mixer_get_volume(), false);
|
||||
ui_update();
|
||||
return 1;
|
||||
}
|
||||
if (event->keycode == mmkeys.mute) {
|
||||
mixer_toggle_mute();
|
||||
ui_update();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Ignore other keys */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void button_release_event(XButtonEvent *event)
|
||||
{
|
||||
int x = event->x;
|
||||
|
|
Loading…
Reference in a new issue