ible
professional vim user
i think it would make sense to fire small scroll events at a low frequency when the nub is less off center, and just fire more frequently if the nub is further off center.
That's a good point, but they're probably handled separately. For example my laptop's touchpad looks like:Analogue scroll events are actually a thing, think of touchpad scrolling. Touchpads are probably providing absolute instead of relative position information, though.
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 272 (BTN_LEFT)
Event code 325 (BTN_TOOL_FINGER)
Event code 328 (BTN_TOOL_QUINTTAP)
Event code 330 (BTN_TOUCH)
Event code 333 (BTN_TOOL_DOUBLETAP)
Event code 334 (BTN_TOOL_TRIPLETAP)
Event code 335 (BTN_TOOL_QUADTAP)
Event type 3 (EV_ABS)
Event code 0 (ABS_X)
Value 42
Min 0
Max 1162
Resolution 12
Event code 1 (ABS_Y)
Value 634
Min 0
Max 634
Resolution 12
Event code 47 (ABS_MT_SLOT)
Value 0
Min 0
Max 4
Event code 53 (ABS_MT_POSITION_X)
Value 0
Min 0
Max 1162
Resolution 12
Event code 54 (ABS_MT_POSITION_Y)
Value 0
Min 0
Max 634
Resolution 12
Event code 55 (ABS_MT_TOOL_TYPE)
Value 0
Min 0
Max 2
Event code 57 (ABS_MT_TRACKING_ID)
Value 0
Min 0
Max 65535
Event type 4 (EV_MSC)
Event code 5 (MSC_TIMESTAMP)
Properties:
Property type 0 (INPUT_PROP_POINTER)
Property type 2 (INPUT_PROP_BUTTONPAD)
It would probably need two limit values: when it switches to slow speed and when it changes to fast speed. If these are the same number there's an uncomfortable area where the speed would skip erratically due to the noise in the nubs. The principle is simple, but there's some tuning like this to make it feel nice.i think it would make sense to fire small scroll events at a low frequency when the nub is less off center, and just fire more frequently if the nub is further off center.
This bug undexsym mentions in the thread about his game is related to pyrainput. As a workaround it helps to set nubs.deadzone = -1.There's a stupid bug with the way SDL2 reports nub movements that I'm done trying to fix or find a workaround for now. It causes ED and/or the camera to move by itself if the nub is let go quickly. Annoying but still playable. If anyone can let me know of a fix I'd be eternally grateful
#include <regex>
#include "pyrainput.h"
struct pyrainput_global global;
void init(char const** argv, unsigned int argc) {
std::vector<unsigned int> keycodes;
for(unsigned int i = FIRST_KEY; i <= LAST_KEY; ++i) {
keycodes.push_back(i);
}
// Initialize data structures
global.keyboard = new UinputDevice("/dev/uinput", BUS_USB, "pyraInput keyboard", 1, 1, 1, {
{ EV_KEY, keycodes }
});
global.behaviors = new KeyBehaviors();
// Read settings
// Must be done before the key behavior to take key remapping via file into account
handleArgs(argv, argc, global.settings);
if(!global.settings.configFile.empty()) {
loadConfig(global.settings.configFile, global.settings);
}
// Set key behavior
global.behaviors->altcomplex(KEY_MENU, &global.Fn.pressed, KEY_MENU, [](int value) {
if(value) {
setCommandMode(!global.commandMode);
}
});
global.behaviors->gphat(pyraKeyMap["PYRA_KEY_UP"], BTN_DPAD_UP);
global.behaviors->gphat(pyraKeyMap["PYRA_KEY_DOWN"], BTN_DPAD_DOWN);
global.behaviors->gphat(pyraKeyMap["PYRA_KEY_LEFT"], BTN_DPAD_LEFT);
global.behaviors->gphat(pyraKeyMap["PYRA_KEY_RIGHT"], BTN_DPAD_RIGHT);
global.behaviors->gpmap2(pyraKeyMap["PYRA_KEY_LEFTALT"], BTN_START, &global.Alt.left, &global.Alt);
global.behaviors->gpmap2(pyraKeyMap["PYRA_KEY_LEFTCTRL"], BTN_SELECT, &global.Ctrl.left, &global.Ctrl);
global.behaviors->gpmap(pyraKeyMap["PYRA_KEY_HOME"], BTN_A);
global.behaviors->gpmap(pyraKeyMap["PYRA_KEY_END"], BTN_B);
global.behaviors->gpmap(pyraKeyMap["PYRA_KEY_PAGEDOWN"], BTN_X);
global.behaviors->gpmap(pyraKeyMap["PYRA_KEY_PAGEUP"], BTN_Y);
global.behaviors->gpmap2(pyraKeyMap["PYRA_KEY_RIGHTSHIFT"],BTN_TL, &global.Shift.right, &global.Shift);
global.behaviors->gpmap2(pyraKeyMap["PYRA_KEY_RIGHTCTRL"], BTN_TR, &global.Ctrl.right, &global.Ctrl);
global.behaviors->gpmap2(pyraKeyMap["PYRA_KEY_RIGHTALT"], BTN_TR2, &global.Alt.right, &global.Alt);
global.behaviors->gpmap(pyraKeyMap["PYRA_KEY_INSERT"], BTN_C); //(I)
global.behaviors->gpmap(pyraKeyMap["PYRA_KEY_DELETE"], BTN_Z); //(II)
global.behaviors->complex(KEY_LEFTSHIFT, [](int value) {
global.Shift.left = (value==1);
global.Shift.pressed = global.Shift.left || global.Shift.right;
global.keyboard->send(EV_KEY, KEY_LEFTSHIFT, value);
});
global.behaviors->complex(KEY_RIGHTMETA, [](int value) {
global.Fn.right = (value==1);
global.Fn.pressed = global.Fn.left || global.Fn.right;
if (global.settings.exportGamepad) {
global.gamepad->send(EV_KEY, BTN_TL2, value);
global.gamepad->send(EV_SYN, 0, 0);
}
});
global.behaviors->complex(KEY_LEFTMETA, [](int value) {
global.Fn.left = (value==1);
global.Fn.pressed = global.Fn.left || global.Fn.right;
});
global.behaviors->altmap(KEY_ESC, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_ESC"], pyraKeyMap["ESC"]);
global.behaviors->altmap(KEY_PAUSE, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_PAUSE"], pyraKeyMap["PAUSE"]);
global.behaviors->complex(KEY_BRIGHTNESSUP, handleBrightness);
//global.behaviors->altmap(KEY_BRIGHTNESSUP, &global.Fn.pressed, KEY_BRIGHTNESSUP, KEY_BRIGHTNESSDOWN);
global.behaviors->altmap(KEY_F11, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_F11"], pyraKeyMap["PYRA_KEY_FN_F11"]);
// Handler function generator function for number keys
auto numKeyBehavior = [](unsigned int regular, unsigned int fn, Settings::ProfileIndex index) {
return [regular, fn, index](int value) {
if(global.commandMode) {
if(value) {
loadProfile(index, global.settings);
setCommandMode(false);
}
} else if(global.Fn.pressed) {
global.keyboard->send(EV_KEY, fn, value);
} else {
global.keyboard->send(EV_KEY, regular, value);
}
};
};
global.behaviors->complex(KEY_1, numKeyBehavior(pyraKeyMap["PYRA_KEY_1"], pyraKeyMap["PYRA_KEY_FN_1"], Settings::PROFILE_1));
global.behaviors->complex(KEY_2, numKeyBehavior(pyraKeyMap["PYRA_KEY_2"], pyraKeyMap["PYRA_KEY_FN_2"], Settings::PROFILE_2));
global.behaviors->complex(KEY_3, numKeyBehavior(pyraKeyMap["PYRA_KEY_3"], pyraKeyMap["PYRA_KEY_FN_3"], Settings::PROFILE_3));
global.behaviors->complex(KEY_4, numKeyBehavior(pyraKeyMap["PYRA_KEY_4"], pyraKeyMap["PYRA_KEY_FN_4"], Settings::PROFILE_4));
global.behaviors->complex(KEY_5, numKeyBehavior(pyraKeyMap["PYRA_KEY_5"], pyraKeyMap["PYRA_KEY_FN_5"], Settings::PROFILE_5));
global.behaviors->complex(KEY_6, numKeyBehavior(pyraKeyMap["PYRA_KEY_6"], pyraKeyMap["PYRA_KEY_FN_6"], Settings::PROFILE_6));
global.behaviors->complex(KEY_7, numKeyBehavior(pyraKeyMap["PYRA_KEY_7"], pyraKeyMap["PYRA_KEY_FN_7"], Settings::PROFILE_7));
global.behaviors->complex(KEY_8, numKeyBehavior(pyraKeyMap["PYRA_KEY_8"], pyraKeyMap["PYRA_KEY_FN_8"], Settings::PROFILE_8));
global.behaviors->complex(KEY_9, numKeyBehavior(pyraKeyMap["PYRA_KEY_9"], pyraKeyMap["PYRA_KEY_FN_9"], Settings::PROFILE_9));
global.behaviors->complex(KEY_0, numKeyBehavior(pyraKeyMap["PYRA_KEY_0"], pyraKeyMap["PYRA_KEY_FN_0"], Settings::PROFILE_0));
global.behaviors->altmap(KEY_TAB, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_TAB"], pyraKeyMap["PYRA_KEY_FN_TAB"]);
global.behaviors->altmap(KEY_Q, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_Q"], pyraKeyMap["PYRA_KEY_FN_Q"]); // I120 // ok
global.behaviors->altmap(KEY_W, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_W"], pyraKeyMap["PYRA_KEY_FN_W"]); // I129 // ok
global.behaviors->altmap(KEY_E, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_E"], pyraKeyMap["PYRA_KEY_FN_E"]); // I149 // ok
global.behaviors->altmap(KEY_R, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_R"], pyraKeyMap["PYRA_KEY_FN_R"]); // I154 // ok
global.behaviors->altmap(KEY_T, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_T"], pyraKeyMap["PYRA_KEY_FN_T"]); // I168 // ok
global.behaviors->altmap(KEY_Y, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_Y"], pyraKeyMap["PYRA_KEY_FN_Y"]); // I178 // ok
global.behaviors->altmap(KEY_U, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_U"], pyraKeyMap["PYRA_KEY_FN_U"]); // I183 // ok
global.behaviors->altmap(KEY_I, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_I"], pyraKeyMap["PYRA_KEY_FN_I"]); // I184 // ok
global.behaviors->altmap(KEY_O, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_O"], pyraKeyMap["PYRA_KEY_FN_O"]); // I230 // ok
global.behaviors->altmap(KEY_P, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_P"], pyraKeyMap["PYRA_KEY_FN_P"]); // I217 // ok
global.behaviors->altmap(KEY_APOSTROPHE, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_APOSTROPHE"], pyraKeyMap["PYRA_KEY_FN_APOSTROPHE"]); // I247 // ok
global.behaviors->altmap(KEY_A, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_A"], pyraKeyMap["PYRA_KEY_FN_A"]); // I222 // ok
global.behaviors->altmap(KEY_S, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_S"], pyraKeyMap["PYRA_KEY_FN_S"]); // I248 // ok
global.behaviors->altmap(KEY_D, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_D"], pyraKeyMap["PYRA_KEY_FN_D"]); // I221 // ok
global.behaviors->altmap(KEY_F, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_F"], pyraKeyMap["PYRA_KEY_FN_F"]); // I219 // ok
global.behaviors->altmap(KEY_G, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_G"], pyraKeyMap["PYRA_KEY_FN_G"]); // I249- AB11 (89)
global.behaviors->altmap(KEY_H, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_H"], pyraKeyMap["PYRA_KEY_FN_H"]); // I250- JPCM (95)
global.behaviors->altmap(KEY_J, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_J"], pyraKeyMap["PYRA_KEY_FN_J"]); // I251- AE13 (124)
global.behaviors->altmap(KEY_K, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_K"], pyraKeyMap["PYRA_KEY_FN_K"]); // I252- FK19 (189)
global.behaviors->altmap(KEY_L, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_L"], pyraKeyMap["PYRA_KEY_FN_L"]); // I253- FK24 (194)
global.behaviors->altmap(KEY_COMMA, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_COMMA"], pyraKeyMap["PYRA_KEY_FN_COMMA"]);
global.behaviors->altmap(KEY_DOT, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_DOT"], pyraKeyMap["PYRA_KEY_FN_DOT"]);
global.behaviors->altmap(KEY_Z, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_Z"], pyraKeyMap["PYRA_KEY_FN_Z"]);
global.behaviors->altmap(KEY_X, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_X"], pyraKeyMap["PYRA_KEY_FN_X"]);
global.behaviors->altmap(KEY_C, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_C"], pyraKeyMap["PYRA_KEY_FN_C"]);
global.behaviors->altmap(KEY_V, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_V"], pyraKeyMap["PYRA_KEY_FN_V"]);
global.behaviors->altmap(KEY_B, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_B"], pyraKeyMap["PYRA_KEY_FN_B"]);
global.behaviors->altmap(KEY_N, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_N"], pyraKeyMap["PYRA_KEY_FN_N"]);
global.behaviors->altmap(KEY_M, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_M"], pyraKeyMap["PYRA_KEY_FN_M"]); // 228- MDSW (195)
global.behaviors->altmap(KEY_SPACE, &global.Fn.pressed, pyraKeyMap["PYRA_KEY_SPACE"], pyraKeyMap["PYRA_KEY_SPACE"]);
global.gamepad = new PyraJoystick("/dev/uinput", BUS_USB, "pyraInput Gamepad", 1, 1, 1, {
{ EV_KEY, {
BTN_A, BTN_B, BTN_X, BTN_Y,
BTN_TL, BTN_TR, BTN_TL2, BTN_TR2,
BTN_SELECT, BTN_START, BTN_C, BTN_Z,
BTN_THUMBL, BTN_THUMBR
} },
{ EV_ABS, { ABS_HAT0X, ABS_HAT0Y, ABS_X, ABS_Y, ABS_RX, ABS_RY } }
}, {
{ ABS_X, -255, 255, 3, 30 },
{ ABS_Y, -255, 255, 3, 30 },
{ ABS_RX, -255, 255, 3, 30 },
{ ABS_RY, -255, 255, 3, 30 },
{ ABS_HAT0X, -65535, 65535, 0, 0 },
{ ABS_HAT0Y, -65535, 65535, 0, 0 },
});
global.mouse = new Mouse {
UinputDevice("/dev/uinput", BUS_USB, "pyraInput Mouse", 1, 1, 1, {
{ EV_KEY, { BTN_LEFT, BTN_RIGHT } },
{ EV_REL, { REL_X, REL_Y, REL_HWHEEL, REL_WHEEL, REL_WHEEL_HI_RES, REL_HWHEEL_HI_RES } }
}), 0, 0, 0, 0, {}, {}
};
global.mouseThread = std::move(std::thread(handleMouse, global.mouse, &global.settings, &global.stop));
global.rumbleThread = std::move(std::thread(handleRumble, global.gamepad, &global.stop));
global.settings.scripts.brightnessNormal = "/usr/share/pyra/scripts/pyra-brightkey.sh screen up";
global.settings.scripts.brightnessShift = "/usr/share/pyra/scripts/pyra-brightkey.sh screen down";
global.settings.scripts.brightnessFn = "/usr/share/pyra/scripts/pyra-brightkey.sh key up";
global.settings.scripts.brightnessFnShift = "/usr/share/pyra/scripts/pyra-brightkey.sh key down";
}
void handle(input_event const& e, unsigned int role) {
switch(e.type) {
case EV_ABS:
if (role == ROLE_LEFT_NUB) {
switch(e.code) {
case ABS_X:
if (global.settings.exportGamepad) {
if (e.value>global.settings.joyDeadzone || e.value<-global.settings.joyDeadzone) {
global.gamepad->send(EV_ABS, ABS_X, e.value);
} else {
global.gamepad->send(EV_ABS, ABS_X, 0);
}
global.gamepad->send(EV_SYN, 0, 0);
}
for(auto mode : global.settings.leftNubModeX) {
handleNubAxis(mode, e.value, global.mouse, global.gamepad, global.settings);
}
break;
case ABS_Y:
if (global.settings.exportGamepad) {
if (e.value>global.settings.joyDeadzone || e.value<-global.settings.joyDeadzone) {
global.gamepad->send(EV_ABS, ABS_Y, e.value);
} else {
global.gamepad->send(EV_ABS, ABS_Y, 0);
}
global.gamepad->send(EV_SYN, 0, 0);
}
for(auto mode : global.settings.leftNubModeY) {
handleNubAxis(mode, e.value, global.mouse, global.gamepad, global.settings);
}
break;
default: break;
};
} else if (role == ROLE_RIGHT_NUB) {
switch(e.code) {
case ABS_X:
if (global.settings.exportGamepad) {
if (e.value>global.settings.joyDeadzone || e.value<-global.settings.joyDeadzone) {
global.gamepad->send(EV_ABS, ABS_RX, e.value);
} else {
global.gamepad->send(EV_ABS, ABS_RX, 0);
}
global.gamepad->send(EV_SYN, 0, 0);
}
for(auto mode : global.settings.rightNubModeX) {
handleNubAxis(mode, e.value, global.mouse, global.gamepad, global.settings);
}
break;
case ABS_Y:
if (global.settings.exportGamepad) {
if (e.value>global.settings.joyDeadzone||e.value<-global.settings.joyDeadzone) {
global.gamepad->send(EV_ABS, ABS_RY, e.value);
} else {
global.gamepad->send(EV_ABS, ABS_RY, 0);
}
global.gamepad->send(EV_SYN, 0, 0);
}
for(auto mode : global.settings.rightNubModeY) {
handleNubAxis(mode, e.value, global.mouse, global.gamepad, global.settings);
}
break;
default: break;
};
}
break;
case EV_KEY:
switch(e.code) {
case BTN_LEFT: // Right nub click
if (role == ROLE_GPIO) {
for(auto mode : global.settings.rightNubClickMode) {
handleNubClick(mode, e.value, global.mouse, global.gamepad, global.settings);
}
}
break;
case BTN_RIGHT: // Left nub click
if (role == ROLE_GPIO) {
for(auto mode : global.settings.leftNubClickMode) {
handleNubClick(mode, e.value, global.mouse, global.gamepad, global.settings);
}
}
break;
default:
global.behaviors->handle(e.code, e.value);
global.keyboard->send(EV_SYN, 0, 0);
break;
}
break;
case EV_REL:
/*
* One of the nub is in mouse mode
* TODO: Should forward the event to the mouse
global.mouse->device.send(EV_REL, e.code, e.value);
global.mouse->signal.notify_all();
printf("REL: type=%d, code=%d, value=%d\n", e.type, e.code, e.value);
*/
break;
}
}
void destroy() {
global.stop = true;
global.mouse->signal.notify_all();
if(global.gamepad) {
delete global.gamepad;
}
if(global.keyboard) {
delete global.keyboard;
}
if(global.behaviors) {
delete global.behaviors;
}
global.mouseThread.join();
global.rumbleThread.join();
}
void user1() {
resetSettings(global.settings);
loadConfig(global.settings.configFile, global.settings);
}
void user2() {
}
void handleArgs(char const** argv, unsigned int argc, Settings& settings) {
std::string configFile;
std::regex configRegex("config=(.*)");
for(unsigned int i = 0; i < argc; ++i) {
std::string arg(argv[i]);
std::smatch match;
if(std::regex_match(arg, match, configRegex)) {
settings.configFile = match[1];
}
}
}
void setCommandMode(bool value) {
if(global.commandMode != value) {
global.commandMode = value;
if(global.commandMode) {
if(!global.settings.scripts.commandModeOn.empty()) {
system(global.settings.scripts.commandModeOn.c_str());
}
} else {
if(!global.settings.scripts.commandModeOff.empty()) {
system(global.settings.scripts.commandModeOff.c_str());
}
}
}
}
void handleNubAxis(Settings::NubAxisMode mode, int value, Mouse* mouse, PyraJoystick* gamepad, Settings const& settings) {
switch(mode) {
case Settings::MOUSE_X:
mouse->dx = value;
if(mouse->dx > settings.mouseDeadzone || mouse->dx < -settings.mouseDeadzone)
mouse->signal.notify_all();
break;
case Settings::MOUSE_Y:
mouse->dy = value;
if(mouse->dy > settings.mouseDeadzone || mouse->dy < -settings.mouseDeadzone)
mouse->signal.notify_all();
break;
case Settings::SCROLL_X:
mouse->dwx = value;
if(mouse->dwx > settings.mouseDeadzone || mouse->dwx < -settings.mouseDeadzone)
mouse->signal.notify_all();
break;
case Settings::SCROLL_Y:
mouse->dwy = value;
if(mouse->dwy > settings.mouseDeadzone || mouse->dwy < -settings.mouseDeadzone)
mouse->signal.notify_all();
break;
case Settings::MOUSE_BTN: {
int new_val = 0;
if (value < -settings.mouseClickDeadzone)
new_val = -1;
else if (value > settings.mouseClickDeadzone)
new_val = 1;
if (global.mouseBtn!=new_val && global.settings.exportMouse) {
if (global.mouseBtn == -1)
mouse->device.send(EV_KEY, BTN_LEFT, 0);
else if (global.mouseBtn == 1)
mouse->device.send(EV_KEY, BTN_RIGHT, 0);
if (new_val == -1 )
mouse->device.send(EV_KEY, BTN_LEFT, 1);
else if (new_val == 1 )
mouse->device.send(EV_KEY, BTN_RIGHT, 1);
mouse->device.send(EV_SYN, 0, 0);
global.mouseBtn=new_val;
}
}
break;
case Settings::UNKNOWN_NUB_AXIS_MODE:
break;
}
}
void handleNubClick(Settings::NubClickMode mode, int value, Mouse* mouse, PyraJoystick* gamepad, Settings const& settings) {
switch(mode) {
case Settings::MOUSE_MIDDLE: {
if (global.settings.exportMouse) {
std::lock_guard<std::mutex> lk(mouse->mutex);
mouse->device.send(EV_KEY, BTN_MIDDLE, value);
mouse->device.send(EV_SYN, 0, 0);
}
break;
}
case Settings::MOUSE_LEFT: {
if (global.settings.exportMouse) {
std::lock_guard<std::mutex> lk(mouse->mutex);
mouse->device.send(EV_KEY, BTN_LEFT, value);
mouse->device.send(EV_SYN, 0, 0);
}
break;
}
case Settings::MOUSE_RIGHT: {
if (global.settings.exportMouse) {
std::lock_guard<std::mutex> lk(mouse->mutex);
mouse->device.send(EV_KEY, BTN_RIGHT, value);
mouse->device.send(EV_SYN, 0, 0);
}
break;
}
case Settings::NUB_CLICK_LEFT:
if (global.settings.exportGamepad) {
gamepad->send(EV_KEY, BTN_THUMBL, value);
gamepad->send(EV_SYN, 0, 0);
}
break;
case Settings::NUB_CLICK_RIGHT:
if (global.settings.exportGamepad) {
gamepad->send(EV_KEY, BTN_THUMBR, value);
gamepad->send(EV_SYN, 0, 0);
}
break;
case Settings::UNKNOWN_NUB_CLICK_MODE:
break;
}
}
void handleBrightness(int value) {
if (value!=1) return;
int ret = 0;
if (global.Shift.pressed && global.Ctrl.pressed && global.Fn.pressed) {
if (!global.settings.scripts.brightnessFnShiftCtrl.empty())
ret=system(global.settings.scripts.brightnessFnShiftCtrl.c_str());
} else if (global.Shift.pressed && global.Alt.pressed && global.Fn.pressed) {
if (!global.settings.scripts.brightnessFnShiftAlt.empty())
ret=system(global.settings.scripts.brightnessFnShiftAlt.c_str());
} else if (global.Shift.pressed && global.Alt.pressed) {
if (!global.settings.scripts.brightnessShiftAlt.empty())
ret=system(global.settings.scripts.brightnessShiftAlt.c_str());
} else if (global.Shift.pressed && global.Ctrl.pressed) {
if (!global.settings.scripts.brightnessShiftCtrl.empty())
ret=system(global.settings.scripts.brightnessShiftCtrl.c_str());
} else if (global.Fn.pressed && global.Alt.pressed) {
if (!global.settings.scripts.brightnessFnAlt.empty())
ret=system(global.settings.scripts.brightnessFnAlt.c_str());
} else if (global.Fn.pressed && global.Ctrl.pressed) {
if (!global.settings.scripts.brightnessFnCtrl.empty())
ret=system(global.settings.scripts.brightnessFnCtrl.c_str());
} else if (global.Alt.pressed && global.Ctrl.pressed) {
if (!global.settings.scripts.brightnessAltCtrl.empty())
ret=system(global.settings.scripts.brightnessAltCtrl.c_str());
} else if (global.Fn.pressed && global.Shift.pressed) {
if (!global.settings.scripts.brightnessFnShift.empty())
ret=system(global.settings.scripts.brightnessFnShift.c_str());
} else if (global.Alt.pressed) {
if (!global.settings.scripts.brightnessAlt.empty())
ret=system(global.settings.scripts.brightnessAlt.c_str());
} else if (global.Alt.pressed) {
if (!global.settings.scripts.brightnessAlt.empty())
ret=system(global.settings.scripts.brightnessAlt.c_str());
} else if (global.Shift.pressed) {
if (!global.settings.scripts.brightnessShift.empty())
ret=system(global.settings.scripts.brightnessShift.c_str());
} else if (global.Fn.pressed) {
if (!global.settings.scripts.brightnessFn.empty())
ret=system(global.settings.scripts.brightnessFn.c_str());
} else {
if (!global.settings.scripts.brightnessNormal.empty())
ret=system(global.settings.scripts.brightnessNormal.c_str());
}
}
void handleRumble(PyraJoystick* gamepad, bool* stop) {
while(!*stop && gamepad->is_ready()) {
gamepad->rumble_handle();
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
}
void handleMouse(Mouse* mouse, Settings* settings, bool* stop) {
while(!*stop) {
if((mouse->dx > settings->mouseDeadzone || mouse->dx < -settings->mouseDeadzone || mouse->dy > settings->mouseDeadzone || mouse->dy < -settings->mouseDeadzone || mouse->dwx > settings->mouseClickDeadzone || mouse->dwx < -settings->mouseClickDeadzone || mouse->dwy > settings->mouseWheelDeadzone || mouse->dwy < -settings->mouseWheelDeadzone)&&global.settings.exportMouse) {
std::lock_guard<std::mutex> lk(mouse->mutex);
if(mouse->dx > settings->mouseDeadzone) {
mouse->device.send(EV_REL, REL_X, (mouse->dx - settings->mouseDeadzone) * settings->mouseSensitivity / 1000);
} else if(mouse->dx < -settings->mouseDeadzone) {
mouse->device.send(EV_REL, REL_X, (mouse->dx + settings->mouseDeadzone) * settings->mouseSensitivity / 1000);
}
if(mouse->dy > settings->mouseDeadzone) {
mouse->device.send(EV_REL, REL_Y, (mouse->dy - settings->mouseDeadzone) * settings->mouseSensitivity / 1000);
} else if(mouse->dy < -settings->mouseDeadzone) {
mouse->device.send(EV_REL, REL_Y, (mouse->dy + settings->mouseDeadzone) * settings->mouseSensitivity / 1000);
}
int hwheelChange = 0;
if(mouse->dwx > settings->mouseWheelDeadzone) {
hwheelChange = (mouse->dwx - settings->mouseWheelDeadzone) * settings->mouseWheelSensitivity / 100;
} else if(mouse->dwx < -settings->mouseWheelDeadzone) {
hwheelChange = (mouse->dwx + settings->mouseWheelDeadzone) * settings->mouseWheelSensitivity / 100;
}
if(hwheelChange != 0) {
mouse->hwheelPosition += hwheelChange;
mouse->device.send(EV_REL, REL_HWHEEL_HI_RES, hwheelChange);
int notches = mouse->hwheelPosition / mouse->WHEEL_HI_RES_PER_NOTCH;
if(notches != 0) {
mouse->device.send(EV_REL, REL_HWHEEL, notches);
mouse->hwheelPosition = mouse->hwheelPosition % mouse->WHEEL_HI_RES_PER_NOTCH;
}
}
int wheelChange = 0;
if(mouse->dwy > settings->mouseWheelDeadzone) {
wheelChange = -(mouse->dwy - settings->mouseWheelDeadzone) * settings->mouseWheelSensitivity / 100;
} else if(mouse->dwy < -settings->mouseWheelDeadzone) {
wheelChange = -(mouse->dwy + settings->mouseWheelDeadzone) * settings->mouseWheelSensitivity / 100;
}
if(wheelChange != 0) {
mouse->wheelPosition += wheelChange;
mouse->device.send(EV_REL, REL_WHEEL_HI_RES, wheelChange);
int notches = mouse->wheelPosition / mouse->WHEEL_HI_RES_PER_NOTCH;
if(notches != 0) {
mouse->device.send(EV_REL, REL_WHEEL, notches);
mouse->wheelPosition = mouse->wheelPosition % mouse->WHEEL_HI_RES_PER_NOTCH;
}
}
mouse->device.send(EV_SYN, 0, 0);
} else {
std::unique_lock<std::mutex> lk(mouse->mutex);
mouse->signal.wait(lk);
}
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
delete mouse;
}