Compare commits

...

2 Commits

Author SHA1 Message Date
3b6495aefc Use precise scrolling values
Since SDL 2.0.18, the amount scrolled horizontally or vertically is
exposed as a float (between 0 and 1). Forward a precise value to the
Android device when possible.

Refs <https://wiki.libsdl.org/SDL_MouseWheelEvent>
Fixes #3363 <https://github.com/Genymobile/scrcpy/issues/3363>
PR #3369 <https://github.com/Genymobile/scrcpy/pull/3369>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2022-07-24 16:49:51 +02:00
72ff957e9a Extract conversion from fixed-point u16 to float
So that it can be reused for other fields.

PR #3369 <https://github.com/Genymobile/scrcpy/pull/3369>
2022-07-24 16:09:17 +02:00
8 changed files with 43 additions and 31 deletions

View File

@ -115,12 +115,15 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
return 28; return 28;
case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT: case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
write_position(&buf[1], &msg->inject_scroll_event.position); write_position(&buf[1], &msg->inject_scroll_event.position);
sc_write32be(&buf[13], // map [-1, 1] to [0, 1], then to uint16
(uint32_t) msg->inject_scroll_event.hscroll); uint16_t hscroll =
sc_write32be(&buf[17], to_fixed_point_16((msg->inject_scroll_event.hscroll + 1) / 2);
(uint32_t) msg->inject_scroll_event.vscroll); uint16_t vscroll =
sc_write32be(&buf[21], msg->inject_scroll_event.buttons); to_fixed_point_16((msg->inject_scroll_event.vscroll + 1) / 2);
return 25; sc_write16be(&buf[13], hscroll);
sc_write16be(&buf[15], vscroll);
sc_write32be(&buf[17], msg->inject_scroll_event.buttons);
return 21;
case SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON: case SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
buf[1] = msg->inject_keycode.action; buf[1] = msg->inject_keycode.action;
return 2; return 2;
@ -191,8 +194,8 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
break; break;
} }
case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT: case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%" PRIi32 LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%g"
" vscroll=%" PRIi32 " buttons=%06lx", " vscroll=%g buttons=%06lx",
msg->inject_scroll_event.position.point.x, msg->inject_scroll_event.position.point.x,
msg->inject_scroll_event.position.point.y, msg->inject_scroll_event.position.point.y,
msg->inject_scroll_event.hscroll, msg->inject_scroll_event.hscroll,

View File

@ -68,8 +68,8 @@ struct sc_control_msg {
} inject_touch_event; } inject_touch_event;
struct { struct {
struct sc_position position; struct sc_position position;
int32_t hscroll; float hscroll;
int32_t vscroll; float vscroll;
enum android_motionevent_buttons buttons; enum android_motionevent_buttons buttons;
} inject_scroll_event; } inject_scroll_event;
struct { struct {

View File

@ -358,8 +358,8 @@ struct sc_mouse_click_event {
struct sc_mouse_scroll_event { struct sc_mouse_scroll_event {
struct sc_position position; struct sc_position position;
int32_t hscroll; float hscroll;
int32_t vscroll; float vscroll;
uint8_t buttons_state; // bitwise-OR of sc_mouse_button values uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
}; };

View File

@ -747,8 +747,13 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
.point = sc_screen_convert_window_to_frame_coords(im->screen, .point = sc_screen_convert_window_to_frame_coords(im->screen,
mouse_x, mouse_y), mouse_x, mouse_y),
}, },
.hscroll = event->x, #if SDL_VERSION_ATLEAST(2, 0, 18)
.vscroll = event->y, .hscroll = CLAMP(event->preciseX, -1.0f, 1.0f),
.vscroll = CLAMP(event->preciseY, -1.0f, 1.0f),
#else
.hscroll = CLAMP(event->x, -1, 1),
.vscroll = CLAMP(event->y, -1, 1),
#endif
.buttons_state = .buttons_state =
sc_mouse_buttons_state_from_sdl(buttons, im->forward_all_clicks), sc_mouse_buttons_state_from_sdl(buttons, im->forward_all_clicks),
}; };

View File

@ -33,8 +33,8 @@ public final class ControlMessage {
private long pointerId; private long pointerId;
private float pressure; private float pressure;
private Position position; private Position position;
private int hScroll; private float hScroll;
private int vScroll; private float vScroll;
private int copyKey; private int copyKey;
private boolean paste; private boolean paste;
private int repeat; private int repeat;
@ -71,7 +71,7 @@ public final class ControlMessage {
return msg; return msg;
} }
public static ControlMessage createInjectScrollEvent(Position position, int hScroll, int vScroll, int buttons) { public static ControlMessage createInjectScrollEvent(Position position, float hScroll, float vScroll, int buttons) {
ControlMessage msg = new ControlMessage(); ControlMessage msg = new ControlMessage();
msg.type = TYPE_INJECT_SCROLL_EVENT; msg.type = TYPE_INJECT_SCROLL_EVENT;
msg.position = position; msg.position = position;
@ -156,11 +156,11 @@ public final class ControlMessage {
return position; return position;
} }
public int getHScroll() { public float getHScroll() {
return hScroll; return hScroll;
} }
public int getVScroll() { public float getVScroll() {
return vScroll; return vScroll;
} }

View File

@ -10,7 +10,7 @@ public class ControlMessageReader {
static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13; static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13;
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27; static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 24; static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
static final int BACK_OR_SCREEN_ON_LENGTH = 1; static final int BACK_OR_SCREEN_ON_LENGTH = 1;
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1; static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
static final int GET_CLIPBOARD_LENGTH = 1; static final int GET_CLIPBOARD_LENGTH = 1;
@ -139,10 +139,7 @@ public class ControlMessageReader {
int action = toUnsigned(buffer.get()); int action = toUnsigned(buffer.get());
long pointerId = buffer.getLong(); long pointerId = buffer.getLong();
Position position = readPosition(buffer); Position position = readPosition(buffer);
// 16 bits fixed-point float pressure = fixedPointToFloat(buffer.getShort());
int pressureInt = toUnsigned(buffer.getShort());
// convert it to a float between 0 and 1 (0x1p16f is 2^16 as float)
float pressure = pressureInt == 0xffff ? 1f : (pressureInt / 0x1p16f);
int buttons = buffer.getInt(); int buttons = buffer.getInt();
return ControlMessage.createInjectTouchEvent(action, pointerId, position, pressure, buttons); return ControlMessage.createInjectTouchEvent(action, pointerId, position, pressure, buttons);
} }
@ -152,8 +149,9 @@ public class ControlMessageReader {
return null; return null;
} }
Position position = readPosition(buffer); Position position = readPosition(buffer);
int hScroll = buffer.getInt(); // map from [0; 1] to [-1; 1]
int vScroll = buffer.getInt(); float hScroll = fixedPointToFloat(buffer.getShort());
float vScroll = fixedPointToFloat(buffer.getShort());
int buttons = buffer.getInt(); int buttons = buffer.getInt();
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons); return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons);
} }
@ -210,4 +208,10 @@ public class ControlMessageReader {
private static int toUnsigned(byte value) { private static int toUnsigned(byte value) {
return value & 0xff; return value & 0xff;
} }
private static float fixedPointToFloat(short value) {
int unsignedShort = toUnsigned(value);
// convert 16 bits fixed-point to a float between 0 and 1 (0x1p16f is 2^16 as float)
return unsignedShort == 0xffff ? 1f : (unsignedShort / 0x1p16f);
}
} }

View File

@ -223,7 +223,7 @@ public class Controller {
return device.injectEvent(event, Device.INJECT_MODE_ASYNC); return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
} }
private boolean injectScroll(Position position, int hScroll, int vScroll, int buttons) { private boolean injectScroll(Position position, float hScroll, float vScroll, int buttons) {
long now = SystemClock.uptimeMillis(); long now = SystemClock.uptimeMillis();
Point point = device.getPhysicalPoint(position); Point point = device.getPhysicalPoint(position);
if (point == null) { if (point == null) {

View File

@ -126,8 +126,8 @@ public class ControlMessageReaderTest {
dos.writeInt(1026); dos.writeInt(1026);
dos.writeShort(1080); dos.writeShort(1080);
dos.writeShort(1920); dos.writeShort(1920);
dos.writeInt(1); dos.writeShort(0x8000);
dos.writeInt(-1); dos.writeShort(0);
dos.writeInt(1); dos.writeInt(1);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
@ -143,8 +143,8 @@ public class ControlMessageReaderTest {
Assert.assertEquals(1026, event.getPosition().getPoint().getY()); Assert.assertEquals(1026, event.getPosition().getPoint().getY());
Assert.assertEquals(1080, event.getPosition().getScreenSize().getWidth()); Assert.assertEquals(1080, event.getPosition().getScreenSize().getWidth());
Assert.assertEquals(1920, event.getPosition().getScreenSize().getHeight()); Assert.assertEquals(1920, event.getPosition().getScreenSize().getHeight());
Assert.assertEquals(1, event.getHScroll()); Assert.assertEquals(0f, event.getHScroll(), 0f);
Assert.assertEquals(-1, event.getVScroll()); Assert.assertEquals(-1f, event.getVScroll(), 0f);
Assert.assertEquals(1, event.getButtons()); Assert.assertEquals(1, event.getButtons());
} }