Skip to content

Instantly share code, notes, and snippets.

@tsutsui
Last active February 5, 2021 14:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsutsui/6ebe82d74b11874b92b167769c312d52 to your computer and use it in GitHub Desktop.
Save tsutsui/6ebe82d74b11874b92b167769c312d52 to your computer and use it in GitHub Desktop.
WIP "Emulate3Buttons" for 2 button mice on NetBSD/x68k Xorg 1.20 based X68k Xserver
Index: sys/arch/x68k/dev/ms.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x68k/dev/ms.c,v
retrieving revision 1.34
diff -u -p -d -r1.34 ms.c
--- sys/arch/x68k/dev/ms.c 25 Jul 2014 08:10:35 -0000 1.34
+++ sys/arch/x68k/dev/ms.c 5 Feb 2021 11:40:09 -0000
@@ -356,8 +356,8 @@ ms_input(struct ms_softc *ms, int c)
{
struct firm_event *fe;
int mb, ub, d, get, put, any;
- static const char to_one[] = { 1, 2, 3 };
- static const int to_id[] = { MS_LEFT, MS_RIGHT, MS_MIDDLE };
+ static const char to_one[] = { 1, 2, 2 };
+ static const int to_id[] = { MS_LEFT, MS_RIGHT };
/*
* Discard input if not ready. Drop sync on parity or framing
@@ -430,12 +430,12 @@ ms_input(struct ms_softc *ms, int c)
ub = ms->ms_ub;
while ((d = mb ^ ub) != 0) {
/*
- * Mouse button change. Convert up to three changes
+ * Mouse button change. Convert up to two changes
* to the `first' change, and drop it into the event queue.
*/
NEXT;
- d = to_one[d - 1]; /* from 1..7 to {1,2,4} */
- fe->id = to_id[d - 1]; /* from {1,2,4} to ID */
+ d = to_one[d - 1]; /* from 1..3 to {1,2} */
+ fe->id = to_id[d - 1]; /* from {1,2} to ID */
fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
firm_gettime(fe);
ADVANCE;
Index: external/mit/xorg/server/xorg-server/hw/netbsd/x68k/Makefile
===================================================================
RCS file: /cvsroot/src/external/mit/xorg/server/xorg-server/hw/netbsd/x68k/Makefile,v
retrieving revision 1.9
diff -u -p -d -r1.9 Makefile
--- external/mit/xorg/server/xorg-server/hw/netbsd/x68k/Makefile 5 Aug 2020 15:48:09 -0000 1.9
+++ external/mit/xorg/server/xorg-server/hw/netbsd/x68k/Makefile 5 Feb 2021 11:40:09 -0000
@@ -18,6 +18,7 @@ WARNS?= 2
.PATH: ${X11SRCDIR.xorg-server}/hw/netbsd/x68k
SRCS= x68kInit.c x68kConfig.c x68kIo.c x68kMouse.c x68kKbd.c x68kKeyMap.c \
x68kFb.c x68kGraph.c x68kText.c
+SRCS+= mouseEmu3btn.c
.PATH: ${X11SRCDIR.xorg-server}/Xi
SRCS+= stubs.c
? external/mit/xorg-server/dist/hw/netbsd/x68k/mouseEmu3btn.c
? external/mit/xorg-server/dist/hw/netbsd/x68k/mouseEmu3btn.h
Index: external/mit/xorg-server/dist/hw/netbsd/x68k/x68k.h
===================================================================
RCS file: /cvsroot/xsrc/external/mit/xorg-server/dist/hw/netbsd/x68k/x68k.h,v
retrieving revision 1.6
diff -u -p -d -r1.6 x68k.h
--- external/mit/xorg-server/dist/hw/netbsd/x68k/x68k.h 3 Nov 2020 15:52:57 -0000 1.6
+++ external/mit/xorg-server/dist/hw/netbsd/x68k/x68k.h 5 Feb 2021 14:35:37 -0000
@@ -64,6 +64,7 @@
#include <mipointer.h>
#include "x68kReg.h"
+#include "mouseEmu3btn.h"
/*
* X68k dependent screen record
@@ -106,6 +107,7 @@ typedef struct _X68kFbProcRec {
typedef struct _X68kMousePriv {
int fd;
int bmask;
+ MouseEmu3btn emu3btn;
} X68kMousePriv, *X68kMousePrivPtr;
typedef struct _X68kKbdPriv {
Index: external/mit/xorg-server/dist/hw/netbsd/x68k/x68kMouse.c
===================================================================
RCS file: /cvsroot/xsrc/external/mit/xorg-server/dist/hw/netbsd/x68k/x68kMouse.c,v
retrieving revision 1.8
diff -u -p -d -r1.8 x68kMouse.c
--- external/mit/xorg-server/dist/hw/netbsd/x68k/x68kMouse.c 20 Nov 2020 19:06:56 -0000 1.8
+++ external/mit/xorg-server/dist/hw/netbsd/x68k/x68kMouse.c 5 Feb 2021 14:35:37 -0000
@@ -128,6 +128,9 @@ x68kMouseProc(DeviceIntPtr device, int w
BYTE map[4];
Atom btn_labels[3] = {0};
Atom axes_labels[2] = { 0, 0 };
+ MouseEmu3btnPtr pEmu3btn;
+ Bool emu3enable;
+ int emu3timeout;
switch (what) {
case DEVICE_INIT:
@@ -149,6 +152,15 @@ x68kMouseProc(DeviceIntPtr device, int w
InitPointerDeviceStruct(pMouse, map, 3, btn_labels,
x68kMouseCtrl, GetMotionHistorySize(),
2, axes_labels);
+
+ /* Initialize emulation 3 buttons settings */
+ emu3enable = TRUE; /* XXX should be configurable */
+ emu3timeout = EMU3B_DEF_TIMEOUT; /* XXX should be configurable */
+ if (emu3enable) {
+ pEmu3btn = &x68kMousePriv.emu3btn;
+ Emulate3ButtonsEnable(pEmu3btn, device, emu3timeout);
+ }
+
break;
case DEVICE_ON:
@@ -279,10 +291,14 @@ x68kMouseEnqueueEvent(DeviceIntPtr devic
* for a single state change. Should we get a button event which
* reflects the current state of affairs, that event is discarded.
*
- * Mouse buttons start at 1.
+ * Mouse buttons start at 1 as defined in <X11/X.h>.
+ *
+ * The bmask stores which buttons are currently pressed.
+ * This bmask is also used for Emulate3Buttons functions that
+ * assume the left button is LSB as defined in mouseEmu3btn.c.
*/
buttons = (fe->id - MS_LEFT) + 1;
- bmask = 1 << buttons;
+ bmask = 1 << (buttons - 1);
if (fe->value == VKEY_UP) {
if (pPriv->bmask & bmask) {
type = ButtonRelease;
@@ -298,9 +314,14 @@ x68kMouseEnqueueEvent(DeviceIntPtr devic
return;
}
}
- flag = POINTER_RELATIVE;
- valuator_mask_zero(&mask);
- QueuePointerEvents(device, type, buttons, flag, &mask);
+ if (buttons == Button1 || buttons == Button3) {
+ /* Handle middle button emulation */
+ Emulate3ButtonsQueueEvent(&pPriv->emu3btn, type, buttons, pPriv->bmask);
+ } else {
+ flag = POINTER_RELATIVE;
+ valuator_mask_zero(&mask);
+ QueuePointerEvents(device, type, buttons, flag, &mask);
+ }
break;
case LOC_X_DELTA:
valuators[0] = fe->value;
--- /dev/null 2021-02-05 23:23:05.873690181 +0900
+++ external/mit/xorg-server/dist/hw/netbsd/x68k/mouseEmu3btn.c 2021-02-05 20:09:13.635358094 +0900
@@ -0,0 +1,773 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/*
+ * 3 button emulation stuff
+ * based on the emulation method in xf86-input-mouse/dist/src/mouse.c
+ */
+
+#include "inpututils.h"
+#include "mouseEmu3btn.h"
+
+static CARD32 buttonTimer(MouseEmu3btnPtr pEmu3btn);
+static void Emulate3ButtonsSetEnabled(MouseEmu3btnPtr pEmu3btn, Bool enable);
+static Bool Emulate3ButtonsSoft(MouseEmu3btnPtr pEmu3btn);
+
+static void MouseBlockHandler(void *data, void *waitTime);
+static void MouseWakeupHandler(void *data, int i);
+
+/**********************************************************************
+ *
+ * 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
+ */
+#define ST_INVALID -1
+#define ST_GROUND 0 /* initial state */
+#define ST_DELAYED_LEFT 1 /* left pressed and waiting timeout */
+#define ST_DELAYED_RIGHT 2 /* right pressed and waiting timeout */
+#define ST_PRESSED_MIDDLE 3 /* middle pressed deteremined */
+#define ST_PRESSED_LEFT 4 /* left pressed determined */
+#define ST_PRESSED_RIGHT 5 /* right pressed determined */
+#define ST_RELEASED_LEFT 6 /* left released after pressed both */
+#define ST_RELEASED_RIGHT 7 /* right released after pressed both */
+#define ST_REPRESSED_LEFT 8 /* left repressed after release */
+#define ST_REPRESSED_RIGHT 9 /* right repressed after release */
+#define ST_PRESSED_BOTH 10 /* both pressed (not as middle) */
+#define NSTATES 11
+
+/*
+ * 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
+ */
+struct button_event {
+ int type; /* ButtonNone / ButtonPress / ButtonRelease */
+#define ButtonNone 0
+ int button;
+#define ButtonLeft Button1
+#define ButtonMiddle Button2
+#define ButtonRight Button3
+};
+
+struct button_action {
+ struct button_event event1;
+ struct button_event event2;
+ int new_state;
+};
+
+/* The set of buttons being pressed passed from DDX mouse events */
+#define BMASK_LEFT 0x01
+#define BMASK_MIDDLE 0x02
+#define BMASK_RIGHT 0x04
+
+/* Event index values per buttons being pressed */
+#define EMU_BUTTONS_NONE 0
+#define EMU_BUTTONS_LEFT 1
+#define EMU_BUTTONS_RIGHT 2
+#define EMU_BUTTONS_BOTH 3
+#define NEMU_BUTTONSTATE 4
+
+#define BMASKTOINDEX(bmask) \
+ ((((bmask) & BMASK_RIGHT) >> 1) | ((bmask) & BMASK_LEFT))
+
+struct button_state {
+ struct button_action buttons[NEMU_BUTTONSTATE];
+ struct button_action timeout;
+};
+
+/*
+ * 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 struct button_state stateTab[NSTATES] = {
+
+ /* 0 ground - initial state */
+ [ST_GROUND] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing -> ground (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left -> delayed left */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right -> delayed right */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right (middle press) -> pressed middle */
+ .event1 = { ButtonPress, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_MIDDLE,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 1 delayed left - left pressed, waiting for right */
+ [ST_DELAYED_LEFT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (left event) -> ground */
+ .event1 = { ButtonPress, ButtonLeft },
+ .event2 = { ButtonRelease, ButtonLeft },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left -> delayed left (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right (left event) -> delayed right */
+ .event1 = { ButtonPress, ButtonLeft },
+ .event2 = { ButtonRelease, ButtonLeft },
+ .new_state = ST_DELAYED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right (middle press) -> pressed middle */
+ .event1 = { ButtonPress, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_MIDDLE,
+ },
+
+ .timeout = {
+ /* timeout (left press) -> pressed left */
+ .event1 = { ButtonPress, ButtonLeft },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_LEFT,
+ },
+ },
+
+ /* 2 delayed right - right pressed, waiting for left */
+ [ST_DELAYED_RIGHT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (right event) -> ground */
+ .event1 = { ButtonPress, ButtonRight },
+ .event2 = { ButtonRelease, ButtonRight },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left (right event) -> delayed left */
+ .event1 = { ButtonPress, ButtonRight },
+ .event2 = { ButtonRelease, ButtonRight },
+ .new_state = ST_DELAYED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right -> delayed right (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right (middle press) -> pressed middle */
+ .event1 = { ButtonPress, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_MIDDLE,
+ },
+
+ .timeout = {
+ /* timeout (right press) -> pressed right */
+ .event1 = { ButtonPress, ButtonRight },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_RIGHT,
+ },
+ },
+
+ /* 3 pressed middle - right and left pressed, emulated middle sent */
+ [ST_PRESSED_MIDDLE] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (middle release) -> ground */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left -> released right */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_RELEASED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right -> released left */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_RELEASED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right -> pressed middle (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_MIDDLE,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 4 pressed left - left pressed and sent */
+ [ST_PRESSED_LEFT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (left release) -> ground */
+ .event1 = { ButtonRelease, ButtonLeft },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left -> pressed left (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right (left release) -> delayed right */
+ .event1 = { ButtonRelease, ButtonLeft },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right (right press) -> pressed both */
+ .event1 = { ButtonPress, ButtonRight },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_BOTH,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 5 pressed right - right pressed and sent */
+ [ST_PRESSED_RIGHT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (right release) -> ground */
+ .event1 = { ButtonRelease, ButtonRight },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left (right release) -> delayed left */
+ .event1 = { ButtonRelease, ButtonRight },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right -> pressed right (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right (left press) -> pressed both */
+ .event1 = { ButtonPress, ButtonLeft },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_BOTH,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 6 released left - left released after emulated middle */
+ [ST_RELEASED_LEFT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (middle release) -> ground */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left (middle release) -> delayed left */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right -> released left (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_RELEASED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right (left press) -> repressed left */
+ .event1 = { ButtonPress, ButtonLeft },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_REPRESSED_LEFT,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 7 released right - right released after emulated middle */
+ [ST_RELEASED_RIGHT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (middle release) -> ground */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left -> released right (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_RELEASED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right (middle release) -> delayed right */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_DELAYED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right (right press) -> repressed right */
+ .event1 = { ButtonPress, ButtonRight },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_REPRESSED_RIGHT,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 8 repressed left - left pressed after released left */
+ [ST_REPRESSED_LEFT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (middle release, left release) -> ground */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonRelease, ButtonLeft },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left (middle release) -> pressed left */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right (left release) -> released left */
+ .event1 = { ButtonRelease, ButtonLeft },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_RELEASED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right -> repressed left (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_REPRESSED_LEFT,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 9 repressed right - right pressed after released right */
+ [ST_REPRESSED_RIGHT] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (middle release, right release) -> ground */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonRelease, ButtonRight },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left (right release) -> released right */
+ .event1 = { ButtonRelease, ButtonRight },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_RELEASED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right (middle release) -> pressed right */
+ .event1 = { ButtonRelease, ButtonMiddle },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right -> repressed right (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_REPRESSED_RIGHT,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+
+ /* 10 pressed both - both pressed, not emulating middle */
+ [ST_PRESSED_BOTH] = {
+
+ .buttons[EMU_BUTTONS_NONE] = {
+ /* nothing (left release, right release) -> ground */
+ .event1 = { ButtonRelease, ButtonLeft },
+ .event2 = { ButtonRelease, ButtonRight },
+ .new_state = ST_GROUND,
+ },
+
+ .buttons[EMU_BUTTONS_LEFT] = {
+ /* left (right release) -> pressed left */
+ .event1 = { ButtonRelease, ButtonRight },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_LEFT,
+ },
+
+ .buttons[EMU_BUTTONS_RIGHT] = {
+ /* right (left release) -> pressed right */
+ .event1 = { ButtonRelease, ButtonLeft },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_RIGHT,
+ },
+
+ .buttons[EMU_BUTTONS_BOTH] = {
+ /* left & right -> pressed both (no change) */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_PRESSED_BOTH,
+ },
+
+ .timeout = {
+ /* timeout N/A */
+ .event1 = { ButtonNone, 0 },
+ .event2 = { ButtonNone, 0 },
+ .new_state = ST_INVALID,
+ },
+ },
+};
+
+static CARD32
+buttonTimer(MouseEmu3btnPtr pEmu3btn)
+{
+ sigset_t sigmask;
+ int type, button, flag;
+ ValuatorMask mask;
+ const struct button_action *timeout_action;
+
+ (void)sigemptyset(&sigmask);
+ (void)sigaddset(&sigmask, SIGIO);
+ (void)sigprocmask(SIG_BLOCK, &sigmask, NULL);
+
+ pEmu3btn->emulate3Pending = FALSE;
+ timeout_action = &stateTab[pEmu3btn->emulateState].timeout;
+ if ((type = timeout_action->event1.type) != ButtonNone) {
+ button = timeout_action->event1.button;
+ flag = POINTER_RELATIVE;
+ valuator_mask_zero(&mask);
+ QueuePointerEvents(pEmu3btn->device, type, button, flag, &mask);
+ pEmu3btn->emulateState = timeout_action->new_state;
+ } else {
+ LogMessageVerbSigSafe(X_WARNING, -1,
+ "Got unexpected buttonTimer in state %d\n", pEmu3btn->emulateState);
+ }
+
+ (void)sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
+ return 0;
+}
+
+static void
+Emulate3ButtonsSetEnabled(MouseEmu3btnPtr pEmu3btn, Bool enable)
+{
+
+ if (pEmu3btn->emulate3Buttons == enable)
+ return;
+
+ pEmu3btn->emulate3Buttons = enable;
+
+ if (enable) {
+ pEmu3btn->emulateState = ST_GROUND;
+ pEmu3btn->emulate3Pending = FALSE;
+ pEmu3btn->emulate3ButtonsSoft = FALSE; /* specifically requested now */
+
+ RegisterBlockAndWakeupHandlers(MouseBlockHandler, MouseWakeupHandler,
+ (void *)pEmu3btn);
+ } else {
+ if (pEmu3btn->emulate3Pending)
+ buttonTimer(pEmu3btn);
+
+ RemoveBlockAndWakeupHandlers(MouseBlockHandler, MouseWakeupHandler,
+ (void *)pEmu3btn);
+ }
+}
+
+static Bool
+Emulate3ButtonsSoft(MouseEmu3btnPtr pEmu3btn)
+{
+
+ if (!pEmu3btn->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(pEmu3btn, FALSE);
+
+ return FALSE;
+#endif
+}
+
+static void
+MouseBlockHandler(void *data, void *waitTime)
+{
+ MouseEmu3btnPtr pEmu3btn = data;
+ int ms;
+
+ if (pEmu3btn->emulate3Pending) {
+ ms = pEmu3btn->emulate3Expires - GetTimeInMillis();
+ if (ms <= 0)
+ ms = 0;
+ AdjustWaitForDelay(waitTime, ms);
+ }
+}
+
+static void
+MouseWakeupHandler(void *data, int i)
+{
+ MouseEmu3btnPtr pEmu3btn = data;
+ int ms;
+
+ if (pEmu3btn->emulate3Pending) {
+ ms = pEmu3btn->emulate3Expires - GetTimeInMillis();
+ if (ms <= 0)
+ buttonTimer(pEmu3btn);
+ }
+}
+
+/*******************************************************************
+ * function "Emulate3ButtonsEnable"
+ *
+ * purpose:
+ * Enable and initialize Emulate3Buttons structures.
+ * argument:
+ * (MouseEmu3btnPtr)pEmu3btn : Emu3btn private record
+ * (DeviceIntPtr)device : pointer device private record
+ * (int)timeout : timeout to wait another button [ms]
+ *
+ *******************************************************************/
+void
+Emulate3ButtonsEnable(MouseEmu3btnPtr pEmu3btn, DeviceIntPtr device, int timeout)
+{
+
+ BUG_RETURN_MSG(device == NULL, "Invalid DeviceIntPtr.\n");
+
+ if (timeout <= 0) {
+ timeout = EMU3B_DEF_TIMEOUT;
+ }
+ pEmu3btn->device = device;
+ pEmu3btn->emulate3Timeout = timeout;
+
+ Emulate3ButtonsSetEnabled(pEmu3btn, TRUE);
+}
+
+/*******************************************************************
+ * function "Emulate3ButtonsQueueEvent"
+ *
+ * purpose:
+ * Emulate middle button per left/right button events and post events.
+ * argument:
+ * (MouseEmu3btnPtr)pEmu3btn : Emu3btn private record
+ * (int)type : event (ButtonPress / ButtonRelease)
+ * (int)buttons : button (Button1 / Button2 / Button3)
+ * (int)bmask : buttons being pressed (0x1:left / 0x4:right)
+ *
+ *******************************************************************/
+
+void
+Emulate3ButtonsQueueEvent(MouseEmu3btnPtr pEmu3btn, int type, int buttons, int bmask)
+{
+ DeviceIntPtr device = pEmu3btn->device;
+ int emulateButtons;
+ int button, flag;
+ ValuatorMask mask;
+
+ BUG_RETURN_MSG(buttons != ButtonLeft && buttons != ButtonRight,
+ "not left or right button event\n");
+
+ if (pEmu3btn->emulate3ButtonsSoft && pEmu3btn->emulate3Pending)
+ buttonTimer(pEmu3btn);
+
+ if (pEmu3btn->emulate3Buttons
+ && ((bmask & BMASK_MIDDLE) == 0 || Emulate3ButtonsSoft(pEmu3btn))) {
+ const struct button_action *button_action, *timeout_action;
+
+ /* emulate the third button by the other two */
+
+ emulateButtons = BMASKTOINDEX(bmask);
+ button_action =
+ &stateTab[pEmu3btn->emulateState].buttons[emulateButtons];
+
+ if ((type = button_action->event1.type) != ButtonNone) {
+ button = button_action->event1.button;
+ flag = POINTER_RELATIVE;
+ valuator_mask_zero(&mask);
+ QueuePointerEvents(device, type, button, flag, &mask);
+ }
+ if ((type = button_action->event2.type) != ButtonNone) {
+ button = button_action->event2.button;
+ flag = POINTER_RELATIVE;
+ valuator_mask_zero(&mask);
+ QueuePointerEvents(device, type, button, flag, &mask);
+ }
+
+ pEmu3btn->emulateState = button_action->new_state;
+
+ timeout_action = &stateTab[pEmu3btn->emulateState].timeout;
+ if (timeout_action->event1.type != ButtonNone) {
+ pEmu3btn->emulate3Expires =
+ GetTimeInMillis() + pEmu3btn->emulate3Timeout;
+ pEmu3btn->emulate3Pending = TRUE;
+ } else {
+ pEmu3btn->emulate3Pending = FALSE;
+ }
+ } else {
+ /* no emulation; post left or right button event as is */
+ flag = POINTER_RELATIVE;
+ valuator_mask_zero(&mask);
+ QueuePointerEvents(device, type, buttons, flag, &mask);
+ }
+}
--- /dev/null 2021-02-05 23:23:05.873690181 +0900
+++ external/mit/xorg-server/dist/hw/netbsd/x68k/mouseEmu3btn.h 2021-02-04 02:06:34.730734641 +0900
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1999-2003 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * 3 button emulation stuff
+ * pulled from xf86-input-mouse/dist/src/mouse.h
+ */
+
+typedef struct _MouseEmu3btn {
+ DeviceIntPtr device;
+
+ int emulateState;
+ Bool emulate3Buttons;
+ Bool emulate3ButtonsSoft;
+ Bool emulate3Pending;
+ int emulate3Timeout;
+ CARD32 emulate3Expires;
+} MouseEmu3btn, *MouseEmu3btnPtr;
+
+/* default timeout value for 3 button emulation */
+#define EMU3B_DEF_TIMEOUT 100 /* ms */
+
+void Emulate3ButtonsEnable(MouseEmu3btnPtr pEmu3btn, DeviceIntPtr device, int timeout);
+void Emulate3ButtonsQueueEvent(MouseEmu3btnPtr pEmu3btn, int type, int buttons, int bmask);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment