diff --git a/Src/BeebEm.rc b/Src/BeebEm.rc index c482850e..0f06abad 100644 --- a/Src/BeebEm.rc +++ b/Src/BeebEm.rc @@ -160,7 +160,7 @@ BEGIN CTEXT "b0",IDC_STATIC,157,10,13,12 END -IDD_SELECT_KEY DIALOGEX 0, 0, 149, 60 +IDD_SELECT_KEY DIALOGEX 0, 0, 149, 78 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Press key for unshifted press..." FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -168,7 +168,8 @@ BEGIN LTEXT "Assigned to PC key(s):",IDC_STATIC,7,7,74,8 LTEXT "Static",IDC_ASSIGNED_KEYS,15,21,127,8 CONTROL "Shift",IDC_SHIFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,40,31,10 - PUSHBUTTON "OK",IDOK,92,39,50,14 + PUSHBUTTON "&Clear",IDC_CLEAR,92,37,50,14 + PUSHBUTTON "OK",IDOK,92,56,50,14 END IDD_DEBUG DIALOGEX 0, 0, 529, 387 diff --git a/Src/BeebEm.vcxproj b/Src/BeebEm.vcxproj index 8b37ff6a..43b19957 100644 --- a/Src/BeebEm.vcxproj +++ b/Src/BeebEm.vcxproj @@ -198,6 +198,7 @@ + @@ -225,7 +226,7 @@ - + @@ -351,6 +352,7 @@ + @@ -379,7 +381,7 @@ - + diff --git a/Src/BeebEm.vcxproj.filters b/Src/BeebEm.vcxproj.filters index a4dc4de5..85d380cd 100644 --- a/Src/BeebEm.vcxproj.filters +++ b/Src/BeebEm.vcxproj.filters @@ -120,6 +120,9 @@ Source Files + + Source Files + Source Files @@ -198,7 +201,7 @@ Source Files - + Source Files @@ -362,6 +365,9 @@ Header Files + + Header Files + Header Files @@ -452,7 +458,7 @@ Header Files - + Header Files diff --git a/Src/KeyMap.cpp b/Src/KeyMap.cpp new file mode 100644 index 00000000..96cee1e2 --- /dev/null +++ b/Src/KeyMap.cpp @@ -0,0 +1,484 @@ +/**************************************************************** +BeebEm - BBC Micro and Master 128 Emulator +Copyright (C) 1997 Laurie Whiffen + +This program 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. + +This program 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 this program; if not, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. +****************************************************************/ + +// User defined keyboard functionality. + +#include "KeyMap.h" +#include "Main.h" + +// Keyboard mappings +KeyMap UserKeyMap; +KeyMap DefaultKeyMap; +KeyMap LogicalKeyMap; + +// Currently selected translation table +const KeyMap *transTable = &DefaultKeyMap; + +// Token written to start of map file +#define KEYMAP_TOKEN "*** BeebEm Keymap ***" + +static const char* GetVirtualKeyCode(int Key); + +/*--------------------------------------------------------------------------*/ + +static void ResetKeyMap(KeyMap* keymap) +{ + for (int PCKey = 0; PCKey < KEYMAP_SIZE; PCKey++) + { + for (int PCShift = 0; PCShift < 2; PCShift++) + { + (*keymap)[PCKey][PCShift].row = -9; + (*keymap)[PCKey][PCShift].row = 0; + UserKeyMap[PCKey][PCShift].shift = PCShift == 1; + } + } +} + +/*--------------------------------------------------------------------------*/ + +void InitKeyMap() +{ + ResetKeyMap(&DefaultKeyMap); + ResetKeyMap(&LogicalKeyMap); + ResetKeyMap(&UserKeyMap); +} + +/*--------------------------------------------------------------------------*/ + +bool ReadKeyMap(const char *filename, KeyMap *keymap) +{ + bool success = true; + char buf[256]; + + FILE *infile = fopen(filename,"r"); + + if (infile == NULL) + { + mainWin->Report(MessageType::Error, + "Failed to read key map file:\n %s", filename); + + success = false; + } + else + { + if (fgets(buf, 255, infile) == nullptr || + strcmp(buf, KEYMAP_TOKEN "\n") != 0) + { + mainWin->Report(MessageType::Error, + "Invalid key map file:\n %s\n", filename); + + success = false; + } + else + { + fgets(buf, 255, infile); + + for (int i = 0; i < 256; ++i) + { + if (fgets(buf, 255, infile) == NULL) + { + mainWin->Report(MessageType::Error, + "Data missing from key map file:\n %s\n", filename); + + success = false; + break; + } + + int shift0 = 0, shift1 = 0; + + sscanf(buf, "%d %d %d %d %d %d", + &(*keymap)[i][0].row, + &(*keymap)[i][0].col, + &shift0, + &(*keymap)[i][1].row, + &(*keymap)[i][1].col, + &shift1); + + (*keymap)[i][0].shift = shift0 != 0; + (*keymap)[i][1].shift = shift1 != 0; + } + } + + fclose(infile); + } + + return success; +} + +/*--------------------------------------------------------------------------*/ + +bool WriteKeyMap(const char *filename, KeyMap *keymap) +{ + FILE *outfile = fopen(filename, "w"); + + if (outfile == nullptr) + { + mainWin->Report(MessageType::Error, + "Failed to write key map file:\n %s", filename); + return false; + } + + fprintf(outfile, KEYMAP_TOKEN "\n\n"); + + for (int i = 0; i < KEYMAP_SIZE; i++) + { + fprintf(outfile, "%d %d %d %d %d %d # 0x%02X", + (*keymap)[i][0].row, + (*keymap)[i][0].col, + (*keymap)[i][0].shift, + (*keymap)[i][1].row, + (*keymap)[i][1].col, + (*keymap)[i][1].shift, + i); + + const char* KeyCode = GetVirtualKeyCode(i); + + if (KeyCode != nullptr) + { + fprintf(outfile, " %s", KeyCode); + } + + fprintf(outfile, "\n"); + } + + fclose(outfile); + + return true; +} + +/*--------------------------------------------------------------------------*/ + +#define CASE(constant) case constant: return (# constant) + +static const char* GetVirtualKeyCode(int Key) +{ + static char Name[2]; + + if ((Key >= '0' && Key <= '9') || + (Key >= 'A' && Key <= 'Z')) + { + Name[0] = (char)Key; + Name[1] = '\0'; + + return Name; + } + + switch (Key) + { + CASE(VK_LBUTTON); + CASE(VK_RBUTTON); + CASE(VK_CANCEL); + CASE(VK_MBUTTON); + CASE(VK_XBUTTON1); + CASE(VK_XBUTTON2); + CASE(VK_BACK); + CASE(VK_TAB); + CASE(VK_CLEAR); + CASE(VK_RETURN); + CASE(VK_SHIFT); + CASE(VK_CONTROL); + CASE(VK_MENU); + CASE(VK_PAUSE); + CASE(VK_CAPITAL); + CASE(VK_KANA); + // CASE(VK_HANGUL); + // CASE(VK_IME_ON); + CASE(VK_JUNJA); + CASE(VK_FINAL); + CASE(VK_HANJA); + // CASE(VK_KANJI); + // CASE(VK_IME_OFF); + CASE(VK_ESCAPE); + CASE(VK_CONVERT); + CASE(VK_NONCONVERT); + CASE(VK_ACCEPT); + CASE(VK_MODECHANGE); + CASE(VK_SPACE); + CASE(VK_PRIOR); + CASE(VK_NEXT); + CASE(VK_END); + CASE(VK_HOME); + CASE(VK_LEFT); + CASE(VK_UP); + CASE(VK_RIGHT); + CASE(VK_DOWN); + CASE(VK_SELECT); + CASE(VK_PRINT); + CASE(VK_EXECUTE); + CASE(VK_SNAPSHOT); + CASE(VK_INSERT); + CASE(VK_DELETE); + CASE(VK_HELP); + CASE(VK_LWIN); + CASE(VK_RWIN); + CASE(VK_APPS); + CASE(VK_SLEEP); + CASE(VK_NUMPAD0); + CASE(VK_NUMPAD1); + CASE(VK_NUMPAD2); + CASE(VK_NUMPAD3); + CASE(VK_NUMPAD4); + CASE(VK_NUMPAD5); + CASE(VK_NUMPAD6); + CASE(VK_NUMPAD7); + CASE(VK_NUMPAD8); + CASE(VK_NUMPAD9); + CASE(VK_MULTIPLY); + CASE(VK_ADD); + CASE(VK_SEPARATOR); + CASE(VK_SUBTRACT); + CASE(VK_DECIMAL); + CASE(VK_DIVIDE); + CASE(VK_F1); + CASE(VK_F2); + CASE(VK_F3); + CASE(VK_F4); + CASE(VK_F5); + CASE(VK_F6); + CASE(VK_F7); + CASE(VK_F8); + CASE(VK_F9); + CASE(VK_F10); + CASE(VK_F11); + CASE(VK_F12); + CASE(VK_F13); + CASE(VK_F14); + CASE(VK_F15); + CASE(VK_F16); + CASE(VK_F17); + CASE(VK_F18); + CASE(VK_F19); + CASE(VK_F20); + CASE(VK_F21); + CASE(VK_F22); + CASE(VK_F23); + CASE(VK_F24); + CASE(VK_NUMLOCK); + CASE(VK_SCROLL); + CASE(VK_LSHIFT); + CASE(VK_RSHIFT); + CASE(VK_LCONTROL); + CASE(VK_RCONTROL); + CASE(VK_LMENU); + CASE(VK_RMENU); + CASE(VK_BROWSER_BACK); + CASE(VK_BROWSER_FORWARD); + CASE(VK_BROWSER_REFRESH); + CASE(VK_BROWSER_STOP); + CASE(VK_BROWSER_SEARCH); + CASE(VK_BROWSER_FAVORITES); + CASE(VK_BROWSER_HOME); + CASE(VK_VOLUME_MUTE); + CASE(VK_VOLUME_DOWN); + CASE(VK_VOLUME_UP); + CASE(VK_MEDIA_NEXT_TRACK); + CASE(VK_MEDIA_PREV_TRACK); + CASE(VK_MEDIA_STOP); + CASE(VK_MEDIA_PLAY_PAUSE); + CASE(VK_LAUNCH_MAIL); + CASE(VK_LAUNCH_MEDIA_SELECT); + CASE(VK_LAUNCH_APP1); + CASE(VK_LAUNCH_APP2); + CASE(VK_OEM_1); + CASE(VK_OEM_PLUS); + CASE(VK_OEM_COMMA); + CASE(VK_OEM_MINUS); + CASE(VK_OEM_PERIOD); + CASE(VK_OEM_2); + CASE(VK_OEM_3); + CASE(VK_OEM_4); + CASE(VK_OEM_5); + CASE(VK_OEM_6); + CASE(VK_OEM_7); + CASE(VK_OEM_8); + CASE(VK_OEM_102); + CASE(VK_PROCESSKEY); + CASE(VK_PACKET); + CASE(VK_ATTN); + CASE(VK_CRSEL); + CASE(VK_EXSEL); + CASE(VK_EREOF); + CASE(VK_PLAY); + CASE(VK_ZOOM); + CASE(VK_NONAME); + CASE(VK_PA1); + CASE(VK_OEM_CLEAR); + } + + return nullptr; +} + +/*--------------------------------------------------------------------------*/ + +const char* GetPCKeyName(int Key) +{ + static char Character[2]; // Used to return single characters. + + switch (Key) + { + case 0x08: return "Backspace"; + case 0x09: return "Tab"; + case 0x0D: return "Enter"; + case 0x10: return "Shift"; + case 0x11: return "Ctrl"; + case 0x12: return "Alt"; + case 0x13: return "Break"; + case 0x14: return "Caps"; + case 0x1B: return "Esc"; + case 0x20: return "Spacebar"; + case 0x21: return "PgUp"; + case 0x22: return "PgDn"; + case 0x23: return "End"; + case 0x24: return "Home"; + case 0x25: return "Left"; + case 0x26: return "Up"; + case 0x27: return "Right"; + case 0x28: return "Down"; + case 0x2D: return "Insert"; + case 0x2E: return "Del"; + case 0x5D: return "Menu"; + case 0x60: return "Pad0"; + case 0x61: return "Pad1"; + case 0x62: return "Pad2"; + case 0x63: return "Pad3"; + case 0x64: return "Pad4"; + case 0x65: return "Pad5"; + case 0x66: return "Pad6"; + case 0x67: return "Pad7"; + case 0x68: return "Pad8"; + case 0x69: return "Pad9"; + case 0x6A: return "Pad*"; + case 0x6B: return "Pad+"; + case 0x6D: return "Pad-"; + case 0x6E: return "Pad."; + case 0x6F: return "Pad/"; + case 0x70: return "F1"; + case 0x71: return "F2"; + case 0x72: return "F3"; + case 0x73: return "F4"; + case 0x74: return "F5"; + case 0x75: return "F6"; + case 0x76: return "F7"; + case 0x77: return "F8"; + case 0x78: return "F9"; + case 0x79: return "F10"; + case 0x7A: return "F11"; + case 0x7B: return "F12"; + case 0x90: return "NumLock"; + case 0x91: return "SclLock"; + case 0xBA: return ";"; + case 0xBB: return "="; + case 0xBC: return ","; + case 0xBD: return "-"; + case 0xBE: return "."; + case 0xBF: return "/"; + case 0xC0: return "\'"; + case 0xDB: return "["; + case 0xDC: return "\\"; + case 0xDD: return "]"; + case 0xDE: return "#"; + case 0xDF: return "`"; + + default: + Character[0] = (char)LOBYTE(Key); + Character[1] = '\0'; + return Character; + } +} + +/*--------------------------------------------------------------------------*/ + +void SetUserKeyMapping(int Row, int Column, bool BBCShift, int PCKey, bool PCShift) +{ + if (PCKey >= 0 && PCKey < KEYMAP_SIZE) + { + UserKeyMap[PCKey][static_cast(PCShift)].row = Row; + UserKeyMap[PCKey][static_cast(PCShift)].col = Column; + UserKeyMap[PCKey][static_cast(PCShift)].shift = BBCShift; + + // DebugTrace("SetBBCKey: key=%d, shift=%d, row=%d, col=%d, bbcshift=%d\n", + // Key, (int)PCShift, Row, Col, BBCShift); + } +} + +/*--------------------------------------------------------------------------*/ + +// Clear any PC keys that correspond to a given BBC keyboard column, row, +// and shift state. + +void ClearUserKeyMapping(int Row, int Column, bool Shift) +{ + for (int PCKey = 0; PCKey < KEYMAP_SIZE; PCKey++) + { + for (int PCShift = 0; PCShift < 2; PCShift++) + { + if (UserKeyMap[PCKey][PCShift].row == Row && + UserKeyMap[PCKey][PCShift].col == Column && + UserKeyMap[PCKey][PCShift].shift == Shift) + { + UserKeyMap[PCKey][PCShift].row = -9; + UserKeyMap[PCKey][PCShift].col = 0; + UserKeyMap[PCKey][PCShift].shift = PCShift == 1; + } + } + } +} + +/*--------------------------------------------------------------------------*/ + +std::string GetKeysUsed(int Row, int Column, bool Shift) +{ + std::string Keys; + + // First see if this key is defined. + if (Row != -9) + { + for (int PCKey = 0; PCKey < KEYMAP_SIZE; PCKey++) + { + for (int PCShift = 0; PCShift < 2; PCShift++) + { + if (UserKeyMap[PCKey][PCShift].row == Row && + UserKeyMap[PCKey][PCShift].col == Column && + UserKeyMap[PCKey][PCShift].shift == Shift) + { + // We have found a key that matches. + if (!Keys.empty()) + { + Keys += ", "; + } + + if (PCShift == 1) + { + Keys += "Sh-"; + } + + Keys += GetPCKeyName(PCKey); + } + } + } + } + + if (Keys.empty()) + { + Keys = "Not Assigned"; + } + + return Keys; +} diff --git a/Src/KeyMap.h b/Src/KeyMap.h new file mode 100644 index 00000000..b5728907 --- /dev/null +++ b/Src/KeyMap.h @@ -0,0 +1,55 @@ +/**************************************************************** +BeebEm - BBC Micro and Master 128 Emulator +Copyright (C) 1997 Laurie Whiffen + +This program 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. + +This program 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 this program; if not, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. +****************************************************************/ + +#ifndef KEYMAP_HEADER +#define KEYMAP_HEADER + +#include + +#include "beebwin.h" + +struct KeyMapping { + int row; // Beeb row + int col; // Beeb col + bool shift; // Beeb shift state +}; + +constexpr int KEYMAP_SIZE = 256; + +typedef KeyMapping KeyMap[KEYMAP_SIZE][2]; // Indices are: [Virt key][shift state] + +void InitKeyMap(); + +bool ReadKeyMap(const char *filename, KeyMap *keymap); +bool WriteKeyMap(const char *filename, KeyMap *keymap); + +const char* GetPCKeyName(int PCKey); + +void SetUserKeyMapping(int Row, int Column, bool BBCShift, int PCKey, bool PCShift); +void ClearUserKeyMapping(int Row, int Column, bool Shift); +std::string GetKeysUsed(int Row, int Column, bool Shift); + +extern KeyMap DefaultKeyMap; +extern KeyMap LogicalKeyMap; +extern KeyMap UserKeyMap; + +extern const KeyMap *transTable; + +#endif diff --git a/Src/Messages.h b/Src/Messages.h index f5c2711a..0b0f5366 100644 --- a/Src/Messages.h +++ b/Src/Messages.h @@ -23,9 +23,10 @@ Boston, MA 02110-1301, USA. #include -const UINT WM_REINITDX = WM_APP; -const UINT WM_USER_KEYBOARD_DIALOG_CLOSED = WM_APP + 1; -const UINT WM_SELECT_KEY_DIALOG_CLOSED = WM_APP + 2; -const UINT WM_USER_PORT_BREAKOUT_DIALOG_CLOSED = WM_APP + 3; +constexpr UINT WM_REINITDX = WM_APP; +constexpr UINT WM_USER_KEYBOARD_DIALOG_CLOSED = WM_APP + 1; +constexpr UINT WM_SELECT_KEY_DIALOG_CLOSED = WM_APP + 2; +constexpr UINT WM_CLEAR_KEY_MAPPING = WM_APP + 3; +constexpr UINT WM_USER_PORT_BREAKOUT_DIALOG_CLOSED = WM_APP + 4; #endif diff --git a/Src/SelectKeyDialog.cpp b/Src/SelectKeyDialog.cpp index 52630375..47cf4211 100644 --- a/Src/SelectKeyDialog.cpp +++ b/Src/SelectKeyDialog.cpp @@ -27,6 +27,7 @@ Boston, MA 02110-1301, USA. #include "beebemrc.h" #include "SelectKeyDialog.h" #include "Messages.h" +#include "KeyMap.h" /****************************************************************************/ @@ -41,14 +42,20 @@ SelectKeyDialog::SelectKeyDialog( HWND hwndParent, const std::string& Title, const std::string& SelectedKey, - bool EnableShift) : + bool BeebKey, + int Row, + int Column, + bool DoingShifted) : m_hInstance(hInstance), m_hwnd(nullptr), m_hwndParent(hwndParent), m_Title(Title), m_SelectedKey(SelectedKey), - m_EnableShift(EnableShift), + m_BeebKey(BeebKey), m_Key(-1), + m_Row(Row), + m_Column(Column), + m_DoingShifted(DoingShifted), m_Shift(false) { } @@ -104,7 +111,7 @@ INT_PTR SelectKeyDialog::DlgProc( SetDlgItemText(m_hwnd, IDC_ASSIGNED_KEYS, m_SelectedKey.c_str()); - if (!m_EnableShift) + if (!m_BeebKey) { ShowWindow(GetDlgItem(m_hwnd, IDC_SHIFT), SW_HIDE); } @@ -133,6 +140,21 @@ INT_PTR SelectKeyDialog::DlgProc( case WM_COMMAND: switch (wParam) { + case IDC_CLEAR: + SendMessage(m_hwndParent, WM_CLEAR_KEY_MAPPING, 0, 0); + + if (m_BeebKey) + { + m_SelectedKey = GetKeysUsed(m_Row, m_Column, m_DoingShifted); + } + else + { + m_SelectedKey = ""; + } + + SetDlgItemText(m_hwnd, IDC_ASSIGNED_KEYS, m_SelectedKey.c_str()); + return TRUE; + case IDOK: Close(IDCONTINUE); return TRUE; @@ -204,81 +226,3 @@ static bool IsDlgItemChecked(HWND hDlg, int nIDDlgItem) { return SendDlgItemMessage(hDlg, nIDDlgItem, BM_GETCHECK, 0, 0) == BST_CHECKED; } - -/****************************************************************************/ - -LPCSTR SelectKeyDialog::KeyName(int Key) -{ - static CHAR Character[2]; // Used to return single characters. - - switch (Key) - { - case 8: return "Backspace"; - case 9: return "Tab"; - case 13: return "Enter"; - case 16: return "Shift"; - case 17: return "Ctrl"; - case 18: return "Alt"; - case 19: return "Break"; - case 20: return "Caps"; - case 27: return "Esc"; - case 32: return "Spacebar"; - case 33: return "PgUp"; - case 34: return "PgDn"; - case 35: return "End"; - case 36: return "Home"; - case 37: return "Left"; - case 38: return "Up"; - case 39: return "Right"; - case 40: return "Down"; - case 45: return "Insert"; - case 46: return "Del"; - case 93: return "Menu"; - case 96: return "Pad0"; - case 97: return "Pad1"; - case 98: return "Pad2"; - case 99: return "Pad3"; - case 100: return "Pad4"; - case 101: return "Pad5"; - case 102: return "Pad6"; - case 103: return "Pad7"; - case 104: return "Pad8"; - case 105: return "Pad9"; - case 106: return "Pad*"; - case 107: return "Pad+"; - case 109: return "Pad-"; - case 110: return "Pad."; - case 111: return "Pad/"; - case 112: return "F1"; - case 113: return "F2"; - case 114: return "F3"; - case 115: return "F4"; - case 116: return "F5"; - case 117: return "F6"; - case 118: return "F7"; - case 119: return "F8"; - case 120: return "F9"; - case 121: return "F10"; - case 122: return "F11"; - case 123: return "F12"; - case 144: return "NumLock"; - case 145: return "SclLock"; - case 186: return ";"; - case 187: return "="; - case 188: return ","; - case 189: return "-"; - case 190: return "."; - case 191: return "/"; - case 192: return "\'"; - case 219: return "["; - case 220: return "\\"; - case 221: return "]"; - case 222: return "#"; - case 223: return "`"; - - default: - Character[0] = (CHAR)LOBYTE(Key); - Character[1] = '\0'; - return Character; - } -} diff --git a/Src/SelectKeyDialog.h b/Src/SelectKeyDialog.h index 73cbe4f4..0a4e126d 100644 --- a/Src/SelectKeyDialog.h +++ b/Src/SelectKeyDialog.h @@ -31,7 +31,10 @@ class SelectKeyDialog HWND hwndParent, const std::string& Title, const std::string& SelectedKey, - bool EnableShift = true + bool BeebKey, + int Row, + int Column, + bool DoingShifted ); bool Open(); @@ -41,8 +44,6 @@ class SelectKeyDialog int Key() const; - static LPCSTR KeyName(int Key); - private: static INT_PTR CALLBACK sDlgProc( HWND hwnd, @@ -64,8 +65,11 @@ class SelectKeyDialog HWND m_hwndParent; std::string m_Title; std::string m_SelectedKey; - bool m_EnableShift; + bool m_BeebKey; int m_Key; + int m_Row; + int m_Column; + bool m_DoingShifted; bool m_Shift; }; diff --git a/Src/userkybd.cpp b/Src/UserKeyboardDialog.cpp similarity index 87% rename from Src/userkybd.cpp rename to Src/UserKeyboardDialog.cpp index 432f3ea2..d4fc05d8 100644 --- a/Src/userkybd.cpp +++ b/Src/UserKeyboardDialog.cpp @@ -25,11 +25,12 @@ Boston, MA 02110-1301, USA. #include #include -#include "Main.h" +#include "UserKeyboardDialog.h" #include "beebemrc.h" -#include "userkybd.h" -#include "SelectKeyDialog.h" +#include "KeyMap.h" +#include "Main.h" #include "Messages.h" +#include "SelectKeyDialog.h" static void SetKeyColour(COLORREF aColour); static void SelectKeyMapping(HWND hwnd, UINT ctrlID, HWND hwndCtrl); @@ -44,7 +45,6 @@ static void DrawSides(HDC hDC, RECT rect, COLORREF TopLeft, COLORREF BottomRight static void DrawBorder(HDC hDC, RECT rect, BOOL Depressed); static void DrawText(HDC hDC, RECT rect, HWND hwndCtrl, COLORREF colour, bool Depressed); static COLORREF GetKeyColour(UINT ctrlID); -static std::string GetKeysUsed(); // Colour used to highlight the selected key. static const COLORREF HighlightColour = 0x00FF0080; // Purple @@ -61,9 +61,6 @@ static int BBCRow; // Used to store the Row and Col values while we wait static int BBCCol; // for a key press from the User. static bool doingShifted; // Selecting shifted or unshifted key press -// Initialised to defaultMapping. -KeyMap UserKeymap; - static const char* szSelectKeyDialogTitle[2] = { "Press key for unshifted press...", "Press key for shifted press..." @@ -121,14 +118,18 @@ static void SelectKeyMapping(HWND hwnd, UINT ctrlID, HWND hwndCtrl) doingShifted = false; - std::string UsedKeys = GetKeysUsed(); + std::string UsedKeys = GetKeysUsed(BBCRow, BBCCol, doingShifted); // Now ask the user to input the PC key to assign to the BBC key. selectKeyDialog = new SelectKeyDialog( hInst, hwnd, szSelectKeyDialogTitle[doingShifted ? 1 : 0], - UsedKeys + UsedKeys, + true, + BBCRow, + BBCCol, + doingShifted ); selectKeyDialog->Open(); @@ -140,9 +141,9 @@ static void SetBBCKeyForVKEY(int Key, bool Shift) { if (Key >= 0 && Key < 256) { - UserKeymap[Key][static_cast(Shift)].row = BBCRow; - UserKeymap[Key][static_cast(Shift)].col = BBCCol; - UserKeymap[Key][static_cast(Shift)].shift = doingShifted; + UserKeyMap[Key][static_cast(Shift)].row = BBCRow; + UserKeyMap[Key][static_cast(Shift)].col = BBCCol; + UserKeyMap[Key][static_cast(Shift)].shift = doingShifted; // DebugTrace("SetBBCKey: key=%d, shift=%d, row=%d, col=%d, bbcshift=%d\n", // Key, shift, BBCRow, BBCCol, doingShifted); @@ -151,6 +152,29 @@ static void SetBBCKeyForVKEY(int Key, bool Shift) /****************************************************************************/ +// Clear any PC keys that correspond to a given BBC keyboard column, row, +// and shift state. + +static void ClearBBCKeyMapping(int Row, int Column, bool Shift) +{ + for (int PCKey = 0; PCKey < KEYMAP_SIZE; PCKey++) + { + for (int PCShift = 0; PCShift < 2; PCShift++) + { + if (UserKeyMap[PCKey][PCShift].row == Row && + UserKeyMap[PCKey][PCShift].col == Column && + UserKeyMap[PCKey][PCShift].shift == Shift) + { + UserKeyMap[PCKey][PCShift].row = 0; + UserKeyMap[PCKey][PCShift].col = 0; + UserKeyMap[PCKey][PCShift].shift = PCShift == 1; + } + } + } +} + +/****************************************************************************/ + static void SetRowCol(UINT ctrlID) { switch (ctrlID) @@ -241,6 +265,7 @@ static void SetRowCol(UINT ctrlID) default: BBCRow = 0; BBCCol = 0; + break; } } @@ -276,6 +301,10 @@ static INT_PTR CALLBACK UserKeyboardDlgProc(HWND hwnd, OnDrawItem((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); return TRUE; + case WM_CLEAR_KEY_MAPPING: + ClearBBCKeyMapping(BBCRow, BBCCol, doingShifted); + break; + case WM_SELECT_KEY_DIALOG_CLOSED: if (wParam == IDOK) { @@ -293,13 +322,17 @@ static INT_PTR CALLBACK UserKeyboardDlgProc(HWND hwnd, { doingShifted = true; - std::string UsedKeys = GetKeysUsed(); + std::string UsedKeys = GetKeysUsed(BBCRow, BBCCol, doingShifted); selectKeyDialog = new SelectKeyDialog( hInst, hwndUserKeyboard, szSelectKeyDialogTitle[doingShifted ? 1 : 0], - UsedKeys + UsedKeys, + true, + BBCRow, + BBCCol, + doingShifted ); selectKeyDialog->Open(); @@ -335,22 +368,22 @@ static void OnDrawItem(UINT CtrlID, LPDRAWITEMSTRUCT lpDrawItemStruct) // Draw the rectanlge. SetBkColor(lpDrawItemStruct->hDC, GetKeyColour(CtrlID)); Rectangle(lpDrawItemStruct->hDC, - lpDrawItemStruct->rcItem.left, - lpDrawItemStruct->rcItem.top, - lpDrawItemStruct->rcItem.right, - lpDrawItemStruct->rcItem.bottom); + lpDrawItemStruct->rcItem.left, + lpDrawItemStruct->rcItem.top, + lpDrawItemStruct->rcItem.right, + lpDrawItemStruct->rcItem.bottom); // Draw border. DrawBorder(lpDrawItemStruct->hDC, - lpDrawItemStruct->rcItem, - lpDrawItemStruct->itemState == (ODS_FOCUS | ODS_SELECTED)); + lpDrawItemStruct->rcItem, + lpDrawItemStruct->itemState == (ODS_FOCUS | ODS_SELECTED)); // Draw the text. DrawText(lpDrawItemStruct->hDC, - lpDrawItemStruct->rcItem, - lpDrawItemStruct->hwndItem, - 0x00FFFFFF, - lpDrawItemStruct->itemState == (ODS_FOCUS | ODS_SELECTED)); + lpDrawItemStruct->rcItem, + lpDrawItemStruct->hwndItem, + 0x00FFFFFF, + lpDrawItemStruct->itemState == (ODS_FOCUS | ODS_SELECTED)); // Clear up. DeleteObject(SelectObject(lpDrawItemStruct->hDC, aBrush)); @@ -387,9 +420,9 @@ static void DrawBorder(HDC hDC, RECT rect, BOOL Depressed) { // Draw outer border. if (Depressed) - DrawSides( hDC, rect, 0x00000000, 0x00FFFFFF ); + DrawSides(hDC, rect, 0x00000000, 0x00FFFFFF); else - DrawSides( hDC, rect, 0x00FFFFFF, 0x00000000 ); + DrawSides(hDC, rect, 0x00FFFFFF, 0x00000000); // Draw inner border. rect.top++; @@ -398,9 +431,9 @@ static void DrawBorder(HDC hDC, RECT rect, BOOL Depressed) rect.bottom--; if (Depressed) - DrawSides( hDC, rect, 0x00777777, 0x00FFFFFF ); + DrawSides(hDC, rect, 0x00777777, 0x00FFFFFF); else - DrawSides( hDC, rect, 0x00FFFFFF, 0x00777777 ); + DrawSides(hDC, rect, 0x00FFFFFF, 0x00777777); } /****************************************************************************/ @@ -455,45 +488,3 @@ static COLORREF GetKeyColour(UINT ctrlID) return NormalKeyColour; } } - -/****************************************************************************/ - -static std::string GetKeysUsed() -{ - std::string Keys; - - // First see if this key is defined. - if (BBCRow != 0 || BBCCol != 0) - { - for (int i = 1; i < 256; i++) - { - for (int s = 0; s < 2; ++s) - { - if (UserKeymap[i][s].row == BBCRow && - UserKeymap[i][s].col == BBCCol && - UserKeymap[i][s].shift == doingShifted) - { - // We have found a key that matches. - if (!Keys.empty()) - { - Keys += ", "; - } - - if (s == 1) - { - Keys += "Sh-"; - } - - Keys += SelectKeyDialog::KeyName(i); - } - } - } - } - - if (Keys.empty()) - { - Keys = "Not Assigned"; - } - - return Keys; -} diff --git a/Src/userkybd.h b/Src/UserKeyboardDialog.h similarity index 92% rename from Src/userkybd.h rename to Src/UserKeyboardDialog.h index b468391c..bc968645 100644 --- a/Src/userkybd.h +++ b/Src/UserKeyboardDialog.h @@ -18,8 +18,8 @@ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ****************************************************************/ -#ifndef USERKYBD_HEADER -#define USERKYBD_HEADER +#ifndef USERKEYBOARDDIALOG_HEADER +#define USERKEYBOARDDIALOG_HEADER #include @@ -27,6 +27,4 @@ Boston, MA 02110-1301, USA. bool UserKeyboardDialog(HWND hwndParent); -extern KeyMap UserKeymap; - #endif diff --git a/Src/UserPortBreakoutBox.cpp b/Src/UserPortBreakoutBox.cpp index 51a80c53..4881f322 100644 --- a/Src/UserPortBreakoutBox.cpp +++ b/Src/UserPortBreakoutBox.cpp @@ -23,6 +23,7 @@ Boston, MA 02110-1301, USA. #include "UserPortBreakoutBox.h" #include "beebemrc.h" +#include "KeyMap.h" #include "Main.h" #include "Messages.h" #include "SelectKeyDialog.h" @@ -307,6 +308,11 @@ INT_PTR UserPortBreakoutDialog::DlgProc( } return TRUE; + case WM_CLEAR_KEY_MAPPING: + BitKeys[m_BitKey] = 0; + ShowBitKey(m_BitKey, BitKeyButtonIDs[m_BitKey]); + break; + case WM_SELECT_KEY_DIALOG_CLOSED: if (wParam == IDOK) { @@ -386,7 +392,7 @@ void UserPortBreakoutDialog::ShowInputs(unsigned char data) void UserPortBreakoutDialog::ShowBitKey(int key, int ctrlID) { - SetDlgItemText(m_hwnd, ctrlID, SelectKeyDialog::KeyName(BitKeys[key])); + SetDlgItemText(m_hwnd, ctrlID, KeyName(BitKeys[key])); } /****************************************************************************/ @@ -397,13 +403,16 @@ void UserPortBreakoutDialog::PromptForBitKeyInput(int bitKey) ShowBitKey(bitKey, BitKeyButtonIDs[bitKey]); - std::string UsedKey = SelectKeyDialog::KeyName(BitKeys[m_BitKey]); + std::string UsedKey = KeyName(BitKeys[m_BitKey]); selectKeyDialog = new SelectKeyDialog( m_hInstance, m_hwnd, "Press the key to use...", UsedKey, + false, + 0, + 0, false ); diff --git a/Src/beebemrc.h b/Src/beebemrc.h index a9daace2..6264b3d2 100644 --- a/Src/beebemrc.h +++ b/Src/beebemrc.h @@ -200,6 +200,7 @@ Boston, MA 02110-1301, USA. #define IDC_IP323_RAW_COMMS 1099 #define IDC_IP232_HANDSHAKE 1100 #define IDC_SERIAL_PORT 1101 +#define IDC_CLEAR 1102 #define IDM_ABOUT 40001 #define IDM_DISC 40002 #define IDM_LOADDISC0 40002 diff --git a/Src/beebwin.cpp b/Src/beebwin.cpp index 23fff017..1e91642a 100644 --- a/Src/beebwin.cpp +++ b/Src/beebwin.cpp @@ -64,7 +64,6 @@ using std::max; #include "beebmem.h" #include "beebemrc.h" #include "atodconv.h" -#include "userkybd.h" #include "Serial.h" #include "Econet.h" // Rob O'Donnell Christmas 2004. #include "tube.h" @@ -77,7 +76,8 @@ using std::max; #include "ide.h" #include "z80mem.h" #include "z80.h" -#include "userkybd.h" +#include "KeyMap.h" +#include "UserKeyboardDialog.h" #include "UserPortBreakoutBox.h" #include "Messages.h" #ifdef SPEECH_ENABLED @@ -136,13 +136,6 @@ static const char *AboutText = "Sprow ARM7TDMI 64MB\n\n" "Version " VERSION_STRING ", " VERSION_DATE; -// Keyboard mappings -static KeyMap defaultMapping; -static KeyMap logicalMapping; - -/* Currently selected translation table */ -static KeyMap *transTable = &defaultMapping; - /****************************************************************************/ BeebWin::BeebWin() { @@ -167,9 +160,6 @@ BeebWin::BeebWin() m_DisableKeysBreak = false; m_DisableKeysEscape = false; m_DisableKeysShortcut = false; - memset(&defaultMapping, 0, sizeof(KeyMap)); - memset(&logicalMapping, 0, sizeof(KeyMap)); - memset(&UserKeymap, 0, sizeof(KeyMap)); memset(m_UserKeyMapPath, 0, sizeof(m_UserKeyMapPath)); m_hBitmap = m_hOldObj = m_hDCBitmap = NULL; m_screen = m_screen_blur = NULL; @@ -230,6 +220,8 @@ BeebWin::BeebWin() m_CaptureMouse = false; m_MouseCaptured = false; + InitKeyMap(); + /* Get the applications path - used for non-user files */ char app_path[_MAX_PATH]; char app_drive[_MAX_DRIVE]; @@ -382,13 +374,14 @@ void BeebWin::ApplyPrefs() strcpy(HardDrivePath, Path); // Load key maps - char keymap[_MAX_PATH]; - strcpy(keymap, "Logical.kmap"); - GetDataPath(m_UserDataPath, keymap); - ReadKeyMap(keymap, &logicalMapping); - strcpy(keymap, "Default.kmap"); - GetDataPath(m_UserDataPath, keymap); - ReadKeyMap(keymap, &defaultMapping); + char KeyMapPath[_MAX_PATH]; + strcpy(KeyMapPath, "Logical.kmap"); + GetDataPath(m_UserDataPath, KeyMapPath); + ReadKeyMap(KeyMapPath, &LogicalKeyMap); + + strcpy(KeyMapPath, "Default.kmap"); + GetDataPath(m_UserDataPath, KeyMapPath); + ReadKeyMap(KeyMapPath, &DefaultKeyMap); InitMenu(); ShowMenu(true); @@ -2457,15 +2450,15 @@ void BeebWin::TranslateKeyMapping(void) { default: case IDM_DEFAULTKYBDMAPPING: - transTable = &defaultMapping; + transTable = &DefaultKeyMap; break; case IDM_LOGICALKYBDMAPPING: - transTable = &logicalMapping; + transTable = &LogicalKeyMap; break; case IDM_USERKYBDMAPPING: - transTable = &UserKeymap; + transTable = &UserKeyMap; break; } } diff --git a/Src/beebwin.h b/Src/beebwin.h index 8f89a963..d8fe10ab 100644 --- a/Src/beebwin.h +++ b/Src/beebwin.h @@ -40,6 +40,7 @@ Boston, MA 02110-1301, USA. #include #include "disctype.h" +#include "KeyMap.h" #include "model.h" #include "port.h" #include "preferences.h" @@ -49,14 +50,6 @@ Boston, MA 02110-1301, USA. #define CFG_KEYBOARD_LAYOUT "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout" #define CFG_SCANCODE_MAP "Scancode Map" -typedef struct KeyMapping { - int row; // Beeb row - int col; // Beeb col - bool shift; // Beeb shift state -} KeyMapping; - -typedef KeyMapping KeyMap[256][2]; // Indices are: [Virt key][shift state] - extern const char *WindowTitle; typedef union EightUChars { @@ -393,8 +386,6 @@ class BeebWin { bool RebootSystem(); void LoadUserKeyMap(void); void SaveUserKeyMap(void); - bool ReadKeyMap(const char *filename, KeyMap *keymap); - bool WriteKeyMap(const char *filename, KeyMap *keymap); MessageResult Report(MessageType type, const char *format, ...); MessageResult ReportV(MessageType type, const char *format, va_list args); diff --git a/Src/beebwinio.cpp b/Src/beebwinio.cpp index b06d6e43..ab2d30c2 100644 --- a/Src/beebwinio.cpp +++ b/Src/beebwinio.cpp @@ -52,16 +52,13 @@ using std::max; #include "Serial.h" #include "ext1770.h" #include "tube.h" -#include "userkybd.h" +#include "KeyMap.h" #include "discedit.h" #include "ExportFileDialog.h" #include "version.h" using namespace Gdiplus; -// Token written to start of map file -#define KEYMAP_TOKEN "*** BeebEm Keymap ***" - extern EDCB ExtBoard; extern bool DiscLoaded[2]; // Set to true when a disc image has been loaded. extern char CDiscName[2][256]; // Filename of disc current in drive 0 and 1; @@ -1124,7 +1121,7 @@ void BeebWin::LoadEmuUEF(FILE *SUEF, int Version) { fread(fileName,1,256,SUEF); GetDataPath(m_UserDataPath, fileName); - if (ReadKeyMap(fileName, &UserKeymap)) + if (ReadKeyMap(fileName, &UserKeyMap)) strcpy(m_UserKeyMapPath, fileName); else id = m_MenuIDKeyMapping; @@ -1171,7 +1168,7 @@ void BeebWin::LoadUserKeyMap() FileDialog fileDialog(m_hWnd, FileName, sizeof(FileName), m_UserDataPath, filter); if (fileDialog.Open()) { - if (ReadKeyMap(FileName, &UserKeymap)) + if (ReadKeyMap(FileName, &UserKeyMap)) strcpy(m_UserKeyMapPath, FileName); } } @@ -1185,6 +1182,7 @@ void BeebWin::SaveUserKeyMap() const char* filter = "Key Map File (*.kmap)\0*.kmap\0"; FileDialog fileDialog(m_hWnd, FileName, sizeof(FileName), m_UserDataPath, filter); + if (fileDialog.Save()) { if (!hasFileExt(FileName, ".kmap")) @@ -1192,103 +1190,13 @@ void BeebWin::SaveUserKeyMap() strcat(FileName,".kmap"); } - if (WriteKeyMap(FileName, &UserKeymap)) + if (WriteKeyMap(FileName, &UserKeyMap)) { strcpy(m_UserKeyMapPath, FileName); } } } -/****************************************************************************/ -bool BeebWin::ReadKeyMap(const char *filename, KeyMap *keymap) -{ - bool success = true; - char buf[256]; - - FILE *infile = fopen(filename,"r"); - - if (infile == NULL) - { - Report(MessageType::Error, - "Failed to read key map file:\n %s", filename); - - success = false; - } - else - { - if (fgets(buf, 255, infile) == NULL || - strcmp(buf, KEYMAP_TOKEN "\n") != 0) - { - Report(MessageType::Error, - "Invalid key map file:\n %s\n", filename); - - success = false; - } - else - { - fgets(buf, 255, infile); - - for (int i = 0; i < 256; ++i) - { - if (fgets(buf, 255, infile) == NULL) - { - Report(MessageType::Error, - "Data missing from key map file:\n %s\n", filename); - - success = false; - break; - } - - int shift0 = 0, shift1 = 0; - - sscanf(buf, "%d %d %d %d %d %d", - &(*keymap)[i][0].row, - &(*keymap)[i][0].col, - &shift0, - &(*keymap)[i][1].row, - &(*keymap)[i][1].col, - &shift1); - - (*keymap)[i][0].shift = shift0 != 0; - (*keymap)[i][1].shift = shift1 != 0; - } - } - - fclose(infile); - } - - return success; -} - -/****************************************************************************/ -bool BeebWin::WriteKeyMap(const char *filename, KeyMap *keymap) -{ - FILE *outfile = fopen(filename, "w"); - - if (outfile == nullptr) - { - Report(MessageType::Error, "Failed to write key map file:\n %s", filename); - return false; - } - - fprintf(outfile, KEYMAP_TOKEN "\n\n"); - - for (int i = 0; i < 256; ++i) - { - fprintf(outfile, "%d %d %d %d %d %d\n", - (*keymap)[i][0].row, - (*keymap)[i][0].col, - (*keymap)[i][0].shift, - (*keymap)[i][1].row, - (*keymap)[i][1].col, - (*keymap)[i][1].shift); - } - - fclose(outfile); - - return true; -} - /****************************************************************************/ /* Clipboard support */ diff --git a/Src/beebwinprefs.cpp b/Src/beebwinprefs.cpp index 2ac824aa..619fea89 100644 --- a/Src/beebwinprefs.cpp +++ b/Src/beebwinprefs.cpp @@ -42,7 +42,7 @@ Boston, MA 02110-1301, USA. #include "ide.h" #include "z80mem.h" #include "z80.h" -#include "userkybd.h" +#include "KeyMap.h" #include "UserPortBreakoutBox.h" #ifdef SPEECH_ENABLED #include "speech.h" @@ -288,7 +288,7 @@ void BeebWin::LoadPreferences() { strcpy(path, m_UserKeyMapPath); GetDataPath(m_UserDataPath, path); - if (ReadKeyMap(path, &UserKeymap)) + if (ReadKeyMap(path, &UserKeyMap)) readDefault = false; } if (readDefault) @@ -296,7 +296,7 @@ void BeebWin::LoadPreferences() strcpy(m_UserKeyMapPath, "DefaultUser.kmap"); strcpy(path, m_UserKeyMapPath); GetDataPath(m_UserDataPath, path); - ReadKeyMap(path, &UserKeymap); + ReadKeyMap(path, &UserKeyMap); } if (!m_Preferences.GetBoolValue("KeyMapAS", m_KeyMapAS))