1/* $NetBSD: x68kMouse.c,v 1.18 2025/06/22 22:33:03 tsutsui Exp $ */
2/*-------------------------------------------------------------------------
3 * Copyright (c) 1996 Yasushi Yamasaki
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *-----------------------------------------------------------------------*/
26
27/*-
28 * Copyright (c) 1987 by the Regents of the University of California
29 *
30 * Permission to use, copy, modify, and distribute this
31 * software and its documentation for any purpose and without
32 * fee is hereby granted, provided that the above copyright
33 * notice appear in all copies.  The University of California
34 * makes no representations about the suitability of this
35 * software for any purpose.  It is provided "as is" without
36 * express or implied warranty.
37 */
38
39/************************************************************
40Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.
41
42                    All Rights Reserved
43
44Permission  to  use,  copy,  modify,  and  distribute   this
45software  and  its documentation for any purpose and without
46fee is hereby granted, provided that the above copyright no-
47tice  appear  in all copies and that both that copyright no-
48tice and this permission notice appear in  supporting  docu-
49mentation,  and  that the names of Sun or X Consortium
50not be used in advertising or publicity pertaining to
51distribution  of  the software  without specific prior
52written permission. Sun and X Consortium make no
53representations about the suitability of this software for
54any purpose. It is provided "as is" without any express or
55implied warranty.
56
57SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
58INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
59NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
60ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
61ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
62PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
63OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
64THE USE OR PERFORMANCE OF THIS SOFTWARE.
65
66********************************************************/
67/*
68 * Copyright 1991, 1992, 1993 Kaleb S. Keithley
69 *
70 * Permission to use, copy, modify, and distribute this
71 * software and its documentation for any purpose and without
72 * fee is hereby granted, provided that the above copyright
73 * notice appear in all copies.  Kaleb S. Keithley makes no
74 * representations about the suitability of this software for
75 * any purpose.  It is provided "as is" without express or
76 * implied warranty.
77 */
78
79#include "x68k.h"
80#include "mi.h"
81#include "input.h"
82#include "inpututils.h"
83
84#include "exevents.h"
85#include "events.h"
86#include "eventstr.h"
87#include <X11/Xatom.h>
88#include "xserver-properties.h"
89
90static void x68kMouseEvents(int, int, void *);
91static int x68kMouseGetEvents(DeviceIntPtr);
92static void x68kMouseEnqueueEvent(DeviceIntPtr, Firm_event *);
93static Bool x68kCursorOffScreen(ScreenPtr *, int *, int *);
94static void x68kCrossScreen(ScreenPtr, int);
95static void x68kWarpCursor(DeviceIntPtr, ScreenPtr, int, int);
96static void x68kMouseCtrl(DeviceIntPtr, PtrCtrl*);
97
98typedef struct _X68kMousePriv {
99    int fd;
100    int bmask;
101    int oformat;
102    MouseEmu3btn emu3btn;
103    Firm_event evbuf[X68K_MAXEVENTS];
104} X68kMousePriv, *X68kMousePrivPtr;
105
106miPointerScreenFuncRec x68kPointerScreenFuncs = {
107    x68kCursorOffScreen,
108    x68kCrossScreen,
109    x68kWarpCursor,
110};
111
112DeviceIntPtr x68kPointerDevice = NULL;
113
114/*------------------------------------------------------------------------
115 * x68kMouseEvents --
116 *	When registered polled mouse input event handler is invoked,
117 *	read device events and enqueue them using the mi event queue.
118 * Results:
119 *	None.
120 *
121 *----------------------------------------------------------------------*/
122static void
123x68kMouseEvents(int fd, int ready, void *data)
124{
125    int i, numEvents;
126    DeviceIntPtr device = (DeviceIntPtr)data;
127    DevicePtr pMouse = &device->public;
128    X68kMousePrivPtr pPriv = pMouse->devicePrivate;
129
130    input_lock();
131
132    do {
133	numEvents = x68kMouseGetEvents(device);
134	for (i = 0; i < numEvents; i++) {
135	    x68kMouseEnqueueEvent(device, &pPriv->evbuf[i]);
136	}
137    } while (numEvents == X68K_MAXEVENTS);
138
139    input_unlock();
140}
141
142/*-
143 *-----------------------------------------------------------------------
144 * x68kMouseProc --
145 *	Handle the initialization, etc. of a mouse
146 *
147 * Results:
148 *	none.
149 *
150 * Side Effects:
151 *-----------------------------------------------------------------------
152 */
153int
154x68kMouseProc(DeviceIntPtr device, int what)
155{
156    DevicePtr   pMouse = &device->public;
157    X68kMousePrivPtr pPriv;
158    int		format;
159    BYTE	map[4];
160    Atom btn_labels[3] = {0};
161    Atom axes_labels[2] = { 0, 0 };
162    MouseEmu3btnPtr pEmu3btn;
163    Bool emu3enable;
164    int emu3timeout;
165
166    switch (what) {
167	case DEVICE_INIT:
168            pPriv = malloc(sizeof(*pPriv));
169            if (pPriv == NULL) {
170                LogMessage(X_ERROR, "Cannot allocate private data for mouse\n");
171                return !Success;
172            }
173            pPriv->fd = open("/dev/mouse", O_RDONLY | O_NONBLOCK);
174            if (pPriv->fd == -1) {
175                LogMessage(X_ERROR, "Can't open mouse device\n");
176                return !Success;
177            }
178            pPriv->bmask = 0;
179            pPriv->oformat = 0;
180            memset(&pPriv->emu3btn, 0, sizeof(pPriv->emu3btn));
181            pMouse->devicePrivate = pPriv;
182	    pMouse->on = FALSE;
183
184	    map[1] = 1;
185	    map[2] = 2;
186	    map[3] = 3;
187	    btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
188	    btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
189	    btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
190	    axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
191	    axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
192
193	    InitPointerDeviceStruct(pMouse, map, 3, btn_labels,
194		x68kMouseCtrl, GetMotionHistorySize(),
195		2, axes_labels);
196
197	    /* X valuator */
198	    InitValuatorAxisStruct(device, 0, axes_labels[0],
199		NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
200	    device->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
201	    device->last.valuators[0] = device->valuator->axisVal[0];
202
203	    /* Y valuator */
204	    InitValuatorAxisStruct(device, 1, axes_labels[1],
205		NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
206	    device->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
207	    device->last.valuators[1] = device->valuator->axisVal[1];
208
209	    /* Initialize emulation 3 buttons settings */
210	    emu3enable = TRUE;			/* XXX should be configurable */
211	    emu3timeout = EMU3B_DEF_TIMEOUT;	/* XXX should be configurable */
212	    if (emu3enable) {
213		pEmu3btn = &pPriv->emu3btn;
214		Emulate3ButtonsEnable(pEmu3btn, device, emu3timeout);
215	    }
216
217	    break;
218
219	case DEVICE_ON:
220	    pPriv = (X68kMousePrivPtr)pMouse->devicePrivate;
221	    if (ioctl(pPriv->fd, VUIDGFORMAT, &pPriv->oformat) == -1) {
222		LogMessage(X_ERROR, "x68kMouseProc ioctl VUIDGFORMAT\n");
223		return !Success;
224	    }
225	    format = VUID_FIRM_EVENT;
226	    if (ioctl(pPriv->fd, VUIDSFORMAT, &format) == -1) {
227		LogMessage(X_ERROR, "x68kMouseProc ioctl VUIDSFORMAT\n");
228		return !Success;
229	    }
230
231	    SetNotifyFd(pPriv->fd, x68kMouseEvents, X_NOTIFY_READ, device);
232
233	    pPriv->bmask = 0;
234	    pMouse->on = TRUE;
235	    break;
236
237	case DEVICE_OFF:
238	    pPriv = (X68kMousePrivPtr)pMouse->devicePrivate;
239	    RemoveNotifyFd(pPriv->fd);
240	    if (ioctl(pPriv->fd, VUIDSFORMAT, &pPriv->oformat) == -1)
241		LogMessage(X_ERROR, "x68kMouseProc ioctl VUIDSFORMAT\n");
242	    pMouse->on = FALSE;
243	    break;
244
245	case DEVICE_CLOSE:
246	    pPriv = (X68kMousePrivPtr)pMouse->devicePrivate;
247	    close(pPriv->fd);
248	    free(pPriv);
249	    break;
250
251	case DEVICE_ABORT:
252	    break;
253    }
254    return Success;
255}
256
257/*-
258 *-----------------------------------------------------------------------
259 * x68kMouseCtrl --
260 *	Alter the control parameters for the mouse. Since acceleration
261 *	etc. is done from the PtrCtrl record in the mouse's device record,
262 *	there's nothing to do here.
263 *
264 * Results:
265 *	None.
266 *
267 * Side Effects:
268 *	None.
269 *
270 *-----------------------------------------------------------------------
271 */
272/*ARGSUSED*/
273static void
274x68kMouseCtrl(DeviceIntPtr device, PtrCtrl* ctrl)
275{
276}
277
278/*-
279 *-----------------------------------------------------------------------
280 * x68kMouseGetEvents --
281 *	Return the events waiting in the wings for the given mouse.
282 *
283 * Results:
284 *      Update Firm_event buffer in DeviceIntPtr if events are received.
285 *      Return the number of received Firm_events in the buffer.
286 *
287 * Side Effects:
288 *	None.
289 *-----------------------------------------------------------------------
290 */
291
292static int
293x68kMouseGetEvents(DeviceIntPtr device)
294{
295    DevicePtr pMouse = &device->public;
296    X68kMousePrivPtr pPriv = pMouse->devicePrivate;
297    int nBytes;               /* number of bytes of events available. */
298    int NumEvents = 0;
299
300    nBytes = read(pPriv->fd, (char *)pPriv->evbuf, sizeof(pPriv->evbuf));
301    if (nBytes == -1) {
302	if (errno != EWOULDBLOCK) {
303	    LogMessage(X_ERROR, "Unexpected error on reading mouse\n");
304	    FatalError("Could not read from mouse");
305	}
306    } else {
307	NumEvents = nBytes / sizeof(pPriv->evbuf[0]);
308    }
309    return NumEvents;
310}
311
312/*-
313 *-----------------------------------------------------------------------
314 * x68kMouseEnqueueEvent --
315 *	Given a Firm_event for a mouse, pass it off the the dix layer
316 *	properly converted...
317 *
318 * Results:
319 *	None.
320 *
321 * Side Effects:
322 *	The cursor may be redrawn...? devPrivate/x/y will be altered.
323 *
324 *-----------------------------------------------------------------------
325 */
326
327static void
328x68kMouseEnqueueEvent(DeviceIntPtr device, Firm_event *fe)
329{
330    X68kMousePrivPtr	pPriv;	/* Private data for pointer */
331    int			bmask;	/* Temporary button mask */
332    int			type, buttons, flag;
333    int			valuators[2];
334    ValuatorMask	mask;
335
336    pPriv = (X68kMousePrivPtr)device->public.devicePrivate;
337
338    switch (fe->id) {
339    case MS_LEFT:
340    case MS_MIDDLE:
341    case MS_RIGHT:
342	/*
343	 * A button changed state. Sometimes we will get two events
344	 * for a single state change. Should we get a button event which
345	 * reflects the current state of affairs, that event is discarded.
346	 *
347	 * Mouse buttons start at 1 as defined in <X11/X.h>.
348	 *
349	 * The bmask stores which buttons are currently pressed.
350	 * This bmask is also used for Emulate3Buttons functions that
351	 * assume the left button is LSB as defined in mouseEmu3btn.c.
352	 */
353	buttons = (fe->id - MS_LEFT) + 1;
354	bmask = 1 << (buttons - 1);
355	if (fe->value == VKEY_UP) {
356	    if (pPriv->bmask & bmask) {
357		type = ButtonRelease;
358		pPriv->bmask &= ~bmask;
359	    } else {
360		return;
361	    }
362	} else {
363	    if ((pPriv->bmask & bmask) == 0) {
364		type = ButtonPress;
365		pPriv->bmask |= bmask;
366	    } else {
367		return;
368	    }
369	}
370	if (buttons == Button1 || buttons == Button3) {
371	    /* Handle middle button emulation */
372	    Emulate3ButtonsQueueEvent(&pPriv->emu3btn, type, buttons, pPriv->bmask);
373	} else {
374	    flag = POINTER_RELATIVE;
375	    valuator_mask_zero(&mask);
376	    QueuePointerEvents(device, type, buttons, flag, &mask);
377	}
378	break;
379    case LOC_X_DELTA:
380	valuators[0] = fe->value;
381	valuators[1] = 0;
382	valuator_mask_set_range(&mask, 0, 2, valuators);
383        flag = POINTER_RELATIVE | POINTER_ACCELERATE;
384	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
385	break;
386    case LOC_Y_DELTA:
387	/*
388	 * For some reason, motion up generates a positive y delta
389	 * and motion down a negative delta, so we must subtract
390	 * here instead of add...
391	 */
392	valuators[0] = 0;
393	valuators[1] = -fe->value;
394	valuator_mask_set_range(&mask, 0, 2, valuators);
395        flag = POINTER_RELATIVE | POINTER_ACCELERATE;
396	QueuePointerEvents(device, MotionNotify, 0, flag, &mask);
397	break;
398    case LOC_X_ABSOLUTE:
399    case LOC_Y_ABSOLUTE:
400	/* XXX not sure how to get current X and Y position */
401    default:
402	FatalError ("%s: unrecognized id\n", __func__);
403	break;
404    }
405}
406
407/*ARGSUSED*/
408static Bool
409x68kCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
410{
411    return FALSE;
412}
413
414static void
415x68kCrossScreen(ScreenPtr pScreen, int entering)
416{
417}
418
419static void
420x68kWarpCursor(DeviceIntPtr device, ScreenPtr pScreen, int x, int y)
421{
422    input_lock();
423    miPointerWarpCursor(device, pScreen, x, y);
424    input_unlock();
425}
426
427/* EOF x68kMouse.c */
428