mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-02-20 11:58:55 +00:00
revent: Added record and replay commands
Added two commands to WA to record and replay input events using revent. As part of this also added the ability to get a device model from android and linux device. This may need to be improved in the future.
This commit is contained in:
parent
6a388ffc71
commit
1e6eaff702
@ -17,6 +17,11 @@ to Android UI Automator for providing automation for workloads. ::
|
||||
info:shows info about each event char device
|
||||
any additional parameters make it verbose
|
||||
|
||||
|
||||
.. note:: There are now also WA commands that perform the below steps.
|
||||
Please see ``wa show record/replay`` and ``wa record/replay --help``
|
||||
for details.
|
||||
|
||||
Recording
|
||||
---------
|
||||
|
||||
|
165
wlauto/commands/record.py
Normal file
165
wlauto/commands/record.py
Normal file
@ -0,0 +1,165 @@
|
||||
# Copyright 2014-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from wlauto import ExtensionLoader, Command, settings
|
||||
from wlauto.common.resources import Executable
|
||||
from wlauto.core.resource import NO_ONE
|
||||
from wlauto.core.resolver import ResourceResolver
|
||||
from wlauto.core.configuration import RunConfiguration
|
||||
from wlauto.core.agenda import Agenda
|
||||
|
||||
|
||||
class RecordCommand(Command):
|
||||
|
||||
name = 'record'
|
||||
description = '''Performs a revent recording
|
||||
|
||||
This command helps making revent recordings. It will automatically
|
||||
deploy revent and even has the option of automatically opening apps.
|
||||
|
||||
Revent allows you to record raw inputs such as screen swipes or button presses.
|
||||
This can be useful for recording inputs for workloads such as games that don't
|
||||
have XML UI layouts that can be used with UIAutomator. As a drawback from this,
|
||||
revent recordings are specific to the device type they were recorded on.
|
||||
|
||||
WA uses two parts to the names of revent recordings in the format,
|
||||
{device_name}.{suffix}.revent.
|
||||
|
||||
- device_name can either be specified manually with the ``-d`` argument or
|
||||
it can be automatically determined. On Android device it will be obtained
|
||||
from ``build.prop``, on Linux devices it is obtained from ``/proc/device-tree/model``.
|
||||
- suffix is used by WA to determine which part of the app execution the
|
||||
recording is for, currently these are either ``setup`` or ``run``. This
|
||||
should be specified with the ``-s`` argument.
|
||||
'''
|
||||
|
||||
def initialize(self, context):
|
||||
self.context = context
|
||||
self.parser.add_argument('-d', '--device', help='The name of the device')
|
||||
self.parser.add_argument('-s', '--suffix', help='The suffix of the revent file, e.g. ``setup``')
|
||||
self.parser.add_argument('-o', '--output', help='Directory to save the recording in')
|
||||
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
|
||||
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
|
||||
action="store_true")
|
||||
|
||||
# Validate command options
|
||||
def validate_args(self, args):
|
||||
if args.clear and not args.package:
|
||||
print "Package must be specified if you want to clear cache\n"
|
||||
self.parser.print_help()
|
||||
sys.exit()
|
||||
|
||||
# pylint: disable=W0201
|
||||
def execute(self, args):
|
||||
self.validate_args(args)
|
||||
self.logger.info("Connecting to device...")
|
||||
|
||||
ext_loader = ExtensionLoader(packages=settings.extension_packages,
|
||||
paths=settings.extension_paths)
|
||||
|
||||
# Setup config
|
||||
self.config = RunConfiguration(ext_loader)
|
||||
for filepath in settings.get_config_paths():
|
||||
self.config.load_config(filepath)
|
||||
self.config.set_agenda(Agenda())
|
||||
self.config.finalize()
|
||||
|
||||
context = LightContext(self.config)
|
||||
|
||||
# Setup device
|
||||
self.device = ext_loader.get_device(settings.device, **settings.device_config)
|
||||
self.device.validate()
|
||||
self.device.dynamic_modules = []
|
||||
self.device.connect()
|
||||
self.device.initialize(context)
|
||||
|
||||
host_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
|
||||
self.target_binary = self.device.install_if_needed(host_binary)
|
||||
|
||||
self.run(args)
|
||||
|
||||
def run(self, args):
|
||||
if args.device:
|
||||
self.device_name = args.device
|
||||
else:
|
||||
self.device_name = self.device.get_device_model()
|
||||
|
||||
if args.suffix:
|
||||
args.suffix += "."
|
||||
|
||||
revent_file = self.device.path.join(self.device.working_directory,
|
||||
'{}.{}revent'.format(self.device_name, args.suffix or ""))
|
||||
|
||||
if args.clear:
|
||||
self.device.execute("pm clear {}".format(args.package))
|
||||
|
||||
if args.package:
|
||||
self.logger.info("Starting {}".format(args.package))
|
||||
self.device.execute('monkey -p {} -c android.intent.category.LAUNCHER 1'.format(args.package))
|
||||
|
||||
self.logger.info("Press Enter when you are ready to record...")
|
||||
raw_input("")
|
||||
command = "{} record -t 100000 -s {}".format(self.target_binary, revent_file)
|
||||
self.device.kick_off(command)
|
||||
|
||||
self.logger.info("Press Enter when you have finished recording...")
|
||||
raw_input("")
|
||||
self.device.killall("revent")
|
||||
|
||||
self.logger.info("Pulling files from device")
|
||||
self.device.pull_file(revent_file, args.output or os.getcwdu())
|
||||
|
||||
|
||||
class ReplayCommand(RecordCommand):
|
||||
|
||||
name = 'replay'
|
||||
description = '''Replay a revent recording
|
||||
|
||||
Revent allows you to record raw inputs such as screen swipes or button presses.
|
||||
See ``wa show record`` to see how to make an revent recording.
|
||||
'''
|
||||
|
||||
def initialize(self, context):
|
||||
self.context = context
|
||||
self.parser.add_argument('revent', help='The name of the file to replay')
|
||||
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
|
||||
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
|
||||
action="store_true")
|
||||
|
||||
# pylint: disable=W0201
|
||||
def run(self, args):
|
||||
self.logger.info("Pushing file to device")
|
||||
self.device.push_file(args.revent, self.device.working_directory)
|
||||
revent_file = self.device.path.join(self.device.working_directory, os.path.split(args.revent)[1])
|
||||
|
||||
if args.clear:
|
||||
self.device.execute("pm clear {}".format(args.package))
|
||||
|
||||
if args.package:
|
||||
self.logger.info("Starting {}".format(args.package))
|
||||
self.device.execute('monkey -p {} -c android.intent.category.LAUNCHER 1'.format(args.package))
|
||||
|
||||
command = "{} replay {}".format(self.target_binary, revent_file)
|
||||
self.device.execute(command)
|
||||
self.logger.info("Finished replay")
|
||||
|
||||
# Used to satisfy the API
|
||||
class LightContext(object):
|
||||
def __init__(self, config):
|
||||
self.resolver = ResourceResolver(config)
|
||||
self.resolver.load()
|
@ -645,6 +645,12 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
|
||||
if se_status == 'Enforcing':
|
||||
self.execute('setenforce 0', as_root=True)
|
||||
|
||||
def get_device_model(self):
|
||||
try:
|
||||
return self.getprop(prop='ro.product.device')
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
# Internal methods: do not use outside of the class.
|
||||
|
||||
def _update_build_properties(self, filepath, props):
|
||||
|
@ -302,7 +302,7 @@ class ReventWorkload(Workload):
|
||||
if _call_super:
|
||||
super(ReventWorkload, self).__init__(device, **kwargs)
|
||||
devpath = self.device.path
|
||||
self.on_device_revent_binary = devpath.join(self.device.working_directory, 'revent')
|
||||
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
|
||||
self.on_device_setup_revent = devpath.join(self.device.working_directory, '{}.setup.revent'.format(self.device.name))
|
||||
self.on_device_run_revent = devpath.join(self.device.working_directory, '{}.run.revent'.format(self.device.name))
|
||||
self.setup_timeout = kwargs.get('setup_timeout', self.default_setup_timeout)
|
||||
|
Binary file not shown.
Binary file not shown.
@ -536,6 +536,14 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
|
||||
command = 'cd {} && {}'.format(in_directory, command)
|
||||
return self.execute(command, background=background, as_root=as_root, timeout=timeout)
|
||||
|
||||
def get_device_model(self):
|
||||
if self.file_exists("/proc/device-tree/model"):
|
||||
raw_model = self.execute("cat /proc/device-tree/model")
|
||||
return '_'.join(raw_model.split()[:2])
|
||||
# Right now we don't know any other way to get device model
|
||||
# info in linux on arm platforms
|
||||
return None
|
||||
|
||||
# internal methods
|
||||
|
||||
def _check_ready(self):
|
||||
|
259
wlauto/external/revent/revent.c
vendored
259
wlauto/external/revent/revent.c
vendored
@ -23,6 +23,8 @@
|
||||
#include <limits.h>
|
||||
#include <linux/input.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
@ -91,14 +93,14 @@ typedef struct {
|
||||
|
||||
|
||||
bool_t verbose = FALSE;
|
||||
|
||||
bool_t wait_for_stdin = TRUE;
|
||||
|
||||
bool_t is_numeric(char *string)
|
||||
{
|
||||
int len = strlen(string);
|
||||
|
||||
int i = 0;
|
||||
while(i < len)
|
||||
while(i < len)
|
||||
{
|
||||
if(!isdigit(string[i]))
|
||||
return FALSE;
|
||||
@ -115,7 +117,7 @@ off_t get_file_size(const char *filename) {
|
||||
return st.st_size;
|
||||
|
||||
die("Cannot determine size of %s: %s\n", filename, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int inpdev_init(inpdev_t **inpdev, int devid)
|
||||
{
|
||||
@ -242,15 +244,15 @@ int replay_buffer_init(replay_buffer_t **buffer, const char *logfile)
|
||||
die("out of memory\n");
|
||||
|
||||
int fdin = open(logfile, O_RDONLY);
|
||||
if (fdin < 0)
|
||||
if (fdin < 0)
|
||||
die("Could not open eventlog %s\n", logfile);
|
||||
|
||||
size_t rb = read(fdin, &(buff->num_fds), sizeof(buff->num_fds));
|
||||
if (rb!=sizeof(buff->num_fds))
|
||||
if (rb!=sizeof(buff->num_fds))
|
||||
die("problems reading eventlog\n");
|
||||
|
||||
buff->fds = malloc(sizeof(int) * buff->num_fds);
|
||||
if (!buff->fds)
|
||||
if (!buff->fds)
|
||||
die("out of memory\n");
|
||||
|
||||
int32_t len, i;
|
||||
@ -258,10 +260,10 @@ int replay_buffer_init(replay_buffer_t **buffer, const char *logfile)
|
||||
for (i = 0; i < buff->num_fds; i++) {
|
||||
memset(path_buff, 0, sizeof(path_buff));
|
||||
rb = read(fdin, &len, sizeof(len));
|
||||
if (rb!=sizeof(len))
|
||||
if (rb!=sizeof(len))
|
||||
die("problems reading eventlog\n");
|
||||
rb = read(fdin, &path_buff[0], len);
|
||||
if (rb != len)
|
||||
if (rb != len)
|
||||
die("problems reading eventlog\n");
|
||||
|
||||
buff->fds[i] = open(path_buff, O_WRONLY | O_NDELAY);
|
||||
@ -274,7 +276,7 @@ int replay_buffer_init(replay_buffer_t **buffer, const char *logfile)
|
||||
i = 0;
|
||||
while(1) {
|
||||
rb = read(fdin, &rep_ev, sizeof(rep_ev));
|
||||
if (rb < (int)sizeof(rep_ev))
|
||||
if (rb < (int)sizeof(rep_ev))
|
||||
break;
|
||||
|
||||
if (i == 0) {
|
||||
@ -321,7 +323,7 @@ int replay_buffer_play(replay_buffer_t *buff)
|
||||
struct input_event ev = (buff->events[i]).event;
|
||||
while((i < buff->num_events) && !timercmp(&ev.time, &last_event_delta, !=)) {
|
||||
rb = write(buff->fds[idx], &ev, sizeof(ev));
|
||||
if (rb!=sizeof(ev))
|
||||
if (rb!=sizeof(ev))
|
||||
die("problems writing\n");
|
||||
dprintf("replayed event: type %d code %d value %d\n", ev.type, ev.code, ev.value);
|
||||
|
||||
@ -347,101 +349,6 @@ void replay(const char *logfile)
|
||||
replay_buffer_close(replay_buffer);
|
||||
}
|
||||
|
||||
void record(inpdev_t *inpdev, int delay, const char *logfile)
|
||||
{
|
||||
fd_set readfds;
|
||||
FILE* fdout;
|
||||
struct input_event ev;
|
||||
int32_t i;
|
||||
int32_t _padding = 0xdeadbeef;
|
||||
int32_t maxfd = 0;
|
||||
int32_t keydev=0;
|
||||
|
||||
int* fds = malloc(sizeof(int)*inpdev->id_pathc);
|
||||
if (!fds) die("out of memory\n");
|
||||
|
||||
fdout = fopen(logfile, "wb");
|
||||
if (!fdout) die("Could not open eventlog %s\n", logfile);
|
||||
|
||||
fwrite(&inpdev->id_pathc, sizeof(inpdev->id_pathc), 1, fdout);
|
||||
for (i=0; i<inpdev->id_pathc; i++) {
|
||||
int32_t len = strlen(inpdev->id_pathv[i]);
|
||||
fwrite(&len, sizeof(len), 1, fdout);
|
||||
fwrite(inpdev->id_pathv[i], len, 1, fdout);
|
||||
}
|
||||
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
{
|
||||
fds[i] = open(inpdev->id_pathv[i], O_RDONLY);
|
||||
if (fds[i]>maxfd) maxfd = fds[i];
|
||||
dprintf("opened %s with %d\n", inpdev->id_pathv[i], fds[i]);
|
||||
if (fds[i]<0) die("could not open \%s\n", inpdev->id_pathv[i]);
|
||||
}
|
||||
|
||||
int count =0;
|
||||
struct timeval tout;
|
||||
while(1)
|
||||
{
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(STDIN_FILENO, &readfds);
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
FD_SET(fds[i], &readfds);
|
||||
/* wait for input */
|
||||
tout.tv_sec = delay;
|
||||
tout.tv_usec = 0;
|
||||
int32_t r = select(maxfd+1, &readfds, NULL, NULL, &tout);
|
||||
/* dprintf("got %d (err %d)\n", r, errno); */
|
||||
if (!r) break;
|
||||
if (FD_ISSET(STDIN_FILENO, &readfds)) {
|
||||
// in this case the key down for the return key will be recorded
|
||||
// so we need to up the key up
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = EV_KEY;
|
||||
ev.code = KEY_ENTER;
|
||||
ev.value = 0;
|
||||
gettimeofday(&ev.time, NULL);
|
||||
fwrite(&keydev, sizeof(keydev), 1, fdout);
|
||||
fwrite(&_padding, sizeof(_padding), 1, fdout);
|
||||
fwrite(&ev, sizeof(ev), 1, fdout);
|
||||
memset(&ev, 0, sizeof(ev)); // SYN
|
||||
gettimeofday(&ev.time, NULL);
|
||||
fwrite(&keydev, sizeof(keydev), 1, fdout);
|
||||
fwrite(&_padding, sizeof(_padding), 1, fdout);
|
||||
fwrite(&ev, sizeof(ev), 1, fdout);
|
||||
dprintf("added fake return exiting...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
{
|
||||
if (FD_ISSET(fds[i], &readfds))
|
||||
{
|
||||
dprintf("Got event from %s\n", inpdev->id_pathv[i]);
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
size_t rb = read(fds[i], (void*) &ev, sizeof(ev));
|
||||
dprintf("%d event: type %d code %d value %d\n",
|
||||
(unsigned int)rb, ev.type, ev.code, ev.value);
|
||||
if (ev.type == EV_KEY && ev.code == KEY_ENTER && ev.value == 1)
|
||||
keydev = i;
|
||||
fwrite(&i, sizeof(i), 1, fdout);
|
||||
fwrite(&_padding, sizeof(_padding), 1, fdout);
|
||||
fwrite(&ev, sizeof(ev), 1, fdout);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
{
|
||||
close(fds[i]);
|
||||
}
|
||||
|
||||
fclose(fdout);
|
||||
free(fds);
|
||||
dprintf("Recorded %d events\n", count);
|
||||
}
|
||||
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("usage:\n revent [-h] [-v] COMMAND [OPTIONS] \n"
|
||||
@ -490,7 +397,7 @@ void revent_args_init(revent_args_t **rargs, int argc, char** argv)
|
||||
revent_args->file = NULL;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "ht:d:v")) != -1)
|
||||
while ((opt = getopt(argc, argv, "ht:d:vs")) != -1)
|
||||
{
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
@ -516,6 +423,10 @@ void revent_args_init(revent_args_t **rargs, int argc, char** argv)
|
||||
case 'v':
|
||||
verbose = TRUE;
|
||||
break;
|
||||
case 's':
|
||||
wait_for_stdin = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Unexpected option: %c", opt);
|
||||
}
|
||||
@ -526,13 +437,13 @@ void revent_args_init(revent_args_t **rargs, int argc, char** argv)
|
||||
usage();
|
||||
die("Must specify a command.\n");
|
||||
}
|
||||
if (!strcmp(argv[next_arg], "record"))
|
||||
if (!strcmp(argv[next_arg], "record"))
|
||||
revent_args->mode = RECORD;
|
||||
else if (!strcmp(argv[next_arg], "replay"))
|
||||
else if (!strcmp(argv[next_arg], "replay"))
|
||||
revent_args->mode = REPLAY;
|
||||
else if (!strcmp(argv[next_arg], "dump"))
|
||||
else if (!strcmp(argv[next_arg], "dump"))
|
||||
revent_args->mode = DUMP;
|
||||
else if (!strcmp(argv[next_arg], "info"))
|
||||
else if (!strcmp(argv[next_arg], "info"))
|
||||
revent_args->mode = INFO;
|
||||
else {
|
||||
usage();
|
||||
@ -569,15 +480,138 @@ int revent_args_close(revent_args_t *rargs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int* fds = NULL;
|
||||
FILE* fdout = NULL;
|
||||
revent_args_t *rargs = NULL;
|
||||
inpdev_t *inpdev = NULL;
|
||||
int count;
|
||||
|
||||
void term_handler(int signum)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
{
|
||||
close(fds[i]);
|
||||
}
|
||||
|
||||
fclose(fdout);
|
||||
free(fds);
|
||||
dprintf("Recorded %d events\n", count);
|
||||
|
||||
inpdev_close(inpdev);
|
||||
revent_args_close(rargs);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void record(inpdev_t *inpdev, int delay, const char *logfile)
|
||||
{
|
||||
fd_set readfds;
|
||||
struct input_event ev;
|
||||
int32_t i;
|
||||
int32_t _padding = 0xdeadbeef;
|
||||
int32_t maxfd = 0;
|
||||
int32_t keydev=0;
|
||||
|
||||
//signal handler
|
||||
struct sigaction action;
|
||||
memset(&action, 0, sizeof(struct sigaction));
|
||||
action.sa_handler = term_handler;
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
|
||||
fds = malloc(sizeof(int)*inpdev->id_pathc);
|
||||
if (!fds) die("out of memory\n");
|
||||
|
||||
fdout = fopen(logfile, "wb");
|
||||
if (!fdout) die("Could not open eventlog %s\n", logfile);
|
||||
|
||||
fwrite(&inpdev->id_pathc, sizeof(inpdev->id_pathc), 1, fdout);
|
||||
for (i=0; i<inpdev->id_pathc; i++) {
|
||||
int32_t len = strlen(inpdev->id_pathv[i]);
|
||||
fwrite(&len, sizeof(len), 1, fdout);
|
||||
fwrite(inpdev->id_pathv[i], len, 1, fdout);
|
||||
}
|
||||
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
{
|
||||
fds[i] = open(inpdev->id_pathv[i], O_RDONLY);
|
||||
if (fds[i]>maxfd) maxfd = fds[i];
|
||||
dprintf("opened %s with %d\n", inpdev->id_pathv[i], fds[i]);
|
||||
if (fds[i]<0) die("could not open \%s\n", inpdev->id_pathv[i]);
|
||||
}
|
||||
|
||||
count = 0;
|
||||
struct timeval tout;
|
||||
while(1)
|
||||
{
|
||||
FD_ZERO(&readfds);
|
||||
if (wait_for_stdin)
|
||||
{
|
||||
FD_SET(STDIN_FILENO, &readfds);
|
||||
}
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
FD_SET(fds[i], &readfds);
|
||||
/* wait for input */
|
||||
tout.tv_sec = delay;
|
||||
tout.tv_usec = 0;
|
||||
int32_t r = select(maxfd+1, &readfds, NULL, NULL, &tout);
|
||||
/* dprintf("got %d (err %d)\n", r, errno); */
|
||||
if (!r) break;
|
||||
if (wait_for_stdin && FD_ISSET(STDIN_FILENO, &readfds)) {
|
||||
// in this case the key down for the return key will be recorded
|
||||
// so we need to up the key up
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = EV_KEY;
|
||||
ev.code = KEY_ENTER;
|
||||
ev.value = 0;
|
||||
gettimeofday(&ev.time, NULL);
|
||||
fwrite(&keydev, sizeof(keydev), 1, fdout);
|
||||
fwrite(&_padding, sizeof(_padding), 1, fdout);
|
||||
fwrite(&ev, sizeof(ev), 1, fdout);
|
||||
memset(&ev, 0, sizeof(ev)); // SYN
|
||||
gettimeofday(&ev.time, NULL);
|
||||
fwrite(&keydev, sizeof(keydev), 1, fdout);
|
||||
fwrite(&_padding, sizeof(_padding), 1, fdout);
|
||||
fwrite(&ev, sizeof(ev), 1, fdout);
|
||||
dprintf("added fake return exiting...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
{
|
||||
if (FD_ISSET(fds[i], &readfds))
|
||||
{
|
||||
dprintf("Got event from %s\n", inpdev->id_pathv[i]);
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
size_t rb = read(fds[i], (void*) &ev, sizeof(ev));
|
||||
dprintf("%d event: type %d code %d value %d\n",
|
||||
(unsigned int)rb, ev.type, ev.code, ev.value);
|
||||
if (ev.type == EV_KEY && ev.code == KEY_ENTER && ev.value == 1)
|
||||
keydev = i;
|
||||
fwrite(&i, sizeof(i), 1, fdout);
|
||||
fwrite(&_padding, sizeof(_padding), 1, fdout);
|
||||
fwrite(&ev, sizeof(ev), 1, fdout);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i < inpdev->id_pathc; i++)
|
||||
{
|
||||
close(fds[i]);
|
||||
}
|
||||
|
||||
fclose(fdout);
|
||||
free(fds);
|
||||
dprintf("Recorded %d events\n", count);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i;
|
||||
char *logfile = NULL;
|
||||
|
||||
revent_args_t *rargs;
|
||||
revent_args_init(&rargs, argc, argv);
|
||||
|
||||
inpdev_t *inpdev;
|
||||
inpdev_init(&inpdev, rargs->device_number);
|
||||
|
||||
switch(rargs->mode) {
|
||||
@ -600,4 +634,3 @@ int main(int argc, char** argv)
|
||||
revent_args_close(rargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user