Mercurial > sdl-ios-xcode
view src/video/win32/SDL_win32events.c @ 1897:c2a27da60b18
Solved the performance problems by introducing the concept of a single-buffered
display, which is a fast path used for the whole-surface SDL 1.2 API.
Solved the flicker problems by implementing a backbuffer in the GDI renderer.
Unfortunately, now using the GDI renderer with a backbuffer and HBITMAPs is
significantly slower than SDL's surface code. *sigh*
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 12 Jul 2006 06:39:26 +0000 |
parents | c121d94672cb |
children | 83420da906a5 |
line wrap: on
line source
/* 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" #include "SDL_win32video.h" #include "SDL_version.h" #include "SDL_syswm.h" #include "SDL_vkeys.h" #include "../../events/SDL_events_c.h" /*#define WMMSG_DEBUG*/ #ifdef WMMSG_DEBUG #include "wmmsg.h" #endif /* Masks for processing the windows KEYDOWN and KEYUP messages */ #define REPEATED_KEYMASK (1<<30) #define EXTENDED_KEYMASK (1<<24) static SDLKey TranslateKey(WPARAM vkey) { SDLKey key; /* FIXME: Assign vkey directly to key if in ASCII range */ switch (vkey) { case VK_BACK: key = SDLK_BACKSPACE; break; case VK_TAB: key = SDLK_TAB; break; case VK_CLEAR: key = SDLK_CLEAR; break; case VK_RETURN: key = SDLK_RETURN; break; case VK_PAUSE: key = SDLK_PAUSE; break; case VK_ESCAPE: key = SDLK_ESCAPE; break; case VK_SPACE: key = SDLK_SPACE; break; case VK_APOSTROPHE: key = SDLK_QUOTE; break; case VK_COMMA: key = SDLK_COMMA; break; case VK_MINUS: key = SDLK_MINUS; break; case VK_PERIOD: key = SDLK_PERIOD; break; case VK_SLASH: key = SDLK_SLASH; break; case VK_0: key = SDLK_0; break; case VK_1: key = SDLK_1; break; case VK_2: key = SDLK_2; break; case VK_3: key = SDLK_3; break; case VK_4: key = SDLK_4; break; case VK_5: key = SDLK_5; break; case VK_6: key = SDLK_6; break; case VK_7: key = SDLK_7; break; case VK_8: key = SDLK_8; break; case VK_9: key = SDLK_9; break; case VK_SEMICOLON: key = SDLK_SEMICOLON; break; case VK_EQUALS: key = SDLK_EQUALS; break; case VK_LBRACKET: key = SDLK_LEFTBRACKET; break; case VK_BACKSLASH: key = SDLK_BACKSLASH; break; case VK_OEM_102: key = SDLK_LESS; break; case VK_RBRACKET: key = SDLK_RIGHTBRACKET; break; case VK_GRAVE: key = SDLK_BACKQUOTE; break; case VK_BACKTICK: key = SDLK_BACKQUOTE; break; case VK_A: key = SDLK_a; break; case VK_B: key = SDLK_b; break; case VK_C: key = SDLK_c; break; case VK_D: key = SDLK_d; break; case VK_E: key = SDLK_e; break; case VK_F: key = SDLK_f; break; case VK_G: key = SDLK_g; break; case VK_H: key = SDLK_h; break; case VK_I: key = SDLK_i; break; case VK_J: key = SDLK_j; break; case VK_K: key = SDLK_k; break; case VK_L: key = SDLK_l; break; case VK_M: key = SDLK_m; break; case VK_N: key = SDLK_n; break; case VK_O: key = SDLK_o; break; case VK_P: key = SDLK_p; break; case VK_Q: key = SDLK_q; break; case VK_R: key = SDLK_r; break; case VK_S: key = SDLK_s; break; case VK_T: key = SDLK_t; break; case VK_U: key = SDLK_u; break; case VK_V: key = SDLK_v; break; case VK_W: key = SDLK_w; break; case VK_X: key = SDLK_x; break; case VK_Y: key = SDLK_y; break; case VK_Z: key = SDLK_z; break; case VK_DELETE: key = SDLK_DELETE; break; case VK_NUMPAD0: key = SDLK_KP0; break; case VK_NUMPAD1: key = SDLK_KP1; break; case VK_NUMPAD2: key = SDLK_KP2; break; case VK_NUMPAD3: key = SDLK_KP3; break; case VK_NUMPAD4: key = SDLK_KP4; break; case VK_NUMPAD5: key = SDLK_KP5; break; case VK_NUMPAD6: key = SDLK_KP6; break; case VK_NUMPAD7: key = SDLK_KP7; break; case VK_NUMPAD8: key = SDLK_KP8; break; case VK_NUMPAD9: key = SDLK_KP9; break; case VK_DECIMAL: key = SDLK_KP_PERIOD; break; case VK_DIVIDE: key = SDLK_KP_DIVIDE; break; case VK_MULTIPLY: key = SDLK_KP_MULTIPLY; break; case VK_SUBTRACT: key = SDLK_KP_MINUS; break; case VK_ADD: key = SDLK_KP_PLUS; break; case VK_UP: key = SDLK_UP; break; case VK_DOWN: key = SDLK_DOWN; break; case VK_RIGHT: key = SDLK_RIGHT; break; case VK_LEFT: key = SDLK_LEFT; break; case VK_INSERT: key = SDLK_INSERT; break; case VK_HOME: key = SDLK_HOME; break; case VK_END: key = SDLK_END; break; case VK_PRIOR: key = SDLK_PAGEUP; break; case VK_NEXT: key = SDLK_PAGEDOWN; break; case VK_F1: key = SDLK_F1; break; case VK_F2: key = SDLK_F2; break; case VK_F3: key = SDLK_F3; break; case VK_F4: key = SDLK_F4; break; case VK_F5: key = SDLK_F5; break; case VK_F6: key = SDLK_F6; break; case VK_F7: key = SDLK_F7; break; case VK_F8: key = SDLK_F8; break; case VK_F9: key = SDLK_F9; break; case VK_F10: key = SDLK_F10; break; case VK_F11: key = SDLK_F11; break; case VK_F12: key = SDLK_F12; break; case VK_F13: key = SDLK_F13; break; case VK_F14: key = SDLK_F14; break; case VK_F15: key = SDLK_F15; break; case VK_NUMLOCK: key = SDLK_NUMLOCK; break; case VK_CAPITAL: key = SDLK_CAPSLOCK; break; case VK_SCROLL: key = SDLK_SCROLLOCK; break; case VK_RSHIFT: key = SDLK_RSHIFT; break; case VK_LSHIFT: key = SDLK_LSHIFT; break; case VK_RCONTROL: key = SDLK_RCTRL; break; case VK_LCONTROL: key = SDLK_LCTRL; break; case VK_RMENU: key = SDLK_RALT; break; case VK_LMENU: key = SDLK_LALT; break; case VK_RWIN: key = SDLK_RSUPER; break; case VK_LWIN: key = SDLK_LSUPER; break; case VK_HELP: key = SDLK_HELP; break; case VK_PRINT: key = SDLK_PRINT; break; case VK_SNAPSHOT: key = SDLK_PRINT; break; case VK_CANCEL: key = SDLK_BREAK; break; case VK_APPS: key = SDLK_MENU; break; default: key = SDLK_UNKNOWN; break; } return key; } LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SDL_WindowData *data; /* Get the window data for the window */ data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData")); if (!data) { return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam); } #ifdef WMMSG_DEBUG fprintf(stderr, "Received windows message: "); if (msg > MAX_WMMSG) { fprintf(stderr, "%d", msg); } else { fprintf(stderr, "%s", wmtab[msg]); } fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam); #endif /* Send a SDL_SYSWMEVENT if the application wants them */ if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) { SDL_SysWMmsg wmmsg; SDL_VERSION(&wmmsg.version); wmmsg.hwnd = hwnd; wmmsg.msg = msg; wmmsg.wParam = wParam; wmmsg.lParam = lParam; SDL_SendSysWMEvent(&wmmsg); } switch (msg) { case WM_SHOWWINDOW: { if (wParam) { SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0); } else { SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0); } } break; case WM_ACTIVATE: { int index; SDL_Keyboard *keyboard; BOOL minimized; minimized = HIWORD(wParam); index = data->videodata->keyboard; keyboard = SDL_GetKeyboard(index); if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) { SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0); SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESTORED, 0, 0); if (IsZoomed(hwnd)) { SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MAXIMIZED, 0, 0); } if (keyboard && keyboard->focus != data->windowID) { SDL_SetKeyboardFocus(index, data->windowID); } /* FIXME: Update keyboard state */ } else { if (keyboard && keyboard->focus == data->windowID) { SDL_SetKeyboardFocus(index, 0); } if (minimized) { SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0, 0); } } return (0); } break; case WM_MOUSEMOVE: { int index; SDL_Mouse *mouse; int x, y; index = data->videodata->mouse; mouse = SDL_GetMouse(index); 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, ¢er); SetCursorPos(center.x, center.y); SDL_SendMouseMotion(index, 1, x, y); } } else { SDL_SendMouseMotion(index, 0, x, y); } } return (0); case WM_MOUSELEAVE: { int index; SDL_Mouse *mouse; index = data->videodata->mouse; mouse = SDL_GetMouse(index); if (mouse->focus == data->windowID) { SDL_SetMouseFocus(index, 0); } } return (0); case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: { 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; 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); } return (0); case WM_MOUSEWHEEL: { int index; int motion = (short) HIWORD(wParam); index = data->videodata->mouse; SDL_SendMouseWheel(index, motion); } return (0); case WM_SYSKEYDOWN: case WM_KEYDOWN: { int index; /* Ignore repeated keys */ if (lParam & REPEATED_KEYMASK) { return (0); } index = data->videodata->keyboard; switch (wParam) { case VK_CONTROL: if (lParam & EXTENDED_KEYMASK) wParam = VK_RCONTROL; else wParam = VK_LCONTROL; break; case VK_SHIFT: /* EXTENDED trick doesn't work here */ { Uint8 *state = SDL_GetKeyState(NULL); if (state[SDLK_LSHIFT] == SDL_RELEASED && (GetKeyState(VK_LSHIFT) & 0x8000)) { wParam = VK_LSHIFT; } else if (state[SDLK_RSHIFT] == SDL_RELEASED && (GetKeyState(VK_RSHIFT) & 0x8000)) { wParam = VK_RSHIFT; } else { /* Probably a key repeat */ return (0); } } break; case VK_MENU: if (lParam & EXTENDED_KEYMASK) wParam = VK_RMENU; else wParam = VK_LMENU; break; } SDL_SendKeyboardKey(index, SDL_PRESSED, (Uint8) HIWORD(lParam), TranslateKey(wParam)); } return (0); case WM_SYSKEYUP: case WM_KEYUP: { int index; index = data->videodata->keyboard; switch (wParam) { case VK_CONTROL: if (lParam & EXTENDED_KEYMASK) wParam = VK_RCONTROL; else wParam = VK_LCONTROL; break; case VK_SHIFT: /* EXTENDED trick doesn't work here */ { Uint8 *state = SDL_GetKeyState(NULL); if (state[SDLK_LSHIFT] == SDL_PRESSED && !(GetKeyState(VK_LSHIFT) & 0x8000)) { wParam = VK_LSHIFT; } else if (state[SDLK_RSHIFT] == SDL_PRESSED && !(GetKeyState(VK_RSHIFT) & 0x8000)) { wParam = VK_RSHIFT; } else { /* Probably a key repeat */ return (0); } } break; case VK_MENU: if (lParam & EXTENDED_KEYMASK) wParam = VK_RMENU; else wParam = VK_LMENU; break; } /* Windows only reports keyup for print screen */ if (wParam == VK_SNAPSHOT && SDL_GetKeyState(NULL)[SDLK_PRINT] == SDL_RELEASED) { SDL_SendKeyboardKey(index, SDL_PRESSED, (Uint8) HIWORD(lParam), TranslateKey(wParam)); } SDL_SendKeyboardKey(index, SDL_RELEASED, (Uint8) HIWORD(lParam), TranslateKey(wParam)); } return (0); case WM_GETMINMAXINFO: { MINMAXINFO *info; RECT size; int x, y; int w, h; int style; /* If we allow resizing, let the resize happen naturally */ if (SDL_GetWindowFlags(data->windowID) & SDL_WINDOW_RESIZABLE) { return (0); } /* Get the current position of our window */ GetWindowRect(hwnd, &size); x = size.left; y = size.top; /* Calculate current size of our window */ SDL_GetWindowSize(data->windowID, &w, &h); size.top = 0; size.left = 0; size.bottom = h; size.right = w; /* DJM - according to the docs for GetMenu(), the return value is undefined if hwnd is a child window. Aparently it's too difficult for MS to check 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); w = size.right - size.left; h = size.bottom - size.top; /* Fix our size to the current size */ info = (MINMAXINFO *) lParam; info->ptMaxSize.x = w; info->ptMaxSize.y = h; info->ptMaxPosition.x = x; info->ptMaxPosition.y = y; info->ptMinTrackSize.x = w; info->ptMinTrackSize.y = h; info->ptMaxTrackSize.x = w; info->ptMaxTrackSize.y = h; } return (0); case WM_WINDOWPOSCHANGED: { RECT rect; int x, y; int w, h; Uint32 window_flags; GetClientRect(hwnd, &rect); ClientToScreen(hwnd, (LPPOINT) & rect); ClientToScreen(hwnd, (LPPOINT) & rect + 1); window_flags = SDL_GetWindowFlags(data->windowID); if ((window_flags & SDL_WINDOW_INPUT_GRABBED) && (window_flags & SDL_WINDOW_INPUT_FOCUS)) { ClipCursor(&rect); } x = rect.left; y = rect.top; SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED, x, y); w = rect.right - rect.left; h = rect.bottom - rect.top; SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED, w, h); } break; case WM_SETCURSOR: { /* Uint16 hittest; hittest = LOWORD(lParam); if (hittest == HTCLIENT) { SetCursor(SDL_hcursor); return (TRUE); } */ } break; /* We are about to get palette focus! */ case WM_QUERYNEWPALETTE: { /* WIN_RealizePalette(current_video); return (TRUE); */ } break; /* Another application changed the palette */ case WM_PALETTECHANGED: { /* WIN_PaletteChanged(current_video, (HWND) wParam); */ } break; /* We were occluded, refresh our display */ case WM_PAINT: { RECT rect; if (GetUpdateRect(hwnd, &rect, FALSE)) { ValidateRect(hwnd, &rect); SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED, 0, 0); } } return (0); /* We'll do our own drawing, prevent flicker */ case WM_ERASEBKGND: { } return (1); case WM_SYSCOMMAND: { /* Don't start the screensaver or blank the monitor in fullscreen apps */ if ((wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER) { if (SDL_GetWindowFlags(data->windowID) & SDL_WINDOW_FULLSCREEN) { return (0); } } } break; case WM_CLOSE: { SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0, 0); } return (0); } return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam); } void WIN_PumpEvents(_THIS) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } static int app_registered = 0; LPTSTR SDL_Appname = NULL; Uint32 SDL_Appstyle = 0; HINSTANCE SDL_Instance = NULL; /* Register the class for this application */ int SDL_RegisterApp(char *name, Uint32 style, void *hInst) { WNDCLASS class; /* Only do this once... */ if (app_registered) { ++app_registered; return (0); } if (!name && !SDL_Appname) { name = "SDL_app"; SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC); SDL_Instance = hInst ? hInst : GetModuleHandle(NULL); } if (name) { SDL_Appname = WIN_UTF8ToString(name); SDL_Appstyle = style; SDL_Instance = hInst ? hInst : GetModuleHandle(NULL); } /* Register the application class */ class.hCursor = NULL; class.hIcon = LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); class.lpszMenuName = NULL; class.lpszClassName = SDL_Appname; class.hbrBackground = NULL; class.hInstance = SDL_Instance; class.style = SDL_Appstyle; class.lpfnWndProc = DefWindowProc; class.cbWndExtra = 0; class.cbClsExtra = 0; if (!RegisterClass(&class)) { SDL_SetError("Couldn't register application class"); return (-1); } app_registered = 1; return (0); } /* Unregisters the windowclass registered in SDL_RegisterApp above. */ void SDL_UnregisterApp() { WNDCLASS class; /* SDL_RegisterApp might not have been called before */ if (!app_registered) { return; } --app_registered; if (app_registered == 0) { /* Check for any registered window classes. */ if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) { UnregisterClass(SDL_Appname, SDL_Instance); } SDL_free(SDL_Appname); SDL_Appname = NULL; } } /* Sets an error message based on GetLastError() */ void WIN_SetError(const char *prefix) { TCHAR buffer[1024]; char *message; 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); } /* vi: set ts=4 sw=4 expandtab: */