Files
nestopia/source/win32/NstDialogInput.cpp
2020-12-05 11:47:00 -05:00

1272 lines
55 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia 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 2 of the License, or
// (at your option) any later version.
//
// Nestopia 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 Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include "NstResourceString.hpp"
#include "NstIoLog.hpp"
#include "NstApplicationConfiguration.hpp"
#include "NstManagerEmulator.hpp"
#include "NstSystemKeyboard.hpp"
#include "NstWindowParam.hpp"
#include "NstWindowDynamic.hpp"
#include "NstWindowUser.hpp"
#include "NstDialogInput.hpp"
#include <Shlwapi.h>
namespace Nestopia
{
namespace Window
{
NST_COMPILE_ASSERT
(
DirectX::DirectInput::AXIS_X == 0x001 &&
DirectX::DirectInput::AXIS_Y == 0x002 &&
DirectX::DirectInput::AXIS_Z == 0x004 &&
DirectX::DirectInput::AXIS_RX == 0x008 &&
DirectX::DirectInput::AXIS_RY == 0x010 &&
DirectX::DirectInput::AXIS_RZ == 0x020 &&
DirectX::DirectInput::AXIS_SLIDER_0 == 0x040 &&
DirectX::DirectInput::AXIS_SLIDER_1 == 0x080 &&
DirectX::DirectInput::AXIS_POV_0 == 0x100 &&
DirectX::DirectInput::AXIS_POV_1 == 0x200 &&
DirectX::DirectInput::AXIS_POV_2 == 0x400 &&
DirectX::DirectInput::AXIS_POV_3 == 0x800 &&
IDC_INPUT_JOYSTICKS_ENABLE == IDC_INPUT_JOYSTICKS + 1 &&
IDC_INPUT_JOYSTICKS_X == IDC_INPUT_JOYSTICKS + 2 &&
IDC_INPUT_JOYSTICKS_Y == IDC_INPUT_JOYSTICKS + 3 &&
IDC_INPUT_JOYSTICKS_Z == IDC_INPUT_JOYSTICKS + 4 &&
IDC_INPUT_JOYSTICKS_RX == IDC_INPUT_JOYSTICKS + 5 &&
IDC_INPUT_JOYSTICKS_RY == IDC_INPUT_JOYSTICKS + 6 &&
IDC_INPUT_JOYSTICKS_RZ == IDC_INPUT_JOYSTICKS + 7 &&
IDC_INPUT_JOYSTICKS_S0 == IDC_INPUT_JOYSTICKS + 8 &&
IDC_INPUT_JOYSTICKS_S1 == IDC_INPUT_JOYSTICKS + 9 &&
IDC_INPUT_JOYSTICKS_POV0 == IDC_INPUT_JOYSTICKS + 10 &&
IDC_INPUT_JOYSTICKS_POV1 == IDC_INPUT_JOYSTICKS + 11 &&
IDC_INPUT_JOYSTICKS_POV2 == IDC_INPUT_JOYSTICKS + 12 &&
IDC_INPUT_JOYSTICKS_POV3 == IDC_INPUT_JOYSTICKS + 13 &&
IDC_INPUT_JOYSTICKS_DEADZONE == IDC_INPUT_JOYSTICKS + 14 &&
IDC_INPUT_JOYSTICKS_DEADZONE_NUM == IDC_INPUT_JOYSTICKS + 15 &&
IDC_INPUT_JOYSTICKS_DEADZONE_TEXT == IDC_INPUT_JOYSTICKS + 16 &&
IDC_INPUT_JOYSTICKS_CALIBRATE == IDC_INPUT_JOYSTICKS + 17 &&
IDC_INPUT_JOYSTICKS_DEFAULT == IDC_INPUT_JOYSTICKS + 18 &&
IDM_MACHINE_INPUT_PORT1_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 1 &&
IDM_MACHINE_INPUT_PORT1_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 2 &&
IDM_MACHINE_INPUT_PORT1_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 3 &&
IDM_MACHINE_INPUT_PORT1_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 4 &&
IDM_MACHINE_INPUT_PORT1_ZAPPER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 5 &&
IDM_MACHINE_INPUT_PORT1_PADDLE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 6 &&
IDM_MACHINE_INPUT_PORT1_POWERPAD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 7 &&
IDM_MACHINE_INPUT_PORT1_POWERGLOVE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 8 &&
IDM_MACHINE_INPUT_PORT1_MOUSE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 9 &&
IDM_MACHINE_INPUT_PORT1_ROB == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 10 &&
IDM_MACHINE_INPUT_PORT2_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 11 &&
IDM_MACHINE_INPUT_PORT2_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 12 &&
IDM_MACHINE_INPUT_PORT2_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 13 &&
IDM_MACHINE_INPUT_PORT2_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 14 &&
IDM_MACHINE_INPUT_PORT2_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 15 &&
IDM_MACHINE_INPUT_PORT2_ZAPPER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 16 &&
IDM_MACHINE_INPUT_PORT2_PADDLE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 17 &&
IDM_MACHINE_INPUT_PORT2_POWERPAD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 18 &&
IDM_MACHINE_INPUT_PORT2_POWERGLOVE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 19 &&
IDM_MACHINE_INPUT_PORT2_MOUSE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 20 &&
IDM_MACHINE_INPUT_PORT2_ROB == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 21 &&
IDM_MACHINE_INPUT_PORT3_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 22 &&
IDM_MACHINE_INPUT_PORT3_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 23 &&
IDM_MACHINE_INPUT_PORT3_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 24 &&
IDM_MACHINE_INPUT_PORT3_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 25 &&
IDM_MACHINE_INPUT_PORT3_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 26 &&
IDM_MACHINE_INPUT_PORT4_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 27 &&
IDM_MACHINE_INPUT_PORT4_PAD1 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 28 &&
IDM_MACHINE_INPUT_PORT4_PAD2 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 29 &&
IDM_MACHINE_INPUT_PORT4_PAD3 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 30 &&
IDM_MACHINE_INPUT_PORT4_PAD4 == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 31 &&
IDM_MACHINE_INPUT_EXP_UNCONNECTED == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 32 &&
IDM_MACHINE_INPUT_EXP_FAMILYTRAINER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 33 &&
IDM_MACHINE_INPUT_EXP_FAMILYBASICKEYBOARD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 34 &&
IDM_MACHINE_INPUT_EXP_SUBORKEYBOARD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 35 &&
IDM_MACHINE_INPUT_EXP_DOREMIKKOKEYBOARD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 36 &&
IDM_MACHINE_INPUT_EXP_HORITRACK == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 37 &&
IDM_MACHINE_INPUT_EXP_PACHINKO == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 38 &&
IDM_MACHINE_INPUT_EXP_PADDLE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 39 &&
IDM_MACHINE_INPUT_EXP_OEKAKIDSTABLET == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 40 &&
IDM_MACHINE_INPUT_EXP_KONAMIHYPERSHOT == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 41 &&
IDM_MACHINE_INPUT_EXP_BANDAIHYPERSHOT == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 42 &&
IDM_MACHINE_INPUT_EXP_CRAZYCLIMBER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 43 &&
IDM_MACHINE_INPUT_EXP_MAHJONG == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 44 &&
IDM_MACHINE_INPUT_EXP_EXCITINGBOXING == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 45 &&
IDM_MACHINE_INPUT_EXP_TOPRIDER == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 46 &&
IDM_MACHINE_INPUT_EXP_POKKUNMOGURAA == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 47 &&
IDM_MACHINE_INPUT_EXP_PARTYTAP == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 48 &&
IDM_MACHINE_INPUT_EXP_TURBOFILE == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 49 &&
IDM_MACHINE_INPUT_EXP_BARCODEWORLD == IDM_MACHINE_INPUT_PORT1_UNCONNECTED + 50
);
const Input::Settings::Type Input::Settings::types[OFFSET_COUNT] =
{
{ PAD1_KEYS, IDS_INPUT_KEY_SECTION_PAD1 },
{ PAD2_KEYS, IDS_INPUT_KEY_SECTION_PAD2 },
{ PAD3_KEYS, IDS_INPUT_KEY_SECTION_PAD3 },
{ PAD4_KEYS, IDS_INPUT_KEY_SECTION_PAD4 },
{ POWERPAD_KEYS, IDS_INPUT_KEY_SECTION_POWERPAD },
{ POWERGLOVE_KEYS, IDS_INPUT_KEY_SECTION_POWERGLOVE },
{ HORITRACK_KEYS, IDS_INPUT_KEY_SECTION_HORITRACK },
{ PACHINKO_KEYS, IDS_INPUT_KEY_SECTION_PACHINKO },
{ CRAZYCLIMBER_KEYS, IDS_INPUT_KEY_SECTION_CRAZYCLIMBER },
{ MAHJONG_KEYS, IDS_INPUT_KEY_SECTION_MAHJONG },
{ EXCITINGBOXING_KEYS, IDS_INPUT_KEY_SECTION_EXCITINGBOXING },
{ POKKUNMOGURAA_KEYS, IDS_INPUT_KEY_SECTION_POKKUNMOGURAA },
{ PARTYTAP_KEYS, IDS_INPUT_KEY_SECTION_PARTYTAP },
{ KARAOKESTUDIO_KEYS, IDS_INPUT_KEY_SECTION_KARAOKESTUDIO },
{ EMULATION_KEYS, IDS_INPUT_KEY_SECTION_EMULATION },
{ FILE_KEYS, IDS_INPUT_KEY_SECTION_FILE },
{ MACHINE_KEYS, IDS_INPUT_KEY_SECTION_MACHINE },
{ NSF_KEYS, IDS_INPUT_KEY_SECTION_NSF },
{ VIEW_KEYS, IDS_INPUT_KEY_SECTION_VIEW },
{ HELP_KEYS, IDS_INPUT_KEY_SECTION_HELP },
{ NUM_KEYS, 0 }
};
const Input::Settings::Mapping Input::Settings::map[NUM_KEYS] =
{
{ PAD1_KEYS + PAD_KEY_LEFT, DIK_LEFT, IDS_INPUT_PAD_KEY_LEFT, "pad-1", "left" },
{ PAD1_KEYS + PAD_KEY_UP, DIK_UP, IDS_INPUT_PAD_KEY_UP, "pad-1", "up" },
{ PAD1_KEYS + PAD_KEY_RIGHT, DIK_RIGHT, IDS_INPUT_PAD_KEY_RIGHT, "pad-1", "right" },
{ PAD1_KEYS + PAD_KEY_DOWN, DIK_DOWN, IDS_INPUT_PAD_KEY_DOWN, "pad-1", "down" },
{ PAD1_KEYS + PAD_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_PAD_KEY_SELECT, "pad-1", "select" },
{ PAD1_KEYS + PAD_KEY_START, DIK_RETURN, IDS_INPUT_PAD_KEY_START, "pad-1", "start" },
{ PAD1_KEYS + PAD_KEY_B, DIK_COMMA, IDS_INPUT_PAD_KEY_B, "pad-1", "b" },
{ PAD1_KEYS + PAD_KEY_A, DIK_PERIOD, IDS_INPUT_PAD_KEY_A, "pad-1", "a" },
{ PAD1_KEYS + PAD_KEY_AUTOFIRE_B, DIK_K, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-1", "auto-fire-b" },
{ PAD1_KEYS + PAD_KEY_AUTOFIRE_A, DIK_L, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-1", "auto-fire-a" },
{ PAD1_KEYS + PAD_KEY_MIC, NO_KEY, IDS_INPUT_PAD_KEY_MIC, "pad-1", "mic" },
{ PAD2_KEYS + PAD_KEY_LEFT, DIK_C, IDS_INPUT_PAD_KEY_LEFT, "pad-2", "left" },
{ PAD2_KEYS + PAD_KEY_UP, DIK_F, IDS_INPUT_PAD_KEY_UP, "pad-2", "up" },
{ PAD2_KEYS + PAD_KEY_RIGHT, DIK_B, IDS_INPUT_PAD_KEY_RIGHT, "pad-2", "right" },
{ PAD2_KEYS + PAD_KEY_DOWN, DIK_V, IDS_INPUT_PAD_KEY_DOWN, "pad-2", "down" },
{ PAD2_KEYS + PAD_KEY_SELECT, DIK_A, IDS_INPUT_PAD_KEY_SELECT, "pad-2", "select" },
{ PAD2_KEYS + PAD_KEY_START, DIK_S, IDS_INPUT_PAD_KEY_START, "pad-2", "start" },
{ PAD2_KEYS + PAD_KEY_B, DIK_Z, IDS_INPUT_PAD_KEY_B, "pad-2", "b" },
{ PAD2_KEYS + PAD_KEY_A, DIK_X, IDS_INPUT_PAD_KEY_A, "pad-2", "a" },
{ PAD2_KEYS + PAD_KEY_AUTOFIRE_B, DIK_Q, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-2", "auto-fire-b" },
{ PAD2_KEYS + PAD_KEY_AUTOFIRE_A, DIK_W, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-2", "auto-fire-a" },
{ PAD2_KEYS + PAD_KEY_MIC, DIK_M, IDS_INPUT_PAD_KEY_MIC, "pad-2", "mic" },
{ PAD3_KEYS + PAD_KEY_LEFT, NO_KEY, IDS_INPUT_PAD_KEY_LEFT, "pad-3", "left" },
{ PAD3_KEYS + PAD_KEY_UP, NO_KEY, IDS_INPUT_PAD_KEY_UP, "pad-3", "up" },
{ PAD3_KEYS + PAD_KEY_RIGHT, NO_KEY, IDS_INPUT_PAD_KEY_RIGHT, "pad-3", "right" },
{ PAD3_KEYS + PAD_KEY_DOWN, NO_KEY, IDS_INPUT_PAD_KEY_DOWN, "pad-3", "down" },
{ PAD3_KEYS + PAD_KEY_SELECT, NO_KEY, IDS_INPUT_PAD_KEY_SELECT, "pad-3", "select" },
{ PAD3_KEYS + PAD_KEY_START, NO_KEY, IDS_INPUT_PAD_KEY_START, "pad-3", "start" },
{ PAD3_KEYS + PAD_KEY_B, NO_KEY, IDS_INPUT_PAD_KEY_B, "pad-3", "b" },
{ PAD3_KEYS + PAD_KEY_A, NO_KEY, IDS_INPUT_PAD_KEY_A, "pad-3", "a" },
{ PAD3_KEYS + PAD_KEY_AUTOFIRE_B, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-3", "auto-fire-b" },
{ PAD3_KEYS + PAD_KEY_AUTOFIRE_A, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-3", "auto-fire-a" },
{ PAD3_KEYS + PAD_KEY_MIC, NO_KEY, IDS_INPUT_PAD_KEY_MIC, "pad-3", "mic" },
{ PAD4_KEYS + PAD_KEY_LEFT, NO_KEY, IDS_INPUT_PAD_KEY_LEFT, "pad-4", "left" },
{ PAD4_KEYS + PAD_KEY_UP, NO_KEY, IDS_INPUT_PAD_KEY_UP, "pad-4", "up" },
{ PAD4_KEYS + PAD_KEY_RIGHT, NO_KEY, IDS_INPUT_PAD_KEY_RIGHT, "pad-4", "right" },
{ PAD4_KEYS + PAD_KEY_DOWN, NO_KEY, IDS_INPUT_PAD_KEY_DOWN, "pad-4", "down" },
{ PAD4_KEYS + PAD_KEY_SELECT, NO_KEY, IDS_INPUT_PAD_KEY_SELECT, "pad-4", "select" },
{ PAD4_KEYS + PAD_KEY_START, NO_KEY, IDS_INPUT_PAD_KEY_START, "pad-4", "start" },
{ PAD4_KEYS + PAD_KEY_B, NO_KEY, IDS_INPUT_PAD_KEY_B, "pad-4", "b" },
{ PAD4_KEYS + PAD_KEY_A, NO_KEY, IDS_INPUT_PAD_KEY_A, "pad-4", "a" },
{ PAD4_KEYS + PAD_KEY_AUTOFIRE_B, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_B, "pad-4", "auto-fire-b" },
{ PAD4_KEYS + PAD_KEY_AUTOFIRE_A, NO_KEY, IDS_INPUT_PAD_KEY_AUTOFIRE_A, "pad-4", "auto-fire-a" },
{ PAD4_KEYS + PAD_KEY_MIC, NO_KEY, IDS_INPUT_PAD_KEY_MIC, "pad-4", "mic" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_1, DIK_Q, IDS_INPUT_POWERPAD_KEY_SIDE_A_1, "powerpad", "side-a-1" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_2, DIK_W, IDS_INPUT_POWERPAD_KEY_SIDE_A_2, "powerpad", "side-a-2" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_3, DIK_E, IDS_INPUT_POWERPAD_KEY_SIDE_A_3, "powerpad", "side-a-3" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_4, DIK_R, IDS_INPUT_POWERPAD_KEY_SIDE_A_4, "powerpad", "side-a-4" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_5, DIK_A, IDS_INPUT_POWERPAD_KEY_SIDE_A_5, "powerpad", "side-a-5" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_6, DIK_S, IDS_INPUT_POWERPAD_KEY_SIDE_A_6, "powerpad", "side-a-6" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_7, DIK_D, IDS_INPUT_POWERPAD_KEY_SIDE_A_7, "powerpad", "side-a-7" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_8, DIK_F, IDS_INPUT_POWERPAD_KEY_SIDE_A_8, "powerpad", "side-a-8" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_9, DIK_Z, IDS_INPUT_POWERPAD_KEY_SIDE_A_9, "powerpad", "side-a-9" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_10, DIK_X, IDS_INPUT_POWERPAD_KEY_SIDE_A_10, "powerpad", "side-a-10" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_11, DIK_C, IDS_INPUT_POWERPAD_KEY_SIDE_A_11, "powerpad", "side-a-11" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_A_12, DIK_V, IDS_INPUT_POWERPAD_KEY_SIDE_A_12, "powerpad", "side-a-12" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_3, DIK_Y, IDS_INPUT_POWERPAD_KEY_SIDE_B_3, "powerpad", "side-b-3" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_2, DIK_U, IDS_INPUT_POWERPAD_KEY_SIDE_B_2, "powerpad", "side-b-2" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_8, DIK_G, IDS_INPUT_POWERPAD_KEY_SIDE_B_8, "powerpad", "side-b-8" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_7, DIK_H, IDS_INPUT_POWERPAD_KEY_SIDE_B_7, "powerpad", "side-b-7" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_6, DIK_J, IDS_INPUT_POWERPAD_KEY_SIDE_B_6, "powerpad", "side-b-6" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_5, DIK_K, IDS_INPUT_POWERPAD_KEY_SIDE_B_5, "powerpad", "side-b-5" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_11, DIK_N, IDS_INPUT_POWERPAD_KEY_SIDE_B_11, "powerpad", "side-b-11" },
{ POWERPAD_KEYS + POWERPAD_KEY_SIDE_B_10, DIK_M, IDS_INPUT_POWERPAD_KEY_SIDE_B_10, "powerpad", "side-b-10" },
{ POWERGLOVE_KEYS + POWERGLOVE_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_POWERGLOVE_KEY_SELECT, "powerglove", "select" },
{ POWERGLOVE_KEYS + POWERGLOVE_KEY_START, DIK_RETURN, IDS_INPUT_POWERGLOVE_KEY_START, "powerglove", "start" },
{ POWERGLOVE_KEYS + POWERGLOVE_KEY_MOVE_IN, DIK_A, IDS_INPUT_POWERGLOVE_KEY_MOVE_IN, "powerglove", "move-in" },
{ POWERGLOVE_KEYS + POWERGLOVE_KEY_MOVE_OUT, DIK_Z, IDS_INPUT_POWERGLOVE_KEY_MOVE_OUT, "powerglove", "move-out" },
{ POWERGLOVE_KEYS + POWERGLOVE_KEY_ROLL_LEFT, DIK_X, IDS_INPUT_POWERGLOVE_KEY_ROLL_LEFT, "powerglove", "roll-left" },
{ POWERGLOVE_KEYS + POWERGLOVE_KEY_ROLL_RIGHT, DIK_C, IDS_INPUT_POWERGLOVE_KEY_ROLL_RIGHT, "powerglove", "roll-right" },
{ HORITRACK_KEYS + HORITRACK_KEY_LEFT, DIK_LEFT, IDS_INPUT_HORITRACK_KEY_LEFT, "horitrack", "left" },
{ HORITRACK_KEYS + HORITRACK_KEY_UP, DIK_UP, IDS_INPUT_HORITRACK_KEY_UP, "horitrack", "up" },
{ HORITRACK_KEYS + HORITRACK_KEY_RIGHT, DIK_RIGHT, IDS_INPUT_HORITRACK_KEY_RIGHT, "horitrack", "right" },
{ HORITRACK_KEYS + HORITRACK_KEY_DOWN, DIK_DOWN, IDS_INPUT_HORITRACK_KEY_DOWN, "horitrack", "down" },
{ HORITRACK_KEYS + HORITRACK_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_HORITRACK_KEY_SELECT, "horitrack", "select" },
{ HORITRACK_KEYS + HORITRACK_KEY_START, DIK_RETURN, IDS_INPUT_HORITRACK_KEY_START, "horitrack", "start" },
{ HORITRACK_KEYS + HORITRACK_KEY_B, DIK_COMMA, IDS_INPUT_HORITRACK_KEY_B, "horitrack", "b" },
{ HORITRACK_KEYS + HORITRACK_KEY_A, DIK_PERIOD, IDS_INPUT_HORITRACK_KEY_A, "horitrack", "a" },
{ HORITRACK_KEYS + HORITRACK_KEY_SPEED, DIK_S, IDS_INPUT_HORITRACK_KEY_SPEED, "horitrack", "speed" },
{ HORITRACK_KEYS + HORITRACK_KEY_ORIENTATION, DIK_D, IDS_INPUT_HORITRACK_KEY_ORIENTATION, "horitrack", "orientation" },
{ PACHINKO_KEYS + PACHINKO_KEY_LEFT, DIK_LEFT, IDS_INPUT_PACHINKO_KEY_LEFT, "pachinko", "left" },
{ PACHINKO_KEYS + PACHINKO_KEY_UP, DIK_UP, IDS_INPUT_PACHINKO_KEY_UP, "pachinko", "up" },
{ PACHINKO_KEYS + PACHINKO_KEY_RIGHT, DIK_RIGHT, IDS_INPUT_PACHINKO_KEY_RIGHT, "pachinko", "right" },
{ PACHINKO_KEYS + PACHINKO_KEY_DOWN, DIK_DOWN, IDS_INPUT_PACHINKO_KEY_DOWN, "pachinko", "down" },
{ PACHINKO_KEYS + PACHINKO_KEY_SELECT, DIK_RSHIFT, IDS_INPUT_PACHINKO_KEY_SELECT, "pachinko", "select" },
{ PACHINKO_KEYS + PACHINKO_KEY_START, DIK_RETURN, IDS_INPUT_PACHINKO_KEY_START, "pachinko", "start" },
{ PACHINKO_KEYS + PACHINKO_KEY_B, DIK_COMMA, IDS_INPUT_PACHINKO_KEY_B, "pachinko", "b" },
{ PACHINKO_KEYS + PACHINKO_KEY_A, DIK_PERIOD, IDS_INPUT_PACHINKO_KEY_A, "pachinko", "a" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_UP, DIK_W, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_UP, "crazyclimber", "left-up" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_RIGHT, DIK_D, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_RIGHT, "crazyclimber", "left-right" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_DOWN, DIK_S, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_DOWN, "crazyclimber", "left-down" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_LEFT_LEFT, DIK_A, IDS_INPUT_CRAZYCLIMBER_KEY_LEFT_LEFT, "crazyclimber", "left-left" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_UP, DIK_Y, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_UP, "crazyclimber", "right-up" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_RIGHT, DIK_J, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_RIGHT, "crazyclimber", "right-right" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_DOWN, DIK_H, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_DOWN, "crazyclimber", "right-down" },
{ CRAZYCLIMBER_KEYS + CRAZYCLIMBER_KEY_RIGHT_LEFT, DIK_G, IDS_INPUT_CRAZYCLIMBER_KEY_RIGHT_LEFT, "crazyclimber", "right-left" },
{ MAHJONG_KEYS + MAHJONG_KEY_A, DIK_Q, IDS_INPUT_MAHJONG_KEY_A, "mahjong", "a" },
{ MAHJONG_KEYS + MAHJONG_KEY_B, DIK_W, IDS_INPUT_MAHJONG_KEY_B, "mahjong", "b" },
{ MAHJONG_KEYS + MAHJONG_KEY_C, DIK_E, IDS_INPUT_MAHJONG_KEY_C, "mahjong", "c" },
{ MAHJONG_KEYS + MAHJONG_KEY_D, DIK_R, IDS_INPUT_MAHJONG_KEY_D, "mahjong", "d" },
{ MAHJONG_KEYS + MAHJONG_KEY_E, DIK_T, IDS_INPUT_MAHJONG_KEY_E, "mahjong", "e" },
{ MAHJONG_KEYS + MAHJONG_KEY_F, DIK_A, IDS_INPUT_MAHJONG_KEY_F, "mahjong", "f" },
{ MAHJONG_KEYS + MAHJONG_KEY_G, DIK_S, IDS_INPUT_MAHJONG_KEY_G, "mahjong", "g" },
{ MAHJONG_KEYS + MAHJONG_KEY_H, DIK_D, IDS_INPUT_MAHJONG_KEY_H, "mahjong", "h" },
{ MAHJONG_KEYS + MAHJONG_KEY_I, DIK_F, IDS_INPUT_MAHJONG_KEY_I, "mahjong", "i" },
{ MAHJONG_KEYS + MAHJONG_KEY_J, DIK_G, IDS_INPUT_MAHJONG_KEY_J, "mahjong", "j" },
{ MAHJONG_KEYS + MAHJONG_KEY_K, DIK_H, IDS_INPUT_MAHJONG_KEY_K, "mahjong", "k" },
{ MAHJONG_KEYS + MAHJONG_KEY_L, DIK_J, IDS_INPUT_MAHJONG_KEY_L, "mahjong", "l" },
{ MAHJONG_KEYS + MAHJONG_KEY_M, DIK_K, IDS_INPUT_MAHJONG_KEY_M, "mahjong", "m" },
{ MAHJONG_KEYS + MAHJONG_KEY_N, DIK_L, IDS_INPUT_MAHJONG_KEY_N, "mahjong", "n" },
{ MAHJONG_KEYS + MAHJONG_KEY_START, DIK_Z, IDS_INPUT_MAHJONG_KEY_START, "mahjong", "start" },
{ MAHJONG_KEYS + MAHJONG_KEY_SELECT, DIK_X, IDS_INPUT_MAHJONG_KEY_SELECT, "mahjong", "select" },
{ MAHJONG_KEYS + MAHJONG_KEY_KAN, DIK_C, IDS_INPUT_MAHJONG_KEY_KAN, "mahjong", "kan" },
{ MAHJONG_KEYS + MAHJONG_KEY_PON, DIK_V, IDS_INPUT_MAHJONG_KEY_PON, "mahjong", "pon" },
{ MAHJONG_KEYS + MAHJONG_KEY_CHI, DIK_B, IDS_INPUT_MAHJONG_KEY_CHI, "mahjong", "chi" },
{ MAHJONG_KEYS + MAHJONG_KEY_REACH, DIK_N, IDS_INPUT_MAHJONG_KEY_REACH, "mahjong", "reach" },
{ MAHJONG_KEYS + MAHJONG_KEY_RON, DIK_M, IDS_INPUT_MAHJONG_KEY_RON, "mahjong", "ron" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_LEFT_HOOK, DIK_K, IDS_INPUT_EXCITINGBOXING_KEY_LEFT_HOOK, "excitingboxing", "left-hook" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_RIGHT_HOOK, DIK_L, IDS_INPUT_EXCITINGBOXING_KEY_RIGHT_HOOK, "excitingboxing", "right-hook" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_LEFT_JAB, DIK_COMMA, IDS_INPUT_EXCITINGBOXING_KEY_LEFT_JAB, "excitingboxing", "left-jab" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_RIGHT_JAB, DIK_PERIOD, IDS_INPUT_EXCITINGBOXING_KEY_RIGHT_JAB, "excitingboxing", "right-jab" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_STRAIGHT, DIK_UP, IDS_INPUT_EXCITINGBOXING_KEY_STRAIGHT, "excitingboxing", "straight" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_BODY, DIK_DOWN, IDS_INPUT_EXCITINGBOXING_KEY_BODY, "excitingboxing", "body" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_LEFT_MOVE, DIK_LEFT, IDS_INPUT_EXCITINGBOXING_KEY_LEFT_MOVE, "excitingboxing", "left-move" },
{ EXCITINGBOXING_KEYS + EXCITINGBOXING_KEY_RIGHT_MOVE, DIK_RIGHT, IDS_INPUT_EXCITINGBOXING_KEY_RIGHT_MOVE, "excitingboxing", "right-move" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_1, DIK_T, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_1, "pokkunmoguraa", "row-1-button-1" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_2, DIK_Y, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_2, "pokkunmoguraa", "row-1-button-2" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_3, DIK_U, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_3, "pokkunmoguraa", "row-1-button-3" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_1_4, DIK_I, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_1_4, "pokkunmoguraa", "row-1-button-4" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_1, DIK_G, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_1, "pokkunmoguraa", "row-2-button-1" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_2, DIK_H, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_2, "pokkunmoguraa", "row-2-button-2" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_3, DIK_J, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_3, "pokkunmoguraa", "row-2-button-3" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_2_4, DIK_K, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_2_4, "pokkunmoguraa", "row-2-button-4" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_1, DIK_B, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_1, "pokkunmoguraa", "row-3-button-1" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_2, DIK_N, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_2, "pokkunmoguraa", "row-3-button-2" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_3, DIK_M, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_3, "pokkunmoguraa", "row-3-button-3" },
{ POKKUNMOGURAA_KEYS + POKKUNMOGURAA_KEY_ROW_3_4, DIK_COMMA, IDS_INPUT_POKKUNMOGURAA_KEY_ROW_3_4, "pokkunmoguraa", "row-3-button-4" },
{ PARTYTAP_KEYS + PARTYTAP_UNIT_1, DIK_Q, IDS_INPUT_PARTYTAP_UNIT_1, "partytap", "unit-1" },
{ PARTYTAP_KEYS + PARTYTAP_UNIT_2, DIK_W, IDS_INPUT_PARTYTAP_UNIT_2, "partytap", "unit-2" },
{ PARTYTAP_KEYS + PARTYTAP_UNIT_3, DIK_E, IDS_INPUT_PARTYTAP_UNIT_3, "partytap", "unit-3" },
{ PARTYTAP_KEYS + PARTYTAP_UNIT_4, DIK_R, IDS_INPUT_PARTYTAP_UNIT_4, "partytap", "unit-4" },
{ PARTYTAP_KEYS + PARTYTAP_UNIT_5, DIK_T, IDS_INPUT_PARTYTAP_UNIT_5, "partytap", "unit-5" },
{ PARTYTAP_KEYS + PARTYTAP_UNIT_6, DIK_Y, IDS_INPUT_PARTYTAP_UNIT_6, "partytap", "unit-6" },
{ KARAOKESTUDIO_KEYS + KARAOKESTUDIO_MIC, DIK_G, IDS_INPUT_KARAOKESTUDIO_MIC, "karaokestudio", "mic" },
{ KARAOKESTUDIO_KEYS + KARAOKESTUDIO_A, DIK_H, IDS_INPUT_KARAOKESTUDIO_A, "karaokestudio", "a" },
{ KARAOKESTUDIO_KEYS + KARAOKESTUDIO_B, DIK_J, IDS_INPUT_KARAOKESTUDIO_B, "karaokestudio", "b" },
{ EMULATION_KEYS + EMULATION_KEY_ALT_SPEED, DIK_TAB, IDS_INPUT_EMULATION_KEY_ALT_SPEED, "emulation", "alt-speed" },
{ EMULATION_KEYS + EMULATION_KEY_REWIND, DIK_BACK, IDS_INPUT_EMULATION_KEY_REWIND, "emulation", "rewind" },
{ EMULATION_KEYS + EMULATION_KEY_INSERT_COIN_1, DIK_F2, IDS_INPUT_EMULATION_KEY_INSERT_COIN_1, "emulation", "insert-coin-1" },
{ EMULATION_KEYS + EMULATION_KEY_INSERT_COIN_2, DIK_F3, IDS_INPUT_EMULATION_KEY_INSERT_COIN_2, "emulation", "insert-coin-2" },
{ FILE_KEYS + FILE_KEY_OPEN, CTRL | 'O', IDS_INPUT_FILE_KEY_OPEN, "file", "open" },
{ FILE_KEYS + FILE_KEY_SAVE_STATE, VK_F5, IDS_INPUT_FILE_KEY_SAVE_STATE, "file", "save-state" },
{ FILE_KEYS + FILE_KEY_LOAD_STATE, VK_F7, IDS_INPUT_FILE_KEY_LOAD_STATE, "file", "load-state" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_1, '1', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_1, "file", "quick-load-state-1" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_2, '2', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_2, "file", "quick-load-state-2" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_3, '3', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_3, "file", "quick-load-state-3" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_4, '4', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_4, "file", "quick-load-state-4" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_5, '5', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_5, "file", "quick-load-state-5" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_6, '6', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_6, "file", "quick-load-state-6" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_7, '7', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_7, "file", "quick-load-state-7" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_8, '8', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_8, "file", "quick-load-state-8" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_STATE_9, '9', IDS_INPUT_FILE_KEY_QUICK_LOAD_STATE_9, "file", "quick-load-state-9" },
{ FILE_KEYS + FILE_KEY_QUICK_LOAD_LAST_STATE, '0', IDS_INPUT_FILE_KEY_QUICK_LOAD_LAST_STATE, "file", "quick-load-state-newest" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_1, SHIFT | '1', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_1, "file", "quick-save-state-1" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_2, SHIFT | '2', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_2, "file", "quick-save-state-2" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_3, SHIFT | '3', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_3, "file", "quick-save-state-3" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_4, SHIFT | '4', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_4, "file", "quick-save-state-4" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_5, SHIFT | '5', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_5, "file", "quick-save-state-5" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_6, SHIFT | '6', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_6, "file", "quick-save-state-6" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_7, SHIFT | '7', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_7, "file", "quick-save-state-7" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_8, SHIFT | '8', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_8, "file", "quick-save-state-8" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_STATE_9, SHIFT | '9', IDS_INPUT_FILE_KEY_QUICK_SAVE_STATE_9, "file", "quick-save-state-9" },
{ FILE_KEYS + FILE_KEY_QUICK_SAVE_NEXT_STATE, SHIFT | '0', IDS_INPUT_FILE_KEY_QUICK_SAVE_NEXT_STATE, "file", "quick-save-state-oldest" },
{ FILE_KEYS + FILE_KEY_SAVE_SCREENSHOT, ALT | 'E', IDS_INPUT_FILE_KEY_SAVE_SCREENSHOT, "file", "save-screenshot" },
{ FILE_KEYS + FILE_KEY_LAUNCHER, ALT | 'L', IDS_INPUT_FILE_KEY_LAUNCHER, "file", "launcher" },
{ FILE_KEYS + FILE_KEY_EXIT, ALT | 'X', IDS_INPUT_FILE_KEY_EXIT, "file", "exit" },
{ MACHINE_KEYS + MACHINE_KEY_POWER, SHIFT | 'D', IDS_INPUT_MACHINE_KEY_POWER, "machine", "power" },
{ MACHINE_KEYS + MACHINE_KEY_RESET_SOFT, SHIFT | 'R', IDS_INPUT_MACHINE_KEY_RESET_SOFT, "machine", "soft-reset" },
{ MACHINE_KEYS + MACHINE_KEY_RESET_HARD, SHIFT | 'T', IDS_INPUT_MACHINE_KEY_RESET_HARD, "machine", "hard-reset" },
{ MACHINE_KEYS + MACHINE_KEY_PAUSE, SHIFT | 'P', IDS_INPUT_MACHINE_KEY_PAUSE, "machine", "pause" },
{ MACHINE_KEYS + MACHINE_KEY_UNLIMITED_SPRITES, SHIFT | 'U', IDS_INPUT_MACHINE_KEY_UNLIMITED_SPRITES, "machine", "no-sprite-limit-toggle" },
{ MACHINE_KEYS + MACHINE_KEY_CHANGE_DISK_SIDE, SHIFT | 'B', IDS_INPUT_MACHINE_KEY_CHANGE_DISK_SIDE, "machine", "change-disk-side" },
{ NSF_KEYS + NSF_KEY_PLAY, SHIFT | VK_UP, IDS_INPUT_NSF_KEY_PLAY, "nsf", "play-song" },
{ NSF_KEYS + NSF_KEY_STOP, SHIFT | VK_DOWN, IDS_INPUT_NSF_KEY_STOP, "nsf", "stop-song" },
{ NSF_KEYS + NSF_KEY_NEXT, SHIFT | VK_RIGHT, IDS_INPUT_NSF_KEY_NEXT, "nsf", "next-song" },
{ NSF_KEYS + NSF_KEY_PREV, SHIFT | VK_LEFT, IDS_INPUT_NSF_KEY_PREV, "nsf", "previous-song" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_1X, ALT | '1', IDS_INPUT_VIEW_KEY_SCREENSIZE_1X, "view", "screen-size-1x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_2X, ALT | '2', IDS_INPUT_VIEW_KEY_SCREENSIZE_2X, "view", "screen-size-2x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_3X, ALT | '3', IDS_INPUT_VIEW_KEY_SCREENSIZE_3X, "view", "screen-size-3x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_4X, ALT | '4', IDS_INPUT_VIEW_KEY_SCREENSIZE_4X, "view", "screen-size-4x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_5X, ALT | '5', IDS_INPUT_VIEW_KEY_SCREENSIZE_5X, "view", "screen-size-5x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_6X, ALT | '6', IDS_INPUT_VIEW_KEY_SCREENSIZE_6X, "view", "screen-size-6x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_7X, ALT | '7', IDS_INPUT_VIEW_KEY_SCREENSIZE_7X, "view", "screen-size-7x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_8X, ALT | '8', IDS_INPUT_VIEW_KEY_SCREENSIZE_8X, "view", "screen-size-8x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_9X, ALT | '9', IDS_INPUT_VIEW_KEY_SCREENSIZE_9X, "view", "screen-size-9x" },
{ VIEW_KEYS + VIEW_KEY_SCREENSIZE_MAX, ALT | 'S', IDS_INPUT_VIEW_KEY_SCREENSIZE_MAX, "view", "screen-size-max" },
{ VIEW_KEYS + VIEW_KEY_SHOW_MENU, VK_ESCAPE, IDS_INPUT_VIEW_KEY_SHOW_MENU, "view", "toggle-menu" },
{ VIEW_KEYS + VIEW_KEY_SHOW_STATUSBAR, CTRL | 'B', IDS_INPUT_VIEW_KEY_SHOW_STATUSBAR, "view", "toggle-status-bar" },
{ VIEW_KEYS + VIEW_KEY_SHOW_ONTOP, CTRL | 'T', IDS_INPUT_VIEW_KEY_SHOW_ONTOP, "view", "toggle-window-on-top" },
{ VIEW_KEYS + VIEW_KEY_SHOW_FPS, CTRL | 'F', IDS_INPUT_VIEW_KEY_SHOW_FPS, "view", "toggle-fps" },
{ VIEW_KEYS + VIEW_KEY_FULLSCREEN, ALT | VK_RETURN, IDS_INPUT_VIEW_KEY_FULLSCREEN, "view", "fullscreen" },
{ HELP_KEYS + HELP_KEY_HELP, VK_F1, IDS_INPUT_HELP_KEY_HELP, "help", "readme" }
};
struct Input::Handlers
{
static const MsgHandler::Entry<Input> messages[];
static const MsgHandler::Entry<Input> commands[];
};
const MsgHandler::Entry<Input> Input::Handlers::messages[] =
{
{ WM_INITDIALOG, &Input::OnInitDialog },
{ WM_HSCROLL, &Input::OnHScroll },
{ WM_DESTROY, &Input::OnDestroy }
};
const MsgHandler::Entry<Input> Input::Handlers::commands[] =
{
{ IDC_INPUT_MAP, &Input::OnCmdDblClk },
{ IDC_INPUT_DEVICES, &Input::OnCmdDevice },
{ IDC_INPUT_JOYSTICKS, &Input::OnCmdJoysticks },
{ IDC_INPUT_SET, &Input::OnCmdSet },
{ IDC_INPUT_SETALL, &Input::OnCmdSetAll },
{ IDC_INPUT_CLEAR, &Input::OnCmdClear },
{ IDC_INPUT_CLEARALL, &Input::OnCmdClearAll },
{ IDC_INPUT_JOYSTICKS_ENABLE, &Input::OnCmdJoystickEnable },
{ IDC_INPUT_JOYSTICKS_X, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_Y, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_Z, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_RX, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_RY, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_RZ, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_S0, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_S1, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_POV0, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_POV1, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_POV2, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_POV3, &Input::OnCmdJoystickAxis },
{ IDC_INPUT_JOYSTICKS_CALIBRATE, &Input::OnCmdCalibrate },
{ IDC_INPUT_JOYSTICKS_DEFAULT, &Input::OnCmdJoysticksDefault },
{ IDC_INPUT_DEFAULT, &Input::OnCmdDefault },
{ IDC_INPUT_DEFAULT_CATEGORY, &Input::OnCmdDefaultCategory },
{ IDC_INPUT_AUTOFIRE_DEFAULT, &Input::OnCmdAutoFireDefault }
};
Input::Settings::Settings()
: autoFireSpeed(AUTOFIRE_DEFAULT_SPEED) {}
inline uint Input::Settings::Mapping::Code() const
{
return key & 0xFF;
}
inline uint Input::Settings::Mapping::Alt() const
{
return (key & ALT) ? VK_MENU : 0;
}
inline uint Input::Settings::Mapping::Shift() const
{
return (key & SHIFT) ? VK_SHIFT : 0;
}
inline uint Input::Settings::Mapping::Ctrl() const
{
return (key & CTRL) ? VK_CONTROL : 0;
}
inline const Input::Settings::Mapping& Input::Settings::GetMapping(uint type,uint index)
{
NST_ASSERT( index < NumTypeKeys(type) );
return map[types[type].offset + index];
}
inline const Input::Settings::Type& Input::Settings::GetType(uint type)
{
NST_ASSERT( type < NUM_TYPES );
return types[type];
}
inline void Input::Settings::Unmap(uint index)
{
NST_ASSERT( index < NUM_KEYS );
keys[index].Unmap();
}
bool Input::Settings::Map(const uint index,const Key& key)
{
NST_ASSERT( index < NUM_KEYS );
if (key.Assigned())
{
if (index >= COMMAND_KEYS)
{
for (uint i=0; i < COMMAND_KEYS; ++i)
{
if (key == keys[i])
return (i == index);
}
}
for (uint i=COMMAND_KEYS; i < NUM_KEYS; ++i)
{
if (key == keys[i])
return (i == index);
}
}
keys[index] = key;
return true;
}
void Input::Settings::Clear()
{
for (uint i=0; i < NUM_KEYS; ++i)
keys[i].Unmap();
}
void Input::Settings::Clear(const uint type)
{
NST_ASSERT( type < NUM_TYPES );
for (uint i=types[type].offset, n=types[type+1].offset; i < n; ++i)
keys[i].Unmap();
}
void Input::Settings::Reset(const DirectX::DirectInput& directInput)
{
for (uint i=0; i < NUM_TYPES; ++i)
Reset( directInput, i );
}
void Input::Settings::Reset(const DirectX::DirectInput& directInput,const uint type)
{
NST_ASSERT( type < NUM_TYPES );
const Mapping* it = map + types[type].offset;
const Mapping* const end = map + types[type + 1].offset;
NST_ASSERT( it < end );
Key key;
if (type < TYPE_FILE)
{
do
{
directInput.MapKeyboard( key, it->key );
Map( it->index, key );
}
while (++it != end);
}
else
{
do
{
key.MapVirtualKey( it->Code(), it->Alt(), it->Ctrl(), it->Shift() );
Map( it->index, key );
}
while (++it != end);
}
}
Input::Input(DirectX::DirectInput& di,Managers::Emulator& emulator,const Configuration& cfg)
:
nes ( emulator ),
directInput ( di ),
dialog ( IDD_INPUT, this, Handlers::messages, Handlers::commands )
{
Configuration::ConstSection input( cfg["input"] );
settings.Clear();
settings.autoFireSpeed = input["auto-fire-speed"].Int( Settings::AUTOFIRE_DEFAULT_SPEED );
settings.allowSimulAxes = input["allow-simultaneous-axes"].Yes();
if (settings.autoFireSpeed > Settings::AUTOFIRE_MAX_SPEED)
settings.autoFireSpeed = Settings::AUTOFIRE_DEFAULT_SPEED;
System::Guid joyGuids[DirectX::DirectInput::MAX_JOYSTICKS];
uint maxGuids = 0;
if (const uint numJoysticks = directInput.NumJoysticks())
{
bool referenced[DirectX::DirectInput::MAX_JOYSTICKS] = {false};
if (Configuration::ConstSection joysticks=input["joysticks"])
{
bool alert = true;
for (uint i=0; i < numJoysticks; ++i)
{
Configuration::ConstSection joystick( joysticks["joystick"][i] );
if (!joystick)
break;
uint index = UINT_MAX;
const System::Guid guid( joystick["device"].Str() );
for (uint j=0; j < numJoysticks; ++j)
{
if (guid == directInput.GetJoystickGuid(j))
{
index = j;
referenced[j] = true;
break;
}
}
if (index == UINT_MAX)
{
for (uint j=0; j < numJoysticks; ++j)
{
if (!referenced[j])
{
index = j;
referenced[j] = true;
break;
}
}
if (index == UINT_MAX || (alert && !Window::User::Confirm( IDS_INPUT_JOY_GUID_MISMATCH )))
break;
alert = false;
}
joyGuids[maxGuids++] = directInput.GetJoystickGuid(index);
directInput.ScanEnableJoystick( index, !joystick["enabled"].No() );
uint deadzone = joystick["deadzone"].Int( DirectX::DirectInput::DEFAULT_DEADZONE );
if (deadzone > DirectX::DirectInput::DEADZONE_MAX)
deadzone = DirectX::DirectInput::DEFAULT_DEADZONE;
directInput.SetAxisDeadZone( index, deadzone );
if (Configuration::ConstSection scan=joystick["scan"])
{
uint axes = 0;
static cstring const names[] =
{
"x","y","z","rx","ry","rz","z0","z1","p0","p1","p2","p3"
};
for (uint j=0; j < sizeof(array(names)); ++j)
{
if (scan[names[j]].Yes())
{
axes |= (1U << j);
}
else if (!scan[names[j]].No())
{
axes |= (1U << j) & DirectX::DirectInput::DEFAULT_AXES;
}
}
directInput.SetScannerAxes( index, axes );
}
}
}
}
Configuration::ConstSection keys( input["keys"] );
HeapString keyName;
for (uint i=0; i < Settings::NUM_TYPES; ++i)
{
for (uint j=0, n=Settings::NumTypeKeys(i); j < n; ++j)
{
const Settings::Mapping& mapping = Settings::GetMapping( i, j );
keyName = keys[mapping.cfgType][mapping.cfgKey].Str();
Settings::Key key;
if (keyName.Length())
{
if (i < Settings::TYPE_COMMAND || !key.MapVirtualKey( keyName ))
directInput.MapKey( key, keyName.Ptr(), joyGuids, maxGuids );
}
else
{
if (i < Settings::TYPE_COMMAND)
directInput.MapKeyboard( key, mapping.key );
else
key.MapVirtualKey( mapping.Code(), mapping.Alt(), mapping.Ctrl(), mapping.Shift() );
}
if (!settings.Map( mapping.index, key ))
{
Io::Log() << "DirectInput: warning, key assigned to \""
<< mapping.cfgType
<< ':'
<< mapping.cfgKey
<< "\" is already in use!\r\n";
}
}
}
}
void Input::Save(Configuration& cfg) const
{
Configuration::Section input( cfg["input"] );
input["auto-fire-speed"].Int() = settings.autoFireSpeed;
input["allow-simultaneous-axes"].YesNo() = settings.allowSimulAxes;
if (const uint numJoysticks=directInput.NumJoysticks())
{
Configuration::Section joysticks( input["joysticks"] );
for (uint i=0; i < numJoysticks; ++i)
{
Configuration::Section joystick( joysticks["joystick"][i] );
joystick["device"].Str() = directInput.GetJoystickGuid(i).GetString();
joystick["enabled"].YesNo() = directInput.JoystickScanEnabled(i);
joystick["deadzone"].Int() = directInput.GetAxisDeadZone(i);
static cstring const names[] =
{
"x","y","z","rx","ry","rz","z0","z1","p0","p1","p2","p3"
};
Configuration::Section scan( joystick["scan"] );
for (uint j=0, axes=directInput.GetScannerAxes(i); j < sizeof(array(names)); ++j)
scan[names[j]].YesNo() = (axes & (1U << j));
}
}
Configuration::Section keys( input["keys"] );
for (uint i=0; i < Settings::NUM_TYPES; ++i)
{
for (uint j=0, n=Settings::NumTypeKeys(i); j < n; ++j)
{
const Settings::Mapping& mapping = Settings::GetMapping( i, j );
keys[mapping.cfgType][mapping.cfgKey].Str() = directInput.GetKeyName( settings.GetKey(mapping.index) );
}
}
}
ibool Input::OnInitDialog(Param&)
{
{
const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_DEVICES) );
listBox.Reserve( Settings::NUM_TYPES );
for (uint i=0; i < Settings::NUM_TYPES; ++i)
listBox.Add( Resource::String(Settings::GetType(i).name) );
listBox[0].Select();
}
if (const uint numJoysticks = directInput.NumJoysticks())
{
const Control::ComboBox comboBox( dialog.ComboBox(IDC_INPUT_JOYSTICKS) );
for (uint i=0; i < numJoysticks; ++i)
comboBox.Add( directInput.GetJoystickName(i).Ptr() );
comboBox[0].Select();
dialog.Slider(IDC_INPUT_JOYSTICKS_DEADZONE).SetRange( 0, DirectX::DirectInput::DEADZONE_MAX );
UpdateJoysticks( 0 );
}
else for (uint i=IDC_INPUT_JOYSTICKS; i <= IDC_INPUT_JOYSTICKS_DEFAULT; ++i)
{
dialog.Control( i ).Disable();
}
dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).SetRange( 0, Settings::AUTOFIRE_MAX_SPEED );
dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position() = settings.autoFireSpeed;
dialog.CheckBox( IDC_INPUT_ALLOW_SIMUL_AXES ).Check( settings.allowSimulAxes );
UpdateKeyNames( 0 );
UpdateKeyMap( 0 );
return true;
}
ibool Input::OnCmdDblClk(Param& param)
{
if (HIWORD(param.wParam) == LBN_DBLCLK)
{
if (ScanKeys() == SCAN_NEXT)
SelectNextMapKey();
return true;
}
return false;
}
ibool Input::OnHScroll(Param& param)
{
if (param.Slider().GetId() == IDC_INPUT_JOYSTICKS_DEADZONE)
{
const uint deadZone = param.Slider().Scroll();
if (directInput.SetAxisDeadZone( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex(), deadZone ))
dialog.Edit( IDC_INPUT_JOYSTICKS_DEADZONE_NUM ) << deadZone;
}
return true;
}
void Input::UpdateKeyNames(const uint type) const
{
NST_ASSERT( type < Settings::NUM_TYPES );
const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_KEYS) );
listBox.Clear();
listBox.Reserve( Settings::NumTypeKeys(type) );
for (uint i=0, n=Settings::NumTypeKeys(type); i < n; ++i)
listBox.Add( Resource::String(Settings::GetMapping(type,i).dlgName) );
}
void Input::UpdateKeyMap(const uint type) const
{
const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_MAP) );
listBox.Clear();
listBox.Reserve( Settings::NumTypeKeys(type) );
for (uint i=0, n=Settings::NumTypeKeys(type); i < n; ++i)
listBox.Add( directInput.GetKeyName( settings.GetKey(Settings::GetMapping(type,i).index) ).Ptr() );
listBox[0].Select();
}
void Input::ResetJoysticks()
{
if (uint numJoysticks = directInput.NumJoysticks())
{
do
{
directInput.ScanEnableJoystick( --numJoysticks, true );
directInput.SetAxisDeadZone( numJoysticks, DirectX::DirectInput::DEFAULT_DEADZONE );
directInput.SetScannerAxes( numJoysticks, DirectX::DirectInput::DEFAULT_AXES );
}
while (numJoysticks);
UpdateJoysticks( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex() );
}
}
void Input::UpdateJoysticks(const uint type) const
{
NST_ASSERT( directInput.NumJoysticks() );
const bool enabled = directInput.JoystickScanEnabled( type );
dialog.CheckBox(IDC_INPUT_JOYSTICKS_ENABLE).Check( enabled );
{
const uint deadZone = directInput.GetAxisDeadZone( type );
dialog.Slider( IDC_INPUT_JOYSTICKS_DEADZONE ).Position() = deadZone;
dialog.Slider( IDC_INPUT_JOYSTICKS_DEADZONE ).Enable( enabled );
dialog.Slider( IDC_INPUT_JOYSTICKS_DEADZONE_TEXT ).Enable( enabled );
dialog.Edit( IDC_INPUT_JOYSTICKS_DEADZONE_NUM ) << deadZone;
dialog.Edit( IDC_INPUT_JOYSTICKS_DEADZONE_NUM ).Enable( enabled );
}
{
const uint axes[] =
{
directInput.GetAvailableAxes( type ),
directInput.GetScannerAxes( type )
};
for (uint i=0; i <= (IDC_INPUT_JOYSTICKS_POV3-IDC_INPUT_JOYSTICKS_X); ++i)
{
const Control::CheckBox box( dialog.CheckBox(IDC_INPUT_JOYSTICKS_X + i) );
box.Enable( enabled && (axes[0] & (1U << i)) );
box.Check( axes[1] & (1U << i) );
}
}
}
ibool Input::OnCmdDevice(Param& param)
{
if (param.ListBox().SelectionChanged())
{
const uint type = dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex();
UpdateKeyNames( type );
UpdateKeyMap( type );
}
return true;
}
ibool Input::OnCmdJoysticks(Param& param)
{
if (param.ComboBox().SelectionChanged())
UpdateJoysticks( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex() );
return true;
}
ibool Input::OnCmdJoystickEnable(Param& param)
{
if (param.Button().Clicked())
{
const uint type = dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex();
directInput.ScanEnableJoystick( type, dialog.CheckBox(param.Button().GetId()).Checked() );
UpdateJoysticks( type );
}
return true;
}
ibool Input::OnCmdJoystickAxis(Param& param)
{
if (param.Button().Clicked())
{
directInput.SetScannerAxes
(
dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex(),
1U << (param.Button().GetId() - IDC_INPUT_JOYSTICKS_X),
dialog.CheckBox(param.Button().GetId()).Checked()
);
}
return true;
}
ibool Input::OnCmdSet(Param& param)
{
if (param.Button().Clicked() && ScanKeys() == SCAN_NEXT)
SelectNextMapKey();
return true;
}
ibool Input::OnCmdSetAll(Param& param)
{
if (param.Button().Clicked())
{
const Control::ListBox listBox( dialog.ListBox(IDC_INPUT_MAP) );
listBox[0].Select();
for (uint count=listBox.Size(); count; --count)
{
if (ScanKeys() == SCAN_ABORT)
break;
SelectNextMapKey();
}
}
return true;
}
ibool Input::OnCmdClear(Param& param)
{
if (param.Button().Clicked())
{
const Control::ListBox keyBox( dialog.ListBox(IDC_INPUT_MAP) );
const uint index = Settings::GetMapping( dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex(), keyBox.Selection().GetIndex() ).index;
settings.Unmap( index );
keyBox.Selection().Text() << directInput.GetKeyName( settings.GetKey(index) ).Ptr();
SelectNextMapKey();
}
return true;
}
ibool Input::OnCmdClearAll(Param& param)
{
if (param.Button().Clicked())
{
const uint type = dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex();
settings.Clear( type );
UpdateKeyMap( type );
}
return true;
}
ibool Input::OnCmdDefaultCategory(Param& param)
{
if (param.Button().Clicked())
{
const uint type = dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex();
settings.Clear( type );
settings.Reset( directInput, type );
UpdateKeyMap( type );
}
return true;
}
ibool Input::OnCmdAutoFireDefault(Param& param)
{
if (param.Button().Clicked())
dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position() = Settings::AUTOFIRE_DEFAULT_SPEED;
return true;
}
ibool Input::OnCmdCalibrate(Param& param)
{
if (param.Button().Clicked())
directInput.Calibrate( dialog.ComboBox(IDC_INPUT_JOYSTICKS).Selection().GetIndex() );
return true;
}
ibool Input::OnCmdJoysticksDefault(Param& param)
{
if (param.Button().Clicked())
ResetJoysticks();
return true;
}
ibool Input::OnCmdDefault(Param& param)
{
if (param.Button().Clicked())
{
settings.Clear();
settings.Reset( directInput );
dialog.CheckBox( IDC_INPUT_ALLOW_SIMUL_AXES ).Uncheck();
dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position() = Settings::AUTOFIRE_DEFAULT_SPEED;
ResetJoysticks();
UpdateKeyMap( dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() );
}
return true;
}
ibool Input::OnDestroy(Param&)
{
settings.autoFireSpeed = dialog.Slider( IDC_INPUT_AUTOFIRE_SLIDER ).Position();
settings.allowSimulAxes = dialog.CheckBox( IDC_INPUT_ALLOW_SIMUL_AXES ).Checked();
return true;
}
class Input::KeyPressWindow : Dynamic
{
public:
enum Result
{
RESULT_OK,
RESULT_ABORT,
RESULT_DUPLICATE,
RESULT_INVALID
};
private:
struct Timer
{
enum
{
RATE = 50,
CLOCK = 1000,
START = 5000,
SEC = 1000
};
int remaining;
int clock;
Timer()
: remaining(START), clock(START) {}
};
Input& base;
Timer timer;
Result result;
void Close(Result r)
{
result = r;
base.dialog.Enable( true );
Destroy();
}
uint OnTimer()
{
timer.remaining -= Timer::RATE;
if (timer.remaining <= 0 || *this != ::GetForegroundWindow())
{
Close( RESULT_ABORT );
return false;
}
if (timer.remaining <= timer.clock)
{
uint msgId;
if (base.dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() >= Settings::TYPE_COMMAND)
msgId = IDS_DIALOG_INPUT_PRESS_ANY_KEY_MENU;
else
msgId = IDS_DIALOG_INPUT_PRESS_ANY_KEY_EMU;
base.dialog.Control(IDC_INPUT_KEYPRESS_TEXT).Text() << Resource::String(msgId).Invoke( wchar_t('0' + (timer.clock / Timer::SEC)) );
timer.clock -= Timer::CLOCK;
}
DirectX::DirectInput::ScanMode scanMode;
if (base.dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() < Settings::TYPE_COMMAND)
scanMode = DirectX::DirectInput::SCAN_MODE_ALL;
else
scanMode = DirectX::DirectInput::SCAN_MODE_JOY;
Settings::Key key;
switch (base.directInput.ScanKey( key, scanMode ))
{
case DirectX::DirectInput::SCAN_GOOD_KEY:
for (uint i=10; i && base.directInput.AnyPressed(); --i)
::Sleep( 100 );
if (base.MapSelectedKey( key ))
{
Close( RESULT_OK );
return false;
}
else
{
Close( RESULT_DUPLICATE );
return false;
}
break;
case DirectX::DirectInput::SCAN_INVALID_KEY:
Close( RESULT_INVALID );
return false;
}
return true;
}
ibool OnCreate(Param& param)
{
base.dialog.Enable( false );
base.directInput.BeginScanMode( param.hWnd );
StartTimer( this, &KeyPressWindow::OnTimer, Timer::RATE );
::SetWindowPos( param.hWnd, HWND_TOP, 0, 0, 0, 0, SWP_HIDEWINDOW );
return false;
}
ibool OnDestroy(Param&)
{
StopTimer( this, &KeyPressWindow::OnTimer );
base.directInput.EndScanMode();
base.dialog.Control(IDC_INPUT_KEYPRESS_TEXT).Text().Clear();
return false;
}
ibool OnKeyDown(Param& param)
{
if (base.dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex() >= Settings::TYPE_COMMAND)
{
if (param.wParam != VK_SHIFT && param.wParam != VK_CONTROL && param.wParam != VK_MENU)
{
const uint vKeys[3] =
{
(::GetAsyncKeyState( VK_SHIFT ) & 0x8000U) ? VK_SHIFT : 0,
(::GetAsyncKeyState( VK_CONTROL ) & 0x8000U) ? VK_CONTROL : 0,
(::GetAsyncKeyState( VK_MENU ) & 0x8000U) ? VK_MENU : 0
};
Settings::Key key;
if (!key.MapVirtualKey( param.wParam, vKeys[0], vKeys[1], vKeys[2] ))
{
Close( RESULT_INVALID );
}
else if (!base.MapSelectedKey( key ))
{
Close( RESULT_DUPLICATE );
}
else
{
Close( RESULT_OK );
}
}
}
return false;
}
public:
explicit KeyPressWindow(Input& b)
: base(b), result(RESULT_ABORT)
{
static const MsgHandler::Entry<KeyPressWindow> messages[] =
{
{ WM_CREATE, &KeyPressWindow::OnCreate },
{ WM_DESTROY, &KeyPressWindow::OnDestroy },
{ WM_KEYDOWN, &KeyPressWindow::OnKeyDown },
{ WM_SYSKEYDOWN, &KeyPressWindow::OnKeyDown }
};
Messages().Set( this, messages );
Context context;
context.className = L"Poll Key";
context.windowName = context.className;
context.winStyle = WS_POPUP;
context.hParent = base.dialog;
Create( context );
}
Result Poll() const
{
for (MSG msg; *this && ::GetMessage( &msg, NULL, 0, 0 ) > 0; )
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
return result;
}
};
INT_PTR Input::ScanKeys()
{
switch (KeyPressWindow(*this).Poll())
{
case KeyPressWindow::RESULT_INVALID:
User::Warn( IDS_DIALOG_INPUT_PRESS_ANY_KEY_INVALID, IDS_TITLE_ERROR );
return SCAN_ABORT;
case KeyPressWindow::RESULT_DUPLICATE:
User::Warn( IDS_DIALOG_INPUT_DUPLICATE_KEYS, IDS_TITLE_ERROR );
return SCAN_ABORT;
case KeyPressWindow::RESULT_ABORT:
return SCAN_ABORT;
}
return SCAN_NEXT;
}
void Input::SelectNextMapKey()
{
const Control::ListBox keyBox( dialog.ListBox(IDC_INPUT_MAP) );
const uint index = keyBox.Selection().GetIndex() + 1;
keyBox[index < keyBox.Size() ? index : 0].Select();
}
bool Input::MapSelectedKey(const Settings::Key& key)
{
const uint index = Settings::GetMapping( dialog.ListBox(IDC_INPUT_DEVICES).Selection().GetIndex(), dialog.ListBox(IDC_INPUT_MAP).Selection().GetIndex() ).index;
if (settings.Map( index, key ))
{
dialog.ListBox(IDC_INPUT_MAP).Selection().Text() << directInput.GetKeyName( settings.GetKey(index) ).Ptr();
return true;
}
return false;
}
}
}