summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Coopersmith <alan.coopersmith@oracle.com>2022-11-09 16:27:42 -0800
committerAlan Coopersmith <alan.coopersmith@oracle.com>2022-11-09 16:27:42 -0800
commitcd5b383c3f6c5b7ffa19f8e6ebb7d6551898a98b (patch)
treeefdbcd28ac148addd65f5cf58c50be11d59c4f2e
parent5f63ab04338fd811c610ae7617757ede52471316 (diff)
sun_mouse: Add RelToAbs option to convert relative events to absolute
Enabled automatically for the Sun ILOM device, to avoid acceleration that causes the Remote KVMS mouse cursor to become unaligned with the X mouse cursor. Code originally written by david.m.marx@oracle.com in 2013 to fix Oracle bug 15798251 - SUNBT7177072 "actual mouse pointer is off from the cursor on remote window" Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
-rw-r--r--src/sun_mouse.c169
1 files changed, 167 insertions, 2 deletions
diff --git a/src/sun_mouse.c b/src/sun_mouse.c
index d7c534e..3539ba7 100644
--- a/src/sun_mouse.c
+++ b/src/sun_mouse.c
@@ -76,6 +76,8 @@
# include <sys/vuid_wheel.h>
#endif
+#include <libdevinfo.h>
+
/* Support for scaling absolute coordinates to screen size in
* Solaris 10 updates and beyond */
#if !defined(HAVE_ABSOLUTE_MOUSE_SCALING)
@@ -111,6 +113,9 @@ typedef struct _VuidMseRec {
Ms_screen_resolution absres;
#endif
OsTimerPtr remove_timer; /* Callback for removal on ENODEV */
+ int relToAbs;
+ int absX;
+ int absY;
} VuidMseRec, *VuidMsePtr;
static VuidMsePtr vuidMouseList = NULL;
@@ -118,6 +123,9 @@ static VuidMsePtr vuidMouseList = NULL;
static int vuidMouseProc(DeviceIntPtr pPointer, int what);
static void vuidReadInput(InputInfoPtr pInfo);
+static int CheckRelToAbs(InputInfoPtr pInfo);
+static int CheckRelToAbsWalker(di_node_t node, void *arg);
+
#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
# include "compat-api.h"
@@ -226,6 +234,11 @@ vuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
pVuidMse->buffer = (unsigned char *)&pVuidMse->event;
pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL);
+ pVuidMse->relToAbs = xf86SetIntOption(pInfo->options, "RelToAbs", -1);
+ if (pVuidMse->relToAbs == -1)
+ pVuidMse->relToAbs = CheckRelToAbs(pInfo);
+ pVuidMse->absX = 0;
+ pVuidMse->absY = 0;
/* Setup the local procs. */
pVuidMse->wrapped_device_control = pInfo->device_control;
@@ -247,6 +260,120 @@ vuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
return TRUE;
}
+/*
+ * It seems that the mouse that is presented by the Emulex ILOM
+ * device (USB 0x430, 0xa101 and USB 0x430, 0xa102) sends relative
+ * mouse movements. But relative mouse movements are subject to
+ * acceleration. This causes the position indicated on the ILOM
+ * window to not match what the Xorg server actually has. This
+ * makes the mouse in this environment rather unusable. So, for the
+ * Emulex ILOM device, we will change all relative mouse movements
+ * into absolute mouse movements, making it appear more like a
+ * tablet. This will not be subject to acceleration, and this
+ * should keep the ILOM window and Xorg server with the same values
+ * for the coordinates of the mouse.
+ */
+
+typedef struct reltoabs_match {
+ int matched;
+ char const *matchname;
+ } reltoabs_match_t;
+
+/* Sun Microsystems, keyboard / mouse */
+#define RELTOABS_MATCH1 "usbif430,a101.config1.1"
+/* Sun Microsystems, keyboard / mouse / storage */
+#define RELTOABS_MATCH2 "usbif430,a102.config1.1"
+
+static int
+CheckRelToAbsWalker(di_node_t node, void *arg)
+{
+ di_minor_t minor;
+ char *path;
+ int numvalues;
+ int valueon;
+ char const *stringptr;
+ int status;
+ reltoabs_match_t *const matchptr = (reltoabs_match_t *)arg;
+ char *stringvalues;
+
+ for (minor = di_minor_next(node, DI_MINOR_NIL);
+ minor != DI_MINOR_NIL;
+ minor = di_minor_next(node, minor)) {
+ path = di_devfs_minor_path(minor);
+ status = path != NULL && strcmp(path, matchptr -> matchname) == 0;
+ di_devfs_path_free(path);
+ if (status)
+ break;
+ }
+
+ if (minor == DI_MINOR_NIL)
+ return (DI_WALK_CONTINUE);
+
+ numvalues = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ "compatible", &stringvalues);
+ if (numvalues <= 0)
+ return (DI_WALK_CONTINUE);
+
+ for (valueon = 0, stringptr = stringvalues; valueon < numvalues;
+ valueon++, stringptr += strlen(stringptr) + 1) {
+ if (strcmp(stringptr, RELTOABS_MATCH1) == 0) {
+ matchptr -> matched = 1;
+ return (DI_WALK_TERMINATE);
+ }
+ if (strcmp(stringptr, RELTOABS_MATCH2) == 0) {
+ matchptr -> matched = 2;
+ return (DI_WALK_TERMINATE);
+ }
+ }
+ return (DI_WALK_CONTINUE);
+}
+
+static int
+CheckRelToAbs(InputInfoPtr pInfo)
+{
+ char const *device;
+ char const *matchname;
+ ssize_t readstatus;
+ di_node_t node;
+ struct stat statbuf;
+ char linkname[512];
+ reltoabs_match_t reltoabs_match;
+
+ device = xf86CheckStrOption(pInfo->options, "Device", NULL);
+ if (device == NULL)
+ return (0);
+
+ matchname = device;
+
+ if (lstat(device, &statbuf) == 0 &&
+ (statbuf.st_mode & S_IFMT) == S_IFLNK) {
+ readstatus = readlink(device, linkname, sizeof(linkname));
+ if (readstatus > 0 && readstatus < (ssize_t) sizeof(linkname)) {
+ linkname[readstatus] = 0;
+ matchname = linkname;
+ if (strncmp(matchname, "../..", sizeof("../..") - 1) == 0)
+ matchname += sizeof("../..") - 1;
+ }
+ }
+
+ if (strncmp(matchname, "/devices", sizeof("/devices") - 1) == 0)
+ matchname += sizeof("/devices") - 1;
+
+ reltoabs_match.matched = 0;
+ reltoabs_match.matchname = matchname;
+
+ node = di_init("/", DINFOCPYALL);
+ if (node == DI_NODE_NIL)
+ return (0);
+
+ di_walk_node(node, DI_WALK_CLDFIRST, (void *)&reltoabs_match,
+ CheckRelToAbsWalker);
+
+ di_fini(node);
+
+ return (reltoabs_match.matched != 0);
+}
+
static void
vuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY,
Bool *absXset, Bool *absYset)
@@ -289,7 +416,9 @@ vuidReadInput(InputInfoPtr pInfo)
ssize_t n;
unsigned char *pBuf;
int absX = 0, absY = 0;
+ int hdisplay = 0, vdisplay = 0;
Bool absXset = FALSE, absYset = FALSE;
+ int relToAbs;
pMse = pInfo->private;
buttons = pMse->lastButtons;
@@ -299,6 +428,18 @@ vuidReadInput(InputInfoPtr pInfo)
return;
}
pBuf = pVuidMse->buffer;
+ relToAbs = pVuidMse->relToAbs;
+ if (relToAbs) {
+ ScreenPtr pScreen = miPointerGetScreen(pInfo->dev);
+ ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
+
+ if (pScr->currentMode) {
+ hdisplay = pScr->currentMode->HDisplay;
+ vdisplay = pScr->currentMode->VDisplay;
+ }
+ absX = pVuidMse->absX;
+ absY = pVuidMse->absY;
+ }
do {
n = read(pInfo->fd, pBuf, sizeof(Firm_event));
@@ -358,10 +499,34 @@ vuidReadInput(InputInfoPtr pInfo)
int delta = pVuidMse->event.value;
switch(pVuidMse->event.id) {
case LOC_X_DELTA:
- dx += delta;
+ if (!relToAbs)
+ dx += delta;
+ else {
+ if (absXset)
+ vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
+ absX += delta;
+ if (absX < 0)
+ absX = 0;
+ else if (absX >= hdisplay && hdisplay > 0)
+ absX = hdisplay - 1;
+ pVuidMse->absX = absX;
+ absXset = TRUE;
+ }
break;
case LOC_Y_DELTA:
- dy -= delta;
+ if (!relToAbs)
+ dy -= delta;
+ else {
+ if (absYset)
+ vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
+ absY -= delta;
+ if (absY < 0)
+ absY = 0;
+ else if (absY >= vdisplay && vdisplay > 0)
+ absY = vdisplay - 1;
+ pVuidMse->absY = absY;
+ absYset = TRUE;
+ }
break;
case LOC_X_ABSOLUTE:
if (absXset) {