Added horizontal scrolling support --HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%402428
652 lines
14 KiB
C
652 lines
14 KiB
C
/*
|
|
SDL - Simple DirectMedia Layer
|
|
Copyright (C) 1997-2006 Sam Lantinga
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
Sam Lantinga
|
|
slouken@libsdl.org
|
|
*/
|
|
#include "SDL_config.h"
|
|
|
|
/* General mouse handling code for SDL */
|
|
|
|
#include "SDL_events.h"
|
|
#include "SDL_events_c.h"
|
|
#include "default_cursor.h"
|
|
|
|
|
|
static int SDL_num_mice;
|
|
static int SDL_current_mouse;
|
|
static SDL_Mouse **SDL_mice;
|
|
|
|
|
|
/* Public functions */
|
|
int
|
|
SDL_MouseInit(void)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
SDL_Mouse *
|
|
SDL_GetMouse(int index)
|
|
{
|
|
if (index < 0 || index >= SDL_num_mice) {
|
|
return NULL;
|
|
}
|
|
return SDL_mice[index];
|
|
}
|
|
|
|
int
|
|
SDL_AddMouse(const SDL_Mouse * mouse, int index)
|
|
{
|
|
SDL_Mouse **mice;
|
|
int selected_mouse;
|
|
|
|
/* Add the mouse to the list of mice */
|
|
if (index < 0 || index >= SDL_num_mice || SDL_mice[index]) {
|
|
mice =
|
|
(SDL_Mouse **) SDL_realloc(SDL_mice,
|
|
(SDL_num_mice + 1) * sizeof(*mice));
|
|
if (!mice) {
|
|
SDL_OutOfMemory();
|
|
return -1;
|
|
}
|
|
|
|
SDL_mice = mice;
|
|
index = SDL_num_mice++;
|
|
}
|
|
SDL_mice[index] = (SDL_Mouse *) SDL_malloc(sizeof(*SDL_mice[index]));
|
|
if (!SDL_mice[index]) {
|
|
SDL_OutOfMemory();
|
|
return -1;
|
|
}
|
|
*SDL_mice[index] = *mouse;
|
|
|
|
/* Create the default cursor for the mouse */
|
|
SDL_mice[index]->cursor_shown = SDL_TRUE;
|
|
selected_mouse = SDL_SelectMouse(index);
|
|
SDL_mice[index]->cur_cursor = NULL;
|
|
SDL_mice[index]->def_cursor =
|
|
SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH,
|
|
DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
|
|
SDL_SetCursor(SDL_mice[index]->def_cursor);
|
|
SDL_SelectMouse(selected_mouse);
|
|
|
|
return index;
|
|
}
|
|
|
|
void
|
|
SDL_DelMouse(int index)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(index);
|
|
|
|
if (!mouse) {
|
|
return;
|
|
}
|
|
|
|
mouse->def_cursor = NULL;
|
|
while (mouse->cursors) {
|
|
SDL_FreeCursor(mouse->cursors);
|
|
}
|
|
|
|
if (mouse->FreeMouse) {
|
|
mouse->FreeMouse(mouse);
|
|
}
|
|
SDL_free(mouse);
|
|
|
|
SDL_mice[index] = NULL;
|
|
}
|
|
|
|
void
|
|
SDL_ResetMouse(int index)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(index);
|
|
|
|
if (!mouse) {
|
|
return;
|
|
}
|
|
|
|
/* FIXME */
|
|
}
|
|
|
|
void
|
|
SDL_MouseQuit(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SDL_num_mice; ++i) {
|
|
SDL_DelMouse(i);
|
|
}
|
|
SDL_num_mice = 0;
|
|
SDL_current_mouse = 0;
|
|
|
|
if (SDL_mice) {
|
|
SDL_free(SDL_mice);
|
|
SDL_mice = NULL;
|
|
}
|
|
}
|
|
|
|
int
|
|
SDL_GetNumMice(void)
|
|
{
|
|
return SDL_num_mice;
|
|
}
|
|
|
|
int
|
|
SDL_SelectMouse(int index)
|
|
{
|
|
if (index >= 0 && index < SDL_num_mice) {
|
|
SDL_current_mouse = index;
|
|
}
|
|
return SDL_current_mouse;
|
|
}
|
|
|
|
SDL_WindowID
|
|
SDL_GetMouseFocusWindow()
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
return 0;
|
|
}
|
|
return mouse->focus;
|
|
}
|
|
|
|
static int SDLCALL
|
|
FlushMouseMotion(void *param, SDL_Event * event)
|
|
{
|
|
if (event->type == SDL_MOUSEMOTION
|
|
&& event->motion.which == (Uint8) SDL_current_mouse) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int
|
|
SDL_SetRelativeMouseMode(SDL_bool enabled)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
return -1;
|
|
}
|
|
|
|
/* Flush pending mouse motion */
|
|
mouse->flush_motion = SDL_TRUE;
|
|
SDL_PumpEvents();
|
|
mouse->flush_motion = SDL_FALSE;
|
|
SDL_FilterEvents(FlushMouseMotion, mouse);
|
|
|
|
/* Set the relative mode */
|
|
mouse->relative_mode = enabled;
|
|
|
|
/* Update cursor visibility */
|
|
SDL_SetCursor(NULL);
|
|
|
|
if (!enabled) {
|
|
/* Restore the expected mouse position */
|
|
SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
SDL_bool
|
|
SDL_GetRelativeMouseMode()
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
return SDL_FALSE;
|
|
}
|
|
return mouse->relative_mode;
|
|
}
|
|
|
|
Uint8
|
|
SDL_GetMouseState(int *x, int *y)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
if (x) {
|
|
*x = 0;
|
|
}
|
|
if (y) {
|
|
*y = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (x) {
|
|
*x = mouse->x;
|
|
}
|
|
if (y) {
|
|
*y = mouse->y;
|
|
}
|
|
return mouse->buttonstate;
|
|
}
|
|
|
|
Uint8
|
|
SDL_GetRelativeMouseState(int *x, int *y)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
if (x) {
|
|
*x = 0;
|
|
}
|
|
if (y) {
|
|
*y = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (x) {
|
|
*x = mouse->xdelta;
|
|
}
|
|
if (y) {
|
|
*y = mouse->ydelta;
|
|
}
|
|
mouse->xdelta = 0;
|
|
mouse->ydelta = 0;
|
|
return mouse->buttonstate;
|
|
}
|
|
|
|
void
|
|
SDL_SetMouseFocus(int index, SDL_WindowID windowID)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(index);
|
|
int i;
|
|
SDL_bool focus;
|
|
|
|
if (!mouse || (mouse->focus == windowID)) {
|
|
return;
|
|
}
|
|
|
|
/* See if the current window has lost focus */
|
|
if (mouse->focus) {
|
|
focus = SDL_FALSE;
|
|
for (i = 0; i < SDL_num_mice; ++i) {
|
|
SDL_Mouse *check;
|
|
if (i != index) {
|
|
check = SDL_GetMouse(i);
|
|
if (check && check->focus == mouse->focus) {
|
|
focus = SDL_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!focus) {
|
|
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
|
|
}
|
|
}
|
|
|
|
mouse->focus = windowID;
|
|
|
|
if (mouse->focus) {
|
|
focus = SDL_FALSE;
|
|
for (i = 0; i < SDL_num_mice; ++i) {
|
|
SDL_Mouse *check;
|
|
if (i != index) {
|
|
check = SDL_GetMouse(i);
|
|
if (check && check->focus == mouse->focus) {
|
|
focus = SDL_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!focus) {
|
|
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
SDL_SendMouseMotion(int index, int relative, int x, int y)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(index);
|
|
int posted;
|
|
int xrel;
|
|
int yrel;
|
|
|
|
if (!mouse || mouse->flush_motion) {
|
|
return 0;
|
|
}
|
|
|
|
if (relative) {
|
|
/* Push the cursor around */
|
|
xrel = x;
|
|
yrel = y;
|
|
x = (mouse->x + xrel);
|
|
y = (mouse->y + yrel);
|
|
} else {
|
|
xrel = x - mouse->x;
|
|
yrel = y - mouse->y;
|
|
}
|
|
|
|
/* Drop events that don't change state */
|
|
if (!xrel && !yrel) {
|
|
#if 0
|
|
printf("Mouse event didn't change state - dropped!\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* Update internal mouse state */
|
|
if (!mouse->relative_mode) {
|
|
mouse->x = x;
|
|
mouse->y = y;
|
|
}
|
|
mouse->xdelta += xrel;
|
|
mouse->ydelta += yrel;
|
|
|
|
/* Move the mouse cursor, if needed */
|
|
if (mouse->cursor_shown && !mouse->relative_mode &&
|
|
mouse->MoveCursor && mouse->cur_cursor) {
|
|
mouse->MoveCursor(mouse->cur_cursor);
|
|
}
|
|
|
|
/* Post the event, if desired */
|
|
posted = 0;
|
|
if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE) {
|
|
SDL_Event event;
|
|
event.motion.type = SDL_MOUSEMOTION;
|
|
event.motion.which = (Uint8) index;
|
|
event.motion.state = mouse->buttonstate;
|
|
event.motion.x = mouse->x;
|
|
event.motion.y = mouse->y;
|
|
event.motion.xrel = xrel;
|
|
event.motion.yrel = yrel;
|
|
event.motion.windowID = mouse->focus;
|
|
posted = (SDL_PushEvent(&event) > 0);
|
|
}
|
|
return posted;
|
|
}
|
|
|
|
int
|
|
SDL_SendMouseButton(int index, Uint8 state, Uint8 button)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(index);
|
|
int posted;
|
|
Uint8 type;
|
|
|
|
if (!mouse) {
|
|
return 0;
|
|
}
|
|
|
|
/* Figure out which event to perform */
|
|
switch (state) {
|
|
case SDL_PRESSED:
|
|
if (mouse->buttonstate & SDL_BUTTON(button)) {
|
|
/* Ignore this event, no state change */
|
|
return 0;
|
|
}
|
|
type = SDL_MOUSEBUTTONDOWN;
|
|
mouse->buttonstate |= SDL_BUTTON(button);
|
|
break;
|
|
case SDL_RELEASED:
|
|
if (!(mouse->buttonstate & SDL_BUTTON(button))) {
|
|
/* Ignore this event, no state change */
|
|
return 0;
|
|
}
|
|
type = SDL_MOUSEBUTTONUP;
|
|
mouse->buttonstate &= ~SDL_BUTTON(button);
|
|
break;
|
|
default:
|
|
/* Invalid state -- bail */
|
|
return 0;
|
|
}
|
|
|
|
/* Post the event, if desired */
|
|
posted = 0;
|
|
if (SDL_ProcessEvents[type] == SDL_ENABLE) {
|
|
SDL_Event event;
|
|
event.type = type;
|
|
event.button.which = (Uint8) index;
|
|
event.button.state = state;
|
|
event.button.button = button;
|
|
event.button.x = mouse->x;
|
|
event.button.y = mouse->y;
|
|
event.button.windowID = mouse->focus;
|
|
posted = (SDL_PushEvent(&event) > 0);
|
|
}
|
|
return posted;
|
|
}
|
|
|
|
int
|
|
SDL_SendMouseWheel(int index, int x, int y)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(index);
|
|
int posted;
|
|
|
|
if (!mouse || (!x && !y)) {
|
|
return 0;
|
|
}
|
|
|
|
/* Post the event, if desired */
|
|
posted = 0;
|
|
if (SDL_ProcessEvents[SDL_MOUSEWHEEL] == SDL_ENABLE) {
|
|
SDL_Event event;
|
|
event.type = SDL_MOUSEWHEEL;
|
|
event.wheel.which = (Uint8) index;
|
|
event.wheel.x = x;
|
|
event.wheel.y = y;
|
|
event.wheel.windowID = mouse->focus;
|
|
posted = (SDL_PushEvent(&event) > 0);
|
|
}
|
|
return posted;
|
|
}
|
|
|
|
void
|
|
SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
return;
|
|
}
|
|
|
|
if (mouse->WarpMouse) {
|
|
mouse->WarpMouse(mouse, windowID, x, y);
|
|
} else {
|
|
SDL_SetMouseFocus(SDL_current_mouse, windowID);
|
|
SDL_SendMouseMotion(SDL_current_mouse, 0, x, y);
|
|
}
|
|
}
|
|
|
|
SDL_Cursor *
|
|
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
|
|
int w, int h, int hot_x, int hot_y)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
SDL_Surface *surface;
|
|
SDL_Cursor *cursor;
|
|
int x, y;
|
|
Uint32 *pixel;
|
|
Uint8 datab, maskb;
|
|
const Uint32 black = 0xFF000000;
|
|
const Uint32 white = 0xFFFFFFFF;
|
|
const Uint32 transparent = 0x00000000;
|
|
|
|
if (!mouse) {
|
|
SDL_SetError("No mice are initialized");
|
|
return NULL;
|
|
}
|
|
|
|
if (!mouse->CreateCursor) {
|
|
SDL_SetError("Current mouse doesn't have cursor support");
|
|
return NULL;
|
|
}
|
|
|
|
/* Sanity check the hot spot */
|
|
if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) {
|
|
SDL_SetError("Cursor hot spot doesn't lie within cursor");
|
|
return NULL;
|
|
}
|
|
|
|
/* Make sure the width is a multiple of 8 */
|
|
w = ((w + 7) & ~7);
|
|
|
|
/* Create the surface from a bitmap */
|
|
surface =
|
|
SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
|
|
0xFF000000);
|
|
if (!surface) {
|
|
return NULL;
|
|
}
|
|
for (y = 0; y < h; ++y) {
|
|
pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
|
|
for (x = 0; x < w; ++x) {
|
|
if ((x % 8) == 0) {
|
|
datab = *data++;
|
|
maskb = *mask++;
|
|
}
|
|
if (maskb & 0x80) {
|
|
*pixel++ = (datab & 0x80) ? black : white;
|
|
} else {
|
|
*pixel++ = (datab & 0x80) ? black : transparent;
|
|
}
|
|
datab <<= 1;
|
|
maskb <<= 1;
|
|
}
|
|
}
|
|
|
|
cursor = mouse->CreateCursor(surface, hot_x, hot_y);
|
|
if (cursor) {
|
|
cursor->mouse = mouse;
|
|
cursor->next = mouse->cursors;
|
|
mouse->cursors = cursor;
|
|
}
|
|
|
|
SDL_FreeSurface(surface);
|
|
|
|
return cursor;
|
|
}
|
|
|
|
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
|
|
if this is desired for any reason. This is used when setting
|
|
the video mode and when the SDL window gains the mouse focus.
|
|
*/
|
|
void
|
|
SDL_SetCursor(SDL_Cursor * cursor)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
SDL_SetError("No mice are initialized");
|
|
return;
|
|
}
|
|
|
|
/* Set the new cursor */
|
|
if (cursor) {
|
|
/* Make sure the cursor is still valid for this mouse */
|
|
SDL_Cursor *found;
|
|
for (found = mouse->cursors; found; found = found->next) {
|
|
if (found == cursor) {
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
SDL_SetError("Cursor not associated with the current mouse");
|
|
return;
|
|
}
|
|
mouse->cur_cursor = cursor;
|
|
} else {
|
|
cursor = mouse->cur_cursor;
|
|
}
|
|
|
|
if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
|
|
if (mouse->ShowCursor) {
|
|
mouse->ShowCursor(cursor);
|
|
}
|
|
} else {
|
|
if (mouse->ShowCursor) {
|
|
mouse->ShowCursor(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_Cursor *
|
|
SDL_GetCursor(void)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
|
|
if (!mouse) {
|
|
return NULL;
|
|
}
|
|
return mouse->cur_cursor;
|
|
}
|
|
|
|
void
|
|
SDL_FreeCursor(SDL_Cursor * cursor)
|
|
{
|
|
SDL_Mouse *mouse;
|
|
SDL_Cursor *curr, *prev;
|
|
|
|
if (!cursor) {
|
|
return;
|
|
}
|
|
mouse = cursor->mouse;
|
|
|
|
if (cursor == mouse->def_cursor) {
|
|
return;
|
|
}
|
|
if (cursor == mouse->cur_cursor) {
|
|
SDL_SetCursor(mouse->def_cursor);
|
|
}
|
|
|
|
for (prev = NULL, curr = mouse->cursors; curr;
|
|
prev = curr, curr = curr->next) {
|
|
if (curr == cursor) {
|
|
if (prev) {
|
|
prev->next = curr->next;
|
|
} else {
|
|
mouse->cursors = curr->next;
|
|
}
|
|
|
|
if (mouse->FreeCursor) {
|
|
mouse->FreeCursor(curr);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
SDL_ShowCursor(int toggle)
|
|
{
|
|
SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
|
|
SDL_bool shown;
|
|
|
|
if (!mouse) {
|
|
return 0;
|
|
}
|
|
|
|
shown = mouse->cursor_shown;
|
|
if (toggle >= 0) {
|
|
if (toggle) {
|
|
mouse->cursor_shown = SDL_TRUE;
|
|
} else {
|
|
mouse->cursor_shown = SDL_FALSE;
|
|
}
|
|
if (mouse->cursor_shown != shown) {
|
|
SDL_SetCursor(NULL);
|
|
}
|
|
}
|
|
return shown;
|
|
}
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|