Compare commits
5 Commits
hidmouse.8
...
hidmouse.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdf220b975 | ||
|
|
001b599b41 | ||
|
|
8a48256305 | ||
|
|
97599c5db3 | ||
|
|
54180fde50 |
@@ -77,6 +77,7 @@ if aoa_hid_support
|
|||||||
src += [
|
src += [
|
||||||
'src/aoa_hid.c',
|
'src/aoa_hid.c',
|
||||||
'src/hid_keyboard.c',
|
'src/hid_keyboard.c',
|
||||||
|
'src/hid_mouse.c',
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
|
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
|
||||||
#define MIN(X,Y) (X) < (Y) ? (X) : (Y)
|
#define MIN(X,Y) (X) < (Y) ? (X) : (Y)
|
||||||
#define MAX(X,Y) (X) > (Y) ? (X) : (Y)
|
#define MAX(X,Y) (X) > (Y) ? (X) : (Y)
|
||||||
|
#define CLAMP(V,X,Y) MIN( MAX((V),(X)), (Y) )
|
||||||
|
|
||||||
#define container_of(ptr, type, member) \
|
#define container_of(ptr, type, member) \
|
||||||
((type *) (((char *) (ptr)) - offsetof(type, member)))
|
((type *) (((char *) (ptr)) - offsetof(type, member)))
|
||||||
|
|||||||
265
app/src/hid_mouse.c
Normal file
265
app/src/hid_mouse.c
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
#include "hid_mouse.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "input_events.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
|
||||||
|
/** Downcast mouse processor to hid_mouse */
|
||||||
|
#define DOWNCAST(MP) container_of(MP, struct sc_hid_mouse, mouse_processor)
|
||||||
|
|
||||||
|
#define HID_MOUSE_ACCESSORY_ID 2
|
||||||
|
|
||||||
|
// 1 byte for buttons + padding, 1 byte for X position, 1 byte for Y position
|
||||||
|
#define HID_MOUSE_EVENT_SIZE 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mouse descriptor from the specification:
|
||||||
|
* <https://www.usb.org/sites/default/files/hid1_11.pdf>
|
||||||
|
*
|
||||||
|
* Appendix E (p71): §E.10 Report Descriptor (Mouse)
|
||||||
|
*
|
||||||
|
* The usage tags (like Wheel) are listed in "HID Usage Tables":
|
||||||
|
* <https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf>
|
||||||
|
* §4 Generic Desktop Page (0x01) (p26)
|
||||||
|
*/
|
||||||
|
static const unsigned char mouse_report_desc[] = {
|
||||||
|
// Usage Page (Generic Desktop)
|
||||||
|
0x05, 0x01,
|
||||||
|
// Usage (Mouse)
|
||||||
|
0x09, 0x02,
|
||||||
|
|
||||||
|
// Collection (Application)
|
||||||
|
0xA1, 0x01,
|
||||||
|
|
||||||
|
// Usage (Pointer)
|
||||||
|
0x09, 0x01,
|
||||||
|
|
||||||
|
// Collection (Physical)
|
||||||
|
0xA1, 0x00,
|
||||||
|
|
||||||
|
// Usage Page (Buttons)
|
||||||
|
0x05, 0x09,
|
||||||
|
|
||||||
|
// Usage Minimum (1)
|
||||||
|
0x19, 0x01,
|
||||||
|
// Usage Maximum (5)
|
||||||
|
0x29, 0x05,
|
||||||
|
// Logical Minimum (0)
|
||||||
|
0x15, 0x00,
|
||||||
|
// Logical Maximum (1)
|
||||||
|
0x25, 0x01,
|
||||||
|
// Report Count (5)
|
||||||
|
0x95, 0x05,
|
||||||
|
// Report Size (1)
|
||||||
|
0x75, 0x01,
|
||||||
|
// Input (Data, Variable, Absolute): 5 buttons bits
|
||||||
|
0x81, 0x02,
|
||||||
|
|
||||||
|
// Report Count (1)
|
||||||
|
0x95, 0x01,
|
||||||
|
// Report Size (3)
|
||||||
|
0x75, 0x03,
|
||||||
|
// Input (Constant): 3 bits padding
|
||||||
|
0x81, 0x01,
|
||||||
|
|
||||||
|
// Usage Page (Generic Desktop)
|
||||||
|
0x05, 0x01,
|
||||||
|
// Usage (X)
|
||||||
|
0x09, 0x30,
|
||||||
|
// Usage (Y)
|
||||||
|
0x09, 0x31,
|
||||||
|
// Usage (Wheel)
|
||||||
|
0x09, 0x38,
|
||||||
|
// Local Minimum (-127)
|
||||||
|
0x15, 0x81,
|
||||||
|
// Local Maximum (127)
|
||||||
|
0x25, 0x7F,
|
||||||
|
// Report Size (8)
|
||||||
|
0x75, 0x08,
|
||||||
|
// Report Count (3)
|
||||||
|
0x95, 0x03,
|
||||||
|
// Input (Data, Variable, Relative): 3 position bytes (X, Y, Wheel)
|
||||||
|
0x81, 0x06,
|
||||||
|
|
||||||
|
// End Collection
|
||||||
|
0xC0,
|
||||||
|
|
||||||
|
// End Collection
|
||||||
|
0xC0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mouse HID event is 3 bytes long:
|
||||||
|
*
|
||||||
|
* - byte 0: buttons state
|
||||||
|
* - byte 1: relative x motion (signed byte from -127 to 127)
|
||||||
|
* - byte 2: relative y motion (signed byte from -127 to 127)
|
||||||
|
*
|
||||||
|
* 7 6 5 4 3 2 1 0
|
||||||
|
* +---------------+
|
||||||
|
* byte 0: |0 0 0 . . . . .| buttons state
|
||||||
|
* +---------------+
|
||||||
|
* ^ ^ ^ ^ ^
|
||||||
|
* | | | | `- left button
|
||||||
|
* | | | `--- right button
|
||||||
|
* | | `----- middle button
|
||||||
|
* | `------- button 4
|
||||||
|
* `--------- button 5
|
||||||
|
*
|
||||||
|
* +---------------+
|
||||||
|
* byte 1: |. . . . . . . .| relative x motion
|
||||||
|
* +---------------+
|
||||||
|
* byte 2: |. . . . . . . .| relative y motion
|
||||||
|
* +---------------+
|
||||||
|
* byte 3: |. . . . . . . .| wheel motion (-1, 0 or 1)
|
||||||
|
* +---------------+
|
||||||
|
*
|
||||||
|
* As an example, here is the report for a motion of (x=5, y=-4) with left
|
||||||
|
* button pressed:
|
||||||
|
*
|
||||||
|
* +---------------+
|
||||||
|
* |0 0 0 0 0 0 0 1| left button pressed
|
||||||
|
* +---------------+
|
||||||
|
* |0 0 0 0 0 1 0 1| horizontal motion (x = 5)
|
||||||
|
* +---------------+
|
||||||
|
* |1 1 1 1 1 1 0 0| relative y motion (y = -4)
|
||||||
|
* +---------------+
|
||||||
|
* |0 0 0 0 0 0 0 0| wheel motion
|
||||||
|
* +---------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sc_hid_mouse_event_init(struct sc_hid_event *hid_event) {
|
||||||
|
unsigned char *buffer = calloc(1, HID_MOUSE_EVENT_SIZE);
|
||||||
|
if (!buffer) {
|
||||||
|
LOG_OOM();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_hid_event_init(hid_event, HID_MOUSE_ACCESSORY_ID, buffer,
|
||||||
|
HID_MOUSE_EVENT_SIZE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char
|
||||||
|
buttons_state_to_hid_buttons(uint8_t buttons_state) {
|
||||||
|
unsigned char c = 0;
|
||||||
|
if (buttons_state & SC_MOUSE_BUTTON_LEFT) {
|
||||||
|
c |= 1 << 0;
|
||||||
|
}
|
||||||
|
if (buttons_state & SC_MOUSE_BUTTON_RIGHT) {
|
||||||
|
c |= 1 << 1;
|
||||||
|
}
|
||||||
|
if (buttons_state & SC_MOUSE_BUTTON_MIDDLE) {
|
||||||
|
c |= 1 << 2;
|
||||||
|
}
|
||||||
|
if (buttons_state & SC_MOUSE_BUTTON_X1) {
|
||||||
|
c |= 1 << 3;
|
||||||
|
}
|
||||||
|
if (buttons_state & SC_MOUSE_BUTTON_X2) {
|
||||||
|
c |= 1 << 4;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
|
||||||
|
const struct sc_mouse_motion_event *event) {
|
||||||
|
struct sc_hid_mouse *mouse = DOWNCAST(mp);
|
||||||
|
|
||||||
|
struct sc_hid_event hid_event;
|
||||||
|
if (!sc_hid_mouse_event_init(&hid_event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *buffer = hid_event.buffer;
|
||||||
|
buffer[0] = buttons_state_to_hid_buttons(event->buttons_state);
|
||||||
|
buffer[1] = CLAMP(event->xrel, -127, 127);
|
||||||
|
buffer[2] = CLAMP(event->yrel, -127, 127);
|
||||||
|
buffer[3] = 0; // wheel coordinates only used for scrolling
|
||||||
|
|
||||||
|
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
|
||||||
|
sc_hid_event_destroy(&hid_event);
|
||||||
|
LOGW("Could request HID event");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
|
||||||
|
const struct sc_mouse_click_event *event) {
|
||||||
|
struct sc_hid_mouse *mouse = DOWNCAST(mp);
|
||||||
|
|
||||||
|
struct sc_hid_event hid_event;
|
||||||
|
if (!sc_hid_mouse_event_init(&hid_event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *buffer = hid_event.buffer;
|
||||||
|
buffer[0] = buttons_state_to_hid_buttons(event->buttons_state);
|
||||||
|
buffer[1] = 0; // no x motion
|
||||||
|
buffer[2] = 0; // no y motion
|
||||||
|
buffer[3] = 0; // wheel coordinates only used for scrolling
|
||||||
|
|
||||||
|
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
|
||||||
|
sc_hid_event_destroy(&hid_event);
|
||||||
|
LOGW("Could request HID event");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
|
||||||
|
const struct sc_mouse_scroll_event *event) {
|
||||||
|
struct sc_hid_mouse *mouse = DOWNCAST(mp);
|
||||||
|
|
||||||
|
struct sc_hid_event hid_event;
|
||||||
|
if (!sc_hid_mouse_event_init(&hid_event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *buffer = hid_event.buffer;
|
||||||
|
buffer[0] = 0; // buttons state irrelevant (and unknown)
|
||||||
|
buffer[1] = 0; // no x motion
|
||||||
|
buffer[2] = 0; // no y motion
|
||||||
|
// In practice, vscroll is always -1, 0 or 1, but in theory other values
|
||||||
|
// are possible
|
||||||
|
buffer[3] = CLAMP(event->vscroll, -127, 127);
|
||||||
|
// Horizontal scrolling ignored
|
||||||
|
|
||||||
|
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
|
||||||
|
sc_hid_event_destroy(&hid_event);
|
||||||
|
LOGW("Could request HID event");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
sc_hid_mouse_init(struct sc_hid_mouse *mouse, struct sc_aoa *aoa) {
|
||||||
|
mouse->aoa = aoa;
|
||||||
|
|
||||||
|
bool ok = sc_aoa_setup_hid(aoa, HID_MOUSE_ACCESSORY_ID, mouse_report_desc,
|
||||||
|
ARRAY_LEN(mouse_report_desc));
|
||||||
|
if (!ok) {
|
||||||
|
LOGW("Register HID mouse failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sc_mouse_processor_ops ops = {
|
||||||
|
.process_mouse_motion = sc_mouse_processor_process_mouse_motion,
|
||||||
|
.process_mouse_click = sc_mouse_processor_process_mouse_click,
|
||||||
|
.process_mouse_scroll = sc_mouse_processor_process_mouse_scroll,
|
||||||
|
// Touch events not supported (coordinates are not relative)
|
||||||
|
.process_touch = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
mouse->mouse_processor.ops = &ops;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_hid_mouse_destroy(struct sc_hid_mouse *mouse) {
|
||||||
|
bool ok = sc_aoa_unregister_hid(mouse->aoa, HID_MOUSE_ACCESSORY_ID);
|
||||||
|
if (!ok) {
|
||||||
|
LOGW("Could not unregister HID");
|
||||||
|
}
|
||||||
|
}
|
||||||
23
app/src/hid_mouse.h
Normal file
23
app/src/hid_mouse.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef HID_MOUSE_H
|
||||||
|
#define HID_MOUSE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "aoa_hid.h"
|
||||||
|
#include "trait/mouse_processor.h"
|
||||||
|
|
||||||
|
struct sc_hid_mouse {
|
||||||
|
struct sc_mouse_processor mouse_processor; // mouse processor trait
|
||||||
|
|
||||||
|
struct sc_aoa *aoa;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
sc_hid_mouse_init(struct sc_hid_mouse *mouse, struct sc_aoa *aoa);
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_hid_mouse_destroy(struct sc_hid_mouse *mouse);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -366,6 +366,8 @@ struct sc_mouse_scroll_event {
|
|||||||
|
|
||||||
struct sc_mouse_motion_event {
|
struct sc_mouse_motion_event {
|
||||||
struct sc_position position;
|
struct sc_position position;
|
||||||
|
int32_t xrel;
|
||||||
|
int32_t yrel;
|
||||||
uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
|
uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -639,10 +639,10 @@ input_manager_process_mouse_motion(struct input_manager *im,
|
|||||||
if (im->forward_all_clicks) {
|
if (im->forward_all_clicks) {
|
||||||
mask |= SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
|
mask |= SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
|
||||||
}
|
}
|
||||||
if (!(event->state & mask)) {
|
//if (!(event->state & mask)) {
|
||||||
// do not send motion events when no click is pressed
|
// // do not send motion events when no click is pressed
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
if (event->which == SDL_TOUCH_MOUSEID) {
|
if (event->which == SDL_TOUCH_MOUSEID) {
|
||||||
// simulated from touch events, so it's a duplicate
|
// simulated from touch events, so it's a duplicate
|
||||||
return;
|
return;
|
||||||
@@ -654,6 +654,8 @@ input_manager_process_mouse_motion(struct input_manager *im,
|
|||||||
.point = screen_convert_window_to_frame_coords(im->screen,
|
.point = screen_convert_window_to_frame_coords(im->screen,
|
||||||
event->x, event->y),
|
event->x, event->y),
|
||||||
},
|
},
|
||||||
|
.xrel = event->xrel,
|
||||||
|
.yrel = event->yrel,
|
||||||
.buttons_state =
|
.buttons_state =
|
||||||
sc_mouse_buttons_state_from_sdl(event->state,
|
sc_mouse_buttons_state_from_sdl(event->state,
|
||||||
im->forward_all_clicks),
|
im->forward_all_clicks),
|
||||||
@@ -775,6 +777,12 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
assert(im->mp->ops->process_mouse_click);
|
assert(im->mp->ops->process_mouse_click);
|
||||||
im->mp->ops->process_mouse_click(im->mp, &evt);
|
im->mp->ops->process_mouse_click(im->mp, &evt);
|
||||||
|
|
||||||
|
if (im->mp->relative_mode) {
|
||||||
|
assert(!im->vfinger_down); // vfinger must not be used in relative mode
|
||||||
|
// No pinch-to-zoom simulation
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Pinch-to-zoom simulation.
|
// Pinch-to-zoom simulation.
|
||||||
//
|
//
|
||||||
// If Ctrl is hold when the left-click button is pressed, then
|
// If Ctrl is hold when the left-click button is pressed, then
|
||||||
|
|||||||
@@ -151,4 +151,6 @@ sc_mouse_inject_init(struct sc_mouse_inject *mi,
|
|||||||
};
|
};
|
||||||
|
|
||||||
mi->mouse_processor.ops = &ops;
|
mi->mouse_processor.ops = &ops;
|
||||||
|
|
||||||
|
mi->mouse_processor.relative_mode = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "input_manager.h"
|
#include "input_manager.h"
|
||||||
#ifdef HAVE_AOA_HID
|
#ifdef HAVE_AOA_HID
|
||||||
# include "hid_keyboard.h"
|
# include "hid_keyboard.h"
|
||||||
|
# include "hid_mouse.h"
|
||||||
#endif
|
#endif
|
||||||
#include "keyboard_inject.h"
|
#include "keyboard_inject.h"
|
||||||
#include "mouse_inject.h"
|
#include "mouse_inject.h"
|
||||||
@@ -56,7 +57,12 @@ struct scrcpy {
|
|||||||
struct sc_hid_keyboard keyboard_hid;
|
struct sc_hid_keyboard keyboard_hid;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
struct sc_mouse_inject mouse_inject;
|
union {
|
||||||
|
struct sc_mouse_inject mouse_inject;
|
||||||
|
#ifdef HAVE_AOA_HID
|
||||||
|
struct sc_hid_mouse mouse_hid;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
struct input_manager input_manager;
|
struct input_manager input_manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -581,8 +587,9 @@ aoa_hid_end:
|
|||||||
kp = &s->keyboard_inject.key_processor;
|
kp = &s->keyboard_inject.key_processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_mouse_inject_init(&s->mouse_inject, &s->controller);
|
//sc_mouse_inject_init(&s->mouse_inject, &s->controller);
|
||||||
mp = &s->mouse_inject.mouse_processor;
|
sc_hid_mouse_init(&s->mouse_hid, &s->aoa);
|
||||||
|
mp = &s->mouse_hid.mouse_processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
input_manager_init(&s->input_manager, &s->controller, &s->screen, kp, mp,
|
input_manager_init(&s->input_manager, &s->controller, &s->screen, kp, mp,
|
||||||
|
|||||||
@@ -485,6 +485,10 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
|||||||
SDL_AddEventWatch(event_watcher, screen);
|
SDL_AddEventWatch(event_watcher, screen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (SDL_SetRelativeMouseMode(true)) {
|
||||||
|
LOGE("Could not set relative mouse mode: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
static const struct sc_frame_sink_ops ops = {
|
static const struct sc_frame_sink_ops ops = {
|
||||||
.open = screen_frame_sink_open,
|
.open = screen_frame_sink_open,
|
||||||
.close = screen_frame_sink_close,
|
.close = screen_frame_sink_close,
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
struct sc_mouse_processor {
|
struct sc_mouse_processor {
|
||||||
const struct sc_mouse_processor_ops *ops;
|
const struct sc_mouse_processor_ops *ops;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, the mouse processor works in relative mode (the absolute
|
||||||
|
* position is irrelevant). In particular, it indicates that the mouse
|
||||||
|
* pointer must be "captured" by the UI.
|
||||||
|
*/
|
||||||
|
bool relative_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_mouse_processor_ops {
|
struct sc_mouse_processor_ops {
|
||||||
|
|||||||
Reference in New Issue
Block a user