Compare commits

..

2 Commits

Author SHA1 Message Date
Romain Vimont
652e210bfb cross-compile 2022-05-23 21:07:30 +02:00
Romain Vimont
a1117c58ac [WIP] build deps 2022-05-23 21:06:52 +02:00
30 changed files with 364 additions and 325 deletions

2
app/deps/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/data
/target-*

64
app/deps/src/build-ffmpeg.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env bash
. init_deps
VERSION=5.0.1
FILENAME=ffmpeg-$VERSION.tar.xz
URL=http://ffmpeg.org/releases/ffmpeg-$VERSION.tar.xz
SHA256SUM=ef2efae259ce80a240de48ec85ecb062cecca26e4352ffb3fda562c21a93007b
DEP_DIR="$DATA_DIR/ffmpeg-$VERSION-$SHA256SUM"
if [[ ! -d "$DEP_DIR" ]]
then
get_file "$URL" "$FILENAME" "$SHA256SUM"
mkdir "$DEP_DIR"
cd "$DEP_DIR"
tar xvf "../$FILENAME"
else
echo "$DEP_DIR found"
cd "$DEP_DIR"
fi
cd "ffmpeg-$VERSION"
rm -rf "build-$HOST"
mkdir "build-$HOST"
cd "build-$HOST"
params=(
--prefix="$INSTALL_DIR"
--arch="$ARCH"
--disable-autodetect
--disable-programs
--disable-everything
--disable-doc
--disable-swresample
--disable-swscale
--disable-avfilter
--disable-postproc
--disable-static
--enable-shared
--enable-decoder=h264
--enable-decoder=png
--enable-muxer=mp4
--enable-muxer=matroska
)
case "$HOST_SYSTEM" in
linux)
params+=(--enable-libv4l2)
;;
windows)
params+=(--target-os=mingw32)
params+=(--cross-prefix="$HOST-")
;;
*)
fail "Unsupported platform: $HOST"
;;
esac
../configure "${params[@]}"
make -j $NJOBS
make install

56
app/deps/src/init_deps Normal file
View File

@@ -0,0 +1,56 @@
set -e
# The caller must set the following environment variable
# - $HOST (e.g. "x86_64-linux-gnu")
# - $HOST_SYSTEM ("linux", "windows", "apple"), for scripts convenience
fail() {
echo "$1" >&2
exit 1
}
[[ -z "$HOST" ]] && fail '$HOST not defined'
if [[ "$HOST" == *linux* ]]
then
HOST_SYSTEM='linux'
elif [[ "$HOST" == *mingw* ]]
then
HOST_SYSTEM='windows'
else
fail "Host system could not be deduced from '$HOST'"
fi
ARCH="${HOST%%-*}"
[[ -z "$ARCH" ]] && fail "Arch could not be deduced from '$HOST'"
DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DIR"
DATA_DIR=$(realpath ../data)
INSTALL_DIR=$(realpath ../target-"$HOST")
NJOBS=$(grep -c ^processor /proc/cpuinfo)
mkdir -p "$DATA_DIR"
cd "$DATA_DIR"
checksum() {
local file="$1"
local sum="$2"
echo "$file: verifying checksum..."
echo "$sum $file" | sha256sum -c
}
get_file() {
local url="$1"
local file="$2"
local sum="$3"
if [[ -f "$file" ]]
then
echo "$file: found"
else
echo "$file: not found, downloading..."
wget "$url" -O "$file"
fi
checksum "$file" "$sum"
}

View File

@@ -245,8 +245,8 @@ if get_option('buildtype') == 'debug'
'src/util/str.c', 'src/util/str.c',
'src/util/strbuf.c', 'src/util/strbuf.c',
]], ]],
['test_binary', [ ['test_buffer_util', [
'tests/test_binary.c', 'tests/test_buffer_util.c',
]], ]],
['test_cbuf', [ ['test_cbuf', [
'tests/test_cbuf.c', 'tests/test_cbuf.c',

View File

@@ -401,7 +401,6 @@ sc_adb_list_devices(struct sc_intr *intr, unsigned flags,
#define BUFSIZE 65536 #define BUFSIZE 65536
char *buf = malloc(BUFSIZE); char *buf = malloc(BUFSIZE);
if (!buf) { if (!buf) {
LOG_OOM();
return false; return false;
} }
@@ -711,5 +710,5 @@ sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
// It is parsed as a NUL-terminated string // It is parsed as a NUL-terminated string
buf[r] = '\0'; buf[r] = '\0';
return sc_adb_parse_device_ip(buf); return sc_adb_parse_device_ip_from_output(buf);
} }

View File

@@ -199,7 +199,7 @@ sc_adb_parse_device_ip_from_line(char *line) {
} }
char * char *
sc_adb_parse_device_ip(char *str) { sc_adb_parse_device_ip_from_output(char *str) {
size_t idx_line = 0; size_t idx_line = 0;
while (str[idx_line] != '\0') { while (str[idx_line] != '\0') {
char *line = &str[idx_line]; char *line = &str[idx_line];

View File

@@ -25,6 +25,6 @@ sc_adb_parse_devices(char *str, struct sc_vec_adb_devices *out_vec);
* Warning: this function modifies the buffer for optimization purposes. * Warning: this function modifies the buffer for optimization purposes.
*/ */
char * char *
sc_adb_parse_device_ip(char *str); sc_adb_parse_device_ip_from_output(char *str);
#endif #endif

View File

@@ -98,7 +98,7 @@ sc_clock_update(struct sc_clock *clock, sc_tick system, sc_tick stream) {
sc_clock_estimate(clock, &clock->slope, &clock->offset); sc_clock_estimate(clock, &clock->slope, &clock->offset);
#ifndef SC_CLOCK_NDEBUG #ifndef SC_CLOCK_NDEBUG
LOGD("Clock estimation: %f * pts + %" PRItick, LOGD("Clock estimation: %g * pts + %" PRItick,
clock->slope, clock->offset); clock->slope, clock->offset);
#endif #endif
} }

View File

@@ -5,7 +5,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "util/binary.h" #include "util/buffer_util.h"
#include "util/log.h" #include "util/log.h"
#include "util/str.h" #include "util/str.h"
@@ -78,6 +78,16 @@ write_string(const char *utf8, size_t max_len, unsigned char *buf) {
return 4 + len; return 4 + len;
} }
static uint16_t
to_fixed_point_16(float f) {
assert(f >= 0.0f && f <= 1.0f);
uint32_t u = f * 0x1p16f; // 2^16
if (u >= 0xffff) {
u = 0xffff;
}
return (uint16_t) u;
}
size_t size_t
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) { sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
buf[0] = msg->type; buf[0] = msg->type;
@@ -99,20 +109,18 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
sc_write64be(&buf[2], msg->inject_touch_event.pointer_id); sc_write64be(&buf[2], msg->inject_touch_event.pointer_id);
write_position(&buf[10], &msg->inject_touch_event.position); write_position(&buf[10], &msg->inject_touch_event.position);
uint16_t pressure = uint16_t pressure =
sc_float_to_u16fp(msg->inject_touch_event.pressure); to_fixed_point_16(msg->inject_touch_event.pressure);
sc_write16be(&buf[22], pressure); sc_write16be(&buf[22], pressure);
sc_write32be(&buf[24], msg->inject_touch_event.buttons); sc_write32be(&buf[24], msg->inject_touch_event.buttons);
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);
int16_t hscroll = sc_write32be(&buf[13],
sc_float_to_i16fp(msg->inject_scroll_event.hscroll); (uint32_t) msg->inject_scroll_event.hscroll);
int16_t vscroll = sc_write32be(&buf[17],
sc_float_to_i16fp(msg->inject_scroll_event.vscroll); (uint32_t) msg->inject_scroll_event.vscroll);
sc_write16be(&buf[13], (uint16_t) hscroll); sc_write32be(&buf[21], msg->inject_scroll_event.buttons);
sc_write16be(&buf[15], (uint16_t) vscroll); return 25;
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;
@@ -162,7 +170,7 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
if (id == POINTER_ID_MOUSE || id == POINTER_ID_VIRTUAL_FINGER) { if (id == POINTER_ID_MOUSE || id == POINTER_ID_VIRTUAL_FINGER) {
// string pointer id // string pointer id
LOG_CMSG("touch [id=%s] %-4s position=%" PRIi32 ",%" PRIi32 LOG_CMSG("touch [id=%s] %-4s position=%" PRIi32 ",%" PRIi32
" pressure=%f buttons=%06lx", " pressure=%g buttons=%06lx",
id == POINTER_ID_MOUSE ? "mouse" : "vfinger", id == POINTER_ID_MOUSE ? "mouse" : "vfinger",
MOTIONEVENT_ACTION_LABEL(action), MOTIONEVENT_ACTION_LABEL(action),
msg->inject_touch_event.position.point.x, msg->inject_touch_event.position.point.x,
@@ -172,7 +180,7 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
} else { } else {
// numeric pointer id // numeric pointer id
LOG_CMSG("touch [id=%" PRIu64_ "] %-4s position=%" PRIi32 ",%" LOG_CMSG("touch [id=%" PRIu64_ "] %-4s position=%" PRIi32 ",%"
PRIi32 " pressure=%f buttons=%06lx", PRIi32 " pressure=%g buttons=%06lx",
id, id,
MOTIONEVENT_ACTION_LABEL(action), MOTIONEVENT_ACTION_LABEL(action),
msg->inject_touch_event.position.point.x, msg->inject_touch_event.position.point.x,
@@ -183,8 +191,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=%f" LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%" PRIi32
" vscroll=%f buttons=%06lx", " vscroll=%" PRIi32 " 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;
float hscroll; int32_t hscroll;
float vscroll; int32_t vscroll;
enum android_motionevent_buttons buttons; enum android_motionevent_buttons buttons;
} inject_scroll_event; } inject_scroll_event;
struct { struct {

View File

@@ -7,7 +7,7 @@
#include "decoder.h" #include "decoder.h"
#include "events.h" #include "events.h"
#include "recorder.h" #include "recorder.h"
#include "util/binary.h" #include "util/buffer_util.h"
#include "util/log.h" #include "util/log.h"
#define SC_PACKET_HEADER_SIZE 12 #define SC_PACKET_HEADER_SIZE 12
@@ -37,8 +37,8 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) {
// CK...... ........ ........ ........ ........ ........ ........ ........ // CK...... ........ ........ ........ ........ ........ ........ ........
// ^^<-------------------------------------------------------------------> // ^^<------------------------------------------------------------------->
// || PTS // || PTS
// | `- key frame // | `- config packet
// `-- config packet // `-- key frame
uint8_t header[SC_PACKET_HEADER_SIZE]; uint8_t header[SC_PACKET_HEADER_SIZE];
ssize_t r = net_recv_all(demuxer->socket, header, SC_PACKET_HEADER_SIZE); ssize_t r = net_recv_all(demuxer->socket, header, SC_PACKET_HEADER_SIZE);

View File

@@ -4,7 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "util/binary.h" #include "util/buffer_util.h"
#include "util/log.h" #include "util/log.h"
ssize_t ssize_t

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;
float hscroll; int32_t hscroll;
float vscroll; int32_t 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,13 +747,8 @@ 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),
}, },
#if SDL_VERSION_ATLEAST(2, 0, 18) .hscroll = event->x,
.hscroll = CLAMP(event->preciseX, -1.0f, 1.0f), .vscroll = event->y,
.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),
}; };

51
app/src/stream.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef STREAM_H
#define STREAM_H
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include "trait/packet_sink.h"
#include "util/net.h"
#include "util/thread.h"
#define STREAM_MAX_SINKS 2
struct stream {
sc_socket socket;
sc_thread thread;
struct sc_packet_sink *sinks[STREAM_MAX_SINKS];
unsigned sink_count;
AVCodecContext *codec_ctx;
AVCodecParserContext *parser;
// successive packets may need to be concatenated, until a non-config
// packet is available
AVPacket *pending;
const struct stream_callbacks *cbs;
void *cbs_userdata;
};
struct stream_callbacks {
void (*on_eos)(struct stream *stream, void *userdata);
};
void
stream_init(struct stream *stream, sc_socket socket,
const struct stream_callbacks *cbs, void *cbs_userdata);
void
stream_add_sink(struct stream *stream, struct sc_packet_sink *sink);
bool
stream_start(struct stream *stream);
void
stream_join(struct stream *stream);
#endif

View File

@@ -23,11 +23,6 @@ read_string(libusb_device_handle *handle, uint8_t desc_index) {
// When non-negative, 'result' contains the number of bytes written // When non-negative, 'result' contains the number of bytes written
char *s = malloc(result + 1); char *s = malloc(result + 1);
if (!s) {
LOG_OOM();
return NULL;
}
memcpy(s, buffer, result); memcpy(s, buffer, result);
s[result] = '\0'; s[result] = '\0';
return s; return s;

View File

@@ -1,9 +1,8 @@
#ifndef SC_BINARY_H #ifndef SC_BUFFER_UTIL_H
#define SC_BINARY_H #define SC_BUFFER_UTIL_H
#include "common.h" #include "common.h"
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -44,33 +43,4 @@ sc_read64be(const uint8_t *buf) {
return ((uint64_t) msb << 32) | lsb; return ((uint64_t) msb << 32) | lsb;
} }
/**
* Convert a float between 0 and 1 to an unsigned 16-bit fixed-point value
*/
static inline uint16_t
sc_float_to_u16fp(float f) {
assert(f >= 0.0f && f <= 1.0f);
uint32_t u = f * 0x1p16f; // 2^16
if (u >= 0xffff) {
assert(u == 0x10000); // for f == 1.0f
u = 0xffff;
}
return (uint16_t) u;
}
/**
* Convert a float between -1 and 1 to a signed 16-bit fixed-point value
*/
static inline int16_t
sc_float_to_i16fp(float f) {
assert(f >= -1.0f && f <= 1.0f);
int32_t i = f * 0x1p15f; // 2^15
assert(i >= -0x8000);
if (i >= 0x7fff) {
assert(i == 0x8000); // for f == 1.0f
i = 0x7fff;
}
return (int16_t) i;
}
#endif #endif

View File

@@ -3,10 +3,11 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <SDL2/SDL_platform.h>
#include "log.h" #include "log.h"
#ifdef _WIN32 #ifdef __WINDOWS__
# include <ws2tcpip.h> # include <ws2tcpip.h>
typedef int socklen_t; typedef int socklen_t;
typedef SOCKET sc_raw_socket; typedef SOCKET sc_raw_socket;
@@ -28,7 +29,7 @@
bool bool
net_init(void) { net_init(void) {
#ifdef _WIN32 #ifdef __WINDOWS__
WSADATA wsa; WSADATA wsa;
int res = WSAStartup(MAKEWORD(2, 2), &wsa) < 0; int res = WSAStartup(MAKEWORD(2, 2), &wsa) < 0;
if (res < 0) { if (res < 0) {
@@ -41,14 +42,14 @@ net_init(void) {
void void
net_cleanup(void) { net_cleanup(void) {
#ifdef _WIN32 #ifdef __WINDOWS__
WSACleanup(); WSACleanup();
#endif #endif
} }
static inline sc_socket static inline sc_socket
wrap(sc_raw_socket sock) { wrap(sc_raw_socket sock) {
#ifdef _WIN32 #ifdef __WINDOWS__
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
return SC_SOCKET_NONE; return SC_SOCKET_NONE;
} }
@@ -71,7 +72,7 @@ wrap(sc_raw_socket sock) {
static inline sc_raw_socket static inline sc_raw_socket
unwrap(sc_socket socket) { unwrap(sc_socket socket) {
#ifdef _WIN32 #ifdef __WINDOWS__
if (socket == SC_SOCKET_NONE) { if (socket == SC_SOCKET_NONE) {
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@@ -247,7 +248,7 @@ net_interrupt(sc_socket socket) {
sc_raw_socket raw_sock = unwrap(socket); sc_raw_socket raw_sock = unwrap(socket);
#ifdef _WIN32 #ifdef __WINDOWS__
if (!atomic_flag_test_and_set(&socket->closed)) { if (!atomic_flag_test_and_set(&socket->closed)) {
return !closesocket(raw_sock); return !closesocket(raw_sock);
} }
@@ -261,7 +262,7 @@ bool
net_close(sc_socket socket) { net_close(sc_socket socket) {
sc_raw_socket raw_sock = unwrap(socket); sc_raw_socket raw_sock = unwrap(socket);
#ifdef _WIN32 #ifdef __WINDOWS__
bool ret = true; bool ret = true;
if (!atomic_flag_test_and_set(&socket->closed)) { if (!atomic_flag_test_and_set(&socket->closed)) {
ret = !closesocket(raw_sock); ret = !closesocket(raw_sock);

View File

@@ -5,8 +5,9 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <SDL2/SDL_platform.h>
#ifdef _WIN32 #ifdef __WINDOWS__
# include <winsock2.h> # include <winsock2.h>
# include <stdatomic.h> # include <stdatomic.h>
@@ -16,7 +17,7 @@
atomic_flag closed; atomic_flag closed;
} *sc_socket; } *sc_socket;
#else // not _WIN32 #else // not __WINDOWS__
# include <sys/socket.h> # include <sys/socket.h>
# define SC_SOCKET_NONE -1 # define SC_SOCKET_NONE -1

View File

@@ -5,7 +5,7 @@
#include "adb/adb_device.h" #include "adb/adb_device.h"
#include "adb/adb_parser.h" #include "adb/adb_parser.h"
static void test_adb_devices(void) { static void test_adb_devices() {
char output[] = char output[] =
"List of devices attached\n" "List of devices attached\n"
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel " "0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
@@ -31,7 +31,7 @@ static void test_adb_devices(void) {
sc_adb_devices_destroy(&vec); sc_adb_devices_destroy(&vec);
} }
static void test_adb_devices_cr(void) { static void test_adb_devices_cr() {
char output[] = char output[] =
"List of devices attached\r\n" "List of devices attached\r\n"
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel " "0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
@@ -57,7 +57,7 @@ static void test_adb_devices_cr(void) {
sc_adb_devices_destroy(&vec); sc_adb_devices_destroy(&vec);
} }
static void test_adb_devices_daemon_start(void) { static void test_adb_devices_daemon_start() {
char output[] = char output[] =
"* daemon not running; starting now at tcp:5037\n" "* daemon not running; starting now at tcp:5037\n"
"* daemon started successfully\n" "* daemon started successfully\n"
@@ -78,7 +78,7 @@ static void test_adb_devices_daemon_start(void) {
sc_adb_devices_destroy(&vec); sc_adb_devices_destroy(&vec);
} }
static void test_adb_devices_daemon_start_mixed(void) { static void test_adb_devices_daemon_start_mixed() {
char output[] = char output[] =
"List of devices attached\n" "List of devices attached\n"
"adb server version (41) doesn't match this client (39); killing...\n" "adb server version (41) doesn't match this client (39); killing...\n"
@@ -105,7 +105,7 @@ static void test_adb_devices_daemon_start_mixed(void) {
sc_adb_devices_destroy(&vec); sc_adb_devices_destroy(&vec);
} }
static void test_adb_devices_without_eol(void) { static void test_adb_devices_without_eol() {
char output[] = char output[] =
"List of devices attached\n" "List of devices attached\n"
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel " "0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
@@ -124,7 +124,7 @@ static void test_adb_devices_without_eol(void) {
sc_adb_devices_destroy(&vec); sc_adb_devices_destroy(&vec);
} }
static void test_adb_devices_without_header(void) { static void test_adb_devices_without_header() {
char output[] = char output[] =
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel " "0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
"device:MyDevice transport_id:1\n"; "device:MyDevice transport_id:1\n";
@@ -134,7 +134,7 @@ static void test_adb_devices_without_header(void) {
assert(!ok); assert(!ok);
} }
static void test_adb_devices_corrupted(void) { static void test_adb_devices_corrupted() {
char output[] = char output[] =
"List of devices attached\n" "List of devices attached\n"
"corrupted_garbage\n"; "corrupted_garbage\n";
@@ -145,7 +145,7 @@ static void test_adb_devices_corrupted(void) {
assert(vec.size == 0); assert(vec.size == 0);
} }
static void test_adb_devices_spaces(void) { static void test_adb_devices_spaces() {
char output[] = char output[] =
"List of devices attached\n" "List of devices attached\n"
"0123456789abcdef unauthorized usb:1-4 transport_id:3\n"; "0123456789abcdef unauthorized usb:1-4 transport_id:3\n";
@@ -163,81 +163,81 @@ static void test_adb_devices_spaces(void) {
sc_adb_devices_destroy(&vec); sc_adb_devices_destroy(&vec);
} }
static void test_get_ip_single_line(void) { static void test_get_ip_single_line() {
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src " char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
"192.168.12.34\r\r\n"; "192.168.12.34\r\r\n";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(ip); assert(ip);
assert(!strcmp(ip, "192.168.12.34")); assert(!strcmp(ip, "192.168.12.34"));
free(ip); free(ip);
} }
static void test_get_ip_single_line_without_eol(void) { static void test_get_ip_single_line_without_eol() {
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src " char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
"192.168.12.34"; "192.168.12.34";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(ip); assert(ip);
assert(!strcmp(ip, "192.168.12.34")); assert(!strcmp(ip, "192.168.12.34"));
free(ip); free(ip);
} }
static void test_get_ip_single_line_with_trailing_space(void) { static void test_get_ip_single_line_with_trailing_space() {
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src " char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
"192.168.12.34 \n"; "192.168.12.34 \n";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(ip); assert(ip);
assert(!strcmp(ip, "192.168.12.34")); assert(!strcmp(ip, "192.168.12.34"));
free(ip); free(ip);
} }
static void test_get_ip_multiline_first_ok(void) { static void test_get_ip_multiline_first_ok() {
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src " char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
"192.168.1.2\r\n" "192.168.1.2\r\n"
"10.0.0.0/24 dev rmnet proto kernel scope link src " "10.0.0.0/24 dev rmnet proto kernel scope link src "
"10.0.0.2\r\n"; "10.0.0.2\r\n";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(ip); assert(ip);
assert(!strcmp(ip, "192.168.1.2")); assert(!strcmp(ip, "192.168.1.2"));
free(ip); free(ip);
} }
static void test_get_ip_multiline_second_ok(void) { static void test_get_ip_multiline_second_ok() {
char ip_route[] = "10.0.0.0/24 dev rmnet proto kernel scope link src " char ip_route[] = "10.0.0.0/24 dev rmnet proto kernel scope link src "
"10.0.0.3\r\n" "10.0.0.3\r\n"
"192.168.1.0/24 dev wlan0 proto kernel scope link src " "192.168.1.0/24 dev wlan0 proto kernel scope link src "
"192.168.1.3\r\n"; "192.168.1.3\r\n";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(ip); assert(ip);
assert(!strcmp(ip, "192.168.1.3")); assert(!strcmp(ip, "192.168.1.3"));
free(ip); free(ip);
} }
static void test_get_ip_no_wlan(void) { static void test_get_ip_no_wlan() {
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src " char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
"192.168.12.34\r\r\n"; "192.168.12.34\r\r\n";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(!ip); assert(!ip);
} }
static void test_get_ip_no_wlan_without_eol(void) { static void test_get_ip_no_wlan_without_eol() {
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src " char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
"192.168.12.34"; "192.168.12.34";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(!ip); assert(!ip);
} }
static void test_get_ip_truncated(void) { static void test_get_ip_truncated() {
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src " char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
"\n"; "\n";
char *ip = sc_adb_parse_device_ip(ip_route); char *ip = sc_adb_parse_device_ip_from_output(ip_route);
assert(!ip); assert(!ip);
} }
@@ -262,6 +262,4 @@ int main(int argc, char *argv[]) {
test_get_ip_no_wlan(); test_get_ip_no_wlan();
test_get_ip_no_wlan_without_eol(); test_get_ip_no_wlan_without_eol();
test_get_ip_truncated(); test_get_ip_truncated();
return 0;
} }

View File

@@ -1,114 +0,0 @@
#include "common.h"
#include <assert.h>
#include "util/binary.h"
static void test_write16be(void) {
uint16_t val = 0xABCD;
uint8_t buf[2];
sc_write16be(buf, val);
assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD);
}
static void test_write32be(void) {
uint32_t val = 0xABCD1234;
uint8_t buf[4];
sc_write32be(buf, val);
assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD);
assert(buf[2] == 0x12);
assert(buf[3] == 0x34);
}
static void test_write64be(void) {
uint64_t val = 0xABCD1234567890EF;
uint8_t buf[8];
sc_write64be(buf, val);
assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD);
assert(buf[2] == 0x12);
assert(buf[3] == 0x34);
assert(buf[4] == 0x56);
assert(buf[5] == 0x78);
assert(buf[6] == 0x90);
assert(buf[7] == 0xEF);
}
static void test_read16be(void) {
uint8_t buf[2] = {0xAB, 0xCD};
uint16_t val = sc_read16be(buf);
assert(val == 0xABCD);
}
static void test_read32be(void) {
uint8_t buf[4] = {0xAB, 0xCD, 0x12, 0x34};
uint32_t val = sc_read32be(buf);
assert(val == 0xABCD1234);
}
static void test_read64be(void) {
uint8_t buf[8] = {0xAB, 0xCD, 0x12, 0x34,
0x56, 0x78, 0x90, 0xEF};
uint64_t val = sc_read64be(buf);
assert(val == 0xABCD1234567890EF);
}
static void test_float_to_u16fp(void) {
assert(sc_float_to_u16fp(0.0f) == 0);
assert(sc_float_to_u16fp(0.03125f) == 0x800);
assert(sc_float_to_u16fp(0.0625f) == 0x1000);
assert(sc_float_to_u16fp(0.125f) == 0x2000);
assert(sc_float_to_u16fp(0.25f) == 0x4000);
assert(sc_float_to_u16fp(0.5f) == 0x8000);
assert(sc_float_to_u16fp(0.75f) == 0xc000);
assert(sc_float_to_u16fp(1.0f) == 0xffff);
}
static void test_float_to_i16fp(void) {
assert(sc_float_to_i16fp(0.0f) == 0);
assert(sc_float_to_i16fp(0.03125f) == 0x400);
assert(sc_float_to_i16fp(0.0625f) == 0x800);
assert(sc_float_to_i16fp(0.125f) == 0x1000);
assert(sc_float_to_i16fp(0.25f) == 0x2000);
assert(sc_float_to_i16fp(0.5f) == 0x4000);
assert(sc_float_to_i16fp(0.75f) == 0x6000);
assert(sc_float_to_i16fp(1.0f) == 0x7fff);
assert(sc_float_to_i16fp(-0.03125f) == -0x400);
assert(sc_float_to_i16fp(-0.0625f) == -0x800);
assert(sc_float_to_i16fp(-0.125f) == -0x1000);
assert(sc_float_to_i16fp(-0.25f) == -0x2000);
assert(sc_float_to_i16fp(-0.5f) == -0x4000);
assert(sc_float_to_i16fp(-0.75f) == -0x6000);
assert(sc_float_to_i16fp(-1.0f) == -0x8000);
}
int main(int argc, char *argv[]) {
(void) argc;
(void) argv;
test_write16be();
test_write32be();
test_write64be();
test_read16be();
test_read32be();
test_read64be();
test_float_to_u16fp();
test_float_to_i16fp();
return 0;
}

View File

@@ -0,0 +1,81 @@
#include "common.h"
#include <assert.h>
#include "util/buffer_util.h"
static void test_buffer_write16be(void) {
uint16_t val = 0xABCD;
uint8_t buf[2];
sc_write16be(buf, val);
assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD);
}
static void test_buffer_write32be(void) {
uint32_t val = 0xABCD1234;
uint8_t buf[4];
sc_write32be(buf, val);
assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD);
assert(buf[2] == 0x12);
assert(buf[3] == 0x34);
}
static void test_buffer_write64be(void) {
uint64_t val = 0xABCD1234567890EF;
uint8_t buf[8];
sc_write64be(buf, val);
assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD);
assert(buf[2] == 0x12);
assert(buf[3] == 0x34);
assert(buf[4] == 0x56);
assert(buf[5] == 0x78);
assert(buf[6] == 0x90);
assert(buf[7] == 0xEF);
}
static void test_buffer_read16be(void) {
uint8_t buf[2] = {0xAB, 0xCD};
uint16_t val = sc_read16be(buf);
assert(val == 0xABCD);
}
static void test_buffer_read32be(void) {
uint8_t buf[4] = {0xAB, 0xCD, 0x12, 0x34};
uint32_t val = sc_read32be(buf);
assert(val == 0xABCD1234);
}
static void test_buffer_read64be(void) {
uint8_t buf[8] = {0xAB, 0xCD, 0x12, 0x34,
0x56, 0x78, 0x90, 0xEF};
uint64_t val = sc_read64be(buf);
assert(val == 0xABCD1234567890EF);
}
int main(int argc, char *argv[]) {
(void) argc;
(void) argv;
test_buffer_write16be();
test_buffer_write32be();
test_buffer_write64be();
test_buffer_read16be();
test_buffer_read32be();
test_buffer_read64be();
return 0;
}

View File

@@ -132,14 +132,14 @@ static void test_serialize_inject_scroll_event(void) {
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE]; unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf); size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 21); assert(size == 25);
const unsigned char expected[] = { const unsigned char expected[] = {
SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT, SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026
0x04, 0x38, 0x07, 0x80, // 1080 1920 0x04, 0x38, 0x07, 0x80, // 1080 1920
0x7F, 0xFF, // 1 (float encoded as i16) 0x00, 0x00, 0x00, 0x01, // 1
0x80, 0x00, // -1 (float encoded as i16) 0xFF, 0xFF, 0xFF, 0xFF, // -1
0x00, 0x00, 0x00, 0x01, // 1 0x00, 0x00, 0x00, 0x01, // 1
}; };
assert(!memcmp(buf, expected, sizeof(expected))); assert(!memcmp(buf, expected, sizeof(expected)));

View File

@@ -19,6 +19,7 @@ android {
} }
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.13.1' testImplementation 'junit:junit:4.13.1'
} }

View File

@@ -1,38 +0,0 @@
package com.genymobile.scrcpy;
public final class Binary {
private Binary() {
// not instantiable
}
public static int toUnsigned(short value) {
return value & 0xffff;
}
public static int toUnsigned(byte value) {
return value & 0xff;
}
/**
* Convert unsigned 16-bit fixed-point to a float between 0 and 1
*
* @param value encoded value
* @return Float value between 0 and 1
*/
public static float u16FixedPointToFloat(short value) {
int unsignedShort = Binary.toUnsigned(value);
// 0x1p16f is 2^16 as float
return unsignedShort == 0xffff ? 1f : (unsignedShort / 0x1p16f);
}
/**
* Convert signed 16-bit fixed-point to a float between -1 and 1
*
* @param value encoded value
* @return Float value between -1 and 1
*/
public static float i16FixedPointToFloat(short value) {
// 0x1p15f is 2^15 as float
return value == 0x7fff ? 1f : (value / 0x1p15f);
}
}

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 float hScroll; private int hScroll;
private float vScroll; private int 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, float hScroll, float vScroll, int buttons) { public static ControlMessage createInjectScrollEvent(Position position, int hScroll, int 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 float getHScroll() { public int getHScroll() {
return hScroll; return hScroll;
} }
public float getVScroll() { public int 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 = 20; static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 24;
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;
@@ -103,7 +103,7 @@ public class ControlMessageReader {
if (buffer.remaining() < INJECT_KEYCODE_PAYLOAD_LENGTH) { if (buffer.remaining() < INJECT_KEYCODE_PAYLOAD_LENGTH) {
return null; return null;
} }
int action = Binary.toUnsigned(buffer.get()); int action = toUnsigned(buffer.get());
int keycode = buffer.getInt(); int keycode = buffer.getInt();
int repeat = buffer.getInt(); int repeat = buffer.getInt();
int metaState = buffer.getInt(); int metaState = buffer.getInt();
@@ -136,10 +136,13 @@ public class ControlMessageReader {
if (buffer.remaining() < INJECT_TOUCH_EVENT_PAYLOAD_LENGTH) { if (buffer.remaining() < INJECT_TOUCH_EVENT_PAYLOAD_LENGTH) {
return null; return null;
} }
int action = Binary.toUnsigned(buffer.get()); int action = toUnsigned(buffer.get());
long pointerId = buffer.getLong(); long pointerId = buffer.getLong();
Position position = readPosition(buffer); Position position = readPosition(buffer);
float pressure = Binary.u16FixedPointToFloat(buffer.getShort()); // 16 bits fixed-point
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);
} }
@@ -149,8 +152,8 @@ public class ControlMessageReader {
return null; return null;
} }
Position position = readPosition(buffer); Position position = readPosition(buffer);
float hScroll = Binary.i16FixedPointToFloat(buffer.getShort()); int hScroll = buffer.getInt();
float vScroll = Binary.i16FixedPointToFloat(buffer.getShort()); int vScroll = buffer.getInt();
int buttons = buffer.getInt(); int buttons = buffer.getInt();
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons); return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons);
} }
@@ -159,7 +162,7 @@ public class ControlMessageReader {
if (buffer.remaining() < BACK_OR_SCREEN_ON_LENGTH) { if (buffer.remaining() < BACK_OR_SCREEN_ON_LENGTH) {
return null; return null;
} }
int action = Binary.toUnsigned(buffer.get()); int action = toUnsigned(buffer.get());
return ControlMessage.createBackOrScreenOn(action); return ControlMessage.createBackOrScreenOn(action);
} }
@@ -167,7 +170,7 @@ public class ControlMessageReader {
if (buffer.remaining() < GET_CLIPBOARD_LENGTH) { if (buffer.remaining() < GET_CLIPBOARD_LENGTH) {
return null; return null;
} }
int copyKey = Binary.toUnsigned(buffer.get()); int copyKey = toUnsigned(buffer.get());
return ControlMessage.createGetClipboard(copyKey); return ControlMessage.createGetClipboard(copyKey);
} }
@@ -195,8 +198,16 @@ public class ControlMessageReader {
private static Position readPosition(ByteBuffer buffer) { private static Position readPosition(ByteBuffer buffer) {
int x = buffer.getInt(); int x = buffer.getInt();
int y = buffer.getInt(); int y = buffer.getInt();
int screenWidth = Binary.toUnsigned(buffer.getShort()); int screenWidth = toUnsigned(buffer.getShort());
int screenHeight = Binary.toUnsigned(buffer.getShort()); int screenHeight = toUnsigned(buffer.getShort());
return new Position(x, y, screenWidth, screenHeight); return new Position(x, y, screenWidth, screenHeight);
} }
private static int toUnsigned(short value) {
return value & 0xffff;
}
private static int toUnsigned(byte value) {
return value & 0xff;
}
} }

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, float hScroll, float vScroll, int buttons) { private boolean injectScroll(Position position, int hScroll, int 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

@@ -1,42 +0,0 @@
package com.genymobile.scrcpy;
import org.junit.Assert;
import org.junit.Test;
public class BinaryTest {
@Test
public void testU16FixedPointToFloat() {
final float delta = 0.0f; // on these values, there MUST be no rounding error
Assert.assertEquals(0.0f, Binary.u16FixedPointToFloat((short) 0), delta);
Assert.assertEquals(0.03125f, Binary.u16FixedPointToFloat((short) 0x800), delta);
Assert.assertEquals(0.0625f, Binary.u16FixedPointToFloat((short) 0x1000), delta);
Assert.assertEquals(0.125f, Binary.u16FixedPointToFloat((short) 0x2000), delta);
Assert.assertEquals(0.25f, Binary.u16FixedPointToFloat((short) 0x4000), delta);
Assert.assertEquals(0.5f, Binary.u16FixedPointToFloat((short) 0x8000), delta);
Assert.assertEquals(0.75f, Binary.u16FixedPointToFloat((short) 0xc000), delta);
Assert.assertEquals(1.0f, Binary.u16FixedPointToFloat((short) 0xffff), delta);
}
@Test
public void testI16FixedPointToFloat() {
final float delta = 0.0f; // on these values, there MUST be no rounding error
Assert.assertEquals(0.0f, Binary.i16FixedPointToFloat((short) 0), delta);
Assert.assertEquals(0.03125f, Binary.i16FixedPointToFloat((short) 0x400), delta);
Assert.assertEquals(0.0625f, Binary.i16FixedPointToFloat((short) 0x800), delta);
Assert.assertEquals(0.125f, Binary.i16FixedPointToFloat((short) 0x1000), delta);
Assert.assertEquals(0.25f, Binary.i16FixedPointToFloat((short) 0x2000), delta);
Assert.assertEquals(0.5f, Binary.i16FixedPointToFloat((short) 0x4000), delta);
Assert.assertEquals(0.75f, Binary.i16FixedPointToFloat((short) 0x6000), delta);
Assert.assertEquals(1.0f, Binary.i16FixedPointToFloat((short) 0x7fff), delta);
Assert.assertEquals(-0.03125f, Binary.i16FixedPointToFloat((short) -0x400), delta);
Assert.assertEquals(-0.0625f, Binary.i16FixedPointToFloat((short) -0x800), delta);
Assert.assertEquals(-0.125f, Binary.i16FixedPointToFloat((short) -0x1000), delta);
Assert.assertEquals(-0.25f, Binary.i16FixedPointToFloat((short) -0x2000), delta);
Assert.assertEquals(-0.5f, Binary.i16FixedPointToFloat((short) -0x4000), delta);
Assert.assertEquals(-0.75f, Binary.i16FixedPointToFloat((short) -0x6000), delta);
Assert.assertEquals(-1.0f, Binary.i16FixedPointToFloat((short) -0x8000), delta);
}
}

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.writeShort(0); // 0.0f encoded as i16 dos.writeInt(1);
dos.writeShort(0x8000); // -1.0f encoded as i16 dos.writeInt(-1);
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(0f, event.getHScroll(), 0f); Assert.assertEquals(1, event.getHScroll());
Assert.assertEquals(-1f, event.getVScroll(), 0f); Assert.assertEquals(-1, event.getVScroll());
Assert.assertEquals(1, event.getButtons()); Assert.assertEquals(1, event.getButtons());
} }