blob: 59c6138a9260ce637b0a9d930ca7dbb2b397055e [file] [log] [blame]
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A module for extracting trackpad device file properties"""
import os
import sys
sys.path.append('/usr/local/autotest/bin/input')
from linux_input import *
# Define some constants
X = 'x'
Y = 'y'
XY = 'xy'
MAX_SLOT = 10
EV_GROUP_TC = 'type-code'
EV_GROUP_TCV = 'type-code-value'
class TrackpadDeviceDecode:
"""Decode trackpad device events."""
def __init__(self):
self._init_event_type_code()
self._init_event_structure()
self._init_event_name_dict()
self._init_axis_dict()
self._init_motion_sep_list()
self._init_hidden_event_list()
def _init_axis_dict(self):
self.axis_dict = {self.abs_mt_x: X,
self.abs_mt_y: Y
}
def _init_motion_sep_list(self):
self.motion_sep_list = [
self.finger_on,
self.finger_off,
self.mouse_click_press,
self.mouse_click_release,
self.two_fingers_on,
self.three_fingers_on,
self.four_fingers_on,
]
def _init_hidden_event_list(self):
self.hidden_event_list = [
self.one_finger_off,
self.two_fingers_off,
self.three_fingers_off,
self.four_fingers_off
]
def _init_event_type_code(self):
"""Initialize event type and code."""
self.ev_format = ev_format = '%04x'
self.tcv_format = '%s %s'
self.max_slot = MAX_SLOT
# Event types
self.EV_SYN = ev_format % EV_SYN
self.EV_KEY = ev_format % EV_KEY
self.EV_ABS = ev_format % EV_ABS
# Event codes for synchronization event
self.SYN_REPORT = ev_format % SYN_REPORT
# Event codes for absolute axes
self.ABS_MT_SLOT = ev_format % ABS_MT_SLOT
self.ABS_MT_TRACKING_ID = ev_format % ABS_MT_TRACKING_ID
# Event codes for keys and buttons
self.BTN_MOUSE = ev_format % BTN_MOUSE
self.BTN_TOUCH = ev_format % BTN_TOUCH
self.BTN_TOOL_FINGER = ev_format % BTN_TOOL_FINGER
self.BTN_TOOL_DOUBLETAP = ev_format % BTN_TOOL_DOUBLETAP
self.BTN_TOOL_TRIPLETAP = ev_format % BTN_TOOL_TRIPLETAP
self.BTN_TOOL_QUADTAP = ev_format % BTN_TOOL_QUADTAP
# Event codes for keys and buttons
self.ABS_X = ev_format % ABS_X
self.ABS_Y = ev_format % ABS_Y
self.ABS_PRESSURE = ev_format % ABS_PRESSURE
self.ABS_MT_SLOT = ev_format % ABS_MT_SLOT
self.ABS_MT_POSITION_X = ev_format % ABS_MT_POSITION_X
self.ABS_MT_POSITION_Y = ev_format % ABS_MT_POSITION_Y
self.ABS_MT_TRACKING_ID = ev_format % ABS_MT_TRACKING_ID
self.ABS_MT_PRESSURE = ev_format % ABS_MT_PRESSURE
def _init_event_structure(self):
ev_type_code = '%s %s'
ev_struct = '%s %s %d'
self.finger_on = ev_struct % (self.EV_KEY, self.BTN_TOUCH, 1)
self.finger_off = ev_struct % (self.EV_KEY, self.BTN_TOUCH, 0)
self.mouse_click_press = ev_struct % (self.EV_KEY, self.BTN_MOUSE, 1)
self.mouse_click_release = ev_struct % (self.EV_KEY, self.BTN_MOUSE, 0)
self.one_finger_on = ev_struct % (self.EV_KEY, self.BTN_TOOL_FINGER, 1)
self.one_finger_off = ev_struct % (self.EV_KEY, self.BTN_TOOL_FINGER, 0)
self.two_fingers_on = ev_struct % (self.EV_KEY,
self.BTN_TOOL_DOUBLETAP, 1)
self.two_fingers_off = ev_struct % (self.EV_KEY,
self.BTN_TOOL_DOUBLETAP, 0)
self.three_fingers_on = ev_struct % (self.EV_KEY,
self.BTN_TOOL_TRIPLETAP, 1)
self.three_fingers_off = ev_struct % (self.EV_KEY,
self.BTN_TOOL_TRIPLETAP, 0)
self.four_fingers_on = ev_struct % (self.EV_KEY,
self.BTN_TOOL_QUADTAP, 1)
self.four_fingers_off = ev_struct % (self.EV_KEY,
self.BTN_TOOL_QUADTAP, 0)
self.tracking_id = ev_type_code % (self.EV_ABS, self.ABS_MT_TRACKING_ID)
self.slot = ev_type_code % (self.EV_ABS, self.ABS_MT_SLOT)
self.abs_mt_x = ev_type_code % (self.EV_ABS, self.ABS_MT_POSITION_X)
self.abs_mt_y = ev_type_code % (self.EV_ABS, self.ABS_MT_POSITION_Y)
self.abs_mt_z = ev_type_code % (self.EV_ABS, self.ABS_MT_PRESSURE)
self.abs_x = ev_type_code % (self.EV_ABS, self.ABS_X)
self.abs_y = ev_type_code % (self.EV_ABS, self.ABS_Y)
self.abs_z = ev_type_code % (self.EV_ABS, self.ABS_PRESSURE)
self.ev_syn = ev_type_code % (self.EV_SYN, self.SYN_REPORT)
def _init_event_name_dict(self):
self.event_name_dict = {
self.finger_on: 'Finger on',
self.finger_off: 'Finger off',
self.mouse_click_press: 'Mouse click press',
self.mouse_click_release: 'Mouse click release',
self.one_finger_on: 'One finger on',
self.one_finger_off: 'One finger off',
self.two_fingers_on: 'Two fingers on',
self.two_fingers_off: 'Two fingers off',
self.three_fingers_on: 'Three fingers on',
self.three_fingers_off: 'Three fingers off',
self.four_fingers_on: 'Four fingers on',
self.four_fingers_off: 'Four fingers off',
self.tracking_id: 'Tracking ID',
self.slot: 'Slot',
self.abs_mt_x: 'Abs mt x',
self.abs_mt_y: 'Abs mt y',
self.abs_mt_z: 'Abs mt z',
self.abs_x: 'Abs x',
self.abs_y: 'Abs y',
self.abs_z: 'Abs z',
self.ev_syn: 'SYN',
}
def _get_axis(self, tc):
return self.axis_dict[tc]
def _calc_accu_motion(self, slot, axis, evalue):
value = int(evalue)
s = slot
if self.prev_pos[s][axis] is not None:
motion = abs(value - self.prev_pos[s][axis])
self.accu_motion[s][axis] += motion
self.accu_motion[s][XY] += motion
self.prev_pos[s][axis] = value
def _reset_accu_motion(self, slot=None):
slots = range(self.max_slot) if slot is None else [slot]
for s in slots:
self.accu_motion[s][X] = 0
self.accu_motion[s][Y] = 0
self.accu_motion[s][XY] = 0
def _reset_accu_pos(self, slot=None):
slots = range(self.max_slot) if slot is None else [slot]
for s in slots:
self.prev_pos[s][X] = None
self.prev_pos[s][Y] = None
def _reset_time(self):
self.time_finger_on = None
self.time_finger_off = None
def _calc_timespan(self, bgn_time, end_time):
if bgn_time is None or end_time is None:
return None
else:
timespan = float(end_time) - float(bgn_time)
return timespan
def _init_pos_and_motion(self):
self.prev_pos = {}
self.accu_motion = {}
for s in range(self.max_slot):
self.prev_pos[s] = {}
self.accu_motion[s] = {}
self._reset_accu_pos()
self._reset_accu_motion()
def _output_append_motion(self, slot):
if self.accu_motion[slot][XY] > 0:
self.output.append(self.motion_format % (slot,
self.accu_motion[slot][X],
self.accu_motion[slot][Y],
self.accu_motion[slot][XY]))
def _output_append_event(self, group, data, evalue=None):
event_str = None
is_finger_on = False
if group == EV_GROUP_TCV:
tcv = data
is_finger_on = tcv == self.finger_on
if tcv not in self.hidden_event_list:
if is_finger_on:
prefix = '\n'
elif tcv == self.finger_off:
prefix = ''
else:
prefix = ' '
event_str = prefix + self.event_name_dict[tcv]
elif group == EV_GROUP_TC:
tc = data
event_str = (' ' + self.tcv_format %
(self.event_name_dict[tc], evalue))
# If finger_on event does not appear yet, save the event_str so
# that it can be appended to the output after the finger_on event.
if event_str is not None:
if self.time_finger_on is None:
self.output_buffer.append(event_str)
else:
self.output.append(event_str)
# Flush any previous event_str stored in output_buffer to output
# if this data is a finger_on event
if is_finger_on:
for e in self.output_buffer:
self.output.append(e)
self.output_buffer = []
def _output_append_time(self, timespan):
if timespan is None:
self.output.append(' warning: finger on event was missing!')
else:
msg = ' timespan for whole finger on period: %f seconds'
self.output.append(msg % timespan)
def decode_device_events(self, file_name):
"""Decode the device event file."""
if not os.path.isfile(file_name):
print ('Warning: the device event file "%s" does not exist.' %
file_name)
return
print '\n\n%s' % ('-' * 60)
print 'Decoding %s ...' % file_name
self.output = []
self.output_buffer = []
self._init_pos_and_motion()
slot = 0
motion_format = (' accu_motion[%d]: x = %d, y = %d, ' 'xy = %d')
self.motion_format = motion_format
self._reset_time()
with open(file_name) as f:
for line in f:
# print 'Decode line: ', line
header, timestamp, etype, ecode, evalue = line.split()
tc = '%s %s' % (etype, ecode)
tcv = '%s %s %s' % (etype, ecode, evalue)
# Output accumulated motion if current event is in the
# motion_sep_list, e.g., mouse_click_press, two_fingers_on, etc.
if tcv in self.motion_sep_list:
for s in range(self.max_slot):
self._output_append_motion(s)
self._reset_accu_motion()
if tcv == self.finger_on:
self.time_finger_on = timestamp
if tcv == self.finger_off:
self._reset_accu_pos()
self._reset_accu_motion()
self.time_finger_off = timestamp
timespan = self._calc_timespan(self.time_finger_on,
self.time_finger_off)
self._output_append_time(timespan)
if tcv in self.event_name_dict:
self._output_append_event(EV_GROUP_TCV, tcv)
elif tc in self.event_name_dict:
if tc == self.slot:
slot = int(evalue)
elif tc == self.tracking_id and evalue == '-1':
self._output_append_motion(slot)
self._reset_accu_pos(slot)
self._reset_accu_motion(slot)
elif tc in self.axis_dict:
self._calc_accu_motion(slot, self._get_axis(tc), evalue)
if tcv == self.finger_off:
self._reset_time()
for line in self.output:
print line
if __name__ == '__main__':
tdd = TrackpadDeviceDecode()
tdd.decode_device_events(sys.argv[1])