/*
    Copyright 2016-2017 StapleButter

    This file is part of melonDS.

    melonDS is free software: you can redistribute it and/or modify it under
    the terms of the GNU General Public License as published by the Free
    Software Foundation, either version 3 of the License, or (at your option)
    any later version.

    melonDS 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with melonDS. If not, see http://www.gnu.org/licenses/.
*/


// conversion from wxWdgets-provided platform-specific keycodes to SDL scancodes
// much of this is taken from the SDL source code


#ifdef __WXMSW__
static const SDL_Scancode windows_scancode_table[] =
{
	/*	0						1							2							3							4						5							6							7 */
	/*	8						9							A							B							C						D							E							F */
	SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_ESCAPE,		SDL_SCANCODE_1,				SDL_SCANCODE_2,				SDL_SCANCODE_3,			SDL_SCANCODE_4,				SDL_SCANCODE_5,				SDL_SCANCODE_6,			/* 0 */
	SDL_SCANCODE_7,				SDL_SCANCODE_8,				SDL_SCANCODE_9,				SDL_SCANCODE_0,				SDL_SCANCODE_MINUS,		SDL_SCANCODE_EQUALS,		SDL_SCANCODE_BACKSPACE,		SDL_SCANCODE_TAB,		/* 0 */

	SDL_SCANCODE_Q,				SDL_SCANCODE_W,				SDL_SCANCODE_E,				SDL_SCANCODE_R,				SDL_SCANCODE_T,			SDL_SCANCODE_Y,				SDL_SCANCODE_U,				SDL_SCANCODE_I,			/* 1 */
	SDL_SCANCODE_O,				SDL_SCANCODE_P,				SDL_SCANCODE_LEFTBRACKET,	SDL_SCANCODE_RIGHTBRACKET,	SDL_SCANCODE_RETURN,	SDL_SCANCODE_LCTRL,			SDL_SCANCODE_A,				SDL_SCANCODE_S,			/* 1 */

	SDL_SCANCODE_D,				SDL_SCANCODE_F,				SDL_SCANCODE_G,				SDL_SCANCODE_H,				SDL_SCANCODE_J,			SDL_SCANCODE_K,				SDL_SCANCODE_L,				SDL_SCANCODE_SEMICOLON,	/* 2 */
	SDL_SCANCODE_APOSTROPHE,	SDL_SCANCODE_GRAVE,			SDL_SCANCODE_LSHIFT,		SDL_SCANCODE_BACKSLASH,		SDL_SCANCODE_Z,			SDL_SCANCODE_X,				SDL_SCANCODE_C,				SDL_SCANCODE_V,			/* 2 */

	SDL_SCANCODE_B,				SDL_SCANCODE_N,				SDL_SCANCODE_M,				SDL_SCANCODE_COMMA,			SDL_SCANCODE_PERIOD,	SDL_SCANCODE_SLASH,			SDL_SCANCODE_RSHIFT,		SDL_SCANCODE_PRINTSCREEN,/* 3 */
	SDL_SCANCODE_LALT,			SDL_SCANCODE_SPACE,			SDL_SCANCODE_CAPSLOCK,		SDL_SCANCODE_F1,			SDL_SCANCODE_F2,		SDL_SCANCODE_F3,			SDL_SCANCODE_F4,			SDL_SCANCODE_F5,		/* 3 */

	SDL_SCANCODE_F6,			SDL_SCANCODE_F7,			SDL_SCANCODE_F8,			SDL_SCANCODE_F9,			SDL_SCANCODE_F10,		SDL_SCANCODE_NUMLOCKCLEAR,	SDL_SCANCODE_SCROLLLOCK,	SDL_SCANCODE_HOME,		/* 4 */
	SDL_SCANCODE_UP,			SDL_SCANCODE_PAGEUP,		SDL_SCANCODE_KP_MINUS,		SDL_SCANCODE_LEFT,			SDL_SCANCODE_KP_5,		SDL_SCANCODE_RIGHT,			SDL_SCANCODE_KP_PLUS,		SDL_SCANCODE_END,		/* 4 */

	SDL_SCANCODE_DOWN,			SDL_SCANCODE_PAGEDOWN,		SDL_SCANCODE_INSERT,		SDL_SCANCODE_DELETE,		SDL_SCANCODE_UNKNOWN,	SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_NONUSBACKSLASH,SDL_SCANCODE_F11,		/* 5 */
	SDL_SCANCODE_F12,			SDL_SCANCODE_PAUSE,			SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_LGUI,			SDL_SCANCODE_RGUI,		SDL_SCANCODE_APPLICATION,	SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,	/* 5 */

	SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_F13,		SDL_SCANCODE_F14,			SDL_SCANCODE_F15,			SDL_SCANCODE_F16,		/* 6 */
	SDL_SCANCODE_F17,			SDL_SCANCODE_F18,			SDL_SCANCODE_F19,			SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,	SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,	/* 6 */

	SDL_SCANCODE_INTERNATIONAL2,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_INTERNATIONAL1,		SDL_SCANCODE_UNKNOWN,	SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN,	/* 7 */
	SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_INTERNATIONAL4,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_INTERNATIONAL5,		SDL_SCANCODE_UNKNOWN,	SDL_SCANCODE_INTERNATIONAL3,		SDL_SCANCODE_UNKNOWN,		SDL_SCANCODE_UNKNOWN	/* 7 */
};
#endif
#ifdef __WXGTK__
#include <gdk/gdkkeysyms.h>
static const struct {
    int keysym;
    SDL_Scancode scancode;
} KeySymToSDLScancode[] = {
    { GDK_Return, SDL_SCANCODE_RETURN },
    { GDK_Escape, SDL_SCANCODE_ESCAPE },
    { GDK_BackSpace, SDL_SCANCODE_BACKSPACE },
    { GDK_Tab, SDL_SCANCODE_TAB },
    { GDK_Caps_Lock, SDL_SCANCODE_CAPSLOCK },
    { GDK_F1, SDL_SCANCODE_F1 },
    { GDK_F2, SDL_SCANCODE_F2 },
    { GDK_F3, SDL_SCANCODE_F3 },
    { GDK_F4, SDL_SCANCODE_F4 },
    { GDK_F5, SDL_SCANCODE_F5 },
    { GDK_F6, SDL_SCANCODE_F6 },
    { GDK_F7, SDL_SCANCODE_F7 },
    { GDK_F8, SDL_SCANCODE_F8 },
    { GDK_F9, SDL_SCANCODE_F9 },
    { GDK_F10, SDL_SCANCODE_F10 },
    { GDK_F11, SDL_SCANCODE_F11 },
    { GDK_F12, SDL_SCANCODE_F12 },
    { GDK_Print, SDL_SCANCODE_PRINTSCREEN },
    { GDK_Scroll_Lock, SDL_SCANCODE_SCROLLLOCK },
    { GDK_Pause, SDL_SCANCODE_PAUSE },
    { GDK_Insert, SDL_SCANCODE_INSERT },
    { GDK_Home, SDL_SCANCODE_HOME },
    { GDK_Prior, SDL_SCANCODE_PAGEUP },
    { GDK_Delete, SDL_SCANCODE_DELETE },
    { GDK_End, SDL_SCANCODE_END },
    { GDK_Next, SDL_SCANCODE_PAGEDOWN },
    { GDK_Right, SDL_SCANCODE_RIGHT },
    { GDK_Left, SDL_SCANCODE_LEFT },
    { GDK_Down, SDL_SCANCODE_DOWN },
    { GDK_Up, SDL_SCANCODE_UP },
    { GDK_Num_Lock, SDL_SCANCODE_NUMLOCKCLEAR },
    { GDK_KP_Divide, SDL_SCANCODE_KP_DIVIDE },
    { GDK_KP_Multiply, SDL_SCANCODE_KP_MULTIPLY },
    { GDK_KP_Subtract, SDL_SCANCODE_KP_MINUS },
    { GDK_KP_Add, SDL_SCANCODE_KP_PLUS },
    { GDK_KP_Enter, SDL_SCANCODE_KP_ENTER },
    { GDK_KP_Delete, SDL_SCANCODE_KP_PERIOD },
    { GDK_KP_End, SDL_SCANCODE_KP_1 },
    { GDK_KP_Down, SDL_SCANCODE_KP_2 },
    { GDK_KP_Next, SDL_SCANCODE_KP_3 },
    { GDK_KP_Left, SDL_SCANCODE_KP_4 },
    { GDK_KP_Begin, SDL_SCANCODE_KP_5 },
    { GDK_KP_Right, SDL_SCANCODE_KP_6 },
    { GDK_KP_Home, SDL_SCANCODE_KP_7 },
    { GDK_KP_Up, SDL_SCANCODE_KP_8 },
    { GDK_KP_Prior, SDL_SCANCODE_KP_9 },
    { GDK_KP_Insert, SDL_SCANCODE_KP_0 },
    { GDK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
    { GDK_KP_1, SDL_SCANCODE_KP_1 },
    { GDK_KP_2, SDL_SCANCODE_KP_2 },
    { GDK_KP_3, SDL_SCANCODE_KP_3 },
    { GDK_KP_4, SDL_SCANCODE_KP_4 },
    { GDK_KP_5, SDL_SCANCODE_KP_5 },
    { GDK_KP_6, SDL_SCANCODE_KP_6 },
    { GDK_KP_7, SDL_SCANCODE_KP_7 },
    { GDK_KP_8, SDL_SCANCODE_KP_8 },
    { GDK_KP_9, SDL_SCANCODE_KP_9 },
    { GDK_KP_0, SDL_SCANCODE_KP_0 },
    { GDK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
    { GDK_Hyper_R, SDL_SCANCODE_APPLICATION },
    { GDK_KP_Equal, SDL_SCANCODE_KP_EQUALS },
    { GDK_F13, SDL_SCANCODE_F13 },
    { GDK_F14, SDL_SCANCODE_F14 },
    { GDK_F15, SDL_SCANCODE_F15 },
    { GDK_F16, SDL_SCANCODE_F16 },
    { GDK_F17, SDL_SCANCODE_F17 },
    { GDK_F18, SDL_SCANCODE_F18 },
    { GDK_F19, SDL_SCANCODE_F19 },
    { GDK_F20, SDL_SCANCODE_F20 },
    { GDK_F21, SDL_SCANCODE_F21 },
    { GDK_F22, SDL_SCANCODE_F22 },
    { GDK_F23, SDL_SCANCODE_F23 },
    { GDK_F24, SDL_SCANCODE_F24 },
    { GDK_Execute, SDL_SCANCODE_EXECUTE },
    { GDK_Help, SDL_SCANCODE_HELP },
    { GDK_Menu, SDL_SCANCODE_MENU },
    { GDK_Select, SDL_SCANCODE_SELECT },
    { GDK_Cancel, SDL_SCANCODE_STOP },
    { GDK_Redo, SDL_SCANCODE_AGAIN },
    { GDK_Undo, SDL_SCANCODE_UNDO },
    { GDK_Find, SDL_SCANCODE_FIND },
    { GDK_KP_Separator, SDL_SCANCODE_KP_COMMA },
    { GDK_Sys_Req, SDL_SCANCODE_SYSREQ },
    { GDK_Control_L, SDL_SCANCODE_LCTRL },
    { GDK_Shift_L, SDL_SCANCODE_LSHIFT },
    { GDK_Alt_L, SDL_SCANCODE_LALT },
    { GDK_Meta_L, SDL_SCANCODE_LGUI },
    { GDK_Super_L, SDL_SCANCODE_LGUI },
    { GDK_Control_R, SDL_SCANCODE_RCTRL },
    { GDK_Shift_R, SDL_SCANCODE_RSHIFT },
    { GDK_Alt_R, SDL_SCANCODE_RALT },
    { GDK_ISO_Level3_Shift, SDL_SCANCODE_RALT },
    { GDK_Meta_R, SDL_SCANCODE_RGUI },
    { GDK_Super_R, SDL_SCANCODE_RGUI },
    { GDK_Mode_switch, SDL_SCANCODE_MODE },
    { GDK_period, SDL_SCANCODE_PERIOD },
    { GDK_comma, SDL_SCANCODE_COMMA },
    { GDK_slash, SDL_SCANCODE_SLASH },
    { GDK_backslash, SDL_SCANCODE_BACKSLASH },
    { GDK_minus, SDL_SCANCODE_MINUS },
    { GDK_equal, SDL_SCANCODE_EQUALS },
    { GDK_space, SDL_SCANCODE_SPACE },
    { GDK_grave, SDL_SCANCODE_GRAVE },
    { GDK_apostrophe, SDL_SCANCODE_APOSTROPHE },
    { GDK_bracketleft, SDL_SCANCODE_LEFTBRACKET },
    { GDK_bracketright, SDL_SCANCODE_RIGHTBRACKET },
};
#endif


SDL_Scancode scancode_wx2sdl(wxKeyEvent& event)
{
#ifdef __WXMSW__

    u32 wParam = event.GetRawKeyCode();
    u32 lParam = event.GetRawKeyFlags();

    SDL_Scancode code;
    char bIsExtended;
    int nScanCode = (lParam >> 16) & 0xFF;

    /* 0x45 here to work around both pause and numlock sharing the same scancode, so use the VK key to tell them apart */
    if (nScanCode == 0 || nScanCode == 0x45)
    {
        switch(wParam)
        {
        case VK_CLEAR: return SDL_SCANCODE_CLEAR;
        case VK_MODECHANGE: return SDL_SCANCODE_MODE;
        case VK_SELECT: return SDL_SCANCODE_SELECT;
        case VK_EXECUTE: return SDL_SCANCODE_EXECUTE;
        case VK_HELP: return SDL_SCANCODE_HELP;
        case VK_PAUSE: return SDL_SCANCODE_PAUSE;
        case VK_NUMLOCK: return SDL_SCANCODE_NUMLOCKCLEAR;

        case VK_F13: return SDL_SCANCODE_F13;
        case VK_F14: return SDL_SCANCODE_F14;
        case VK_F15: return SDL_SCANCODE_F15;
        case VK_F16: return SDL_SCANCODE_F16;
        case VK_F17: return SDL_SCANCODE_F17;
        case VK_F18: return SDL_SCANCODE_F18;
        case VK_F19: return SDL_SCANCODE_F19;
        case VK_F20: return SDL_SCANCODE_F20;
        case VK_F21: return SDL_SCANCODE_F21;
        case VK_F22: return SDL_SCANCODE_F22;
        case VK_F23: return SDL_SCANCODE_F23;
        case VK_F24: return SDL_SCANCODE_F24;

        case VK_OEM_NEC_EQUAL: return SDL_SCANCODE_KP_EQUALS;
        case VK_BROWSER_BACK: return SDL_SCANCODE_AC_BACK;
        case VK_BROWSER_FORWARD: return SDL_SCANCODE_AC_FORWARD;
        case VK_BROWSER_REFRESH: return SDL_SCANCODE_AC_REFRESH;
        case VK_BROWSER_STOP: return SDL_SCANCODE_AC_STOP;
        case VK_BROWSER_SEARCH: return SDL_SCANCODE_AC_SEARCH;
        case VK_BROWSER_FAVORITES: return SDL_SCANCODE_AC_BOOKMARKS;
        case VK_BROWSER_HOME: return SDL_SCANCODE_AC_HOME;
        case VK_VOLUME_MUTE: return SDL_SCANCODE_AUDIOMUTE;
        case VK_VOLUME_DOWN: return SDL_SCANCODE_VOLUMEDOWN;
        case VK_VOLUME_UP: return SDL_SCANCODE_VOLUMEUP;

        case VK_MEDIA_NEXT_TRACK: return SDL_SCANCODE_AUDIONEXT;
        case VK_MEDIA_PREV_TRACK: return SDL_SCANCODE_AUDIOPREV;
        case VK_MEDIA_STOP: return SDL_SCANCODE_AUDIOSTOP;
        case VK_MEDIA_PLAY_PAUSE: return SDL_SCANCODE_AUDIOPLAY;
        case VK_LAUNCH_MAIL: return SDL_SCANCODE_MAIL;
        case VK_LAUNCH_MEDIA_SELECT: return SDL_SCANCODE_MEDIASELECT;

        case VK_OEM_102: return SDL_SCANCODE_NONUSBACKSLASH;

        case VK_ATTN: return SDL_SCANCODE_SYSREQ;
        case VK_CRSEL: return SDL_SCANCODE_CRSEL;
        case VK_EXSEL: return SDL_SCANCODE_EXSEL;
        case VK_OEM_CLEAR: return SDL_SCANCODE_CLEAR;

        case VK_LAUNCH_APP1: return SDL_SCANCODE_APP1;
        case VK_LAUNCH_APP2: return SDL_SCANCODE_APP2;

        default: return SDL_SCANCODE_UNKNOWN;
        }
    }

    if (nScanCode > 127)
        return SDL_SCANCODE_UNKNOWN;

    code = windows_scancode_table[nScanCode];

    bIsExtended = (lParam & (1 << 24)) != 0;
    if (!bIsExtended)
    {
        switch (code)
        {
        case SDL_SCANCODE_HOME:
            return SDL_SCANCODE_KP_7;
        case SDL_SCANCODE_UP:
            return SDL_SCANCODE_KP_8;
        case SDL_SCANCODE_PAGEUP:
            return SDL_SCANCODE_KP_9;
        case SDL_SCANCODE_LEFT:
            return SDL_SCANCODE_KP_4;
        case SDL_SCANCODE_RIGHT:
            return SDL_SCANCODE_KP_6;
        case SDL_SCANCODE_END:
            return SDL_SCANCODE_KP_1;
        case SDL_SCANCODE_DOWN:
            return SDL_SCANCODE_KP_2;
        case SDL_SCANCODE_PAGEDOWN:
            return SDL_SCANCODE_KP_3;
        case SDL_SCANCODE_INSERT:
            return SDL_SCANCODE_KP_0;
        case SDL_SCANCODE_DELETE:
            return SDL_SCANCODE_KP_PERIOD;
        case SDL_SCANCODE_PRINTSCREEN:
            return SDL_SCANCODE_KP_MULTIPLY;
        default:
            break;
        }
    }
    else
    {
        switch (code)
        {
        case SDL_SCANCODE_RETURN:
            return SDL_SCANCODE_KP_ENTER;
        case SDL_SCANCODE_LALT:
            return SDL_SCANCODE_RALT;
        case SDL_SCANCODE_LCTRL:
            return SDL_SCANCODE_RCTRL;
        case SDL_SCANCODE_SLASH:
            return SDL_SCANCODE_KP_DIVIDE;
        case SDL_SCANCODE_CAPSLOCK:
            return SDL_SCANCODE_KP_PLUS;
        default:
            break;
        }
    }

    return code;

#endif
#ifdef __WXGTK__

    int keysym = event.GetRawKeyCode();

    if (keysym == 0)
    {
        return SDL_SCANCODE_UNKNOWN;
    }

    if (keysym >= GDK_a && keysym <= GDK_z)
    {
        return (SDL_Scancode)(SDL_SCANCODE_A + (keysym - GDK_a));
    }
    if (keysym >= GDK_A && keysym <= GDK_Z)
    {
        return (SDL_Scancode)(SDL_SCANCODE_A + (keysym - GDK_A));
    }

    if (keysym == GDK_0)
    {
        return SDL_SCANCODE_0;
    }
    if (keysym >= GDK_1 && keysym <= GDK_9)
    {
        return (SDL_Scancode)(SDL_SCANCODE_1 + (keysym - GDK_1));
    }

    for (int i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i)
    {
        if (keysym == KeySymToSDLScancode[i].keysym)
        {
            return KeySymToSDLScancode[i].scancode;
        }
    }
    return SDL_SCANCODE_UNKNOWN;

#endif
    return SDL_SCANCODE_UNKNOWN;
}