You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

304 lines
6.7 KiB

#include "pch.h"
/** @file
* *
* Windows message handling and keyboard event conversion for SDL.
*/
namespace dvl {
static std::deque<MSG> message_queue;
static int translate_sdl_key(SDL_Keysym key)
{
int sym = key.sym;
switch (sym) {
case SDLK_ESCAPE:
return VK_ESCAPE;
case SDLK_RETURN:
case SDLK_KP_ENTER:
return VK_RETURN;
case SDLK_TAB:
return VK_TAB;
case SDLK_SPACE:
return VK_SPACE;
case SDLK_BACKSPACE:
return VK_BACK;
case SDLK_DOWN:
return VK_DOWN;
case SDLK_LEFT:
return VK_LEFT;
case SDLK_RIGHT:
return VK_RIGHT;
case SDLK_UP:
return VK_UP;
case SDLK_PAGEUP:
return VK_PRIOR;
case SDLK_PAGEDOWN:
return VK_NEXT;
case SDLK_PAUSE:
return VK_PAUSE;
case SDLK_SEMICOLON:
return VK_OEM_1;
case SDLK_QUESTION:
return VK_OEM_2;
case SDLK_BACKQUOTE:
return VK_OEM_3;
case SDLK_LEFTBRACKET:
return VK_OEM_4;
case SDLK_BACKSLASH:
return VK_OEM_5;
case SDLK_RIGHTBRACKET:
return VK_OEM_6;
case SDLK_QUOTE:
return VK_OEM_7;
case SDLK_MINUS:
return VK_OEM_MINUS;
case SDLK_PLUS:
return VK_OEM_PLUS;
case SDLK_PERIOD:
return VK_OEM_PERIOD;
case SDLK_COMMA:
return VK_OEM_COMMA;
case SDLK_LSHIFT:
case SDLK_RSHIFT:
return VK_SHIFT;
case SDLK_PRINTSCREEN:
return VK_SNAPSHOT;
default:
if (sym >= SDLK_a && sym <= SDLK_z) {
return 'A' + (sym - SDLK_a);
} else if (sym >= SDLK_0 && sym <= SDLK_9) {
return '0' + (sym - SDLK_0);
} else if (sym >= SDLK_F1 && sym <= SDLK_F12) {
return VK_F1 + (sym - SDLK_F1);
}
DUMMY_PRINT("unknown key: name=%s sym=0x%X scan=%d mod=0x%X", SDL_GetKeyName(sym), sym, key.scancode, key.mod);
return -1;
}
}
static WPARAM keystate_for_mouse(WPARAM ret)
{
const Uint8 *keystate = SDL_GetKeyboardState(NULL);
ret |= keystate[SDL_SCANCODE_LSHIFT] ? MK_SHIFT : 0;
ret |= keystate[SDL_SCANCODE_RSHIFT] ? MK_SHIFT : 0;
// XXX: other MK_* codes not implemented
return ret;
}
static WINBOOL false_avail()
{
DUMMY_PRINT("return FALSE although event avaliable");
return FALSE;
}
WINBOOL PeekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
if (wMsgFilterMin != 0)
UNIMPLEMENTED();
if (wMsgFilterMax != 0)
UNIMPLEMENTED();
if (hWnd != NULL)
UNIMPLEMENTED();
if (wRemoveMsg == DVL_PM_NOREMOVE) {
// This does not actually fill out lpMsg, but this is ok
// since the engine never uses it in this case
return !message_queue.empty() || SDL_PollEvent(NULL);
}
if (wRemoveMsg != DVL_PM_REMOVE) {
UNIMPLEMENTED();
}
if (!message_queue.empty()) {
*lpMsg = message_queue.front();
message_queue.pop_front();
return TRUE;
}
SDL_Event e;
if (!SDL_PollEvent(&e)) {
return FALSE;
}
lpMsg->hwnd = hWnd;
lpMsg->lParam = 0;
lpMsg->wParam = 0;
switch (e.type) {
case SDL_QUIT:
lpMsg->message = DVL_WM_QUIT;
break;
case SDL_KEYDOWN:
case SDL_KEYUP: {
int key = translate_sdl_key(e.key.keysym);
if (key == -1)
return false_avail();
lpMsg->message = e.type == SDL_KEYDOWN ? WM_KEYDOWN : WM_KEYUP;
lpMsg->wParam = (DWORD)key;
// HACK: Encode modifier in lParam for TranslateMessage later
lpMsg->lParam = e.key.keysym.mod << 16;
} break;
case SDL_MOUSEMOTION:
lpMsg->message = WM_MOUSEMOVE;
lpMsg->lParam = (e.motion.y << 16) | (e.motion.x & 0xFFFF);
lpMsg->wParam = keystate_for_mouse(0);
break;
case SDL_MOUSEBUTTONDOWN: {
int button = e.button.button;
if (button == SDL_BUTTON_LEFT) {
lpMsg->message = WM_LBUTTONDOWN;
lpMsg->lParam = (e.button.y << 16) | (e.button.x & 0xFFFF);
lpMsg->wParam = keystate_for_mouse(MK_LBUTTON);
} else if (button == SDL_BUTTON_RIGHT) {
lpMsg->message = WM_RBUTTONDOWN;
lpMsg->lParam = (e.button.y << 16) | (e.button.x & 0xFFFF);
lpMsg->wParam = keystate_for_mouse(MK_RBUTTON);
} else {
return false_avail();
}
} break;
case SDL_MOUSEBUTTONUP: {
int button = e.button.button;
if (button == SDL_BUTTON_LEFT) {
lpMsg->message = WM_LBUTTONUP;
lpMsg->lParam = (e.button.y << 16) | (e.button.x & 0xFFFF);
lpMsg->wParam = keystate_for_mouse(0);
} else if (button == SDL_BUTTON_RIGHT) {
lpMsg->message = WM_RBUTTONUP;
lpMsg->lParam = (e.button.y << 16) | (e.button.x & 0xFFFF);
lpMsg->wParam = keystate_for_mouse(0);
} else {
return false_avail();
}
} break;
case SDL_TEXTINPUT:
case SDL_WINDOWEVENT:
if (e.window.event == SDL_WINDOWEVENT_CLOSE) {
lpMsg->message = WM_QUERYENDSESSION;
} else {
return false_avail();
}
break;
default:
DUMMY_PRINT("unknown SDL message 0x%X", e.type);
return false_avail();
}
return TRUE;
}
WINBOOL TranslateMessage(CONST MSG *lpMsg)
{
assert(lpMsg->hwnd == 0);
if (lpMsg->message == WM_KEYDOWN) {
int key = lpMsg->wParam;
unsigned mod = (DWORD)lpMsg->lParam >> 16;
bool shift = (mod & KMOD_SHIFT) != 0;
bool upper = shift != (mod & KMOD_CAPS);
bool is_alpha = (key >= 'A' && key <= 'Z');
bool is_numeric = (key >= '0' && key <= '9');
bool is_control = key == VK_SPACE || key == VK_BACK || key == VK_ESCAPE || key == VK_TAB || key == VK_RETURN;
bool is_oem = (key >= VK_OEM_1 && key <= VK_OEM_7);
if (is_control || is_alpha || is_numeric || is_oem) {
if (!upper && is_alpha) {
key = tolower(key);
} else if (shift && is_numeric) {
key = key == '0' ? ')' : key - 0x10;
} else if (is_oem) {
// XXX: This probably only supports US keyboard layout
switch (key) {
case VK_OEM_1:
key = shift ? ':' : ';';
break;
case VK_OEM_2:
key = shift ? '?' : '/';
break;
case VK_OEM_3:
key = shift ? '~' : '`';
break;
case VK_OEM_4:
key = shift ? '{' : '[';
break;
case VK_OEM_5:
key = shift ? '|' : '\\';
break;
case VK_OEM_6:
key = shift ? '}' : ']';
break;
case VK_OEM_7:
key = shift ? '"' : '\'';
break;
case VK_OEM_MINUS:
key = shift ? '_' : '-';
break;
case VK_OEM_PLUS:
key = shift ? '+' : '=';
break;
case VK_OEM_PERIOD:
key = shift ? '>' : '.';
break;
case VK_OEM_COMMA:
key = shift ? '<' : ',';
break;
default:
UNIMPLEMENTED();
}
}
if (key >= 32) {
DUMMY_PRINT("char: %c", key);
}
// XXX: This does not add extended info to lParam
PostMessageA(lpMsg->hwnd, WM_CHAR, key, 0);
}
}
return TRUE;
}
SHORT GetAsyncKeyState(int vKey)
{
DUMMY_ONCE();
// TODO: Not handled yet.
return 0;
}
LRESULT DispatchMessageA(CONST MSG *lpMsg)
{
DUMMY_ONCE();
assert(lpMsg->hwnd == 0);
assert(CurrentProc);
// assert(CurrentProc == GM_Game);
return CurrentProc(lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
}
WINBOOL PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
DUMMY();
assert(hWnd == 0);
MSG msg;
msg.hwnd = hWnd;
msg.message = Msg;
msg.wParam = wParam;
msg.lParam = lParam;
message_queue.push_back(msg);
return TRUE;
}
}