#!/bin/env python3 # -*- coding: utf-8 -*- # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # import sys class AGM(object): def __init__(self): self.w = None self.x = None self.y = None self.z = None self.agm_count = None # hw->w = (((buf[0] & 0x30) >> 2) | # ((buf[0] & 0x04) >> 1) | # ((buf[3] & 0x04) >> 2)); # # if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || # SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && # hw->w == 2) { # synaptics_parse_agm(buf, priv, hw); # return 1; # } # # hw->x = (((buf[3] & 0x10) << 8) | # ((buf[1] & 0x0f) << 8) | # buf[4]); # hw->y = (((buf[3] & 0x20) << 7) | # ((buf[1] & 0xf0) << 4) | # buf[5]); # hw->z = buf[2]; # # hw->left = (buf[0] & 0x01) ? 1 : 0; # hw->right = (buf[0] & 0x02) ? 1 : 0; # # if (priv->is_forcepad) { # /* # * ForcePads, like Clickpads, use middle button # * bits to report primary button clicks. # * Unfortunately they report primary button not # * only when user presses on the pad above certain # * threshold, but also when there are more than one # * finger on the touchpad, which interferes with # * out multi-finger gestures. # */ # if (hw->z == 0) { # /* No contacts */ # priv->press = priv->report_press = false; # } else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) { # /* # * Single-finger touch with pressure above # * the threshold. If pressure stays long # * enough, we'll start reporting primary # * button. We rely on the device continuing # * sending data even if finger does not # * move. # */ # if (!priv->press) { # priv->press_start = jiffies; # priv->press = true; # } else if (time_after(jiffies, # priv->press_start + # msecs_to_jiffies(50))) { # priv->report_press = true; # } # } else { # priv->press = false; # } # # hw->left = priv->report_press; # # } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { # /* # * Clickpad's button is transmitted as middle button, # * however, since it is primary button, we will report # * it as BTN_LEFT. # */ # hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; # # } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { # hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; # if (hw->w == 2) # hw->scroll = (signed char)(buf[1]); # } # # if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { # hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; # hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; # } # # if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 && # ((buf[0] ^ buf[3]) & 0x02)) { # synaptics_parse_ext_buttons(buf, priv, hw); # } def parse_agm(buf, w): agm = AGM() agm_packet_type = (buf[5] & 0x30) >> 4 if agm_packet_type == 1: # Gesture packet: (x, y, z) half resolution agm.w = w agm.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1 agm.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1 agm.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1 elif agm_packet_type == 2: # AGM-CONTACT packet: we are only interested in the count agm.agm_count = buf[1] return agm def process_synaptics_packet(time, buf): str_buf = ["{0:02x}".format(d) for d in buf] timestamp = "{0:02.06f}".format(time / 1000000) w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)) if w == 2: agm = parse_agm(buf, w) print(timestamp, str_buf, "w:", w, "(AGM)", "x:", agm.x, "y:", agm.y, "z:", agm.z) return x = (((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4]) y = (((buf[3] & 0x20) << 7) | ((buf[1] & 0xf0) << 4) | buf[5]) z = buf[2] # left = (buf[0] & 0x01) ? 1 : 0; # right = (buf[0] & 0x02) ? 1 : 0; print(timestamp, str_buf, "w:", w, "(SGM)", "x:", x, "y:", y, "z:", z) current_data = [] with open(sys.argv[1]) as f_in: request = False for line in f_in.readlines(): if line.startswith("S:"): print(line) continue if not line.startswith('E:'): continue e, time, r, data, rest = line.split(maxsplit=4) try: time = int(time) data = int(data, 16) except: continue if r == "S": request = True continue if r != "R": continue if request: request = False current_data = [] continue current_data.append(data) if len(current_data) == 6: process_synaptics_packet(time, current_data) current_data = []