diff --git a/input.cpp b/input.cpp index 03ce6e5..15e0197 100644 --- a/input.cpp +++ b/input.cpp @@ -1198,6 +1198,7 @@ typedef struct char id[80]; char name[128]; char sysfs[512]; + int max_range; } devInput; static devInput input[NUMDEV] = {}; @@ -2074,16 +2075,30 @@ static void joy_digital(int jnum, uint32_t mask, uint32_t code, char press, int } } -static void joy_analog(int num, int axis, int offset, int stick = 0) +static void joy_analog(int dev, int axis, int offset, int stick = 0) { + int num = input[dev].num; static int pos[2][NUMPLAYERS][2] = {}; if (grabbed && num > 0 && num < NUMPLAYERS+1) { num--; pos[stick][num][axis] = offset; - if(stick) user_io_r_analog_joystick(num, (char)(pos[1][num][0]), (char)(pos[1][num][1])); - else user_io_l_analog_joystick(num, (char)(pos[0][num][0]), (char)(pos[0][num][1])); + int x = pos[stick][num][0]; + int y = pos[stick][num][1]; + if (is_n64() && stick == 0) + { + const int abs_x = abs(x); + const int abs_y = abs(y); + + if (abs_x > input[dev].max_range) input[dev].max_range = abs_x; + if (abs_y > input[dev].max_range) input[dev].max_range = abs_y; + + // emulate n64 joystick range and shape for regular -127-+127 controllers + n64_joy_emu(x, y, &x, &y, input[dev].max_range); + } + if(stick) user_io_r_analog_joystick(num, (char)x, (char)y); + else user_io_l_analog_joystick(num, (char)x, (char)y); } } @@ -3323,58 +3338,58 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int // steering wheel passes full range, pedals are standardised in +127 to 0 to -127 range if (ev->code == input[dev].wh_steer) { - joy_analog(input[dev].num, 0, value, 0); + joy_analog(dev, 0, value, 0); } else if (ev->code == input[dev].wh_accel) { - joy_analog(input[dev].num, 1, wh_value, 0); + joy_analog(dev, 1, wh_value, 0); } else if (ev->code == input[dev].wh_brake) { - joy_analog(input[dev].num, 1, wh_value, 1); + joy_analog(dev, 1, wh_value, 1); } else if (ev->code == input[dev].wh_clutch) { - joy_analog(input[dev].num, 0, wh_value, 1); + joy_analog(dev, 0, wh_value, 1); } else if (ev->code == input[dev].wh_combo) { // if accel and brake pedal use a shared axis then map negative to accel and positive to brake - if (value < -1) joy_analog(input[dev].num, 1, value, 0); - else if (value > 1) joy_analog(input[dev].num, 1, -value, 1); + if (value < -1) joy_analog(dev, 1, value, 0); + else if (value > 1) joy_analog(dev, 1, -value, 1); else { - joy_analog(input[dev].num, 1, 0, 0); - joy_analog(input[dev].num, 1, 0, 0); + joy_analog(dev, 1, 0, 0); + joy_analog(dev, 1, 0, 0); } } } else if (ev->code == 0 && input[dev].lightgun) { - joy_analog(input[dev].num, 0, value); + joy_analog(dev, 0, value); } else if (ev->code == 1 && input[dev].lightgun) { - joy_analog(input[dev].num, 1, value); + joy_analog(dev, 1, value); } else { int offset = (value < -1 || value>1) ? value : 0; if (input[dev].stick_l[0] && ev->code == (uint16_t)input[dev].mmap[input[dev].stick_l[0]]) { - joy_analog(input[dev].num, 0, offset, 0); + joy_analog(dev, 0, offset, 0); } else if (input[dev].stick_l[1] && ev->code == (uint16_t)input[dev].mmap[input[dev].stick_l[1]]) { - joy_analog(input[dev].num, 1, offset, 0); + joy_analog(dev, 1, offset, 0); } else if (input[dev].stick_r[0] && ev->code == (uint16_t)input[dev].mmap[input[dev].stick_r[0]]) { - joy_analog(input[dev].num, 0, offset, 1); + joy_analog(dev, 0, offset, 1); } else if (input[dev].stick_r[1] && ev->code == (uint16_t)input[dev].mmap[input[dev].stick_r[1]]) { - joy_analog(input[dev].num, 1, offset, 1); + joy_analog(dev, 1, offset, 1); } } } diff --git a/support.h b/support.h index 49e23c9..adcc6df 100644 --- a/support.h +++ b/support.h @@ -47,3 +47,4 @@ // N64 support #include "support/n64/n64.h" +#include "support/n64/n64_joy_emu.h" diff --git a/support/n64/n64_joy_emu.cpp b/support/n64/n64_joy_emu.cpp new file mode 100644 index 0000000..ada266d --- /dev/null +++ b/support/n64/n64_joy_emu.cpp @@ -0,0 +1,52 @@ +#include +#include +#include + +void n64_joy_emu(int x, int y, int* x2, int* y2, int max_range) +{ + // Move to top right quadrant to standardize solutions + const int x_flip = x < 0 ? -1 : 1; + const int y_flip = y < 0 ? -1 : 1; + const int abs_x = x * x_flip; + const int abs_y = y * y_flip; + + // Reduce range to radius 97.5807358037f ((69,69) diagonal of original controller) + // assumes the max range is at least 85 (max cardinal of original controller) + if (max_range < 85) max_range = 85; + float scale = 97.5807358037f / max_range; + float scaled_x = abs_x * scale; + float scaled_y = abs_y * scale; + + // Move to octagon's lower wedge in top right quadrant to further standardize solution + float scaled_max; + float scaled_min; + if (abs_x > abs_y) { + scaled_max = scaled_x; + scaled_min = scaled_y; + } else { + scaled_max = scaled_y; + scaled_min = scaled_x; + } + + // Clamp scaled_min and scaled_max + // Note: wedge boundary is given by x = 85 - y * ((85 - 69) / 69) + // If x + y * (16 / 69) > 85, coordinates exceed boundary and need clamped + float boundary = scaled_max + scaled_min * 0.231884057971f; + if (boundary > 85) { + // We know target value is on: + // 1) Boundary line: x = 85 - y * (16 / 69) + // 2) Observed slope line: y = (scaled_max / scaled_min) * x + // Solving system of equations yields: + scaled_min = 85 * scaled_min / boundary; + scaled_max = 85 - scaled_min * 0.231884057971f; // Boundary line + } + + // Move back from wedge to actual coordinates + if (abs_x > abs_y) { + *x2 = x_flip * scaled_max; + *y2 = y_flip * scaled_min; + } else { + *x2 = x_flip * scaled_min; + *y2 = y_flip * scaled_max; + } +} diff --git a/support/n64/n64_joy_emu.h b/support/n64/n64_joy_emu.h new file mode 100644 index 0000000..4398ad3 --- /dev/null +++ b/support/n64/n64_joy_emu.h @@ -0,0 +1 @@ +void n64_joy_emu(int x, int y, int* x2, int* y2, int max_range);