Inital commit
This commit is contained in:
commit
25583f2451
2 changed files with 204 additions and 0 deletions
193
vivevolume.c
Normal file
193
vivevolume.c
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/hidraw.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAX_DEVICE_NAME_LEN 256
|
||||
#define MAX_REPORT_LEN 128
|
||||
#define VIVE_PRO_VID 0x0bb4
|
||||
#define VIVE_PRO_PID 0x0309
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VIVE_PRO_BTN_NONE = 0,
|
||||
VIVE_PRO_BTN_VOL_UP = 0b1,
|
||||
VIVE_PRO_BTN_VOL_DOWN = 0b10,
|
||||
VIVE_PRO_BTN_MIC_MUTE = 0b100,
|
||||
} vive_pro_btn_t;
|
||||
|
||||
static int open_vive_pro_hidraw(const char *device)
|
||||
{
|
||||
int fd = open(device, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char device_name[MAX_DEVICE_NAME_LEN];
|
||||
int res = ioctl(fd, HIDIOCGRAWNAME(MAX_DEVICE_NAME_LEN), device_name);
|
||||
if (res < 0)
|
||||
perror("Unable to read device name");
|
||||
else
|
||||
printf("Connected to device: %s\n", device_name);
|
||||
|
||||
struct hidraw_devinfo info;
|
||||
res = ioctl(fd, HIDIOCGRAWINFO, &info);
|
||||
if(res < 0)
|
||||
{
|
||||
perror("Unable to get device info");
|
||||
return -2;
|
||||
}
|
||||
else if (info.vendor != VIVE_PRO_VID || info.product != VIVE_PRO_PID)
|
||||
{
|
||||
fprintf(stderr, "%s is not a vive pro\n", device);
|
||||
return -3;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int register_uinput_device(const char* uinputdev, const char* devname, uint16_t vid, uint16_t pid)
|
||||
{
|
||||
int fd = open(uinputdev, O_RDWR);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
struct uinput_setup dev = {};
|
||||
size_t len = strlen(devname);
|
||||
if(len > UINPUT_MAX_NAME_SIZE)
|
||||
len = UINPUT_MAX_NAME_SIZE;
|
||||
strncpy(dev.name, devname, len);
|
||||
|
||||
dev.id.bustype = BUS_VIRTUAL;
|
||||
dev.id.vendor = vid;
|
||||
dev.id.product = pid;
|
||||
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_VOLUMEUP);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_VOLUMEDOWN);
|
||||
ioctl(fd, UI_SET_KEYBIT, KEY_MICMUTE);
|
||||
|
||||
int ret = ioctl(fd, UI_DEV_SETUP, &dev);
|
||||
if(ret < 0)
|
||||
{
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
ret = ioctl(fd, UI_DEV_CREATE);
|
||||
if(ret < 0)
|
||||
{
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct vive_key_state
|
||||
{
|
||||
bool volup;
|
||||
bool voldown;
|
||||
bool micmute;
|
||||
};
|
||||
|
||||
static int send_keys(struct vive_key_state* state, int uinput_fd, uint8_t keys)
|
||||
{
|
||||
struct input_event ev = {};
|
||||
bool syn = false;
|
||||
|
||||
bool volup = keys & VIVE_PRO_BTN_VOL_UP;
|
||||
if(volup != state->volup)
|
||||
{
|
||||
ev.type = EV_KEY;
|
||||
ev.code = KEY_VOLUMEUP;
|
||||
ev.value = volup;
|
||||
state->volup = volup;
|
||||
if(write(uinput_fd, &ev, sizeof(ev)) != sizeof(ev))
|
||||
return -1;
|
||||
syn = true;
|
||||
}
|
||||
|
||||
bool voldown = keys & VIVE_PRO_BTN_VOL_DOWN;
|
||||
if(voldown != state->voldown)
|
||||
{
|
||||
ev.type = EV_KEY;
|
||||
ev.code = KEY_VOLUMEDOWN;
|
||||
ev.value = voldown;
|
||||
state->voldown = voldown;
|
||||
if(write(uinput_fd, &ev, sizeof(ev)) != sizeof(ev))
|
||||
return -1;
|
||||
syn = true;
|
||||
}
|
||||
|
||||
bool micmute = keys & VIVE_PRO_BTN_MIC_MUTE;
|
||||
if(micmute != state->micmute)
|
||||
{
|
||||
ev.type = EV_KEY;
|
||||
ev.code = KEY_MICMUTE;
|
||||
ev.value = micmute;
|
||||
state->micmute = micmute;
|
||||
if(write(uinput_fd, &ev, sizeof(ev)) != sizeof(ev))
|
||||
return -1;
|
||||
syn = true;
|
||||
}
|
||||
|
||||
if(syn)
|
||||
{
|
||||
gettimeofday(&ev.time, NULL);
|
||||
ev.type = EV_SYN;
|
||||
ev.code = SYN_REPORT;
|
||||
ev.value = 0;
|
||||
if(write(uinput_fd, &ev, sizeof(ev)) != sizeof(ev))
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int res;
|
||||
|
||||
char *device;
|
||||
if(argc > 1)
|
||||
{
|
||||
device = argv[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(argc > 0)
|
||||
fprintf(stderr, "Usage: %s [VIVE PRO HIDRAW DEVICE]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hidraw_fd = open_vive_pro_hidraw(device);
|
||||
if(hidraw_fd < 0)
|
||||
return abs(hidraw_fd);
|
||||
|
||||
int uinput_fd = register_uinput_device("/dev/uinput", "VIVE PRO", VIVE_PRO_VID, VIVE_PRO_PID);
|
||||
if(uinput_fd < 0)
|
||||
{
|
||||
perror("Unable to register uninput device\n");
|
||||
return abs(uinput_fd);
|
||||
}
|
||||
|
||||
uint8_t buffer[MAX_REPORT_LEN];
|
||||
struct vive_key_state state = {};
|
||||
while((res = read(hidraw_fd, buffer, MAX_REPORT_LEN)) >= 0)
|
||||
{
|
||||
send_keys(&state, uinput_fd, buffer[9]);
|
||||
}
|
||||
|
||||
close(hidraw_fd);
|
||||
close(uinput_fd);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue