Created
November 29, 2020 14:57
-
-
Save tsutsui/3859b59488d58da242d27ac15130e630 to your computer and use it in GitHub Desktop.
pseudo code to confirm how to apply emulation 3rd button code derived from xf86-input-mouse/dist/src/mouse.c to xorg-server/dist/hw/netbsd/x68k (and other DDX) server mouse drivers.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. | |
* Copyright 1993 by David Dawes <dawes@xfree86.org> | |
* Copyright 2002 by SuSE Linux AG, Author: Egbert Eich | |
* Copyright 1994-2002 by The XFree86 Project, Inc. | |
* Copyright 2002 by Paul Elliott | |
* | |
* Permission to use, copy, modify, distribute, and sell this software and its | |
* documentation for any purpose is hereby granted without fee, provided that | |
* the above copyright notice appear in all copies and that both that | |
* copyright notice and this permission notice appear in supporting | |
* documentation, and that the names of copyright holders not be | |
* used in advertising or publicity pertaining to distribution of the | |
* software without specific, written prior permission. The copyright holders | |
* make no representations about the suitability of this | |
* software for any purpose. It is provided "as is" without express or | |
* implied warranty. | |
* | |
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER | |
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF | |
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
* | |
*/ | |
#include "x68k.h" | |
#include "mi.h" | |
#include "input.h" | |
#include "inpututils.h" | |
#include "exevents.h" | |
#include "events.h" | |
#include "eventstr.h" | |
#include <X11/Xatom.h> | |
#include "xserver-properties.h" | |
#ifdef __NetBSD__ | |
#include <time.h> | |
#include <dev/wscons/wsconsio.h> | |
#include <sys/ioctl.h> | |
#endif | |
static CARD32 buttonTimer(DeviceInfoPtr device); | |
static void Emulate3ButtonsSetEnabled(DeviceInfoPtr device, Bool enable); | |
static Bool Emulate3ButtonsSoft(DeviceInfoPtr device); | |
static void MouseBlockHandler(void *data, void *waitTime); | |
static void MouseWakeupHandler(void *data, int i); | |
static void MouseDoPostEvent(DeviceInfoPtr device, int buttons, int dx, int dy); | |
/********************************************************************** | |
* | |
* Emulate3Button support code | |
* | |
**********************************************************************/ | |
/* | |
* Lets create a simple finite-state machine for 3 button emulation: | |
* | |
* We track buttons 1 and 3 (left and right). There are 11 states: | |
* 0 ground - initial state | |
* 1 delayed left - left pressed, waiting for right | |
* 2 delayed right - right pressed, waiting for left | |
* 3 pressed middle - right and left pressed, emulated middle sent | |
* 4 pressed left - left pressed and sent | |
* 5 pressed right - right pressed and sent | |
* 6 released left - left released after emulated middle | |
* 7 released right - right released after emulated middle | |
* 8 repressed left - left pressed after released left | |
* 9 repressed right - right pressed after released right | |
* 10 pressed both - both pressed, not emulating middle | |
* | |
* At each state, we need handlers for the following events | |
* 0: no buttons down | |
* 1: left button down | |
* 2: right button down | |
* 3: both buttons down | |
* 4: emulate3Timeout passed without a button change | |
* Note that button events are not deltas, they are the set of buttons being | |
* pressed now. It's possible (ie, mouse hardware does it) to go from (eg) | |
* left down to right down without anything in between, so all cases must be | |
* handled. | |
* | |
* a handler consists of three values: | |
* 0: action1 | |
* 1: action2 | |
* 2: new emulation state | |
* | |
* action > 0: ButtonPress | |
* action = 0: nothing | |
* action < 0: ButtonRelease | |
* | |
* The comment preceeding each section is the current emulation state. | |
* The comments to the right are of the form | |
* <button state> (<events>) -> <new emulation state> | |
* which should be read as | |
* If the buttons are in <button state>, generate <events> then go to | |
* <new emulation state>. | |
*/ | |
static const signed char stateTab[11][5][3] = { | |
/* 0 ground */ | |
{ | |
{ 0, 0, 0 }, /* nothing -> ground (no change) */ | |
{ 0, 0, 1 }, /* left -> delayed left */ | |
{ 0, 0, 2 }, /* right -> delayed right */ | |
{ 2, 0, 3 }, /* left & right (middle press) -> pressed middle */ | |
{ 0, 0, -1 } /* timeout N/A */ | |
}, | |
/* 1 delayed left */ | |
{ | |
{ 1, -1, 0 }, /* nothing (left event) -> ground */ | |
{ 0, 0, 1 }, /* left -> delayed left (no change) */ | |
{ 1, -1, 2 }, /* right (left event) -> delayed right */ | |
{ 2, 0, 3 }, /* left & right (middle press) -> pressed middle */ | |
{ 1, 0, 4 }, /* timeout (left press) -> pressed left */ | |
}, | |
/* 2 delayed right */ | |
{ | |
{ 3, -3, 0 }, /* nothing (right event) -> ground */ | |
{ 3, -3, 1 }, /* left (right event) -> delayed left (no change) */ | |
{ 0, 0, 2 }, /* right -> delayed right (no change) */ | |
{ 2, 0, 3 }, /* left & right (middle press) -> pressed middle */ | |
{ 3, 0, 5 }, /* timeout (right press) -> pressed right */ | |
}, | |
/* 3 pressed middle */ | |
{ | |
{ -2, 0, 0 }, /* nothing (middle release) -> ground */ | |
{ 0, 0, 7 }, /* left -> released right */ | |
{ 0, 0, 6 }, /* right -> released left */ | |
{ 0, 0, 3 }, /* left & right -> pressed middle (no change) */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
/* 4 pressed left */ | |
{ | |
{ -1, 0, 0 }, /* nothing (left release) -> ground */ | |
{ 0, 0, 4 }, /* left -> pressed left (no change) */ | |
{ -1, 0, 2 }, /* right (left release) -> delayed right */ | |
{ 3, 0, 10 }, /* left & right (right press) -> pressed both */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
/* 5 pressed right */ | |
{ | |
{ -3, 0, 0 }, /* nothing (right release) -> ground */ | |
{ -3, 0, 1 }, /* left (right release) -> delayed left */ | |
{ 0, 0, 5 }, /* right -> pressed right (no change) */ | |
{ 1, 0, 10 }, /* left & right (left press) -> pressed both */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
/* 6 released left */ | |
{ | |
{ -2, 0, 0 }, /* nothing (middle release) -> ground */ | |
{ -2, 0, 1 }, /* left (middle release) -> delayed left */ | |
{ 0, 0, 6 }, /* right -> released left (no change) */ | |
{ 1, 0, 8 }, /* left & right (left press) -> repressed left */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
/* 7 released right */ | |
{ | |
{ -2, 0, 0 }, /* nothing (middle release) -> ground */ | |
{ 0, 0, 7 }, /* left -> released right (no change) */ | |
{ -2, 0, 2 }, /* right (middle release) -> delayed right */ | |
{ 3, 0, 9 }, /* left & right (right press) -> repressed right */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
/* 8 repressed left */ | |
{ | |
{ -2, -1, 0 }, /* nothing (middle release, left release) -> ground */ | |
{ -2, 0, 4 }, /* left (middle release) -> pressed left */ | |
{ -1, 0, 6 }, /* right (left release) -> released left */ | |
{ 0, 0, 8 }, /* left & right -> repressed left (no change) */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
/* 9 repressed right */ | |
{ | |
{ -2, -3, 0 }, /* nothing (middle release, right release) -> ground */ | |
{ -3, 0, 7 }, /* left (right release) -> released right */ | |
{ -2, 0, 5 }, /* right (middle release) -> pressed right */ | |
{ 0, 0, 9 }, /* left & right -> repressed right (no change) */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
/* 10 pressed both */ | |
{ | |
{ -1, -3, 0 }, /* nothing (left release, right release) -> ground */ | |
{ -3, 0, 4 }, /* left (right release) -> pressed left */ | |
{ -1, 0, 5 }, /* right (left release) -> pressed right */ | |
{ 0, 0, 10 }, /* left & right -> pressed both (no change) */ | |
{ 0, 0, -1 }, /* timeout N/A */ | |
}, | |
}; | |
static CARD32 | |
buttonTimer(DeviceInfoPtr device) | |
{ | |
X68kMousePrivPtr pPriv; | |
sigset_t sigmask; | |
int id; | |
int type, button, flag; | |
ValuatorMask mask; | |
pPriv = device->public.devicePrivate; | |
(void)sigemptyset(&sigmask); | |
(void)sigaddset(&sigmask, SIGIO); | |
(void)sigprocmask(SIG_BLOCK, &sigmask, NULL); | |
pPriv->emulate3Pending = FALSE; | |
if ((id = stateTab[pPriv->emulateState][4][0]) != 0) { | |
button = abs(id); | |
type = (id >= 0) ? ButtonPress : ButtonRelease; | |
flag = POINTER_RELATIVE; | |
valuator_mask_zero(&mask); | |
QueuePointerEvents(device, type, button, flag, &mask); | |
pPriv->emulateState = stateTab[pPriv->emulateState][4][2]; | |
} else { | |
LogMessageVerbSigSafe(X_WARNING, -1, | |
"Got unexpected buttonTimer in state %d\n", pPriv->emulateState); | |
} | |
(void)sigprocmask(SIG_UNBLOCK, &sigmask, NULL); | |
return 0; | |
} | |
static void | |
Emulate3ButtonsSetEnabled(DeviceInfoPtr device, Bool enable) | |
{ | |
X68kMousePrivPtr pPriv = device->public.devicePrivate; | |
if (pPriv->emulate3Buttons == enable) | |
return; | |
pPriv->emulate3Buttons = enable; | |
if (enable) { | |
pPriv->emulateState = 0; | |
pPriv->emulate3Pending = FALSE; | |
pPriv->emulate3ButtonsSoft = FALSE; /* specifically requested now */ | |
RegisterBlockAndWakeupHandlers(MouseBlockHandler, MouseWakeupHandler, | |
(void *)device); | |
} else { | |
if (pPriv->emulate3Pending) | |
buttonTimer(device); | |
RemoveBlockAndWakeupHandlers(MouseBlockHandler, MouseWakeupHandler, | |
(void *)device); | |
} | |
} | |
static Bool | |
Emulate3ButtonsSoft(DeviceInfoPtr device) | |
{ | |
X68kMousePrivPtr pPriv; | |
pPriv = device->public.devicePrivate; | |
if (!pPriv->emulate3ButtonsSoft) | |
return TRUE; | |
#if defined(__NetBSD__) && defined(WSCONS_SUPPORT) | |
/* | |
* On NetBSD a wsmouse is a multiplexed device. Imagine a notebook | |
* with two-button mousepad, and an external USB mouse plugged in | |
* temporarily. After using button 3 on the external mouse and | |
* unplugging it again, the mousepad will still need to emulate | |
* 3 buttons. | |
*/ | |
return TRUE; | |
#else | |
LogMessageVerbSigSafe(X_INFO, 4, | |
"mouse: 3rd Button detected: disabling emulate3Button\n"); | |
Emulate3ButtonsSetEnabled(device, FALSE); | |
return FALSE; | |
#endif | |
} | |
static void | |
MouseBlockHandler(void *data, void *waitTime) | |
{ | |
DeviceInfoPtr device = data; | |
X68kMousePrivPtr pPriv = device->public.devicePrivate; | |
int ms; | |
if (pPriv->emulate3Pending) { | |
ms = pPriv->emulate3Expires - GetTimeInMillis(); | |
if (ms <= 0) | |
ms = 0; | |
AdjustWaitForDelay(waitTime, ms); | |
} | |
} | |
static void | |
MouseWakeupHandler(void *data, int i) | |
{ | |
DeviceInfoPtr device = data; | |
X68kMousePrivPtr pPriv = device->public.devicePrivate; | |
int ms; | |
if (pPriv->emulate3Pending) { | |
ms = pPriv->emulate3Expires - GetTimeInMillis(); | |
if (ms <= 0) | |
buttonTimer(device); | |
} | |
} | |
/******************************************************************* | |
* | |
* Post mouse events | |
* | |
*******************************************************************/ | |
static void | |
MouseDoPostEvent(DeviceInfoPtr device, int buttons, int dx, int dy) | |
{ | |
X68kMousePrivPtr pPriv; | |
int emulateButtons; | |
int id, change; | |
int ms; | |
int type, button; | |
ValuatorMask mask; | |
pPriv = device->public.devicePrivate; | |
change = buttons ^ pPriv->lastMappedButtons; | |
pPriv->lastMappedButtons = buttons; | |
if (pPriv->emulate3ButtonsSoft && pPriv->emulate3Pending && (dx || dy)) | |
buttonTimer(device); | |
if (dx || dy) { | |
type = MotionNotify; | |
flag = POINTER_RELATIVE | POINTER_ACCELERATE; | |
valuator[0] = dx; | |
valuator[1] = dy; | |
valuator_mask_set_range(&mask, 0, 2, valuators); | |
QueuePointerEvents(device, type, 0, flag, &mask); | |
} | |
if (change) { | |
if (pPriv->emulate3Buttons | |
&& (!(buttons & 0x02) || Emulate3ButtonsSoft(device))) { | |
/* handle all but buttons 1 & 3 normally */ | |
change &= ~(0x01 | 0x04); | |
/* emulate the third button by the other two */ | |
emulateButtons = (buttons & 0x01) | ((buttons & 0x04) >> 1); | |
if ((id = stateTab[pPriv->emulateState][emulateButtons][0]) != 0) { | |
button = abs(id); | |
type = (id >= 0) ? ButtonPress : ButtonRelease; | |
flag = POINTER_RELATIVE; | |
valuator_mask_zero(&mask); | |
QueuePointerEvents(device, type, button, flag, &mask); | |
} | |
if ((id = stateTab[pPriv->emulateState][emulateButtons][1]) != 0) { | |
button = abs(id); | |
type = (id >= 0) ? ButtonPress : ButtonRelease; | |
flag = POINTER_RELATIVE; | |
valuator_mask_zero(&mask); | |
QueuePointerEvents(device, type, button, flag, &mask); | |
} | |
pPriv->emulateState = | |
stateTab[pPriv->emulateState][emulateButtons][2]; | |
if (stateTab[pPriv->emulateState][4][0] != 0) { | |
pPriv->emulate3Expires = | |
GetTimeInMillis() + pPriv->emulate3Timeout; | |
pPriv->emulate3Pending = TRUE; | |
} else { | |
pPriv->emulate3Pending = FALSE; | |
} | |
} | |
while (change) { | |
id = ffs(change); | |
change &= ~(1 << (id - 1)); | |
button = id; | |
type = (buttons & (1 << (id - 1))) ? ButtonPress : ButtonRelease; | |
flag = POINTER_RELATIVE; | |
valuator_mask_zero(&mask); | |
QueuePointerEvents(device, type, button, flag, &mask); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment