o cleanup

This commit is contained in:
optixx
2009-04-22 20:04:28 +02:00
parent 55e3468f74
commit 0c378a9f7c
1078 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,369 @@
/*
Copyright (c) 2003-2007 Ryan C. Gordon and others.
http://icculus.org/manymouse/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Ryan C. Gordon <icculus@icculus.org>
*/
//Support for Linux evdevs...the /dev/input/event* devices.
#include "mm.h"
#ifdef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h> /* evdev interface... */
#define test_bit(array, bit) (array[bit/8] & (1<<(bit%8)))
/* linux allows 32 evdev nodes currently. */
#define MAX_MICE 32
typedef struct
{
int fd;
int min_x;
int min_y;
int max_x;
int max_y;
char name[64];
} MouseStruct;
static MouseStruct mice[MAX_MICE];
static unsigned int available_mice = 0;
static int poll_mouse(MouseStruct *mouse, ManyMouseEvent *outevent)
{
int unhandled = 1;
while (unhandled) /* read until failure or valid event. */
{
struct input_event event;
int br = read(mouse->fd, &event, sizeof (event));
if (br == -1)
{
if (errno == EAGAIN)
return(0); /* just no new data at the moment. */
/* mouse was unplugged? */
close(mouse->fd); /* stop reading from this mouse. */
mouse->fd = -1;
outevent->type = MANYMOUSE_EVENT_DISCONNECT;
return(1);
} /* if */
if (br != sizeof (event))
return(0); /* oh well. */
unhandled = 0; /* will reset if necessary. */
outevent->value = event.value;
if (event.type == EV_REL)
{
outevent->type = MANYMOUSE_EVENT_RELMOTION;
if ((event.code == REL_X) || (event.code == REL_DIAL))
outevent->item = 0;
else if (event.code == REL_Y)
outevent->item = 1;
else if (event.code == REL_WHEEL)
{
outevent->type = MANYMOUSE_EVENT_SCROLL;
outevent->item = 0;
} /* else if */
else if (event.code == REL_HWHEEL)
{
outevent->type = MANYMOUSE_EVENT_SCROLL;
outevent->item = 1;
} /* else if */
else
{
unhandled = 1;
} /* else */
} /* if */
else if (event.type == EV_ABS)
{
outevent->type = MANYMOUSE_EVENT_ABSMOTION;
if (event.code == ABS_X)
{
outevent->item = 0;
outevent->minval = mouse->min_x;
outevent->maxval = mouse->max_x;
} /* if */
else if (event.code == ABS_Y)
{
outevent->item = 1;
outevent->minval = mouse->min_y;
outevent->maxval = mouse->max_y;
} /* if */
else
{
unhandled = 1;
} /* else */
} /* else if */
else if (event.type == EV_KEY)
{
outevent->type = MANYMOUSE_EVENT_BUTTON;
if ((event.code >= BTN_LEFT) && (event.code <= BTN_BACK))
outevent->item = event.code - BTN_MOUSE;
/* just in case some device uses this block of events instead... */
else if ((event.code >= BTN_MISC) && (event.code <= BTN_LEFT))
outevent->item = (event.code - BTN_MISC);
else if (event.code == BTN_TOUCH) /* tablet... */
outevent->item = 0;
else if (event.code == BTN_STYLUS) /* tablet... */
outevent->item = 1;
else if (event.code == BTN_STYLUS2) /* tablet... */
outevent->item = 2;
else
{
/*printf("unhandled mouse button: 0x%X\n", event.code);*/
unhandled = 1;
} /* else */
} /* else if */
else
{
unhandled = 1;
} /* else */
} /* while */
return(1); /* got a valid event */
} /* poll_mouse */
static int init_mouse(const char *fname, int fd)
{
MouseStruct *mouse = &mice[available_mice];
int has_absolutes = 0;
int is_mouse = 0;
unsigned char relcaps[(REL_MAX / 8) + 1];
unsigned char abscaps[(ABS_MAX / 8) + 1];
unsigned char keycaps[(KEY_MAX / 8) + 1];
memset(relcaps, '\0', sizeof (relcaps));
memset(abscaps, '\0', sizeof (abscaps));
memset(keycaps, '\0', sizeof (keycaps));
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof (keycaps)), keycaps) == -1)
return 0; /* gotta have some buttons! :) */
if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof (relcaps)), relcaps) != -1)
{
if ( (test_bit(relcaps, REL_X)) && (test_bit(relcaps, REL_Y)) )
{
if (test_bit(keycaps, BTN_MOUSE))
is_mouse = 1;
} /* if */
#if ALLOW_DIALS_TO_BE_MICE
if (test_bit(relcaps, REL_DIAL))
is_mouse = 1; // griffin powermate?
#endif
} /* if */
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof (abscaps)), abscaps) != -1)
{
if ( (test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y)) )
{
/* might be a touchpad... */
if (test_bit(keycaps, BTN_TOUCH))
{
is_mouse = 1; /* touchpad, touchscreen, or tablet. */
has_absolutes = 1;
} /* if */
} /* if */
} /* if */
if (!is_mouse)
return 0;
mouse->min_x = mouse->min_y = mouse->max_x = mouse->max_y = 0;
if (has_absolutes)
{
struct
{
int value;
int minimum;
int maximum;
int fuzz;
int flat;
} absinfo;
if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1)
return 0;
mouse->min_x = absinfo.minimum;
mouse->max_x = absinfo.maximum;
if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1)
return 0;
mouse->min_y = absinfo.minimum;
mouse->max_y = absinfo.maximum;
} /* if */
if (ioctl(fd, EVIOCGNAME(sizeof (mouse->name)), mouse->name) == -1)
snprintf(mouse->name, sizeof (mouse->name), "Unknown device");
mouse->fd = fd;
return 1; /* we're golden. */
} /* init_mouse */
/* Return a file descriptor if this is really a mouse, -1 otherwise. */
static int open_if_mouse(const char *fname)
{
struct stat statbuf;
int fd;
int devmajor, devminor;
if (stat(fname, &statbuf) == -1)
return 0;
if (S_ISCHR(statbuf.st_mode) == 0)
return 0; /* not a character device... */
/* evdev node ids are major 13, minor 64-96. Is this safe to check? */
devmajor = (statbuf.st_rdev & 0xFF00) >> 8;
devminor = (statbuf.st_rdev & 0x00FF);
if ( (devmajor != 13) || (devminor < 64) || (devminor > 96) )
return 0; /* not an evdev. */
if ((fd = open(fname, O_RDONLY | O_NONBLOCK)) == -1)
return 0;
if (init_mouse(fname, fd))
return 1;
close(fd);
return 0;
} /* open_if_mouse */
static int linux_evdev_init(void)
{
DIR *dirp;
struct dirent *dent;
int i;
for (i = 0; i < MAX_MICE; i++)
mice[i].fd = -1;
dirp = opendir("/dev/input");
if (!dirp)
return -1;
while ((dent = readdir(dirp)) != NULL)
{
char fname[128];
snprintf(fname, sizeof (fname), "/dev/input/%s", dent->d_name);
if (open_if_mouse(fname))
available_mice++;
} /* while */
closedir(dirp);
return available_mice;
} /* linux_evdev_init */
static void linux_evdev_quit(void)
{
while (available_mice)
{
int fd = mice[available_mice--].fd;
if (fd != -1)
close(fd);
} /* while */
} /* linux_evdev_quit */
static const char *linux_evdev_name(unsigned int index)
{
if (index < available_mice)
return(mice[index].name);
return(NULL);
} /* linux_evdev_name */
static int linux_evdev_poll(ManyMouseEvent *event)
{
/*
* (i) is static so we iterate through all mice round-robin. This
* prevents a chatty mouse from dominating the queue.
*/
static unsigned int i = 0;
if (i >= available_mice)
i = 0; /* handle reset condition. */
if (event != NULL)
{
while (i < available_mice)
{
MouseStruct *mouse = &mice[i];
if (mouse->fd != -1)
{
if (poll_mouse(mouse, event))
{
event->device = i;
return(1);
} /* if */
} /* if */
i++;
} /* while */
} /* if */
return(0); /* no new events */
} /* linux_evdev_poll */
#else
static int linux_evdev_init(void) { return(-1); }
static void linux_evdev_quit(void) {}
static const char *linux_evdev_name(unsigned int index) { return(0); }
static int linux_evdev_poll(ManyMouseEvent *event) { return(0); }
#endif /* defined __linux__ */
ManyMouseDriver ManyMouseDriver_evdev =
{
linux_evdev_init,
linux_evdev_quit,
linux_evdev_name,
linux_evdev_poll
};
/* end of linux_evdev.c ... */

114
tools/zsnes/src/mmlib/mm.c Normal file
View File

@@ -0,0 +1,114 @@
/*
Copyright (c) 2003-2007 Ryan C. Gordon and others.
http://icculus.org/manymouse/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Ryan C. Gordon <icculus@icculus.org>
*/
//ManyMouse foundation code; apps talks to this and it talks to the lowlevel
//code for various platforms.
#include <stdlib.h>
#include "mm.h"
static const char *manymouse_copyright =
"ManyMouse " MANYMOUSE_VERSION " (c) 2003-2007 Ryan C. Gordon.";
extern const ManyMouseDriver ManyMouseDriver_windows;
extern const ManyMouseDriver ManyMouseDriver_evdev;
extern const ManyMouseDriver ManyMouseDriver_hidmanager;
extern const ManyMouseDriver ManyMouseDriver_xinput;
static const ManyMouseDriver *mice_drivers[] =
{
#if SUPPORT_XINPUT
&ManyMouseDriver_xinput,
#endif
#ifdef __linux__
&ManyMouseDriver_evdev,
#endif
#if ((defined _WIN32) || defined(__CYGWIN__))
&ManyMouseDriver_windows,
#endif
#if ((defined(__MACH__)) && (defined(__APPLE__)))
&ManyMouseDriver_hidmanager,
#endif
NULL
};
static const ManyMouseDriver *driver = NULL;
int ManyMouse_Init(void)
{
int i;
int retval = -1;
/* impossible test to keep manymouse_copyright linked into the binary. */
if (manymouse_copyright == NULL)
return(-1);
if (driver != NULL)
return(-1);
for (i = 0; mice_drivers[i]; i++)
{
int mice = mice_drivers[i]->init();
if (mice > retval)
retval = mice; /* may just move from "error" to "no mice found". */
if (mice > 0)
{
driver = mice_drivers[i];
break;
} /* if */
} /* for */
return(retval);
} /* ManyMouse_Init */
void ManyMouse_Quit(void)
{
if (driver != NULL)
driver->quit();
driver = NULL;
} /* ManyMouse_Quit */
const char *ManyMouse_DeviceName(unsigned int index)
{
if (driver != NULL)
return(driver->name(index));
return(NULL);
} /* ManyMouse_PollEvent */
int ManyMouse_PollEvent(ManyMouseEvent *event)
{
if (driver != NULL)
return(driver->poll(event));
return(0);
} /* ManyMouse_PollEvent */
/* end of manymouse.c ... */

View File

@@ -0,0 +1,81 @@
/*
Copyright (c) 2003-2007 Ryan C. Gordon and others.
http://icculus.org/manymouse/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Ryan C. Gordon <icculus@icculus.org>
*/
//ManyMouse main header. Include this from your app.
#ifndef _INCLUDE_MANYMOUSE_H_
#define _INCLUDE_MANYMOUSE_H_
#ifdef __cplusplus
extern "C" {
#endif
#define MANYMOUSE_VERSION "0.0.1"
typedef enum
{
MANYMOUSE_EVENT_ABSMOTION = 0,
MANYMOUSE_EVENT_RELMOTION,
MANYMOUSE_EVENT_BUTTON,
MANYMOUSE_EVENT_SCROLL,
MANYMOUSE_EVENT_DISCONNECT,
MANYMOUSE_EVENT_MAX
} ManyMouseEventType;
typedef struct
{
ManyMouseEventType type;
unsigned int device;
unsigned int item;
int value;
int minval;
int maxval;
} ManyMouseEvent;
/* internal use only. */
typedef struct
{
int (*init)(void);
void (*quit)(void);
const char *(*name)(unsigned int index);
int (*poll)(ManyMouseEvent *event);
} ManyMouseDriver;
int ManyMouse_Init(void);
void ManyMouse_Quit(void);
const char *ManyMouse_DeviceName(unsigned int index);
int ManyMouse_PollEvent(ManyMouseEvent *event);
#ifdef __cplusplus
}
#endif
#endif /* !defined _INCLUDE_MANYMOUSE_H_ */
/* end of manymouse.h ... */

1690
tools/zsnes/src/mmlib/osx.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,759 @@
/*
Copyright (c) 2003-2007 Ryan C. Gordon and others.
http://icculus.org/manymouse/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Ryan C. Gordon <icculus@icculus.org>
*/
//Support for Windows via the WM_INPUT message.
#include "mm.h"
#if (defined(_WIN32) || defined(__CYGWIN__))
/* WinUser.h won't include rawinput stuff without this... */
#if (_WIN32_WINNT < 0x0501)
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <windows.h>
#include <malloc.h> /* needed for alloca(). */
/* Cygwin's headers don't have WM_INPUT right now... */
#ifndef WM_INPUT
#define WM_INPUT 0x00FF
#endif
/* that should be enough, knock on wood. */
#define MAX_MICE 32
/*
* Just trying to avoid malloc() here...we statically allocate a buffer
* for events and treat it as a ring buffer.
*/
/* !!! FIXME: tweak this? */
#define MAX_EVENTS 1024
static ManyMouseEvent input_events[MAX_EVENTS];
static volatile int input_events_read = 0;
static volatile int input_events_write = 0;
static unsigned int available_mice = 0;
static int did_api_lookup = 0;
static HWND raw_hwnd = NULL;
static const char *class_name = "ManyMouseRawInputCatcher";
static const char *win_name = "ManyMouseRawInputMsgWindow";
static ATOM class_atom = 0;
static CRITICAL_SECTION mutex;
typedef struct
{
HANDLE handle;
char name[256];
} MouseStruct;
static MouseStruct mice[MAX_MICE];
/*
* The RawInput APIs only exist in Windows XP and later, so you want this
* to fail gracefully on earlier systems instead of refusing to start the
* process due to missing symbols. To this end, we do a symbol lookup on
* User32.dll, etc to get the entry points.
*
* A lot of these are available all the way back to the start of win32 in
* Windows 95 and WinNT 3.1, but just so you don't have to track down any
* import libraries, I've added those here, too. That fits well with the
* idea of just adding the sources to your build and going forward.
*/
static UINT (WINAPI *pGetRawInputDeviceList)(
PRAWINPUTDEVICELIST pRawInputDeviceList,
PUINT puiNumDevices,
UINT cbSize
);
/* !!! FIXME: use unicode version */
static UINT (WINAPI *pGetRawInputDeviceInfoA)(
HANDLE hDevice,
UINT uiCommand,
LPVOID pData,
PUINT pcbSize
);
static BOOL (WINAPI *pRegisterRawInputDevices)(
PCRAWINPUTDEVICE pRawInputDevices,
UINT uiNumDevices,
UINT cbSize
);
static LRESULT (WINAPI *pDefRawInputProc)(
PRAWINPUT *paRawInput,
INT nInput,
UINT cbSizeHeader
);
static UINT (WINAPI *pGetRawInputBuffer)(
PRAWINPUT pData,
PUINT pcbSize,
UINT cbSizeHeader
);
static UINT (WINAPI *pGetRawInputData)(
HRAWINPUT hRawInput,
UINT uiCommand,
LPVOID pData,
PUINT pcbSize,
UINT cbSizeHeader
);
static LONG (WINAPI *pRegQueryValueExA)(
HKEY hKey,
LPCTSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
static LONG (WINAPI *pRegOpenKeyExA)(
HKEY hKey,
LPCTSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult
);
static LONG (WINAPI *pRegCloseKey)(
HKEY hKey
);
static HWND (WINAPI *pCreateWindowExA)(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
static ATOM (WINAPI *pRegisterClassExA)(
CONST WNDCLASSEX *lpwcx
);
static LRESULT (WINAPI *pDefWindowProcA)(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
static BOOL (WINAPI *pUnregisterClassA)(
LPCTSTR lpClassName,
HINSTANCE hInstance
);
static HMODULE (WINAPI *pGetModuleHandleA)(
LPCTSTR lpModuleName
);
static BOOL (WINAPI *pPeekMessageA)(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg
);
static BOOL (WINAPI *pTranslateMessage)(
const MSG *lpMsg
);
static LRESULT (WINAPI *pDispatchMessageA)(
const MSG *lpmsg
);
static BOOL (WINAPI *pDestroyWindow)(
HWND hWnd
);
static void (WINAPI *pInitializeCriticalSection)(
LPCRITICAL_SECTION lpCriticalSection
);
static void (WINAPI *pEnterCriticalSection)(
LPCRITICAL_SECTION lpCriticalSection
);
static void (WINAPI *pLeaveCriticalSection)(
LPCRITICAL_SECTION lpCriticalSection
);
static void (WINAPI *pDeleteCriticalSection)(
LPCRITICAL_SECTION lpCriticalSection
);
static int symlookup(HMODULE dll, void **addr, const char *sym)
{
*addr = GetProcAddress(dll, sym);
if (*addr == NULL)
{
FreeLibrary(dll);
return(0);
} /* if */
return(1);
} /* symlookup */
static int find_api_symbols(void)
{
HMODULE dll;
if (did_api_lookup)
return(1);
#define LOOKUP(x) { if (!symlookup(dll, (void **) &p##x, #x)) return(0); }
dll = LoadLibrary("user32.dll");
if (dll == NULL)
return(0);
LOOKUP(GetRawInputDeviceInfoA);
LOOKUP(RegisterRawInputDevices);
LOOKUP(GetRawInputDeviceList);
LOOKUP(DefRawInputProc);
LOOKUP(GetRawInputBuffer);
LOOKUP(GetRawInputData);
LOOKUP(CreateWindowExA);
LOOKUP(RegisterClassExA);
LOOKUP(UnregisterClassA);
LOOKUP(DefWindowProcA);
LOOKUP(PeekMessageA);
LOOKUP(TranslateMessage);
LOOKUP(DispatchMessageA);
LOOKUP(DestroyWindow);
dll = LoadLibrary("advapi32.dll");
if (dll == NULL)
return(0);
LOOKUP(RegOpenKeyExA);
LOOKUP(RegQueryValueExA);
LOOKUP(RegCloseKey);
dll = LoadLibrary("kernel32.dll");
if (dll == NULL)
return(0);
LOOKUP(GetModuleHandleA);
LOOKUP(InitializeCriticalSection);
LOOKUP(EnterCriticalSection);
LOOKUP(LeaveCriticalSection);
LOOKUP(DeleteCriticalSection);
#undef LOOKUP
did_api_lookup = 1;
return(1);
} /* find_api_symbols */
static void queue_event(const ManyMouseEvent *event)
{
/* copy the event info. We'll process it in ManyMouse_PollEvent(). */
CopyMemory(&input_events[input_events_write], event, sizeof (ManyMouseEvent));
input_events_write = ((input_events_write + 1) % MAX_EVENTS);
/* Ring buffer full? Lose oldest event. */
if (input_events_write == input_events_read)
{
/* !!! FIXME: we need to not lose mouse buttons here. */
input_events_read = ((input_events_read + 1) % MAX_EVENTS);
} /* if */
} /* queue_event */
static void queue_from_rawinput(const RAWINPUT *raw)
{
unsigned int i;
const RAWINPUTHEADER *header = &raw->header;
const RAWMOUSE *mouse = &raw->data.mouse;
ManyMouseEvent event;
if (raw->header.dwType != RIM_TYPEMOUSE)
return;
for (i = 0; i < available_mice; i++) /* find the device for event. */
{
if (mice[i].handle == header->hDevice)
break;
} /* for */
if (i == available_mice)
return; /* not found?! */
/*
* RAWINPUT packs a bunch of events into one, so we split it up into
* a bunch of ManyMouseEvents here and store them in an internal queue.
* Then ManyMouse_PollEvent() just shuffles items off that queue
* without any complicated processing.
*/
event.device = i;
pEnterCriticalSection(&mutex);
if (mouse->usFlags & MOUSE_MOVE_ABSOLUTE)
{
/* !!! FIXME: How do we get the min and max values for absmotion? */
event.type = MANYMOUSE_EVENT_ABSMOTION;
event.item = 0;
event.value = mouse->lLastX;
queue_event(&event);
event.item = 1;
event.value = mouse->lLastY;
queue_event(&event);
} /* if */
else /*if (mouse->usFlags & MOUSE_MOVE_RELATIVE)*/
{
event.type = MANYMOUSE_EVENT_RELMOTION;
if (mouse->lLastX != 0)
{
event.item = 0;
event.value = mouse->lLastX;
queue_event(&event);
} /* if */
if (mouse->lLastY != 0)
{
event.item = 1;
event.value = mouse->lLastY;
queue_event(&event);
} /* if */
} /* else if */
event.type = MANYMOUSE_EVENT_BUTTON;
#define QUEUE_BUTTON(x) { \
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_##x##_DOWN) { \
event.item = x-1; \
event.value = 1; \
queue_event(&event); \
} \
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_##x##_UP) { \
event.item = x-1; \
event.value = 0; \
queue_event(&event); \
} \
}
QUEUE_BUTTON(1);
QUEUE_BUTTON(2);
QUEUE_BUTTON(3);
QUEUE_BUTTON(4);
QUEUE_BUTTON(5);
#undef QUEUE_BUTTON
if (mouse->usButtonFlags & RI_MOUSE_WHEEL)
{
if (mouse->usButtonData != 0) /* !!! FIXME: can this ever be zero? */
{
event.type = MANYMOUSE_EVENT_SCROLL;
event.item = 0; /* !!! FIXME: horizontal wheel? */
event.value = ( ((SHORT) mouse->usButtonData) > 0) ? 1 : -1;
queue_event(&event);
} /* if */
} /* if */
pLeaveCriticalSection(&mutex);
} /* queue_from_rawinput */
static void wminput_handler(WPARAM wParam, LPARAM lParam)
{
UINT dwSize = 0;
LPBYTE lpb;
pGetRawInputData((HRAWINPUT) lParam, RID_INPUT, NULL, &dwSize,
sizeof (RAWINPUTHEADER));
if (dwSize < sizeof (RAWINPUT))
return; /* unexpected packet? */
lpb = (LPBYTE) alloca(dwSize);
if (lpb == NULL)
return;
if (pGetRawInputData((HRAWINPUT) lParam, RID_INPUT, lpb, &dwSize,
sizeof (RAWINPUTHEADER)) != dwSize)
return;
queue_from_rawinput((RAWINPUT *) lpb);
} /* wminput_handler */
static LRESULT CALLBACK RawWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_INPUT)
wminput_handler(wParam, lParam);
else if (Msg == WM_DESTROY)
return(0);
return pDefWindowProcA(hWnd, Msg, wParam, lParam);
} /* RawWndProc */
static int init_event_queue(void)
{
HINSTANCE hInstance = pGetModuleHandleA(NULL);
WNDCLASSEX wce;
RAWINPUTDEVICE rid;
ZeroMemory(input_events, sizeof (input_events));
input_events_read = input_events_write = 0;
ZeroMemory(&wce, sizeof (wce));
wce.cbSize = sizeof(WNDCLASSEX);
wce.lpfnWndProc = RawWndProc;
wce.lpszClassName = class_name;
wce.hInstance = hInstance;
class_atom = pRegisterClassExA(&wce);
if (class_atom == 0)
return(0);
raw_hwnd = pCreateWindowExA(0, class_name, win_name, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, HWND_MESSAGE, NULL, hInstance, NULL);
if (raw_hwnd == NULL)
return(0);
pInitializeCriticalSection(&mutex);
ZeroMemory(&rid, sizeof (rid));
rid.usUsagePage = 1; /* GenericDesktop page */
rid.usUsage = 2; /* GeneralDestop Mouse usage. */
rid.dwFlags = RIDEV_INPUTSINK;
rid.hwndTarget = raw_hwnd;
if (!pRegisterRawInputDevices(&rid, 1, sizeof (rid)))
{
pDeleteCriticalSection(&mutex);
return(0);
} /* if */
return(1);
} /* init_event_queue */
static void cleanup_window(void)
{
if (raw_hwnd)
{
MSG Msg;
pDestroyWindow(raw_hwnd);
while (pPeekMessageA(&Msg, raw_hwnd, 0, 0, PM_REMOVE))
{
pTranslateMessage(&Msg);
pDispatchMessageA(&Msg);
} /* while */
raw_hwnd = 0;
} /* if */
if (class_atom)
{
pUnregisterClassA(class_name, pGetModuleHandleA(NULL));
class_atom = 0;
} /* if */
} /* cleanup_window */
static int accept_device(const RAWINPUTDEVICELIST *dev)
{
const char rdp_ident[] = "\\??\\Root#RDP_MOU#0000#";
char *buf = NULL;
UINT ct = 0;
if (dev->dwType != RIM_TYPEMOUSE)
return(0); /* keyboard or some other fruity thing. */
if (pGetRawInputDeviceInfoA(dev->hDevice, RIDI_DEVICENAME, NULL, &ct) < 0)
return(0);
/* ct == is chars, not bytes, but we used the ASCII version. */
buf = (char *) alloca(ct);
if (buf == NULL)
return(0);
if (pGetRawInputDeviceInfoA(dev->hDevice, RIDI_DEVICENAME, buf, &ct) < 0)
return(0);
/*
* Apparently there's a fake "RDP" device...I guess this is
* "Remote Desktop Protocol" for controlling the system pointer
* remotely via Windows Remote Desktop, but that's just a guess.
* At any rate, we don't want that device, so skip it if detected.
*
* Idea for this found here:
* http://link.mywwwserver.com/~jstookey/arcade/rawmouse/raw_mouse.c
*/
/* avoiding memcmp here so we don't get a C runtime dependency... */
if (ct >= sizeof (rdp_ident) - 1)
{
int i;
for (i = 0; i < sizeof (rdp_ident) - 1; i++)
{
if (buf[i] != rdp_ident[i])
break;
} /* for */
if (i == sizeof (rdp_ident) - 1)
return(0); /* this is an RDP thing. Skip this device. */
} /* if */
return(1); /* we want this device. */
} /* accept_device */
/* !!! FIXME: this code sucks. */
static void get_device_product_name(char *name, size_t namesize,
const RAWINPUTDEVICELIST *dev)
{
const char regkeyroot[] = "System\\CurrentControlSet\\Enum\\";
const char default_device_name[] = "Unidentified input device";
DWORD outsize = namesize;
DWORD regtype = REG_SZ;
char *buf = NULL;
char *ptr = NULL;
char *keyname = NULL;
UINT i = 0;
UINT ct = 0;
LONG rc = 0;
HKEY hkey;
*name = '\0'; /* really insane default. */
if (sizeof (default_device_name) >= namesize)
return;
/* in case we can't stumble upon something better... */
CopyMemory(name, default_device_name, sizeof (default_device_name));
if (pGetRawInputDeviceInfoA(dev->hDevice, RIDI_DEVICENAME, NULL, &ct) < 0)
return;
/* ct == is chars, not bytes, but we used the ASCII version. */
buf = (char *) alloca(ct+1);
keyname = (char *) alloca(ct + sizeof (regkeyroot));
if ((buf == NULL) || (keyname == NULL))
return;
if (pGetRawInputDeviceInfoA(dev->hDevice, RIDI_DEVICENAME, buf, &ct) < 0)
return;
/*
* This string tap dancing gets us a registry keyname in this form:
* SYSTEM\CurrentControlSet\Enum\BUSTYPE\DEVICECLASS\DEVICEID
* (those are my best-guess for the actual elements, but the format
* appears to be sound.)
*/
ct -= 4;
buf += 4; /* skip the "\\??\\" on the front of the string. */
for (i = 0, ptr = buf; i < ct; i++, ptr++) /* convert '#' to '\\' ... */
{
if (*ptr == '#')
*ptr = '\\';
else if (*ptr == '{') /* hit the GUID part of the string. */
break;
} /* for */
*ptr = '\0';
CopyMemory(keyname, regkeyroot, sizeof (regkeyroot) - 1);
CopyMemory(keyname + (sizeof (regkeyroot) - 1), buf, i + 1);
rc = pRegOpenKeyExA(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey);
if (rc != ERROR_SUCCESS)
return;
rc = pRegQueryValueExA(hkey, "DeviceDesc", NULL, &regtype, name, &outsize);
pRegCloseKey(hkey);
if (rc != ERROR_SUCCESS)
{
/* msdn says failure may mangle the buffer, so default it again. */
CopyMemory(name, default_device_name, sizeof (default_device_name));
return;
} /* if */
name[namesize-1] = '\0'; /* just in case. */
} /* get_device_product_name */
static void init_mouse(const RAWINPUTDEVICELIST *dev)
{
MouseStruct *mouse = &mice[available_mice];
if (accept_device(dev))
{
ZeroMemory(mouse, sizeof (MouseStruct));
get_device_product_name(mouse->name, sizeof (mouse->name), dev);
mouse->handle = dev->hDevice;
available_mice++; /* we're good. */
} /* if */
} /* init_mouse */
static int windows_wminput_init(void)
{
RAWINPUTDEVICELIST *devlist = NULL;
UINT ct = 0;
UINT i;
available_mice = 0;
if (!find_api_symbols()) /* only supported on WinXP and later. */
return(0);
pGetRawInputDeviceList(NULL, &ct, sizeof (RAWINPUTDEVICELIST));
if (ct == 0) /* no devices. */
return(0);
devlist = (PRAWINPUTDEVICELIST) alloca(sizeof (RAWINPUTDEVICELIST) * ct);
pGetRawInputDeviceList(devlist, &ct, sizeof (RAWINPUTDEVICELIST));
for (i = 0; i < ct; i++)
init_mouse(&devlist[i]);
if (!init_event_queue())
{
cleanup_window();
available_mice = 0;
} /* if */
return(available_mice);
} /* windows_wminput_init */
static void windows_wminput_quit(void)
{
/* unregister WM_INPUT devices... */
RAWINPUTDEVICE rid;
ZeroMemory(&rid, sizeof (rid));
rid.usUsagePage = 1; /* GenericDesktop page */
rid.usUsage = 2; /* GeneralDestop Mouse usage. */
rid.dwFlags |= RIDEV_REMOVE;
pRegisterRawInputDevices(&rid, 1, sizeof (rid));
cleanup_window();
available_mice = 0;
pDeleteCriticalSection(&mutex);
} /* windows_wminput_quit */
static const char *windows_wminput_name(unsigned int index)
{
if (index < available_mice)
return(mice[index].name);
return(NULL);
} /* windows_wminput_name */
/*
* Windows doesn't send a WM_INPUT event when you unplug a mouse,
* so we try to do a basic query by device handle here; if the
* query fails, we assume the device has vanished and generate a
* disconnect.
*/
static int check_for_disconnects(ManyMouseEvent *ev)
{
/*
* (i) is static so we iterate through all mice round-robin and check
* one mouse per call to ManyMouse_PollEvent(). This makes this test O(1).
*/
static unsigned int i = 0;
MouseStruct *mouse = NULL;
if (++i >= available_mice) /* check first in case of redetect */
i = 0;
mouse = &mice[i];
if (mouse->handle != NULL) /* not NULL == still plugged in. */
{
UINT size = 0;
UINT rc = pGetRawInputDeviceInfoA(mouse->handle, RIDI_DEVICEINFO,
NULL, &size);
if (rc == (UINT) -1) /* failed...probably unplugged... */
{
mouse->handle = NULL;
ev->type = MANYMOUSE_EVENT_DISCONNECT;
ev->device = i;
return(1);
} /* if */
} /* if */
return(0); /* no disconnect event this time. */
} /* check_for_disconnects */
static int windows_wminput_poll(ManyMouseEvent *ev)
{
MSG Msg; /* run the queue for WM_INPUT messages, etc ... */
int found = 0;
/* ...favor existing events in the queue... */
pEnterCriticalSection(&mutex);
if (input_events_read != input_events_write) /* no events if equal. */
{
CopyMemory(ev, &input_events[input_events_read], sizeof (*ev));
input_events_read = ((input_events_read + 1) % MAX_EVENTS);
found = 1;
} /* if */
pLeaveCriticalSection(&mutex);
if (!found)
{
/* pump Windows for new hardware events... */
while (pPeekMessageA(&Msg, raw_hwnd, 0, 0, PM_REMOVE))
{
pTranslateMessage(&Msg);
pDispatchMessageA(&Msg);
} /* while */
/* In case something new came in, give it to the app... */
pEnterCriticalSection(&mutex);
if (input_events_read != input_events_write) /* no events if equal. */
{
CopyMemory(ev, &input_events[input_events_read], sizeof (*ev));
input_events_read = ((input_events_read + 1) % MAX_EVENTS);
found = 1;
} /* if */
pLeaveCriticalSection(&mutex);
} /* if */
/*
* Check for disconnects if queue is totally empty and Windows didn't
* report anything new at this time. This ensures that we don't send a
* disconnect event through ManyMouse and then later give a valid
* event to the app for a device that is now missing.
*/
if (!found)
found = check_for_disconnects(ev);
return(found);
} /* windows_wminput_poll */
#else
static int windows_wminput_init(void) { return(-1); }
static void windows_wminput_quit(void) {}
static const char *windows_wminput_name(unsigned int index) { return(0); }
static int windows_wminput_poll(ManyMouseEvent *event) { return(0); }
#endif /* ifdef WINDOWS blocker */
ManyMouseDriver ManyMouseDriver_windows =
{
windows_wminput_init,
windows_wminput_quit,
windows_wminput_name,
windows_wminput_poll
};
/* end of windows_wminput.c ... */