Skip to content
Snippets Groups Projects
Commit bdff7d84 authored by Martin Piatka's avatar Martin Piatka
Browse files

Add volume-knob helper

parent d6d51c96
No related branches found
No related tags found
No related merge requests found
all: rotomatic pulseled
rotomatic: rotomatic.o findpowermate.o
$(CC) findpowermate.o rotomatic.o -o rotomatic -lxdo
pulseled: pulseled.o findpowermate.o
$(CC) findpowermate.o pulseled.o -o pulseled
clean:
rm -f *.o *~ rotomatic pulseled
%.o: %.c
$(CC) -O2 -Wall -c $< -o $@
Tools to support the Griffin powermate volume knob
The source was taken from https://sowerbutts.com/powermate/ and modified to
send mouse scroll wheel events.
Run rotomatic with the input device path as an argument.
```
./rotomatic /dev/input/event<num>
```
#include <linux/input.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "findpowermate.h"
#define NUM_VALID_PREFIXES 2
static const char *valid_prefix[NUM_VALID_PREFIXES] = {
"Griffin PowerMate",
"Griffin SoundKnob"
};
#define NUM_EVENT_DEVICES 16
int open_powermate(const char *dev, int mode)
{
int fd = open(dev, mode);
int i;
char name[255];
if(fd < 0){
fprintf(stderr, "Unable to open \"%s\": %s\n", dev, strerror(errno));
return -1;
}
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0){
fprintf(stderr, "\"%s\": EVIOCGNAME failed: %s\n", dev, strerror(errno));
close(fd);
return -1;
}
// it's the correct device if the prefix matches what we expect it to be:
for(i=0; i<NUM_VALID_PREFIXES; i++)
if(!strncasecmp(name, valid_prefix[i], strlen(valid_prefix[i])))
return fd;
close(fd);
return -1;
}
int find_powermate(int mode)
{
char devname[256];
int i, r;
for(i=0; i<NUM_EVENT_DEVICES; i++){
sprintf(devname, "/dev/input/event%d", i);
r = open_powermate(devname, mode);
if(r >= 0)
return r;
}
return -1;
}
#ifndef __FIND_POWERMATE__DOT_H__SENTRY__
#define __FIND_POWERMATE__DOT_H__SENTRY__
int open_powermate(const char *dev, int mode);
int find_powermate(int mode);
#endif
#include <linux/input.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include "findpowermate.h"
#ifndef MSC_PULSELED
/* this may not have made its way into the kernel headers yet ... */
#define MSC_PULSELED 0x01
#endif
void powermate_pulse_led(int fd, int static_brightness, int pulse_speed, int pulse_table, int pulse_asleep, int pulse_awake)
{
struct input_event ev;
memset(&ev, 0, sizeof(struct input_event));
static_brightness &= 0xFF;
if(pulse_speed < 0)
pulse_speed = 0;
if(pulse_speed > 510)
pulse_speed = 510;
if(pulse_table < 0)
pulse_table = 0;
if(pulse_table > 2)
pulse_table = 2;
pulse_asleep = !!pulse_asleep;
pulse_awake = !!pulse_awake;
ev.type = EV_MSC;
ev.code = MSC_PULSELED;
ev.value = static_brightness | (pulse_speed << 8) | (pulse_table << 17) | (pulse_asleep << 19) | (pulse_awake << 20);
if(write(fd, &ev, sizeof(struct input_event)) != sizeof(struct input_event))
fprintf(stderr, "write(): %s\n", strerror(errno));
}
void usage(void)
{
printf("Usage:\n");
printf("pulseled [options]\n");
printf("\t--device [filename]\tEvent device to use\n");
printf("\t--level [level] \tLED intensity with pulsing disabled (0-255)\n");
printf("\t--speed [rate] \tPulsing speed (0-510); around 255 works best\n");
printf("\t--style [style] \tPulsing style (0, 1 or 2)\n");
printf("\t--pulseawake \tEnable pulsing whilst host is awake\n");
printf("\t--nopulseawake \tDisable pulsing whilst host is awake\n");
printf("\t--pulseasleep \tEnable pulsing whilst host is asleep\n");
printf("\t--nopulseasleep \tDisable pulsing whilst host is asleep\n");
}
#define TAKE_NEXT_ARG {if(++args_processed >= argc){fprintf(stderr, "Missing argument to %s!\n", argv[args_processed-1]);return 1;}}
int main(int argc, char *argv[])
{
int powermate = -1;
int args_processed = 1;
int static_brightness = 0x80;
int pulse_speed = 255;
int pulse_table = 0;
int pulse_asleep = 1;
int pulse_awake = 0;
const char *device = 0;
while(args_processed < argc){
if(!strcasecmp(argv[args_processed], "--device")){
TAKE_NEXT_ARG;
device = argv[args_processed];
}else if(!strcasecmp(argv[args_processed], "--level")){
TAKE_NEXT_ARG;
static_brightness = atoi(argv[args_processed]);
}else if(!strcasecmp(argv[args_processed], "--speed")){
TAKE_NEXT_ARG;
pulse_speed = atoi(argv[args_processed]);
}else if(!strcasecmp(argv[args_processed], "--style")){
TAKE_NEXT_ARG;
pulse_table = atoi(argv[args_processed]);
}else if(!strcasecmp(argv[args_processed], "--pulseawake")){
pulse_awake = 1;
}else if(!strcasecmp(argv[args_processed], "--pulseasleep")){
pulse_asleep = 1;
}else if(!strcasecmp(argv[args_processed], "--nopulseawake")){
pulse_awake = 0;
}else if(!strcasecmp(argv[args_processed], "--nopulseasleep")){
pulse_asleep = 0;
}else{
usage();
return 1;
}
args_processed++;
}
if(device)
powermate = open_powermate(device, O_WRONLY);
else
powermate = find_powermate(O_WRONLY);
if(powermate < 0){
fprintf(stderr, "Unable to locate powermate\n");
fprintf(stderr, "Try: %s [device]\n", argv[0]);
return 1;
}
powermate_pulse_led(powermate, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
close(powermate);
return 0;
}
#include <linux/input.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <xdo.h>
#include "findpowermate.h"
int abs_offset = 0;
xdo_t *x_ctx = NULL;
void process_event(struct input_event *ev)
{
#ifdef VERBOSE
fprintf(stderr, "type=0x%04x, code=0x%04x, value=%d\n",
ev->type, ev->code, (int)ev->value);
#endif
switch(ev->type){
case EV_MSC:
printf("The LED pulse settings were changed; code=0x%04x, value=0x%08x\n", ev->code, ev->value);
break;
case EV_REL:
if(ev->code != REL_DIAL)
fprintf(stderr, "Warning: unexpected rotation event; ev->code = 0x%04x\n", ev->code);
else{
abs_offset += (int)ev->value;
printf("Button was rotated %d units; Offset from start is now %d units\n", (int)ev->value, abs_offset);
for(int i = (int) ev->value; i > 0; i--){
xdo_mouse_down(x_ctx, CURRENTWINDOW, 5);
xdo_mouse_up(x_ctx, CURRENTWINDOW, 5);
}
for(int i = (int) ev->value; i < 0; i++){
xdo_mouse_down(x_ctx, CURRENTWINDOW, 4);
xdo_mouse_up(x_ctx, CURRENTWINDOW, 4);
}
}
break;
case EV_KEY:
if(ev->code != BTN_0)
fprintf(stderr, "Warning: unexpected key event; ev->code = 0x%04x\n", ev->code);
else
printf("Button was %s\n", ev->value? "pressed":"released");
break;
default:
fprintf(stderr, "Warning: unexpected event type; ev->type = 0x%04x\n", ev->type);
}
fflush(stdout);
}
#define BUFFER_SIZE 32
void watch_powermate(int fd)
{
struct input_event ibuffer[BUFFER_SIZE];
int r, events, i;
while(1){
r = read(fd, ibuffer, sizeof(struct input_event) * BUFFER_SIZE);
if( r > 0 ){
events = r / sizeof(struct input_event);
for(i=0; i<events; i++)
process_event(&ibuffer[i]);
}else{
fprintf(stderr, "read() failed: %s\n", strerror(errno));
return;
}
}
}
int main(int argc, char *argv[])
{
int powermate = -1;
if(argc == 1)
powermate = find_powermate(O_RDONLY);
else
powermate = open_powermate(argv[1], O_RDONLY);
if(powermate < 0){
fprintf(stderr, "Unable to locate powermate\n");
fprintf(stderr, "Try: %s [device]\n", argv[0]);
return 1;
}
x_ctx = xdo_new(NULL);
if(!x_ctx){
printf("Unable to init xdo\n");
close(powermate);
return -1;
}
watch_powermate(powermate);
close(powermate);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment