Skip to content

Commit

Permalink
xpadneo, mouse: Implement mouse support
Browse files Browse the repository at this point in the history
Co-authored-by: Jacob Essex <[email protected]>
Co-authored-by: Florian Dollinger <[email protected]>
Closes: atar-axis#99
Closes: atar-axis#105
Closes: atar-axis#160
Fixes: atar-axis#333
See-also: atar-axis#419
See-also: atar-axis#435
Signed-off-by: Kai Krakow <[email protected]>
  • Loading branch information
3 people committed Nov 24, 2024
1 parent 289d3bf commit 55466f5
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 17 deletions.
19 changes: 19 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ PID 0x0B22 while the other models identify with PID 0x0B13. This has some known
* Supports customization through profiles (work in progress)
* Optional high-precision mode for Wine/Proton users (disables dead zones so games don't apply an additional one)
* Share button support on supported controllers
* Works as a mouse if you're are in couch-mode (press <key>Guide</key>+<key>Select</key>)


## Unavailable Features
Expand Down Expand Up @@ -222,6 +223,24 @@ or Y while holding down the Xbox logo button. However, the following caveats app
parameter `disable_shift_mode`).


### Mouse Profile Support

The driver can switch to emulating a mouse (and limited keyboard) on all supported controllers. Press
<key>Guide</key>+<key>Select</key> to switch to mouse mode or back to controller mode:

- Left stick moves the mouse pointer
- Right stick can be used as a scrolling wheel/ball
- Triggers for left and right mouse button
- Shoulder buttons for back and forward button
- D-pad for cursor movement
- Menu to show on-screen keyboard (FIXME possible? KEY_KEYBOARD)
- A for <key>Enter</key>
- B for <key>Escape</key>

**Important:** The mouse profile won't work if you disabled the shift-mode of the Xbox logo button (module parameter
`disable_shift_mode`).


## Getting Started

### Distribution Packages
Expand Down
2 changes: 1 addition & 1 deletion hid-xpadneo/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ hid-xpadneo-y += xpadneo.o
$(obj)/xpadneo.c: $(src)/hid-xpadneo.c
cp $< $@

hid-xpadneo-y += xpadneo/core.o xpadneo/consumer.o xpadneo/keyboard.o
hid-xpadneo-y += xpadneo/core.o xpadneo/consumer.o xpadneo/keyboard.o xpadneo/mouse.o
29 changes: 15 additions & 14 deletions hid-xpadneo/src/hid-xpadneo.c
Original file line number Diff line number Diff line change
Expand Up @@ -719,20 +719,6 @@ static const __u8 *xpadneo_report_fixup(struct hid_device *hdev, __u8 *rdesc, un
return rdesc;
}

static void xpadneo_toggle_mouse(struct xpadneo_devdata *xdata)
{
if (xdata->mouse_mode) {
xdata->mouse_mode = false;
hid_info(xdata->hdev, "mouse mode disabled\n");
} else {
xdata->mouse_mode = true;
hid_info(xdata->hdev, "mouse mode enabled\n");
}

/* Indicate that a request was made */
xdata->profile_switched = true;
}

static void xpadneo_switch_profile(struct xpadneo_devdata *xdata, const u8 profile,
const bool emulated)
{
Expand Down Expand Up @@ -839,6 +825,9 @@ static int xpadneo_raw_event(struct hid_device *hdev, struct hid_report *report,
}
}

if (xpadneo_mouse_raw_event(xdata, report, data, reportsize))
return -1;

return 0;
}

Expand Down Expand Up @@ -871,6 +860,7 @@ static int xpadneo_input_configured(struct hid_device *hdev, struct hid_input *h
return 0;
default:
hid_warn(hdev, "unhandled input application 0x%x\n", hi->application);
return 0;
}

if (param_disable_deadzones) {
Expand Down Expand Up @@ -920,6 +910,9 @@ static int xpadneo_event(struct hid_device *hdev, struct hid_field *field,
struct input_dev *gamepad = xdata->gamepad;
struct input_dev *keyboard = xdata->keyboard;

if (xpadneo_mouse_event(xdata, usage, value))
goto stop_processing;

if ((usage->type == EV_KEY) && (usage->code == BTN_PADDLES(0))) {
if (gamepad && xdata->profile == 0) {
/* report the paddles individually */
Expand Down Expand Up @@ -1206,6 +1199,10 @@ static int xpadneo_probe(struct hid_device *hdev, const struct hid_device_id *id
if (ret)
return ret;

ret = xpadneo_init_mouse(xdata);
if (ret)
return ret;

ret = xpadneo_init_hw(hdev);
if (ret) {
hid_err(hdev, "hw init failed: %d\n", ret);
Expand All @@ -1217,6 +1214,9 @@ static int xpadneo_probe(struct hid_device *hdev, const struct hid_device_id *id
if (ret)
hid_err(hdev, "could not initialize ff, continuing anyway\n");

timer_setup(&xdata->mouse_timer, xpadneo_mouse_report, 0);
mod_timer(&xdata->mouse_timer, jiffies);

hid_info(hdev, "%s connected\n", xdata->battery.name);

return 0;
Expand Down Expand Up @@ -1252,6 +1252,7 @@ static void xpadneo_remove(struct hid_device *hdev)
hdev->product = xdata->original_product;
}

del_timer_sync(&xdata->mouse_timer);
cancel_delayed_work_sync(&xdata->ff_worker);

kfree(xdata->battery.name);
Expand Down
18 changes: 16 additions & 2 deletions hid-xpadneo/src/xpadneo.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define XPADNEO_H_FILE

#include <linux/hid.h>
#include <linux/timer.h>
#include <linux/version.h>

#include "hid-ids.h"
Expand Down Expand Up @@ -138,8 +139,8 @@ struct xpadneo_devdata {

/* logical device interfaces */
struct hid_device *hdev;
struct input_dev *consumer, *gamepad, *keyboard;
bool consumer_sync, gamepad_sync, keyboard_sync;
struct input_dev *consumer, *gamepad, *keyboard, *mouse;
bool consumer_sync, gamepad_sync, keyboard_sync, mouse_sync;
short int missing_reported;

/* revert fixups on removal */
Expand All @@ -156,6 +157,14 @@ struct xpadneo_devdata {

/* mouse mode */
bool mouse_mode;
struct timer_list mouse_timer;
struct {
s32 rel_x, rel_y, wheel_x, wheel_y;
s32 rel_x_err, rel_y_err, wheel_x_err, wheel_y_err;
struct {
bool left, right;
} analog_button;
} mouse_state;

/* trigger scale */
struct {
Expand Down Expand Up @@ -193,8 +202,13 @@ struct xpadneo_devdata {

extern int xpadneo_init_consumer(struct xpadneo_devdata *);
extern int xpadneo_init_keyboard(struct xpadneo_devdata *);
extern int xpadneo_init_mouse(struct xpadneo_devdata *);
extern int xpadneo_init_synthetic(struct xpadneo_devdata *, char *, struct input_dev **);
extern int xpadneo_mouse_event(struct xpadneo_devdata *, struct hid_usage *, __s32);
extern int xpadneo_mouse_raw_event(struct xpadneo_devdata *, struct hid_report *, u8 *, int);
extern void xpadneo_report(struct hid_device *, struct hid_report *);
extern void xpadneo_core_missing(struct xpadneo_devdata *, u32);
extern void xpadneo_mouse_report(struct timer_list *);
extern void xpadneo_toggle_mouse(struct xpadneo_devdata *);

#endif
3 changes: 3 additions & 0 deletions hid-xpadneo/src/xpadneo/consumer.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ extern int xpadneo_init_consumer(struct xpadneo_devdata *xdata)
return ret;
}

/* enable consumer events for mouse mode */
input_set_capability(xdata->consumer, EV_KEY, KEY_ONSCREEN_KEYBOARD);

if (synth) {
ret = input_register_device(xdata->consumer);
if (ret) {
Expand Down
8 changes: 8 additions & 0 deletions hid-xpadneo/src/xpadneo/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ extern void xpadneo_report(struct hid_device *hdev, struct hid_report *report)
xdata->keyboard_sync = false;
input_sync(xdata->keyboard);
}

if (xdata->mouse && xdata->mouse_sync) {
xdata->mouse_sync = false;
input_sync(xdata->mouse);
}
}

extern void xpadneo_core_missing(struct xpadneo_devdata *xdata, u32 flag)
Expand All @@ -63,6 +68,9 @@ extern void xpadneo_core_missing(struct xpadneo_devdata *xdata, u32 flag)
if ((xdata->missing_reported & flag) == 0) {
xdata->missing_reported |= flag;
switch (flag) {
case XPADNEO_MISSING_CONSUMER:
hid_err(hdev, "consumer control not detected\n");
break;
case XPADNEO_MISSING_GAMEPAD:
hid_err(hdev, "gamepad not detected\n");
break;
Expand Down
8 changes: 8 additions & 0 deletions hid-xpadneo/src/xpadneo/keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ extern int xpadneo_init_keyboard(struct xpadneo_devdata *xdata)
/* enable key events for keyboard */
input_set_capability(xdata->keyboard, EV_KEY, BTN_SHARE);

/* enable key events for mouse mode */
input_set_capability(xdata->keyboard, EV_KEY, KEY_ESC);
input_set_capability(xdata->keyboard, EV_KEY, KEY_ENTER);
input_set_capability(xdata->keyboard, EV_KEY, KEY_UP);
input_set_capability(xdata->keyboard, EV_KEY, KEY_LEFT);
input_set_capability(xdata->keyboard, EV_KEY, KEY_RIGHT);
input_set_capability(xdata->keyboard, EV_KEY, KEY_DOWN);

if (synth) {
ret = input_register_device(xdata->keyboard);
if (ret) {
Expand Down
Loading

0 comments on commit 55466f5

Please sign in to comment.