Final merge of Google Summer of Code 2008 work...

Many-mouse and tablet support
by Szymon Wilczek, mentored by Ryan C. Gordon

Everything concerning the project is noted on the wiki:
http://wilku.ravenlord.ws/doku.php?id=start

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%403155
This commit is contained in:
Sam Lantinga 2008-08-25 06:33:00 +00:00
parent 95134b6d3c
commit e7d72614c3
22 changed files with 805 additions and 267 deletions

View file

@ -19,6 +19,12 @@
Sam Lantinga
slouken@libsdl.org
*/
#if (_WIN32_WINNT < 0x0501)
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include "SDL_config.h"
#include "SDL_win32video.h"
@ -26,6 +32,11 @@
#include "SDL_vkeys.h"
#include "../../events/SDL_events_c.h"
#include <wintab.h>
#define PACKETDATA ( PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_CURSOR)
#define PACKETMODE 0
#include <pktdef.h>
/*#define WMMSG_DEBUG*/
#ifdef WMMSG_DEBUG
#include <stdio.h>
@ -49,6 +60,12 @@
#define GET_XBUTTON_WPARAM(w) (HIWORD(w))
#endif
extern HCTX *g_hCtx;
extern HANDLE *mice;
extern int total_mice;
extern int tablet;
int pressure = 0; /* the pressure reported by the tablet */
static WPARAM
RemapVKEY(WPARAM wParam, LPARAM lParam)
{
@ -84,6 +101,8 @@ LRESULT CALLBACK
WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
SDL_WindowData *data;
RAWINPUT *raw;
PACKET packet;
/* Send a SDL_SYSWMEVENT if the application wants them */
if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
@ -114,10 +133,40 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
fclose(log);
}
#endif
switch (msg) {
case WT_PACKET:
{
/* if we receive such data we need to update the pressure */
if (WTPacket((HCTX) lParam, wParam, &packet)) {
SDL_ChangeEnd(tablet, (int) packet.pkCursor);
pressure = (int) packet.pkNormalPressure;
}
}
break;
case WT_PROXIMITY:
{
/* checking where the proximity message showed up */
int h_context = LOWORD(lParam);
LPPOINT point;
GetCursorPos(&point);
ScreenToClient(hwnd, &point);
/* are we in proximity or out of proximity */
if (h_context == 0) {
SDL_SendProximity(tablet, (int) (&point->x),
(int) (&point->y), SDL_PROXIMITYOUT);
} else {
SDL_SendProximity(tablet, (int) (&point->x),
(int) (&point->y), SDL_PROXIMITYIN);
}
}
break;
case WM_SHOWWINDOW:
{
if (wParam) {
@ -161,48 +210,72 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
SDL_WINDOWEVENT_MINIMIZED, 0, 0);
}
}
return (0);
}
break;
return (0);
case WM_MOUSEMOVE:
case WM_INPUT: /* mouse events */
{
LPBYTE lpb;
int w, h;
const RAWINPUTHEADER *header;
int index;
SDL_Mouse *mouse;
int x, y;
int i;
int size = 0;
const RAWMOUSE *raw_mouse = NULL;
LPPOINT point;
USHORT flags;
index = data->videodata->mouse;
mouse = SDL_GetMouse(index);
/* we're collecting data from the mouse */
GetRawInputData((HRAWINPUT) lParam, RID_INPUT, NULL, &size,
sizeof(RAWINPUTHEADER));
lpb = SDL_malloc(size * sizeof(LPBYTE));
GetRawInputData((HRAWINPUT) lParam, RID_INPUT, lpb, &size,
sizeof(RAWINPUTHEADER));
raw = (RAWINPUT *) lpb;
header = &raw->header;
flags = raw->data.mouse.usButtonFlags;
if (mouse->focus != data->windowID) {
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd;
TrackMouseEvent(&tme);
SDL_SetMouseFocus(index, data->windowID);
}
/* mouse has moved within the window */
x = LOWORD(lParam);
y = HIWORD(lParam);
if (mouse->relative_mode) {
int w, h;
POINT center;
SDL_GetWindowSize(data->windowID, &w, &h);
center.x = (w / 2);
center.y = (h / 2);
x -= center.x;
y -= center.y;
if (x || y) {
ClientToScreen(hwnd, &center);
SetCursorPos(center.x, center.y);
SDL_SendMouseMotion(index, 1, x, y);
/* we're checking which mouse generated the event */
for (i = 0; i < total_mice; ++i) {
if (mice[i] == header->hDevice) {
index = i;
break;
}
}
GetCursorPos(&point);
ScreenToClient(hwnd, &point);
SDL_GetWindowSize(data->windowID, &w, &h);
SDL_UpdateCoordinates(w, h); /* we're updating the current window size */
/* if the message was sent by a tablet we have to send also pressure */
if (i == tablet) {
SDL_SendMouseMotion(index, 0, (int) (&point->x),
(int) (&point->y), pressure);
} else {
SDL_SendMouseMotion(index, 0, x, y);
SDL_SendMouseMotion(index, 0, (int) (&point->x),
(int) (&point->y), 0);
}
/* we're sending mouse buttons messages to check up if sth changed */
if (flags & RI_MOUSE_BUTTON_1_DOWN) {
SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_LEFT);
} else if (flags & RI_MOUSE_BUTTON_1_UP) {
SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_LEFT);
}
if (flags & RI_MOUSE_BUTTON_2_DOWN) {
SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_MIDDLE);
} else if (flags & RI_MOUSE_BUTTON_2_UP) {
SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_MIDDLE);
}
if (flags & RI_MOUSE_BUTTON_3_DOWN) {
SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_RIGHT);
} else if (flags & RI_MOUSE_BUTTON_3_UP) {
SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_RIGHT);
}
if (flags & RI_MOUSE_WHEEL) {
if (raw->data.mouse.usButtonData != 0) {
SDL_SendMouseWheel(index, 0,
raw->data.mouse.usButtonData);
}
}
}
return (0);
@ -221,117 +294,6 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
return (0);
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
{
int xbuttonval = 0;
int index;
SDL_Mouse *mouse;
Uint8 button, state;
/* DJM:
We want the SDL window to take focus so that
it acts like a normal windows "component"
(e.g. gains keyboard focus on a mouse click).
*/
SetFocus(hwnd);
index = data->videodata->mouse;
mouse = SDL_GetMouse(index);
/* Figure out which button to use */
switch (msg) {
case WM_LBUTTONDOWN:
button = SDL_BUTTON_LEFT;
state = SDL_PRESSED;
break;
case WM_LBUTTONUP:
button = SDL_BUTTON_LEFT;
state = SDL_RELEASED;
break;
case WM_MBUTTONDOWN:
button = SDL_BUTTON_MIDDLE;
state = SDL_PRESSED;
break;
case WM_MBUTTONUP:
button = SDL_BUTTON_MIDDLE;
state = SDL_RELEASED;
break;
case WM_RBUTTONDOWN:
button = SDL_BUTTON_RIGHT;
state = SDL_PRESSED;
break;
case WM_RBUTTONUP:
button = SDL_BUTTON_RIGHT;
state = SDL_RELEASED;
break;
case WM_XBUTTONDOWN:
xbuttonval = GET_XBUTTON_WPARAM(wParam);
button = SDL_BUTTON_X1 + xbuttonval - 1;
state = SDL_PRESSED;
break;
case WM_XBUTTONUP:
xbuttonval = GET_XBUTTON_WPARAM(wParam);
button = SDL_BUTTON_X1 + xbuttonval - 1;
state = SDL_RELEASED;
break;
default:
/* Eh? Unknown button? */
return (0);
}
if (state == SDL_PRESSED) {
/* Grab mouse so we get up events */
if (++data->mouse_pressed > 0) {
SetCapture(hwnd);
}
} else {
/* Release mouse after all up events */
if (--data->mouse_pressed <= 0) {
ReleaseCapture();
data->mouse_pressed = 0;
}
}
if (!mouse->relative_mode) {
int x, y;
x = LOWORD(lParam);
y = HIWORD(lParam);
SDL_SendMouseMotion(index, 0, x, y);
}
SDL_SendMouseButton(index, state, button);
/*
* MSDN says:
* "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP
* messages, an application should return TRUE from [an
* XBUTTON message] if it processes it. Doing so will allow
* software that simulates this message on Microsoft Windows
* systems earlier than Windows 2000 to determine whether
* the window procedure processed the message or called
* DefWindowProc to process it.
*/
if (xbuttonval > 0) {
return (TRUE);
}
}
return (0);
case WM_MOUSEWHEEL:
{
int index;
int motion = (short) HIWORD(wParam);
index = data->videodata->mouse;
SDL_SendMouseWheel(index, 0, motion);
}
return (0);
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
{
@ -426,6 +388,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
wParam = VK_ENTER;
break;
}
/* Windows only reports keyup for print screen */
if (wParam == VK_SNAPSHOT
&& SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
@ -499,11 +462,9 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
inside their function, so I have to do it here.
*/
style = GetWindowLong(hwnd, GWL_STYLE);
AdjustWindowRect(&size,
style,
style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd) !=
NULL);
AdjustWindowRect(&size, style,
style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd)
!= NULL);
w = size.right - size.left;
h = size.bottom - size.top;
@ -661,8 +622,9 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst)
/* Register the application class */
class.hCursor = NULL;
class.hIcon = LoadImage(SDL_Instance, SDL_Appname,
IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
class.hIcon =
LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
LR_DEFAULTCOLOR);
class.lpszMenuName = NULL;
class.lpszClassName = SDL_Appname;
class.hbrBackground = NULL;
@ -707,11 +669,8 @@ WIN_SetError(const char *prefix)
{
TCHAR buffer[1024];
char *message;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(), 0, buffer, SDL_arraysize(buffer), NULL);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
buffer, SDL_arraysize(buffer), NULL);
message = WIN_StringToUTF8(buffer);
SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ":" : "", message);
SDL_free(message);