summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen M. Webb <stephen.webb@canonical.com>2011-11-30 15:11:37 -0500
committerStephen M. Webb <stephen.webb@canonical.com>2011-11-30 15:11:37 -0500
commit6dea9767c0fd3a716095da2c56e5f3bb78b79cf2 (patch)
treee1f401cd10a4ace3a8d4fd5c81d1aad3fc50f0fd
parent64dac9f4a2a637419b7a8b4385760283f005a4e0 (diff)
Replaced the original convoluted set of python classes with a single Device class.
-rw-r--r--Makefile.am2
-rw-r--r--data/synaptics.prop32
-rw-r--r--python/Makefile.am2
-rw-r--r--python/evemu/__init__.py255
-rw-r--r--python/evemu/data.py60
-rw-r--r--python/evemu/device.py353
-rw-r--r--python/evemu/script.py66
-rw-r--r--python/evemu/testing/result.py11
-rw-r--r--python/evemu/testing/runner.py8
-rw-r--r--python/evemu/testing/testcase.py20
-rw-r--r--python/evemu/tests/test_base.py5
-rw-r--r--python/evemu/tests/test_data.py0
-rw-r--r--python/evemu/tests/test_device.py305
-rw-r--r--python/evemu/tests/test_device2.py223
-rw-r--r--python/evemu/tests/test_script.py29
-rw-r--r--python/evemu/tests/test_util.py54
-rw-r--r--python/evemu/tests/test_wrapper.py48
-rw-r--r--python/evemu/util.py99
-rw-r--r--python/evemu/wrapper.py66
-rw-r--r--src/evemu.c2
20 files changed, 539 insertions, 1101 deletions
diff --git a/Makefile.am b/Makefile.am
index 7d02cc0..f117981 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,3 +22,5 @@ ChangeLog:
$${cmd} log > ChangeLog;
dist-hook: ChangeLog INSTALL
+
+DISTCLEANFILES = ChangeLog
diff --git a/data/synaptics.prop b/data/synaptics.prop
new file mode 100644
index 0000000..05e27de
--- /dev/null
+++ b/data/synaptics.prop
@@ -0,0 +1,32 @@
+N: SynPS/2 Synaptics TouchPad
+I: 0011 0002 0007 01b1
+P: 09 00 00 00 00 00 00 00
+B: 00 0b 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 03 00 00 00 00 00
+B: 01 20 64 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 02 00 00 00 00 00 00 00 00
+B: 03 03 00 00 11 00 80 60 02
+B: 04 00 00 00 00 00 00 00 00
+B: 05 00 00 00 00 00 00 00 00
+B: 11 00 00 00 00 00 00 00 00
+B: 12 00 00 00 00 00 00 00 00
+B: 15 00 00 00 00 00 00 00 00
+B: 15 00 00 00 00 00 00 00 00
+A: 00 1472 5888 0 0
+A: 01 1408 4820 0 0
+A: 18 0 255 0 0
+A: 1c 0 15 0 0
+A: 2f 0 1 0 0
+A: 35 1472 5888 0 0
+A: 36 1408 4820 0 0
+A: 39 0 65535 0 0
diff --git a/python/Makefile.am b/python/Makefile.am
index 4b33e2c..5a17793 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -34,4 +34,4 @@ evemu-test-runner: evemu-test-runner.in Makefile
BUILT_SOURCES = evemu-test-runner
EXTRA_DIST = evemu-test-runner.in $(wildcard evemu/test*)
-CLEAN_FILES = $(BUILD_SOURCES)
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/python/evemu/__init__.py b/python/evemu/__init__.py
index 8b13789..0ac7dce 100644
--- a/python/evemu/__init__.py
+++ b/python/evemu/__init__.py
@@ -1 +1,256 @@
+"""
+The evemu module provides the Python interface to the kernel-level input device
+raw events.
+"""
+
+# Copyright 2011 Canonical Ltd.
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 3, as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranties of
+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from ctypes.util import find_library
+
+import ctypes
+import evemu.base
+import evemu.const
+import glob
+import os
+import re
+import stat
+
+__all__ = ["Device"]
+
+
+class Device(object):
+ """
+ Encapsulates a raw kernel input event device, either an existing one as
+ reported by the kernel or a pseudodevice as created through a .prop file.
+ """
+
+ def __init__(self, f):
+ """
+ Initializas an evemu Device.
+
+ args:
+ f -- a file object or filename string for either an existing input
+ device node (/dev/input/eventNN) or an evemu prop file that can be used
+ to create a pseudo-device node.
+ """
+
+ if type(f).__name__ == 'str':
+ self._file = open(f, 'r+b')
+ elif type(f).__name__ == 'file':
+ self._file = f
+ else:
+ raise TypeError("expected file or file name")
+
+ self._is_propfile = True
+ if stat.S_ISCHR(os.fstat(self._file.fileno()).st_mode):
+ self._is_propfile = False
+ elif self._file.read(3) == 'N: ':
+ self._file.seek(0)
+ else:
+ raise TypeError("file must be a device special or prop file")
+
+ self._evemu = evemu.base.EvEmuBase(find_library(evemu.const.LIB))
+ self._uinput = None
+
+ libevemu_new = self._evemu.get_lib().evemu_new
+ libevemu_new.restype = ctypes.c_void_p
+ self._evemu_device = libevemu_new("")
+
+ if self._is_propfile:
+ fs = self._evemu._call0(self._evemu.get_c_lib().fdopen,
+ self._file.fileno(),
+ 'r')
+ self._evemu._call(self._evemu.get_lib().evemu_read,
+ self._evemu_device,
+ fs)
+ self._uinput = os.open(evemu.const.UINPUT_NODE, os.O_WRONLY)
+ self._file = self._create_devnode()
+ else:
+ self._evemu._call(self._evemu.get_lib().evemu_extract,
+ self._evemu_device,
+ self._file.fileno())
+
+ def __del__(self):
+ if self._is_propfile:
+ self._file.close()
+ self._evemu._call(self._evemu.get_lib().evemu_destroy,
+ self._uinput)
+
+ def _create_devnode(self):
+ self._evemu._call(self._evemu.get_lib().evemu_create,
+ self._evemu_device,
+ self._uinput)
+ return open(self._find_newest_devnode(self.name), 'r+')
+
+ def _find_newest_devnode(self, target_name):
+ newest_node = (None, float(0))
+ for sysname in glob.glob("/sys/class/input/event*/device/name"):
+ with open(sysname) as f:
+ name = f.read().rstrip()
+ if name == target_name:
+ ev = re.search("(event\d+)", sysname)
+ if ev:
+ devname = os.path.join("/dev/input", ev.group(1))
+ ctime = os.stat(devname).st_ctime
+ if ctime > newest_node[1]:
+ newest_node = (devname, ctime)
+ return newest_node[0]
+
+ def describe(self, prop_file):
+ """
+ Gathers information about the input device and prints it
+ to prop_file. This information can be parsed later when constructing
+ a Device to create a virtual input device with the same properties.
+
+ Scripts that use this method need to be run as root.
+ """
+ if type(prop_file).__name__ != 'file':
+ raise TypeError("expected file")
+
+ fs = self._evemu._call0(self._evemu.get_c_lib().fdopen,
+ prop_file.fileno(),
+ "w")
+ self._evemu._call(self._evemu.get_lib().evemu_write,
+ self._evemu_device,
+ fs)
+ self._evemu.get_c_lib().fflush(fs)
+
+ def play(self, events_file):
+ """
+ Replays an event sequence, as provided by the events_file,
+ through the input device. The event sequence must be in
+ the form created by the record method.
+
+ Scripts that use this method need to be run as root.
+ """
+ if type(events_file).__name__ != 'file':
+ raise TypeError("expected file")
+
+ fs = self._evemu._call0(self._evemu.get_c_lib().fdopen,
+ events_file.fileno(),
+ "r")
+ self._evemu._call(self._evemu.get_lib().evemu_play,
+ fs,
+ self._file.fileno())
+
+ def record(self, events_file, timeout=10000):
+ """
+ Captures events from the input device and prints them to the
+ events_file. The events can be parsed by the play method,
+ allowing a virtual input device to emit the exact same event
+ sequence.
+
+ Scripts that use this method need to be run as root.
+ """
+ if type(events_file).__name__ != 'file':
+ raise TypeError("expected file")
+
+ fs = self._evemu._call0(self._evemu.get_c_lib().fdopen,
+ events_file.fileno(),
+ "w")
+ self._evemu._call(self._evemu.get_lib().evemu_record,
+ fs,
+ self._file.fileno(),
+ timeout)
+ self._evemu.get_c_lib().fflush(fs)
+
+ @property
+ def version(self):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_version,
+ self._evemu_device)
+
+ @property
+ def devnode(self):
+ """
+ Gets the name of the /dev node of the input device.
+ """
+ return self._file.name
+
+ @property
+ def name(self):
+ """
+ Gets the name of the input device (as reported by the device).
+ """
+ func = self._evemu.get_lib().evemu_get_name
+ func.restype = ctypes.c_char_p
+ return self._evemu._call(func, self._evemu_device)
+
+ @property
+ def id_bustype(self):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_id_bustype,
+ self._evemu_device)
+
+ @property
+ def id_vendor(self):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_id_vendor,
+ self._evemu_device)
+
+ @property
+ def id_product(self):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_id_product,
+ self._evemu_device)
+
+ @property
+ def id_version(self):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_id_version,
+ self._evemu_device)
+
+ def get_abs_minimum(self, event_code):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_abs_minimum,
+ self._evemu_device,
+ int(event_code))
+
+ def get_abs_maximum(self, event_code):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_abs_maximum,
+ self._evemu_device,
+ event_code)
+
+ def get_abs_fuzz(self, event_code):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_abs_fuzz,
+ self._evemu_device,
+ event_code)
+
+ def get_abs_flat(self, event_code):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_abs_flat,
+ self._evemu_device,
+ event_code)
+
+ def get_abs_resolution(self, event_code):
+ return self._evemu._call(self._evemu.get_lib().evemu_get_abs_resolution,
+ self._evemu_device,
+ event_code)
+
+ def has_prop(self, event_code):
+ return self._evemu._call(self._evemu.get_lib().evemu_has_prop,
+ self._evemu_device,
+ event_code)
+
+ def has_event(self, event_type, event_code):
+ """
+ This method's 'even_type' parameter is expected to mostly take the
+ value for EV_ABS (i.e., 0x03), but may on occasion EV_KEY (i.e., 0x01).
+ If the former, then the even_code parameter will take the same values
+ as the methods above (ABS_*). However, if the latter, then the legal
+ values will be BTN_*.
+
+ The reason for including the button data, is that buttons are sometimes
+ used to simulate gestures for a higher number of touches than are
+ possible with just 2-touch hardware.
+ """
+ return self._evemu._call(self._evemu.get_lib().evemu_has_event,
+ self._evemu_device,
+ event_type,
+ event_code)
diff --git a/python/evemu/data.py b/python/evemu/data.py
deleted file mode 100644
index 502ed50..0000000
--- a/python/evemu/data.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import ctypes
-
-from evemu import const
-
-
-ABS_CNT = const.ABS_MAX + 1
-
-
-class InputIdStruct(ctypes.Structure):
- """
- Data structure based on input_id in linux/uinput.h.
- """
- _fields_ = [
- ("bustype", ctypes.c_uint),
- ("vendor", ctypes.c_uint),
- ("product", ctypes.c_uint),
- ("version", ctypes.c_uint),
- ]
-
-
-class InputAbsInfoStruct(ctypes.Structure):
- """
- Data structure based on input_absinfo in XXX.
- """
- _fields_ = [
- ("value", ctypes.c_ulong),
- ("minimum", ctypes.c_ulong),
- ("maximum", ctypes.c_ulong),
- ("fuzz", ctypes.c_ulong),
- ("flat", ctypes.c_ulong),
- ("resolution", ctypes.c_ulong),
- ]
-
-
-class EvEmuDeviceStruct(ctypes.Structure):
- """
- Data structure based on evemu_device in evemu-impl.h.
- """
- _fields_ = [
- ("version", ctypes.c_uint),
- ("name", ctypes.c_byte * const.UINPUT_MAX_NAME_SIZE),
- ("id", InputIdStruct),
- ("prop", ctypes.c_ubyte * const.EVPLAY_NBYTES),
- ("mask", ctypes.c_ubyte),
- ("pbytes", ctypes.c_int),
- ("mbytes", ctypes.c_int * const.EV_CNT),
- ("abs", InputAbsInfoStruct * ABS_CONT),
- ]
-"""
-struct evemu_device {
- unsigned int version; //
- char name[UINPUT_MAX_NAME_SIZE]; // string, max size
- struct input_id id; // struct input_id from linux/uinput.h
- unsigned char prop[EVPLAY_NBYTES]; //
- unsigned char mask[EV_CNT][EVPLAY_NBYTES]; // doubly indexed array... first index is what type, second field is a bitmask
- int pbytes //
- int mbytes[EV_CNT]; // array of integers
- struct input_absinfo abs[ABS_CNT]; // array structures
-};
-"""
diff --git a/python/evemu/device.py b/python/evemu/device.py
deleted file mode 100644
index 03d04ac..0000000
--- a/python/evemu/device.py
+++ /dev/null
@@ -1,353 +0,0 @@
-import ctypes
-import os
-
-from evemu import base
-from evemu import const
-from evemu import exception
-from evemu import util
-
-
-class EvEmuDevice(base.EvEmuBase):
- """
- A wrapper class for the evemu device fucntions.
-
- For the methods with the @property decorator, as well as the the get_* and
- has_* methods, the following notes apply:
-
- The medhod parameters 'event_type' and 'event_code' take their meanings
- from the input event system in linux (the input_event struct defined in
- linux/input.h).
-
- Ordinarily, to know a code, one must first know the type. However, in our
- case, we mostly just case about multi-touch. Since MT data only uses
- EV_ABS, it is understood that methods without a type are implicitly
- expecting a context of EV_ABS.
-
- As such, for those methods, the valid codes are the ABS_* values listed in
- the evemu.const module.
-
- @event_type: one of the EV_* constants
-
- @event_code: a code related to the event type
- """
- def __init__(self, library):
- super(EvEmuDevice, self).__init__(library)
- # the path to the node that will be the virtual device
- self._node = ""
- # the stream produced by fopen (used to open the virtual device
- # description file)
- self._device_file_stream = None
- # the python variable that holds the reference to the C pointer for the
- # device data structure; ctypes handles the byref internals via the
- # _as_parameter_ method magic
- self._device_pointer = None
- # the file descriptor used by ioctl to create the virtual device
- self._uinput_fd = None
- try:
- self._new()
- except exception.EvEmuError, error:
- self.delete()
- raise error
-
- def __del__(self):
- self.delete()
- try:
- self.close_device_file_stream()
- self.set_device_file_stream(None)
- except exception.NullFileHandleError, error:
- # If there's no filehandle, there's nothing we can do, so move
- # along, folks... nothing to see here!
- pass
- self.destroy()
- self.close()
- # XXX is this code necessary? if so, it might need to be fixed...
- #if self.get_node_name():
- # print self.get_node_name()
- # if os.path.exists(self.get_node_name()):
- # print "unlinking %s ..." % self.get_node_name()
- # os.unlink(self.get_node_name())
-
- def _new(self):
- device_new = self.get_lib().evemu_new
- device_new.restype = ctypes.c_void_p
- # The C API expects a device name to be passed, however, it doesn't do
- # anything with it, so we're not going to provide it as an option in
- # the Python API.
- self._device_pointer = device_new("")
-
- def _get_device_struct(self):
- pointer = self.get_device_pointer()
- import pdb;pdb.set_trace()
-
- @property
- def _as_parameter_(self):
- return self.get_deivce_pointer()
-
- def get_lib(self):
- return self._lib
-
- def get_device_pointer(self):
- return self._device_pointer
-
- def get_device_file_stream(self):
- return self._device_file_stream
-
- def set_device_file_stream(self, stream):
- self._device_file_stream = stream
-
- def _close_device_file_stream(self):
- if self.get_device_pointer() is None:
- raise exception.NullFileHandleError(
- "Cannot close an undefined file pointer!")
- self._call(
- self.get_c_lib().fclose,
- self.get_device_file_stream())
-
- def close_device_file_stream(self):
- try:
- self._close_device_file_stream()
- pass
- except exception.EvEmuError, error:
- self.delete()
- raise error
-
- def set_node_name(self, node_name):
- self._node = node_name
-
- def get_node_name(self):
- return self._node
-
- def delete(self):
- """
- Frees up the memory associated with the pointer (and deletes the
- pointer).
-
- This is done when:
- * uncessessfully attempting to create a new device data structure
- * unsuccessfully attempting to read the device description file
- * unsuccessfully attempting to open the UINPUT_NODE for writing
-
- Note that when uncsuccessfully calling evemu_create, just the close
- operation is performed, nothing else.
- """
- if self.get_device_pointer():
- self._call(self.get_lib().evemu_delete, self.get_device_pointer())
- self._device_pointer = None
-
- def destroy(self):
- """
- Deletes the /dev/device/eventXX device that was created.
-
- This is done when:
- * successfully setup up the eventXX device, after all the work is done
-
- Note that when uncsuccessfully calling evemu_create, just the close
- operation is performed, nothing else.
- """
- if self._uinput_fd:
- self._call(self.get_lib().evemu_destroy, self._uinput_fd)
-
- def close(self):
- """
- Closes the uinput device.
-
- This is done when:
- * unsuccessfully calling evemu_create
- """
- if self._uinput_fd:
- os.close(self._uinput_fd)
- self._uinput_fd = None
-
- def _read(self, filename):
- file_pointer = self._call0(
- self.get_c_lib().fopen, filename, "r")
- self.set_device_file_stream(file_pointer)
- self._call(
- self.get_lib().evemu_read,
- self.get_device_pointer(),
- self.get_device_file_stream())
-
- def read(self, filename):
- """
- Pre-load the device structure with data from the virtual device
- description file.
- """
- try:
- self._read(filename)
- except exception.EvEmuError, error:
- self.delete()
- raise error
-
- def _open_uinput(self):
- self._uinput_fd = os.open(const.UINPUT_NODE, os.O_WRONLY)
-
- def _create(self):
- self._call(
- self.get_lib().evemu_create,
- self.get_device_pointer(),
- self._uinput_fd)
-
- def create_node(self, device_file):
- # load device data from the virtual device description file into the
- # data structure referenced by the device pointer
- self.read(device_file)
- # create the node
- try:
- self._open_uinput()
- except exception.EvEmuError, error:
- self.delete()
- raise error
- # populate the new node with data from the device pointer
- try:
- self._create()
- self.set_node_name(util.get_last_device())
- except exception.EvEmuError, error:
- self.close()
- raise error
-
- def _write(self, filename):
- # XXX what about writing to stdout? let's do that later; open a bug for
- # supporting writing to stdout...
- file_pointer = self._call0(
- self.get_c_lib().fopen, filename, "w+")
- self.set_device_file_stream(file_pointer)
- self._call(
- self.get_lib().evemu_write,
- self.get_device_pointer(),
- self.get_device_file_stream())
- self.close_device_file_stream()
-
- def write(self, filename):
- """
- Whatever data has been stored in the struct will get written to the
- passed file.
- """
- try:
- self._write(filename)
- except exception.EvEmuError, error:
- self.delete()
- raise error
-
- def _extract(self, device_node):
- file_descriptor = os.open(device_node, os.O_RDONLY)
- self._call(
- self.get_lib().evemu_extract,
- self.get_device_pointer(),
- file_descriptor)
- os.close(file_descriptor)
-
- def extract(self, device_node):
- """
- A linux input device node is opened and read, storing all the retrieved
- data in the device data structure.
- """
- try:
- self._extract(device_node)
- except exception.EvEmuError, error:
- self.delete()
- raise error
-
- def _record(self, device_node):
- pass
-
- def record(self, device_node):
- pass
-
- def _play(self, device_node, events_file):
- pass
-
- def play(self, device_node, events_file):
- pass
-
- # Property methods
- @property
- def version(self):
- return self._call(
- self.get_lib().evemu_get_version,
- self.get_device_pointer())
-
- @property
- def name(self):
- func = self.get_lib().evemu_get_name
- func.restype = ctypes.c_char_p
- return self._call(func, self.get_device_pointer())
-
- @property
- def id_bustype(self):
- return self._call(
- self.get_lib().evemu_get_id_bustype,
- self.get_device_pointer())
-
- @property
- def id_vendor(self):
- return self._call(
- self.get_lib().evemu_get_id_vendor,
- self.get_device_pointer())
-
- @property
- def id_product(self):
- return self._call(
- self.get_lib().evemu_get_id_product,
- self.get_device_pointer())
-
- @property
- def id_version(self):
- return self._call(
- self.get_lib().evemu_get_id_version,
- self.get_device_pointer())
-
- # Getter methods
- def get_abs_minimum(self, event_code):
- return self._call(
- self.get_lib().evemu_get_abs_minimum,
- self.get_device_pointer(),
- int(event_code))
-
- def get_abs_maximum(self, event_code):
- return self._call(
- self.get_lib().evemu_get_abs_maximum,
- self.get_device_pointer(),
- event_code)
-
- def get_abs_fuzz(self, event_code):
- return self._call(
- self.get_lib().evemu_get_abs_fuzz,
- self.get_device_pointer(),
- event_code)
-
- def get_abs_flat(self, event_code):
- return self._call(
- self.get_lib().evemu_get_abs_flat,
- self.get_device_pointer(),
- event_code)
-
- def get_abs_resolution(self, event_code):
- return self._call(
- self.get_lib().evemu_get_abs_resolution,
- self.get_device_pointer(),
- event_code)
-
- # Haser methods ;-)
- def has_prop(self, event_code):
- return self._call(
- self.get_lib().evemu_has_prop,
- self.get_device_pointer(),
- event_code)
-
- def has_event(self, event_type, event_code):
- """
- This method's 'even_type' parameter is expected to mostly take the
- value for EV_ABS (i.e., 0x03), but may on occasion EV_KEY (i.e., 0x01).
- If the former, then the even_code parameter will take the same values
- as the methods above (ABS_*). However, if the latter, then the legal
- values will be BTN_*.
-
- The reason for including the button data, is that buttons are sometimes
- used to simulate gestures for a higher number of touches than are
- possible with just 2-touch hardware.
- """
- return self._call(
- self.get_lib().evemu_has_event,
- self.get_device_pointer(),
- event_type,
- event_code)
diff --git a/python/evemu/script.py b/python/evemu/script.py
deleted file mode 100644
index ee0cb44..0000000
--- a/python/evemu/script.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import os
-import sys
-
-
-class EvEmu(object):
- """
- This class wraps the functionality offerened by the evemu utility programs.
- """
- def __init__(self, library=""):
- """
- """
- pass
-
- def describe(self, path_to_touch_device):
- """
- The describe gathers information about the input device and prints it
- to stdout. This information can be parsed by the create_device to
- create a virtual input device with the same properties.
-
- Scripts that use this method need to be run as root.
- """
- fd = open(path_to_touch_device, "r")
- device = self._wrapper.evemu_new(0)
- # XXX check for device being not none, err out if so
- data = self._wrapper.evemu_extract(device, fd)
- # XXX check for data being not none, err out if so
- fd.close()
- # XXX I don't like writing to stdout by default with a library. I'd
- # prefer that this were an option. For now, we'll duplicate the scripts
- # and keep it as is...
- self._wrapper.evemu_write(device, sys.stdout)
- return data
-
- def create_device(self, device_description_file):
- """
- The create_device method creates a virtual input device based on the
- provided description-file. This description will have been created by
- the describe method. The create_device method then creates a new input
- device with uinput and prints the name and the device file to stdout.
-
- Scripts that use this method need to be run as root.
- """
- if self._virtual_device:
- return self._virtual_device
-
- def record(self):
- """
- This method captures events from the input device and prints them to
- stdout. The events can be parsed by the play method, allowing a virtual
- input device created with the create_device method to emit the exact
- same event sequence.
-
- Scripts that use this method need to be run as root.
- """
-
- def play(self, device_description_file="", events_file=""):
- """
- The play method replays the event sequence, as provided by the
- events-file, through the input device. The event sequence must be in
- the form created by the record method.
-
- Scripts that use this method need to be run as root.
- """
- device_fd = os.open(device_description_file, os.O_WRONLY)
- events_fd = os.open(events_file, os.O_WRONLY)
- self._wrapper.play(device_fd, events_fd)
diff --git a/python/evemu/testing/result.py b/python/evemu/testing/result.py
index e3480cd..d824b36 100644
--- a/python/evemu/testing/result.py
+++ b/python/evemu/testing/result.py
@@ -6,7 +6,14 @@ except ImportError:
# Python 2.4, 2.5, 2.6
from unittest import _TextTestResult as TextTestResult
-from evemu import util
+
+def get_test_directory():
+ from evemu import tests
+ return tests.__path__[0]
+
+
+def get_test_module():
+ return get_test_directory().replace("/", ".")
class CustomTestResult(TextTestResult):
@@ -31,7 +38,7 @@ class CustomTestResult(TextTestResult):
this_class = module_and_class.split(".")[-1]
self.current_class = this_class
if self.last_module != self.current_module:
- heading = "\n%s.%s" % (util.get_test_module(), this_module)
+ heading = "\n%s.%s" % (get_test_module(), this_module)
self.stream.writeln(heading)
if self.last_class != self.current_class:
self.stream.writeln(" %s" % this_class)
diff --git a/python/evemu/testing/runner.py b/python/evemu/testing/runner.py
index f5662a2..d7bf814 100644
--- a/python/evemu/testing/runner.py
+++ b/python/evemu/testing/runner.py
@@ -1,10 +1,14 @@
import os
import unittest
-from evemu import util
from evemu.testing import result
+def get_test_directory():
+ from evemu import tests
+ return tests.__path__[0]
+
+
class CustomTestRunner(unittest.TextTestRunner):
"""
This is only needed for Python 2.6 and lower.
@@ -51,7 +55,7 @@ def get_runner():
def run_tests():
loader = unittest.TestLoader()
- suite = get_suite(loader, util.get_test_directory())
+ suite = get_suite(loader, get_test_directory())
get_runner().run(suite)
diff --git a/python/evemu/testing/testcase.py b/python/evemu/testing/testcase.py
index 0301adb..35b7a0b 100644
--- a/python/evemu/testing/testcase.py
+++ b/python/evemu/testing/testcase.py
@@ -4,7 +4,11 @@ import unittest
from evemu import const
from evemu import exception
-from evemu import util
+
+
+def get_top_directory():
+ import evemu
+ return evemu.__path__[0]
def skip(message):
@@ -49,7 +53,7 @@ class BaseTestCase(unittest.TestCase):
else:
library = const.LOCAL_LIB
self.library = library
- basedir = util.get_top_directory()
+ basedir = get_top_directory()
self.data_dir = os.path.join(basedir, "..", "..", "data")
self.device = None
@@ -64,15 +68,3 @@ class BaseTestCase(unittest.TestCase):
def get_events_file(self):
return os.path.join(self.data_dir, "ntrig-dell-xt2.event")
- def create_testing_device(self, device_class=None):
- """
- This is a conveneince test function for tests that need a device. Have
- this method be called in each test (as opposed to once in the setUp
- method) also allows for use to check device counts before and after
- device creation.
- """
- from evemu.device import EvEmuDevice
- if not device_class:
- device_class = EvEmuDevice
- self.device = device_class(self.library)
- self.device.create_node(self.get_device_file())
diff --git a/python/evemu/tests/test_base.py b/python/evemu/tests/test_base.py
index 60f8eed..0b72abd 100644
--- a/python/evemu/tests/test_base.py
+++ b/python/evemu/tests/test_base.py
@@ -7,12 +7,15 @@ from evemu.testing import testcase
class EvEmuBaseTestCase(testcase.BaseTestCase):
- def test_initialize(self):
+ def test_so_library_found(self):
wrapper = EvEmuBase(self.library)
# Make sure that the library loads
self.assertNotEqual(
wrapper._lib._name.find("libutouch-evemu"), -1)
+
+ def test_c_symbols_found(self):
# Make sure that the expected functions are present
+ wrapper = EvEmuBase(self.library)
for function_name in const.API:
function = getattr(wrapper._lib, function_name)
self.assertTrue(function is not None)
diff --git a/python/evemu/tests/test_data.py b/python/evemu/tests/test_data.py
deleted file mode 100644
index e69de29..0000000
--- a/python/evemu/tests/test_data.py
+++ /dev/null
diff --git a/python/evemu/tests/test_device.py b/python/evemu/tests/test_device.py
deleted file mode 100644
index 65112fd..0000000
--- a/python/evemu/tests/test_device.py
+++ /dev/null
@@ -1,305 +0,0 @@
-import ctypes
-import os
-import tempfile
-import unittest
-
-from evemu import const
-from evemu import exception
-from evemu import util
-from evemu.device import EvEmuDevice
-from evemu.testing import testcase
-
-
-class EvEmuDeviceTestCase(testcase.BaseTestCase):
-
- def test_initialize_error_new(self):
- class FakeDevice(EvEmuDevice):
- def _new(self):
- raise exception.EvEmuError("Error new'ing in init!")
- self.assertRaises(
- exception.EvEmuError, self.create_testing_device, FakeDevice)
-
- def test_initialize(self):
- self.create_testing_device()
- self.assertTrue(self.device._device_pointer is not None)
-
- def test_get_lib(self):
- self.create_testing_device()
- lib = self.device.get_lib()
- self.assertTrue(lib is not None)
-
- def test_get_device_file_stream(self):
- self.create_testing_device()
- self.device._device_file_stream = 1234
- self.assertEqual(self.device.get_device_file_stream(), 1234)
-
- def test_set_device_file_stream(self):
- self.create_testing_device()
- self.device.set_device_file_stream(1234)
- self.assertEqual(self.device._device_file_stream, 1234)
-
- @testcase.skip("Test not implemented")
- def test_close_device_file_stream_error_close(self):
- pass
-
- @testcase.skip("Test not implemented")
- def test_close_device_file_stream(self):
- pass
-
- def test_get_device_pointer(self):
- self.create_testing_device()
- pointer = self.device.get_device_pointer()
- self.assertEqual(type(pointer), int)
-
- def test_read_error(self):
- class FakeDevice(EvEmuDevice):
- def _read(self, *args, **kwds):
- raise exception.EvEmuError("Error calling lib in _read")
- def create_node(self, *args):
- pass
- self.create_testing_device(FakeDevice)
- self.assertRaises(
- exception.EvEmuError, self.device.read, self.get_device_file())
-
- # XXX finish unit test
- def test_read(self):
- pass
-
- def test_create_node_error_uinput(self):
- class FakeDevice(EvEmuDevice):
- def _open_uinput(self, *args, **kwds):
- raise exception.EvEmuError("Error calling lib in _uinput")
- def _new(self):
- pass
- def read(self, *args):
- pass
- def delete(self):
- pass
- device = FakeDevice(self.library)
- self.assertRaises(
- exception.EvEmuError,
- device.create_node,
- self.get_device_file())
-
- def test_create_node_error_create(self):
- class FakeDevice(EvEmuDevice):
- def _create(self, *args, **kwds):
- raise exception.EvEmuError("Error calling lib in _create")
- def _open_uinput(self, *args, **kwds):
- pass
- def _new(self):
- pass
- def read(self, *args):
- pass
- def close(self):
- pass
- device = FakeDevice(self.library)
- self.assertRaises(
- exception.EvEmuError,
- device.create_node,
- self.get_device_file())
-
- def test_create_node(self):
- device_count_before = len(util.get_all_device_numbers())
- self.create_testing_device()
- device_count_after = len(util.get_all_device_numbers())
- self.assertEqual(device_count_before + 1, device_count_after)
-
- def test_write(self):
- # prep a temp file to hold the written data
- self.create_testing_device()
- (output_fd, filename) = tempfile.mkstemp()
- self.device.write(filename)
- os.close(output_fd)
- # now test the data to make sure the write happened correctly
- file_object = open(filename)
- data = file_object.read()
- file_object.close()
- # correct length
- self.assertEqual(len(data), 840)
- # value looks as expected
- expected = "N: N-Trig-MultiTouch-Virtual-Device\n"
- self.assertTrue(data.startswith(expected))
- # files are identicatl
- file_object = open(self.get_device_file())
- expected_data = file_object.read()
- file_object.close()
- self.assertEqual(data, expected_data)
-
- def test_extract(self):
- """
- This test does the following in order to test device data extraction:
-
- 1) uses the virtual device created during setUp as the target for the
- extraction of device data,
-
- 2) writes the device data (stored in the device data structure in the
- evemu_extract library function) to a tempfile, and
-
- 3) checks the .prop file and the tempfile to see that the values they
- have stored are identical.
-
- """
-
- # get the device node for the virtual device created as part of the
- # test
- self.create_testing_device()
- node = self.device.get_node_name()
- # extract the device info from the node, saving it to the device data
- # structure
- self.device.extract(node)
- # prep a temp file to hold the written data
- (output_fd, filename) = tempfile.mkstemp()
- # write the device data structure contents to a file and compare with
- # the device .prop file that was used to create the virtual device to
- # begin with; they should be identical
- self.device.write(filename)
- os.close(output_fd)
- # then, now test the data to make sure the write happened correctly
- file_object = open(filename)
- data = file_object.read()
- file_object.close()
- # do the checks
- file_object = open(self.get_device_file())
- expected_data = file_object.read()
- file_object.close()
- # the evemu_extract library function doesn't generate a P:
- # (properties) line on kernels older than 2.6.38, so this test only
- # compares the lines that will be the same across supported kernels.
- self.assertEqual(
- data.splitlines()[0:1],
- expected_data.splitlines()[0:1])
- self.assertEqual(
- data.splitlines()[-28:-1],
- expected_data.splitlines()[-28:-1])
-
- @testcase.skip("Implementation not complete.")
- def test_record(self):
- pass
-
- @testcase.skip("Implementation not complete.")
- def test_play(self):
- pass
-
-
-class EvEmuDevicePropertyTestCase(testcase.BaseTestCase):
-
- def get_ev_abs_codes(self):
- return const.absolute_axes.values()
-
- def test_version(self):
- self.create_testing_device()
- self.assertEqual(self.device.version, 0)
-
- def test_name(self):
- self.create_testing_device()
- self.assertEqual(self.device.name, "N-Trig-MultiTouch-Virtual-Device")
-
- def test_id_bustype(self):
- self.create_testing_device()
- self.assertEqual(self.device.id_bustype, 3)
-
- def test_id_vendor(self):
- self.create_testing_device()
- self.assertEqual(hex(self.device.id_vendor), "0x1b96")
-
- def test_id_product(self):
- self.create_testing_device()
- self.assertEqual(self.device.id_product, 1)
-
- def test_id_version(self):
- self.create_testing_device()
- self.assertEqual(self.device.id_version, 272)
-
-
-class EvEmuDeviceGetterTestCase(testcase.BaseTestCase):
-
- def test_get_abs_minimum(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- ]
- results = [self.device.get_abs_minimum(x)
- for x in const.absolute_axes.values()]
- self.assertEqual(results, expected)
-
- def test_get_abs_maximum(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9600, 7200, 0, 0, 0, 0,
- 7200, 1, 7200, 0, 9600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9600,
- 0, 0,
- ]
- # Skipping the entry for ABS_CNT; some times it's 0, sometimes a very
- # large negative number.
- results = [self.device.get_abs_maximum(x)
- for x in const.absolute_axes.values()]
- self.assertEqual(results[:-1], expected[:-1])
-
- def test_get_abs_fuzz(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 78, 0, 0, 0, 0, 150,
- 0, 78, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0,
- ]
- results = [self.device.get_abs_fuzz(x)
- for x in const.absolute_axes.values()]
- self.assertEqual(results, expected)
-
- def test_get_abs_flat(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- ]
- results = [self.device.get_abs_flat(x)
- for x in const.absolute_axes.values()]
- self.assertEqual(results, expected)
-
- def test_get_abs_resolution(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- ]
- results = [self.device.get_abs_resolution(x)
- for x in const.absolute_axes.values()]
- self.assertEqual(results, expected)
-
- def test_has_prop(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- ]
- results = [self.device.has_prop(x)
- for x in const.absolute_axes.values()]
- self.assertEqual(results, expected)
-
- def test_has_event_ev_abs(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1,
- 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
- ]
- results = [self.device.has_event(const.event_types["EV_ABS"], x)
- for x in const.absolute_axes.values()]
- self.assertEqual(results, expected)
-
- def test_has_event_ev_key(self):
- self.create_testing_device()
- expected = [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- ]
- results = [self.device.has_event(const.event_types["EV_KEY"], x)
- for x in const.buttons.values()]
- self.assertEqual(results, expected)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/evemu/tests/test_device2.py b/python/evemu/tests/test_device2.py
new file mode 100644
index 0000000..a22858f
--- /dev/null
+++ b/python/evemu/tests/test_device2.py
@@ -0,0 +1,223 @@
+
+from evemu.testing import testcase
+from multiprocessing import Process, Queue, Event
+
+import evemu
+import os
+import re
+import tempfile
+import unittest
+
+
+def record(recording_started, device_node, q):
+ """
+ Runs the recorder in a separate process because the evemu API is a
+ blocking API.
+ """
+ device = evemu.Device(device_node)
+ with tempfile.TemporaryFile() as event_file:
+ recording_started.set()
+ device.record(event_file, 1000)
+ event_file.flush()
+ event_file.seek(0)
+ outdata = event_file.readlines()
+ q.put(outdata)
+
+
+class DeviceActionTestCase(testcase.BaseTestCase):
+ """
+ Verifies the high-level Device functions (create, describe, play, record).
+ """
+
+ def test_construct_from_dev_node_name(self):
+ """
+ Verifies a Device can be constructed from an existing input device node
+ name.
+ """
+ d = evemu.Device("/dev/input/event10")
+
+ def test_construct_from_dev_node_file(self):
+ """
+ Verifies a Device can be constructed from an existing input device node
+ file object.
+ """
+ d = evemu.Device(open("/dev/input/event10"))
+
+ def test_construct_from_prop_file_name(self):
+ """
+ Verifies a device can be constructed from an evemu prop file name.
+ """
+ d = evemu.Device(self.get_device_file())
+
+ def test_construct_from_prop_file_file(self):
+ """
+ Verifies a device can be constructed from an evemu prop file file
+ object.
+ """
+ d = evemu.Device(open(self.get_device_file()))
+
+ def test_describe(self):
+ """
+ Verifies that a device description can be correctly extracted from a
+ Device.
+ """
+ # Get original description
+ with open(self.get_device_file()) as f:
+ data = f.readlines()
+
+ # Create a pseudo device with that description
+ d = evemu.Device(self.get_device_file())
+
+ # get the description to a temporary file
+ with tempfile.TemporaryFile() as t:
+ d.describe(t)
+
+ # read in the temporary file and compare to the original
+ t.flush()
+ t.seek(0)
+ newdata = t.readlines()
+ self.assertEquals(data, newdata)
+
+ def test_play_and_record(self):
+ """
+ Verifies that a Device and play back prerecorded events.
+ """
+ device = evemu.Device(self.get_device_file())
+ devnode = device.devnode
+ events_file = self.get_events_file()
+ with open(events_file) as e:
+ indata = e.readlines()
+
+ recording_started = Event()
+ q = Queue()
+ record_process = Process(target=record,
+ args=(recording_started, devnode, q))
+ record_process.start()
+ recording_started.wait(100)
+ device.play(open(events_file))
+
+ outdata = q.get()
+ record_process.join()
+
+ self.assertEquals(len(indata), len(outdata))
+ fuzz = re.compile("E: \d+\.\d+ (.*)")
+ for i in range(len(indata)):
+ lhs = fuzz.match(indata[i])
+ self.assertTrue(lhs)
+ rhs = fuzz.match(outdata[i])
+ self.assertTrue(rhs)
+ self.assertEquals(lhs.group(1), rhs.group(1))
+
+
+class DevicePropertiesTestCase(testcase.BaseTestCase):
+ """
+ Verifies the workings of the various device property accessors.
+ """
+
+ def setUp(self):
+ super(DevicePropertiesTestCase, self).setUp()
+ self._device = evemu.Device(self.get_device_file())
+
+ def tearDown(self):
+ del self._device
+ super(DevicePropertiesTestCase, self).tearDown()
+
+ def test_version(self):
+ self.assertEqual(self._device.version, 0)
+
+ def test_name(self):
+ self.assertEqual(self._device.name, "N-Trig-MultiTouch-Virtual-Device")
+
+ def test_id_bustype(self):
+ self.assertEqual(self._device.id_bustype, 3)
+
+ def test_id_vendor(self):
+ self.assertEqual(hex(self._device.id_vendor), "0x1b96")
+
+ def test_id_product(self):
+ self.assertEqual(self._device.id_product, 1)
+
+ def test_id_version(self):
+ self.assertEqual(self._device.id_version, 272)
+
+ def test_get_abs_minimum(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ]
+ results = [self._device.get_abs_minimum(x)
+ for x in evemu.const.absolute_axes.values()]
+ self.assertEqual(results, expected)
+
+ def test_get_abs_maximum(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9600, 7200, 0, 0, 0, 0,
+ 7200, 1, 7200, 0, 9600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9600,
+ 0, 0,
+ ]
+ # Skipping the entry for ABS_CNT; some times it's 0, sometimes a very
+ # large negative number.
+ results = [self._device.get_abs_maximum(x)
+ for x in evemu.const.absolute_axes.values()]
+ self.assertEqual(results[:-1], expected[:-1])
+
+ def test_get_abs_fuzz(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 78, 0, 0, 0, 0, 150,
+ 0, 78, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0,
+ ]
+ results = [self._device.get_abs_fuzz(x)
+ for x in evemu.const.absolute_axes.values()]
+ self.assertEqual(results, expected)
+
+ def test_get_abs_flat(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ]
+ results = [self._device.get_abs_flat(x)
+ for x in evemu.const.absolute_axes.values()]
+ self.assertEqual(results, expected)
+
+ def test_get_abs_resolution(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ]
+ results = [self._device.get_abs_resolution(x)
+ for x in evemu.const.absolute_axes.values()]
+ self.assertEqual(results, expected)
+
+ def test_has_prop(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ]
+ results = [self._device.has_prop(x)
+ for x in evemu.const.absolute_axes.values()]
+ self.assertEqual(results, expected)
+
+ def test_has_event_ev_abs(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1,
+ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ ]
+ results = [self._device.has_event(evemu.const.event_types["EV_ABS"], x)
+ for x in evemu.const.absolute_axes.values()]
+ self.assertEqual(results, expected)
+
+ def test_has_event_ev_key(self):
+ expected = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ]
+ results = [self._device.has_event(evemu.const.event_types["EV_KEY"], x)
+ for x in evemu.const.buttons.values()]
+ self.assertEqual(results, expected)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/python/evemu/tests/test_script.py b/python/evemu/tests/test_script.py
deleted file mode 100644
index b8889c4..0000000
--- a/python/evemu/tests/test_script.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import unittest
-
-from evemu.script import EvEmu
-from evemu.testing import testcase
-
-
-class EvEmuTestCase(testcase.BaseTestCase):
-
- def setUp(self):
- super(EvEmuTestCase, self).setUp()
- self.evemu = EvEmu(library=self.library)
-
- def test_describe(self):
- pass
-
- def test_create_device(self):
- # Load the device file
- pass
-
- def test_record(self):
- pass
-
- def test_play(self):
- #self.evemu.play(self.get_events_file(), self.get_device_file())
- pass
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/evemu/tests/test_util.py b/python/evemu/tests/test_util.py
deleted file mode 100644
index 7bc5076..0000000
--- a/python/evemu/tests/test_util.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import unittest
-
-from evemu import util
-from evemu.testing import testcase
-
-
-class CommandsTestCase(testcase.Non26BaseTestCase):
-
- def test_lsinput_raw(self):
- results = util.lsinput_raw()
- self.assertIn("/dev/input/event", results)
- self.assertIn("bustype", results)
- self.assertIn("name", results)
- self.assertIn("product", results)
- self.assertIn("version", results)
-
- def test_lsinput(self):
- # let's just check the first one
- result = util.lsinput()[0]
- self.assertEqual(result.get("device"), "/dev/input/event0")
- self.assertTrue(result.get("bustype") is not None)
- self.assertTrue(result.get("name") is not None)
- self.assertTrue(result.get("product") is not None)
- self.assertTrue(result.get("version") is not None)
-
-
-class DevicesTestCase(testcase.Non26BaseTestCase):
-
- def test_get_all_device_numbers(self):
- result = util.get_all_device_numbers()
- self.assertTrue(result != [])
-
- def test_get_all_device_names(self):
- result = util.get_all_device_names()
- self.assertTrue(result != [])
-
- def test_get_last_device_number(self):
- self.assertTrue(isinstance(util.get_last_device_number(), int))
-
- def test_get_last_device(self):
- result = util.get_last_device()
- self.assertIn("/dev/input/event", result)
-
- def test_get_next_device(self):
- last_device = util.get_last_device()
- next_device = util.get_next_device()
- self.assertIn("/dev/input/event", next_device)
- self.assertEqual(
- (int(last_device[-1]) + 1) % 10,
- int(next_device[-1]))
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/evemu/tests/test_wrapper.py b/python/evemu/tests/test_wrapper.py
deleted file mode 100644
index dcd51c4..0000000
--- a/python/evemu/tests/test_wrapper.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import unittest
-
-from evemu import util
-from evemu.testing import testcase
-from evemu.wrapper import EvEmuWrapper
-
-
-class EvEmuWrapperTestCase(testcase.BaseTestCase):
-
- def setUp(self):
- super(EvEmuWrapperTestCase, self).setUp()
- self.wrapper = EvEmuWrapper(self.library)
-
- def tearDown(self):
- if self.wrapper.device:
- self.wrapper.device.destroy()
- super(EvEmuWrapperTestCase, self).tearDown()
-
- def test_initialize(self):
- self.assertTrue(self.wrapper.device is not None)
- self.assertTrue(self.wrapper.get_device() is not None)
-
- def test_create_already_created(self):
- pass
-
- def test_create(self):
- self.wrapper.create(self.get_device_file())
- device_list = util.get_all_device_names()
- self.assertTrue("N-Trig-MultiTouch-Virtual-Device" in device_list)
-
- @testcase.skip("Implemnentation not complete")
- def test_read(self):
- # XXX finish unit test
- result = self.wrapper.read(self.get_device_file())
- # XXX need to do checks against the result
-
- @testcase.skip("Implemnentation not complete")
- def test_extract(self):
- # XXX finish unit test
- result = self.wrapper.extract(self.get_device_file())
- print "\nfilename: %s" % self.get_device_file()
- import os
- print "exists? %s" % str(os.path.exists(self.get_device_file()))
- print "result:\n%s" % result
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/evemu/util.py b/python/evemu/util.py
deleted file mode 100644
index e86fcb1..0000000
--- a/python/evemu/util.py
+++ /dev/null
@@ -1,99 +0,0 @@
-import os
-import re
-import subprocess
-
-from evemu import const
-
-
-def lsinput_raw():
- command_parts = ["lsinput"]
- try:
- # Python 2.7
- output = subprocess.check_output(command_parts)
- except AttributeError:
- # Python 2.4, 2.5, 2.6
- output = subprocess.Popen(
- command_parts, stdout=subprocess.PIPE).communicate()[0]
- return output
-
-
-def lsinput():
- devices = []
- data = {}
- for line in lsinput_raw().splitlines():
- line = line.strip()
- if line.startswith("/dev/input"):
- if data:
- devices.append(data)
- data = {}
- data["device"] = line
- else:
- key = line[:7].strip()
- value = line[10:].strip()
- if key == "name":
- # trim the quotes
- value = value[1:-1]
- if key:
- data[key] = value
- if data:
- devices.append(data)
- return devices
-
-
-def get_top_directory():
- import evemu
- return evemu.__path__[0]
-
-
-def get_test_directory():
- from evemu import tests
- return tests.__path__[0]
-
-
-def get_test_module():
- return get_test_directory().replace("/", ".")
-
-
-def get_all_device_numbers():
- numbers = []
- for index in xrange(const.MAX_EVENT_NODE):
- path = const.DEVICE_PATH_TEMPLATE % index
- if os.path.exists(path):
- numbers.append(index)
- return numbers
-
-
-def get_all_device_names():
- names = []
- for device_number in get_all_device_numbers():
- filename = const.DEVICE_NAME_PATH_TEMPLATE % device_number
- if os.path.exists(filename):
- file_handle = open(filename)
- #names.append({"name": file_handle.read(), "id": device_number})
- names.append(file_handle.read().strip())
- file_handle.close()
- return names
-
-
-def get_last_device_number():
- """
- Get the last used device node number.
- """
- return get_all_device_numbers()[-1]
-
-
-def get_last_device():
- """
- Get the last used device node.
- """
- return const.DEVICE_PATH_TEMPLATE % get_last_device_number()
-
-
-def get_next_device():
- """
- Get the next availne device node.
- """
- next_number = get_last_device_number() + 1
- if next_number > const.MAX_EVENT_NODE:
- raise EvEmuError("device count exceeded MAX_EVENT_NODE")
- return const.DEVICE_PATH_TEMPLATE % next_number
diff --git a/python/evemu/wrapper.py b/python/evemu/wrapper.py
deleted file mode 100644
index 8f9ab4c..0000000
--- a/python/evemu/wrapper.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import ctypes
-import os
-import tempfile
-
-from evemu import base
-from evemu import const
-from evemu import device
-from evemu.exception import ExecutionError
-
-
-class EvEmuWrapper(base.EvEmuBase):
- """
- This class wraps the functionality offered by several of the evemu command
- line tools.
- """
- def __init__(self, library=""):
- """
- This method allocates a new evemu device structure and initializes
- all fields to zero.
- """
- super(EvEmuWrapper, self).__init__(library)
- self.device = device.EvEmuDevice(library)
-
- def __del__(self):
- del(self.device)
-
- @property
- def _as_parameter_(self):
- return self.get_device()
-
- def get_device(self):
- return self.device.get_device_pointer()
-
- def create(self, device_file):
- self.device.create_node(device_file)
-
- # XXX maybe this isn't needed at this level of abstraction...
- def delete(self):
- """
- Frees up the memory associated with the pointer (and deletes the
- pointer).
-
- See the docstring for EvEmuDevice.delete for more info.
- """
- self.device.delete()
-
- # XXX maybe this isn't needed at this level of abstraction...
- def destroy(self):
- """
- Deletes the /dev/device/eventXX device that was created.
-
- See the docstring for EvEmuDevice.destroy for more info.
- """
- self.device.destroy()
-
- def describe(self, device_path, output_file):
- """
- """
- self.device.extract(device_path)
- self.device.write(output_file)
-
- def play(self):
- pass
-
- def record(self):
- pass
diff --git a/src/evemu.c b/src/evemu.c
index 6c84f9d..ebcab2c 100644
--- a/src/evemu.c
+++ b/src/evemu.c
@@ -337,7 +337,7 @@ int evemu_read(struct evemu_device *dev, FILE *fp)
memset(dev, 0, sizeof(*dev));
- ret = fscanf(fp, "N: %ms\n", &devname);
+ ret = fscanf(fp, "N: %m[^\n]\n", &devname);
if (ret <= 0) {
if (devname != NULL)
free(devname);