はじめに
VRChatをプレイ中、GeForce Experienceで録画するときに毎回キーボードを探して入力するのが面倒だったのですが、トラッカーのボタン使えたら便利じゃね?と思ったのが今回のきっかけです。
※今回の話はVIVEトラッカー(2018)でしか動作確認していないので旧VIVEトラッカーでは動かない可能性があります。
VIVEトラッカー
VRChatでフルボディトラッキングをするために使うVIVEトラッカーですが、電源ボタンとPOGO pinを利用して5つまでのボタン入力を扱うことができます。
しかし、現在のSteamVRのバージョンではコントローラの入力を左右の手で行うことしか想定されていないため、3台目以降のコントローラ及びトラッカーのボタン入力を取得することができません。
ではどうするのかというと、トラッカーのHID Inputレポートからボタン入力を取得します。
実装
HIDの実装にはhidapiを利用します。また、VIVEコントローラで似たようなことをしている人がいたので参考にしました。
まず、トラッカー(正確にはトラッカーとペアリングされたドングル)のInputレポートを読み取るためには、トラッカーのベンダーIDとプロダクトIDとシリアル番号を知る必要があります。トラッカーのHID情報はhidpaiのhid_enumerateという関数を利用して知ることができます。
# include <stdio.h>
# include "hidapi.h"
int main(int argc, char* argv[]){
//Enumerate and print the HID devices on the system
struct hid_device_info *devs, *cur_dev;
devs = hid_enumerate(0x0, 0x0);
cur_dev = devs;
while (1) {
fprintf(stderr, "Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls",
cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
fprintf(stderr, "\n");
fprintf(stderr, " Manufacturer: %ls\n", cur_dev->manufacturer_string);
fprintf(stderr, " Product: %ls\n", cur_dev->product_string);
fprintf(stderr, "\n");
if (cur_dev->next) {
cur_dev = cur_dev->next;
}
else {
break;
}
}
hid_free_enumeration(devs);
return 0;
}
これを実行すると、トラッカのベンダーIDは0x28deで、プロダクトIDは0x2101であり、トラッカーごとに別々のシリアル番号があるということが分かりますが、VIVEコントローラのベンダーIDとプロダクトIDも同じ値なので、注意が必要です。
トラッカーのInputレポートには様々な情報が含まれますが、ボタン入力を取得するためにはInputレポートの4バイト目と6バイト目のデータを見る必要があります。
4バイト目の値 | 6バイト目の値 | ボタン |
---|---|---|
0x20 | 0x01 | Trigger |
0x20 | 0x04 | Pad |
0x20 | 0x08 | Power |
0x20 | 0x10 | Grip |
0x20 | 0x20 | Menu |
ボタン入力があったとき4バイト目の値が0x20になり、6バイト目のデータからどのボタンが押されたかが分かります。また、ボタンを離したときも、4バイト目の値が0x20になり、6バイト目の押していたボタンに対応するビット値が0になります。
以上のことを踏まえて、トラッカーのボタンでGeForce Experienceを利用した録画するためのコードが以下のようになります。
# include <stdio.h>
# include <windows.h>
# include "hidapi.h"
# define VID 0x28de
# define PID 0x2101
wchar_t serial_number[] = L"3A6F5B0637"
int main(int argc, char* argv[]){
int res;
unsigned char buf[128] = { 0 };
hid_device *handle;
// Open the device
handle = hid_open(VID, PID, serial_number);
if (!handle) {
fprintf(stderr, "Couldn't get hid handle\n");
exit(1);
}
while (1) {
res = hid_read(handle, buf, 128);
if (!res) continue;
if (buf[4] == 0x20) {
if ((buf[6] & 0x08) == 0x08){
fprintf(stderr, "power\n");
MessageBeep(MB_ICONINFORMATION);
keybd_event(VK_LMENU, 0x00, KEYEVENTF_EXTENDEDKEY | 0, 0); //ALT
keybd_event(VK_F9, 0x00, KEYEVENTF_EXTENDEDKEY | 0, 0); //F9
keybd_event(VK_F9, 0x00, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
keybd_event(VK_LMENU, 0x00, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
Sleep(100); //Chattering prevention
}
}
}
return 0;
}
GeForce Experienceで録画するためにはキーボードのALTとF9を同時に入力する必要があるのでkeybd_eventという関数を使っています。また、HMDをかぶっていると録画が開始されたかわからないので、ボタンが押されたときに音を出すようにしています。ボタンのチャタリングの影響で同じInputレポートを何回も送信することがあるので、100msの待ち時間を追加しています。
おわりに
トラッカーのHID Imputレポートを読み取ることで、簡単にボタン入力を取得することができました、プログラムを工夫することで、ボタンの長押しやダブルクリックにも対応できそうです。今回の目的以外にも結構応用できそうなので、是非試してみてください。
トラッカーの電源ボタンで録画出きるようになった#VRChat pic.twitter.com/zpoQT4PwFB
— mako@VRC (@mako_vr) 2019年4月15日