From 75ab57efed93204659c626fa8d5aa94837984de4 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 13 Jan 2014 17:50:12 +0100 Subject: [PATCH] Fix T38190: Linux tablet: Issue with XInput/GHOST? With edits by Campbell, thanks! Looks like in some cases (driver dependent?), `XDeviceMotionEvent` get generated with only part of expected data (e.g. only x coordinate, only pressure, etc.), data which did not change since last event being NULL. We know which data to actually handle with `XDeviceMotionEvent.first_axis` and `XDeviceMotionEvent.axes_count` values. Reviewed by: campbellbarton Differential Revision: https://developer.blender.org/D208 --- intern/ghost/intern/GHOST_SystemX11.cpp | 39 ++++++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 3b12d917ced..1d625a5329f 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -1148,21 +1148,44 @@ GHOST_SystemX11::processEvent(XEvent *xe) #ifdef WITH_X11_XINPUT if (xe->type == m_xtablet.MotionEvent) { XDeviceMotionEvent *data = (XDeviceMotionEvent *)xe; + const unsigned char axis_first = data->first_axis; + const unsigned char axes_end = axis_first + data->axes_count; /* after the last */ + int axis_value; /* stroke might begin without leading ProxyIn event, * this happens when window is opened when stylus is already hovering * around tablet surface */ setTabletMode(this, window, data->deviceid); - window->GetTabletData()->Pressure = - data->axis_data[2] / ((float)m_xtablet.PressureLevels); + /* Note: This event might be generated with incomplete dataset (don't exactly know why, looks like in + * some cases, if the value does not change, it is not included in subsequent XDeviceMotionEvent + * events). So we have to check which values this event actually contains! + */ + +#define AXIS_VALUE_GET(axis, val) ((axis_first <= axis && axes_end > axis) && ((void)(val = data->axis_data[axis]), true)) + + if (AXIS_VALUE_GET(2, axis_value)) { + window->GetTabletData()->Pressure = axis_value / ((float)m_xtablet.PressureLevels); + } + + /* the (short) cast and the & 0xffff is bizarre and unexplained anywhere, + * but I got garbage data without it. Found it in the xidump.c source --matt + * + * The '& 0xffff' just truncates the value to its two lowest bytes, this probably means + * some drivers do not properly set the whole int value? Since we convert to float afterward, + * I don't think we need to cast to short here, but do not have a device to check this. --mont29 + */ + if (AXIS_VALUE_GET(3, axis_value)) { + window->GetTabletData()->Xtilt = (short)(axis_value & 0xffff) / + ((float)m_xtablet.XtiltLevels); + } + if (AXIS_VALUE_GET(4, axis_value)) { + window->GetTabletData()->Ytilt = (short)(axis_value & 0xffff) / + ((float)m_xtablet.YtiltLevels); + } + +#undef AXIS_VALUE_GET - /* the (short) cast and the &0xffff is bizarre and unexplained anywhere, - * but I got garbage data without it. Found it in the xidump.c source --matt */ - window->GetTabletData()->Xtilt = - (short)(data->axis_data[3] & 0xffff) / ((float)m_xtablet.XtiltLevels); - window->GetTabletData()->Ytilt = - (short)(data->axis_data[4] & 0xffff) / ((float)m_xtablet.YtiltLevels); } else if (xe->type == m_xtablet.ProxInEvent) { XProximityNotifyEvent *data = (XProximityNotifyEvent *)xe;