- Implement debounce support.
- Clean up examples. - Call deamon(3) after we open the PID file. Submitted by: Mathew Kanner <mat@cnd.mcgill.ca>
This commit is contained in:
parent
68d25868d0
commit
f5a4d3f069
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=113309
@ -43,12 +43,10 @@
|
||||
.Nd perform actions according to USB HID controls
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl diev
|
||||
.Fl c Ar config-file
|
||||
.Op Fl d
|
||||
.Op Fl i
|
||||
.Fl f Ar device
|
||||
.Op Fl p Ar pidfile
|
||||
.Op Fl v
|
||||
.Ar arg ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
@ -60,12 +58,19 @@ die when the USB device is unplugged.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl c Ar config-file
|
||||
Specify a path name for the config file.
|
||||
.It Fl d
|
||||
Toggle the daemon flag.
|
||||
.It Fl e
|
||||
Instruct
|
||||
.Nm
|
||||
to die early. Useful when specified with multiple
|
||||
verbose options to see how files are parsed.
|
||||
.It Fl i
|
||||
Ignore HID items in the config file that does not exist in the device.
|
||||
.It Fl v
|
||||
Be verbose, and do not become a daemon.
|
||||
.It Fl c Ar config-file
|
||||
Specify a path name for the config file.
|
||||
.It Fl f Ar device
|
||||
Specify a path name for the device to operate on.
|
||||
If
|
||||
@ -77,8 +82,6 @@ path, it is taken to be the name of the device under
|
||||
An absolute path is taken to be the literal device pathname.
|
||||
.It Fl p Ar pidfile
|
||||
Specify an alternate file in which to store the process ID.
|
||||
.It Fl v
|
||||
Be verbose, and do not become a daemon.
|
||||
.El
|
||||
.Pp
|
||||
The config file will be re-read if the process gets a HUP signal.
|
||||
@ -89,8 +92,8 @@ action; if a line begins with a whitespace it is considered a continuation
|
||||
of the previous line.
|
||||
Lines beginning with `#' are considered as comments.
|
||||
.Pp
|
||||
Each line has three parts: a name of a USB HID item, a value for that item,
|
||||
and an action.
|
||||
Each line has four parts: a name of a USB HID item, a value for that item,
|
||||
a debounce value, and an action.
|
||||
There must be whitespace between the parts.
|
||||
.Pp
|
||||
The item names are similar to those used by
|
||||
@ -102,6 +105,12 @@ When the item reports this value
|
||||
the action will be performed.
|
||||
If the value is `*' it will match any value.
|
||||
.Pp
|
||||
The debouce value is an integer not less than 0. The value of 0
|
||||
indicates that no debouncing should occur. A value of 1 will only
|
||||
execute the action when the state changes. Values greater than one
|
||||
specify that an action should be performed only when the value
|
||||
changes by that amount.
|
||||
.Pp
|
||||
The action is a normal command that is executed with
|
||||
.Xr system 3 .
|
||||
Before it is executed some substitution will occur:
|
||||
@ -111,7 +120,7 @@ of the HID item, `$N' will be replaced by the name
|
||||
of the control, and `$H' will be replaced by the name
|
||||
of the HID device.
|
||||
.Sh FILES
|
||||
.Bl -tag -indent
|
||||
.Bl -tag -width indent
|
||||
.It Pa /usr/share/misc/usb_hid_usages
|
||||
The HID usage table.
|
||||
.It Pa /var/run/usbaction.pid
|
||||
@ -122,22 +131,26 @@ The following configuration file can be used to control a pair
|
||||
of Philips USB speakers with the HID controls on the speakers.
|
||||
.Bd -literal -offset indent
|
||||
# Configuration for various Philips USB speakers
|
||||
Consumer:Consumer_Control.Consumer:Volume_Up 1
|
||||
mixerctl -f $1 -n -w fea8-i7-master++
|
||||
Consumer:Consumer_Control.Consumer:Volume_Down 1
|
||||
mixerctl -f $1 -n -w fea8-i7-master--
|
||||
Consumer:Consumer_Control.Consumer:Mute 1
|
||||
mixerctl -f $1 -n -w fea8-i7-mute++
|
||||
Consumer:Consumer_Control.Consumer:Channel_Top.Microsoft:Base_Up 1
|
||||
mixerctl -f $1 -n -w fea8-i7-bass++
|
||||
Consumer:Consumer_Control.Consumer:Channel_Top.Microsoft:Base_Down 1
|
||||
mixerctl -f $1 -n -w fea8-i7-bass--
|
||||
Consumer:Volume_Up 1 0 mixer -f $1 vol +1
|
||||
Consumer:Volume_Down 1 0 mixer -f $1 vol -1
|
||||
# mute not supported
|
||||
#Consumer:Mute 1 0 mixer -f $1 mute
|
||||
Consumer:Channel_Top.Microsoft:Base_Up 1 0 mixer -f $1 bass +1
|
||||
Consumer:Channel_Top.Microsoft:Base_Down 1 0 mixer -f $1 bass -1
|
||||
.Ed
|
||||
.Pp
|
||||
A sample invocation using this configuration would be
|
||||
.Bd -literal -offset indent
|
||||
usbhidaction -f /dev/uhid1 -c conf /dev/mixer1
|
||||
.Ed
|
||||
.Pp
|
||||
The following example controls the mixer volume using a Logitech Wingman.
|
||||
Notice the debouce of 1 for buttons and 5 for the slider.
|
||||
.Bd -literal -offset indent
|
||||
Button:Button_1 1 1 mixer vol +10
|
||||
Button:Button_2 1 1 mixer vol -10
|
||||
Generic_Desktop:Z * 5 mixer vol `echo $V | awk '{print int($$1/255*100)}'`
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr usbhidctl 1 ,
|
||||
.Xr usbhid 3 ,
|
||||
|
@ -66,6 +66,9 @@ struct command {
|
||||
|
||||
struct hid_item item;
|
||||
int value;
|
||||
int lastseen;
|
||||
int lastused;
|
||||
int debounce;
|
||||
char anyvalue;
|
||||
char *name;
|
||||
char *action;
|
||||
@ -91,7 +94,7 @@ main(int argc, char **argv)
|
||||
const char *conf = NULL;
|
||||
const char *dev = NULL;
|
||||
int fd, fp, ch, sz, n, val, i;
|
||||
int demon, ignore;
|
||||
int demon, ignore, dieearly;
|
||||
report_desc_t repd;
|
||||
char buf[100];
|
||||
char devnamebuf[PATH_MAX];
|
||||
@ -100,7 +103,8 @@ main(int argc, char **argv)
|
||||
|
||||
demon = 1;
|
||||
ignore = 0;
|
||||
while ((ch = getopt(argc, argv, "c:df:ip:v")) != -1) {
|
||||
dieearly = 0;
|
||||
while ((ch = getopt(argc, argv, "c:def:ip:v")) != -1) {
|
||||
switch(ch) {
|
||||
case 'c':
|
||||
conf = optarg;
|
||||
@ -108,6 +112,9 @@ main(int argc, char **argv)
|
||||
case 'd':
|
||||
demon ^= 1;
|
||||
break;
|
||||
case 'e':
|
||||
dieearly = 1;
|
||||
break;
|
||||
case 'i':
|
||||
ignore++;
|
||||
break;
|
||||
@ -161,8 +168,6 @@ main(int argc, char **argv)
|
||||
(void)signal(SIGHUP, sighup);
|
||||
|
||||
if (demon) {
|
||||
if (daemon(0, 0) < 0)
|
||||
err(1, "daemon()");
|
||||
fp = open(pidfile, O_WRONLY|O_CREAT, S_IRUSR|S_IRGRP|S_IROTH);
|
||||
if (fp >= 0) {
|
||||
sz=snprintf(buf,100, "%d\n", getpid());
|
||||
@ -170,6 +175,8 @@ main(int argc, char **argv)
|
||||
close(fp);
|
||||
} else
|
||||
err(1, "%s", pidfile);
|
||||
if (daemon(0, 0) < 0)
|
||||
err(1, "daemon()");
|
||||
isdemon = 1;
|
||||
}
|
||||
|
||||
@ -194,9 +201,28 @@ main(int argc, char **argv)
|
||||
#endif
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
val = hid_get_data(buf, &cmd->item);
|
||||
if (cmd->value == val || cmd->anyvalue)
|
||||
if (cmd->value != val && cmd->anyvalue == 0)
|
||||
goto next;
|
||||
if ((cmd->debounce == 0) ||
|
||||
(cmd->debounce && ((cmd->lastseen == -1) ||
|
||||
(cmd->lastseen != val)))) {
|
||||
docmd(cmd, val, dev, argc, argv);
|
||||
goto next;
|
||||
}
|
||||
if ((cmd->debounce > 1) &&
|
||||
((cmd->lastused == -1) ||
|
||||
(abs(cmd->lastused - val) >= cmd->debounce))) {
|
||||
docmd(cmd, val, dev, argc, argv);
|
||||
cmd->lastused = val;
|
||||
goto next;
|
||||
}
|
||||
next:
|
||||
cmd->lastseen = val;
|
||||
}
|
||||
|
||||
if (dieearly)
|
||||
exit(0);
|
||||
|
||||
if (reparse) {
|
||||
struct command *cmds =
|
||||
parse_conf(conf, repd, reportid, ignore);
|
||||
@ -215,8 +241,8 @@ void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "Usage: %s -c config_file [-d] -f hid_dev "
|
||||
"[-i] [-p pidfile] [-v]\n", getprogname());
|
||||
fprintf(stderr, "Usage: %s [-deiv] -c config_file -f hid_dev "
|
||||
"[-p pidfile]\n", getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -237,7 +263,7 @@ parse_conf(const char *conf, report_desc_t repd, int reportid, int ignore)
|
||||
FILE *f;
|
||||
char *p;
|
||||
int line;
|
||||
char buf[SIZE], name[SIZE], value[SIZE], action[SIZE];
|
||||
char buf[SIZE], name[SIZE], value[SIZE], debounce[SIZE], action[SIZE];
|
||||
char usage[SIZE], coll[SIZE];
|
||||
struct command *cmd, *cmds;
|
||||
struct hid_data *d;
|
||||
@ -263,7 +289,8 @@ parse_conf(const char *conf, report_desc_t repd, int reportid, int ignore)
|
||||
}
|
||||
if (p)
|
||||
*p = 0;
|
||||
if (sscanf(buf, "%s %s %[^\n]", name, value, action) != 3) {
|
||||
if (sscanf(buf, "%s %s %s %[^\n]",
|
||||
name, value, debounce, action) != 4) {
|
||||
if (isdemon) {
|
||||
syslog(LOG_WARNING, "config file `%s', line %d"
|
||||
", syntax error: %s", conf, line, buf);
|
||||
@ -290,18 +317,33 @@ parse_conf(const char *conf, report_desc_t repd, int reportid, int ignore)
|
||||
if (isdemon) {
|
||||
syslog(LOG_WARNING,
|
||||
"config file `%s', line %d, "
|
||||
"bad value: %s\n",
|
||||
"bad value: %s (should be * or a number)\n",
|
||||
conf, line, value);
|
||||
freecommands(cmds);
|
||||
return (NULL);
|
||||
} else {
|
||||
errx(1, "config file `%s', line %d, "
|
||||
"bad value: %s\n",
|
||||
"bad value: %s (should be * or a number)\n",
|
||||
conf, line, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sscanf(debounce, "%d", &cmd->debounce) != 1) {
|
||||
if (isdemon) {
|
||||
syslog(LOG_WARNING,
|
||||
"config file `%s', line %d, "
|
||||
"bad value: %s (should be a number >= 0)\n",
|
||||
conf, line, debounce);
|
||||
freecommands(cmds);
|
||||
return (NULL);
|
||||
} else {
|
||||
errx(1, "config file `%s', line %d, "
|
||||
"bad value: %s (should be a number >= 0)\n",
|
||||
conf, line, debounce);
|
||||
}
|
||||
}
|
||||
|
||||
coll[0] = 0;
|
||||
for (d = hid_start_parse(repd, 1 << hid_input, reportid);
|
||||
hid_get_item(d, &h); ) {
|
||||
|
Loading…
Reference in New Issue
Block a user