Added keybind customization system
This commit is contained in:
@@ -73,7 +73,7 @@ if(WIN32)
|
|||||||
|
|
||||||
# Default value for the `WIN32` target property, which specifies whether
|
# Default value for the `WIN32` target property, which specifies whether
|
||||||
# to build the application for the Windows GUI or console subsystem
|
# to build the application for the Windows GUI or console subsystem
|
||||||
option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" ON)
|
option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" OFF)
|
||||||
else()
|
else()
|
||||||
# Prefer dynamic builds everywhere else
|
# Prefer dynamic builds everywhere else
|
||||||
set(PREFER_STATIC OFF)
|
set(PREFER_STATIC OFF)
|
||||||
|
|||||||
24
src/86box.c
24
src/86box.c
@@ -222,6 +222,9 @@ int other_ide_present = 0; /* IDE control
|
|||||||
int other_scsi_present = 0; /* SCSI controllers from non-SCSI cards are
|
int other_scsi_present = 0; /* SCSI controllers from non-SCSI cards are
|
||||||
present */
|
present */
|
||||||
|
|
||||||
|
// Accelerator key array
|
||||||
|
struct accelKey acc_keys[NUM_ACCELS];
|
||||||
|
|
||||||
/* Statistics. */
|
/* Statistics. */
|
||||||
extern int mmuflush;
|
extern int mmuflush;
|
||||||
extern int readlnum;
|
extern int readlnum;
|
||||||
@@ -654,7 +657,6 @@ usage:
|
|||||||
#ifdef USE_INSTRUMENT
|
#ifdef USE_INSTRUMENT
|
||||||
printf("-J or --instrument name - set 'name' to be the profiling instrument\n");
|
printf("-J or --instrument name - set 'name' to be the profiling instrument\n");
|
||||||
#endif
|
#endif
|
||||||
printf("-K or --keycodes codes - set 'codes' to be the uncapture combination\n");
|
|
||||||
printf("-L or --logfile path - set 'path' to be the logfile\n");
|
printf("-L or --logfile path - set 'path' to be the logfile\n");
|
||||||
printf("-M or --missing - dump missing machines and video cards\n");
|
printf("-M or --missing - dump missing machines and video cards\n");
|
||||||
printf("-N or --noconfirm - do not ask for confirmation on quit\n");
|
printf("-N or --noconfirm - do not ask for confirmation on quit\n");
|
||||||
@@ -745,13 +747,6 @@ usage:
|
|||||||
do_nothing = 1;
|
do_nothing = 1;
|
||||||
} else if (!strcasecmp(argv[c], "--nohook") || !strcasecmp(argv[c], "-W")) {
|
} else if (!strcasecmp(argv[c], "--nohook") || !strcasecmp(argv[c], "-W")) {
|
||||||
hook_enabled = 0;
|
hook_enabled = 0;
|
||||||
} else if (!strcasecmp(argv[c], "--keycodes") || !strcasecmp(argv[c], "-K")) {
|
|
||||||
if ((c + 1) == argc)
|
|
||||||
goto usage;
|
|
||||||
|
|
||||||
sscanf(argv[++c], "%03hX,%03hX,%03hX,%03hX,%03hX,%03hX",
|
|
||||||
&key_prefix_1_1, &key_prefix_1_2, &key_prefix_2_1, &key_prefix_2_2,
|
|
||||||
&key_uncapture_1, &key_uncapture_2);
|
|
||||||
} else if (!strcasecmp(argv[c], "--clearboth") || !strcasecmp(argv[c], "-X")) {
|
} else if (!strcasecmp(argv[c], "--clearboth") || !strcasecmp(argv[c], "-X")) {
|
||||||
if ((c + 1) == argc)
|
if ((c + 1) == argc)
|
||||||
goto usage;
|
goto usage;
|
||||||
@@ -1789,3 +1784,16 @@ do_pause(int p)
|
|||||||
}
|
}
|
||||||
atomic_store(&pause_ack, 0);
|
atomic_store(&pause_ack, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to find an accelerator key and return it's index in acc_keys
|
||||||
|
int FindAccelerator(const char *name) {
|
||||||
|
for(int x=0;x<NUM_ACCELS;x++)
|
||||||
|
{
|
||||||
|
if(strcmp(acc_keys[x].name, name) == 0)
|
||||||
|
{
|
||||||
|
return(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No key was found
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
84
src/config.c
84
src/config.c
@@ -107,6 +107,30 @@ config_log(const char *fmt, ...)
|
|||||||
# define config_log(fmt, ...)
|
# define config_log(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Default accelerator key values
|
||||||
|
struct accelKey def_acc_keys[NUM_ACCELS] = {
|
||||||
|
{ .name="send_ctrl_alt_del", .desc="Send Control+Alt+Del",
|
||||||
|
.seq="Ctrl+F12" },
|
||||||
|
|
||||||
|
{ .name="send_ctrl_alt_esc", .desc="Send Control+Alt+Escape",
|
||||||
|
.seq="Ctrl+F10" },
|
||||||
|
|
||||||
|
{ .name="fullscreen", .desc="Fullscreen",
|
||||||
|
.seq="Ctrl+Alt+PgUp" },
|
||||||
|
|
||||||
|
{ .name="screenshot", .desc="Screenshot",
|
||||||
|
.seq="Ctrl+F11" },
|
||||||
|
|
||||||
|
{ .name="release_mouse", .desc="Release mouse pointer",
|
||||||
|
.seq="Ctrl+End" },
|
||||||
|
|
||||||
|
{ .name="hard_reset", .desc="Hard reset",
|
||||||
|
.seq="Ctrl+Alt+F12" },
|
||||||
|
|
||||||
|
{ .name="leave_fullscreen", .desc="Leave fullscreen",
|
||||||
|
.seq="Ctrl+Alt+PgDn" }
|
||||||
|
};
|
||||||
|
|
||||||
/* Load "General" section. */
|
/* Load "General" section. */
|
||||||
static void
|
static void
|
||||||
load_general(void)
|
load_general(void)
|
||||||
@@ -1762,6 +1786,41 @@ load_gl3_shaders(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Load "Keybinds" section. */
|
||||||
|
static void
|
||||||
|
load_keybinds(void)
|
||||||
|
{
|
||||||
|
ini_section_t cat = ini_find_section(config, "Keybinds");
|
||||||
|
char *p;
|
||||||
|
char temp[512];
|
||||||
|
memset(temp, 0, sizeof(temp));
|
||||||
|
|
||||||
|
// Initialize the bind list with the defaults
|
||||||
|
for(int x=0;x<NUM_ACCELS;x++) {
|
||||||
|
strcpy(acc_keys[x].name, def_acc_keys[x].name);
|
||||||
|
strcpy(acc_keys[x].desc, def_acc_keys[x].desc);
|
||||||
|
strcpy(acc_keys[x].seq, def_acc_keys[x].seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now load values from config
|
||||||
|
for(int x=0;x<NUM_ACCELS;x++)
|
||||||
|
{
|
||||||
|
p = ini_section_get_string(cat, acc_keys[x].name, "none");
|
||||||
|
// If there's no binding in the file, leave it alone.
|
||||||
|
if (p != "none")
|
||||||
|
{
|
||||||
|
// It would be ideal to validate whether the user entered a
|
||||||
|
// valid combo at this point, but the Qt method for testing that is
|
||||||
|
// not available from C. Fortunately, if you feed Qt an invalid
|
||||||
|
// keysequence string it just assigns nothing, so this won't blow up.
|
||||||
|
// However, to improve the user experience, we should validate keys
|
||||||
|
// and erase any bad combos from config on mainwindow load.
|
||||||
|
|
||||||
|
strcpy(acc_keys[x].seq, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Load the specified or a default configuration file. */
|
/* Load the specified or a default configuration file. */
|
||||||
void
|
void
|
||||||
config_load(void)
|
config_load(void)
|
||||||
@@ -1863,6 +1922,7 @@ config_load(void)
|
|||||||
#ifndef USE_SDL_UI
|
#ifndef USE_SDL_UI
|
||||||
load_gl3_shaders(); /* GL3 Shaders */
|
load_gl3_shaders(); /* GL3 Shaders */
|
||||||
#endif
|
#endif
|
||||||
|
load_keybinds(); /* Load shortcut keybinds */
|
||||||
|
|
||||||
/* Migrate renamed device configurations. */
|
/* Migrate renamed device configurations. */
|
||||||
c = ini_find_section(config, "MDA");
|
c = ini_find_section(config, "MDA");
|
||||||
@@ -2488,6 +2548,29 @@ save_ports(void)
|
|||||||
ini_delete_section_if_empty(config, cat);
|
ini_delete_section_if_empty(config, cat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Save "Keybinds" section. */
|
||||||
|
static void
|
||||||
|
save_keybinds(void)
|
||||||
|
{
|
||||||
|
ini_section_t cat = ini_find_or_create_section(config, "Keybinds");
|
||||||
|
char temp[512];
|
||||||
|
|
||||||
|
for(int x=0;x<NUM_ACCELS;x++)
|
||||||
|
{
|
||||||
|
// Has accelerator been changed from default?
|
||||||
|
printf("%s, %s\n", def_acc_keys[x].seq, acc_keys[x].seq);
|
||||||
|
if (strcmp(def_acc_keys[x].seq, acc_keys[x].seq) == 0)
|
||||||
|
{
|
||||||
|
printf("...was equal.\n");
|
||||||
|
ini_section_delete_var(cat, acc_keys[x].name);
|
||||||
|
} else {
|
||||||
|
ini_section_set_string(cat, acc_keys[x].name, acc_keys[x].seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_delete_section_if_empty(config, cat);
|
||||||
|
}
|
||||||
|
|
||||||
/* Save "Storage Controllers" section. */
|
/* Save "Storage Controllers" section. */
|
||||||
static void
|
static void
|
||||||
save_storage_controllers(void)
|
save_storage_controllers(void)
|
||||||
@@ -3098,6 +3181,7 @@ config_save(void)
|
|||||||
#ifndef USE_SDL_UI
|
#ifndef USE_SDL_UI
|
||||||
save_gl3_shaders(); /* GL3 Shaders */
|
save_gl3_shaders(); /* GL3 Shaders */
|
||||||
#endif
|
#endif
|
||||||
|
save_keybinds(); /* Key bindings */
|
||||||
|
|
||||||
ini_write(config, cfg_path);
|
ini_write(config, cfg_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,14 +36,6 @@ uint16_t scancode_map[768] = { 0 };
|
|||||||
|
|
||||||
int keyboard_scan;
|
int keyboard_scan;
|
||||||
|
|
||||||
/* F8+F12 */
|
|
||||||
uint16_t key_prefix_1_1 = 0x042; /* F8 */
|
|
||||||
uint16_t key_prefix_1_2 = 0x000; /* Invalid */
|
|
||||||
uint16_t key_prefix_2_1 = 0x000; /* Invalid */
|
|
||||||
uint16_t key_prefix_2_2 = 0x000; /* Invalid */
|
|
||||||
uint16_t key_uncapture_1 = 0x058; /* F12 */
|
|
||||||
uint16_t key_uncapture_2 = 0x000; /* Invalid */
|
|
||||||
|
|
||||||
#ifdef ENABLE_KBC_AT_LOG
|
#ifdef ENABLE_KBC_AT_LOG
|
||||||
int kbc_at_do_log = ENABLE_KBC_AT_LOG;
|
int kbc_at_do_log = ENABLE_KBC_AT_LOG;
|
||||||
|
|
||||||
@@ -481,19 +473,6 @@ keyboard_isfsexit_up(void)
|
|||||||
return (!recv_key_ui[0x01d] && !recv_key_ui[0x11d] && !recv_key_ui[0x038] && !recv_key_ui[0x138] && !recv_key_ui[0x051] && !recv_key_ui[0x151]);
|
return (!recv_key_ui[0x01d] && !recv_key_ui[0x11d] && !recv_key_ui[0x038] && !recv_key_ui[0x138] && !recv_key_ui[0x051] && !recv_key_ui[0x151]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do we have the mouse uncapture combination in the keyboard buffer? */
|
|
||||||
int
|
|
||||||
keyboard_ismsexit(void)
|
|
||||||
{
|
|
||||||
if ((key_prefix_2_1 != 0x000) || (key_prefix_2_2 != 0x000))
|
|
||||||
return ((recv_key_ui[key_prefix_1_1] || recv_key_ui[key_prefix_1_2]) &&
|
|
||||||
(recv_key_ui[key_prefix_2_1] || recv_key_ui[key_prefix_2_2]) &&
|
|
||||||
(recv_key_ui[key_uncapture_1] || recv_key_ui[key_uncapture_2]));
|
|
||||||
else
|
|
||||||
return ((recv_key_ui[key_prefix_1_1] || recv_key_ui[key_prefix_1_2]) &&
|
|
||||||
(recv_key_ui[key_uncapture_1] || recv_key_ui[key_uncapture_2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is so we can disambiguate scan codes that would otherwise conflict and get
|
/* This is so we can disambiguate scan codes that would otherwise conflict and get
|
||||||
passed on incorrectly. */
|
passed on incorrectly. */
|
||||||
uint16_t
|
uint16_t
|
||||||
|
|||||||
@@ -172,14 +172,6 @@ extern int pit_mode; /* (C) force setting PIT mode */
|
|||||||
extern int fm_driver; /* (C) select FM sound driver */
|
extern int fm_driver; /* (C) select FM sound driver */
|
||||||
extern int hook_enabled; /* (C) Keyboard hook is enabled */
|
extern int hook_enabled; /* (C) Keyboard hook is enabled */
|
||||||
|
|
||||||
/* Keyboard variables for future key combination redefinition. */
|
|
||||||
extern uint16_t key_prefix_1_1;
|
|
||||||
extern uint16_t key_prefix_1_2;
|
|
||||||
extern uint16_t key_prefix_2_1;
|
|
||||||
extern uint16_t key_prefix_2_2;
|
|
||||||
extern uint16_t key_uncapture_1;
|
|
||||||
extern uint16_t key_uncapture_2;
|
|
||||||
|
|
||||||
extern char exe_path[2048]; /* path (dir) of executable */
|
extern char exe_path[2048]; /* path (dir) of executable */
|
||||||
extern char usr_path[1024]; /* path (dir) of user data */
|
extern char usr_path[1024]; /* path (dir) of user data */
|
||||||
extern char cfg_path[1024]; /* full path of config file */
|
extern char cfg_path[1024]; /* full path of config file */
|
||||||
@@ -244,6 +236,16 @@ extern int framecountx;
|
|||||||
extern volatile int cpu_thread_run;
|
extern volatile int cpu_thread_run;
|
||||||
extern uint8_t postcard_codes[POSTCARDS_NUM];
|
extern uint8_t postcard_codes[POSTCARDS_NUM];
|
||||||
|
|
||||||
|
// Accelerator key structure, defines, helper functions
|
||||||
|
struct accelKey {
|
||||||
|
char name[64];
|
||||||
|
char desc[64];
|
||||||
|
char seq[64];
|
||||||
|
};
|
||||||
|
#define NUM_ACCELS 7
|
||||||
|
extern struct accelKey acc_keys[NUM_ACCELS];
|
||||||
|
extern int FindAccelerator(const char *name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -137,6 +137,11 @@ add_library(ui STATIC
|
|||||||
qt_joystickconfiguration.cpp
|
qt_joystickconfiguration.cpp
|
||||||
qt_joystickconfiguration.hpp
|
qt_joystickconfiguration.hpp
|
||||||
qt_joystickconfiguration.ui
|
qt_joystickconfiguration.ui
|
||||||
|
qt_keybind.cpp
|
||||||
|
qt_keybind.hpp
|
||||||
|
qt_keybind.ui
|
||||||
|
qt_singlekeyseqedit.cpp
|
||||||
|
qt_singlekeyseqedit.hpp
|
||||||
|
|
||||||
qt_filefield.cpp
|
qt_filefield.cpp
|
||||||
qt_filefield.hpp
|
qt_filefield.hpp
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ namespace IOKit {
|
|||||||
# include "be_keyboard.hpp"
|
# include "be_keyboard.hpp"
|
||||||
|
|
||||||
extern MainWindow *main_window;
|
extern MainWindow *main_window;
|
||||||
|
QShortcut *windowedShortcut;
|
||||||
|
|
||||||
filter_result
|
filter_result
|
||||||
keyb_filter(BMessage *message, BHandler **target, BMessageFilter *filter)
|
keyb_filter(BMessage *message, BHandler **target, BMessageFilter *filter)
|
||||||
@@ -676,9 +677,9 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
connect(new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F10), this), &QShortcut::activated, this, [](){});
|
connect(new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F10), this), &QShortcut::activated, this, [](){});
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
auto windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_PageDown), this);
|
windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_PageDown), this);
|
||||||
#else
|
#else
|
||||||
auto windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_PageDown), this);
|
windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_PageDown), this);
|
||||||
#endif
|
#endif
|
||||||
windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut);
|
windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut);
|
||||||
connect(windowedShortcut, &QShortcut::activated, this, [this] () {
|
connect(windowedShortcut, &QShortcut::activated, this, [this] () {
|
||||||
@@ -761,6 +762,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
updateShortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -826,6 +829,56 @@ MainWindow::closeEvent(QCloseEvent *event)
|
|||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::updateShortcuts()
|
||||||
|
{
|
||||||
|
// Update menu shortcuts from accelerator table
|
||||||
|
// Note that the "Release mouse" shortcut is hardcoded elsewhere
|
||||||
|
// This section only applies to shortcuts anchored to UI elements
|
||||||
|
|
||||||
|
ui->actionTake_screenshot->setShortcut(QKeySequence());
|
||||||
|
ui->actionCtrl_Alt_Del->setShortcut(QKeySequence());
|
||||||
|
ui->actionCtrl_Alt_Esc->setShortcut(QKeySequence());
|
||||||
|
ui->actionFullscreen->setShortcut(QKeySequence());
|
||||||
|
ui->actionHard_Reset->setShortcut(QKeySequence());
|
||||||
|
|
||||||
|
int accID;
|
||||||
|
QKeySequence seq;
|
||||||
|
|
||||||
|
accID = FindAccelerator("screenshot");
|
||||||
|
seq = QKeySequence::fromString(acc_keys[accID].seq);
|
||||||
|
ui->actionTake_screenshot->setShortcut(seq);
|
||||||
|
|
||||||
|
accID = FindAccelerator("send_ctrl_alt_del");
|
||||||
|
seq = QKeySequence::fromString(acc_keys[accID].seq);
|
||||||
|
ui->actionCtrl_Alt_Del->setShortcut(seq);
|
||||||
|
|
||||||
|
accID = FindAccelerator("send_ctrl_alt_esc");
|
||||||
|
seq = QKeySequence::fromString(acc_keys[accID].seq);
|
||||||
|
ui->actionCtrl_Alt_Esc->setShortcut(seq);
|
||||||
|
|
||||||
|
accID = FindAccelerator("fullscreen");
|
||||||
|
seq = QKeySequence::fromString(acc_keys[accID].seq);
|
||||||
|
//printf("shortcut: %s\n", qPrintable(ui->actionFullscreen->shortcut().toString()));
|
||||||
|
ui->actionFullscreen->setShortcut(seq);
|
||||||
|
|
||||||
|
accID = FindAccelerator("hard_reset");
|
||||||
|
seq = QKeySequence::fromString(acc_keys[accID].seq);
|
||||||
|
ui->actionHard_Reset->setShortcut(seq);
|
||||||
|
|
||||||
|
// To rebind leave_fullscreen we have to disconnect the existing signal,
|
||||||
|
// build a new shortcut, then connect it.
|
||||||
|
accID = FindAccelerator("leave_fullscreen");
|
||||||
|
seq = QKeySequence::fromString(acc_keys[accID].seq);
|
||||||
|
disconnect(windowedShortcut,0,0,0);
|
||||||
|
windowedShortcut = new QShortcut(seq, this);
|
||||||
|
windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut);
|
||||||
|
connect(windowedShortcut, &QShortcut::activated, this, [this] () {
|
||||||
|
if (video_fullscreen)
|
||||||
|
ui->actionFullscreen->trigger();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::resizeEvent(QResizeEvent *event)
|
MainWindow::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
@@ -1026,6 +1079,8 @@ MainWindow::on_actionSettings_triggered()
|
|||||||
case QDialog::Accepted:
|
case QDialog::Accepted:
|
||||||
settings.save();
|
settings.save();
|
||||||
config_changed = 2;
|
config_changed = 2;
|
||||||
|
printf("about to try\n");
|
||||||
|
updateShortcuts();
|
||||||
pc_reset_hard();
|
pc_reset_hard();
|
||||||
break;
|
break;
|
||||||
case QDialog::Rejected:
|
case QDialog::Rejected:
|
||||||
@@ -1394,9 +1449,14 @@ MainWindow::keyPressEvent(QKeyEvent *event)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboard_ismsexit())
|
// Check if mouse release combo has been entered
|
||||||
|
int accID = FindAccelerator("release_mouse");
|
||||||
|
QKeySequence seq = QKeySequence::fromString(acc_keys[accID].seq);
|
||||||
|
if (seq[0] == (event->key() | event->modifiers()))
|
||||||
plat_mouse_capture(0);
|
plat_mouse_capture(0);
|
||||||
|
|
||||||
|
// TODO: Other accelerators should probably be here?
|
||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QFocusEvent>
|
#include <QFocusEvent>
|
||||||
|
#include <QShortcut>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -32,6 +33,7 @@ public:
|
|||||||
QSize getRenderWidgetSize();
|
QSize getRenderWidgetSize();
|
||||||
void setSendKeyboardInput(bool enabled);
|
void setSendKeyboardInput(bool enabled);
|
||||||
void reloadAllRenderers();
|
void reloadAllRenderers();
|
||||||
|
QShortcut *windowedShortcut;
|
||||||
|
|
||||||
std::array<std::unique_ptr<RendererStack>, 8> renderers;
|
std::array<std::unique_ptr<RendererStack>, 8> renderers;
|
||||||
signals:
|
signals:
|
||||||
@@ -159,6 +161,7 @@ private:
|
|||||||
std::unique_ptr<MachineStatus> status;
|
std::unique_ptr<MachineStatus> status;
|
||||||
std::shared_ptr<MediaMenu> mm;
|
std::shared_ptr<MediaMenu> mm;
|
||||||
|
|
||||||
|
void updateShortcuts();
|
||||||
void processKeyboardInput(bool down, uint32_t keycode);
|
void processKeyboardInput(bool down, uint32_t keycode);
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
uint32_t last_modifiers = 0;
|
uint32_t last_modifiers = 0;
|
||||||
@@ -184,7 +187,6 @@ private:
|
|||||||
friend class RendererStack; // For UI variable access by non-primary renderer windows.
|
friend class RendererStack; // For UI variable access by non-primary renderer windows.
|
||||||
friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes.
|
friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes.
|
||||||
|
|
||||||
|
|
||||||
bool isShowMessage = false;
|
bool isShowMessage = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
#include "qt_settingsinput.hpp"
|
#include "qt_settingsinput.hpp"
|
||||||
#include "ui_qt_settingsinput.h"
|
#include "ui_qt_settingsinput.h"
|
||||||
|
#include "qt_mainwindow.hpp"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
@@ -25,11 +28,18 @@ extern "C" {
|
|||||||
#include <86box/machine.h>
|
#include <86box/machine.h>
|
||||||
#include <86box/mouse.h>
|
#include <86box/mouse.h>
|
||||||
#include <86box/gameport.h>
|
#include <86box/gameport.h>
|
||||||
|
#include <86box/ui.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "qt_models_common.hpp"
|
#include "qt_models_common.hpp"
|
||||||
#include "qt_deviceconfig.hpp"
|
#include "qt_deviceconfig.hpp"
|
||||||
#include "qt_joystickconfiguration.hpp"
|
#include "qt_joystickconfiguration.hpp"
|
||||||
|
#include "qt_keybind.hpp"
|
||||||
|
|
||||||
|
extern MainWindow *main_window;
|
||||||
|
|
||||||
|
// Temporary working copy of key list
|
||||||
|
accelKey acc_keys_t[NUM_ACCELS];
|
||||||
|
|
||||||
SettingsInput::SettingsInput(QWidget *parent)
|
SettingsInput::SettingsInput(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
@@ -37,9 +47,55 @@ SettingsInput::SettingsInput(QWidget *parent)
|
|||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
QStandardItemModel *model;
|
||||||
|
QStringList horizontalHeader;
|
||||||
|
QStringList verticalHeader;
|
||||||
|
|
||||||
|
horizontalHeader.append("Action");
|
||||||
|
horizontalHeader.append("Keybind");
|
||||||
|
|
||||||
|
QTableWidget *keyTable = ui->tableKeys;
|
||||||
|
keyTable->setRowCount(10);
|
||||||
|
keyTable->setColumnCount(3);
|
||||||
|
keyTable->setColumnHidden(2, true);
|
||||||
|
keyTable->setColumnWidth(0, 200);
|
||||||
|
keyTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||||
|
QStringList headers;
|
||||||
|
headers << "Action" << "Bound key";
|
||||||
|
keyTable->setHorizontalHeaderLabels(headers);
|
||||||
|
keyTable->verticalHeader()->setVisible(false);
|
||||||
|
keyTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
keyTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
keyTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
keyTable->setShowGrid(true);
|
||||||
|
keyTable->setStyleSheet("QTableWidget::item:hover { }");
|
||||||
|
keyTable->setFocusPolicy(Qt::NoFocus);
|
||||||
|
keyTable->setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
|
|
||||||
|
// Make a working copy of acc_keys so we can check for dupes later without getting
|
||||||
|
// confused
|
||||||
|
printf("Instantiating list\n");
|
||||||
|
for(int x=0;x<NUM_ACCELS;x++) {
|
||||||
|
strcpy(acc_keys_t[x].name, acc_keys[x].name);
|
||||||
|
strcpy(acc_keys_t[x].desc, acc_keys[x].desc);
|
||||||
|
strcpy(acc_keys_t[x].seq, acc_keys[x].seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshInputList();
|
||||||
|
|
||||||
|
connect(ui->tableKeys, &QTableWidget::cellDoubleClicked,
|
||||||
|
this, &SettingsInput::on_tableKeys_doubleClicked);
|
||||||
|
|
||||||
|
connect(ui->pushButtonBind, &QPushButton::clicked,
|
||||||
|
this, &SettingsInput::on_pushButtonBind_Clicked);
|
||||||
|
|
||||||
|
connect(ui->pushButtonClearBind, &QPushButton::clicked,
|
||||||
|
this, &SettingsInput::on_pushButtonClearBind_Clicked);
|
||||||
|
|
||||||
onCurrentMachineChanged(machine);
|
onCurrentMachineChanged(machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SettingsInput::~SettingsInput()
|
SettingsInput::~SettingsInput()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
@@ -50,6 +106,13 @@ SettingsInput::save()
|
|||||||
{
|
{
|
||||||
mouse_type = ui->comboBoxMouse->currentData().toInt();
|
mouse_type = ui->comboBoxMouse->currentData().toInt();
|
||||||
joystick_type = ui->comboBoxJoystick->currentData().toInt();
|
joystick_type = ui->comboBoxJoystick->currentData().toInt();
|
||||||
|
|
||||||
|
// Copy accelerators from working set to global set
|
||||||
|
for(int x=0;x<NUM_ACCELS;x++) {
|
||||||
|
strcpy(acc_keys[x].name, acc_keys_t[x].name);
|
||||||
|
strcpy(acc_keys[x].desc, acc_keys_t[x].desc);
|
||||||
|
strcpy(acc_keys[x].seq, acc_keys_t[x].seq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -105,6 +168,100 @@ SettingsInput::onCurrentMachineChanged(int machineId)
|
|||||||
ui->comboBoxJoystick->setCurrentIndex(selectedRow);
|
ui->comboBoxJoystick->setCurrentIndex(selectedRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsInput::refreshInputList()
|
||||||
|
{
|
||||||
|
|
||||||
|
for (int x=0;x<NUM_ACCELS;x++) {
|
||||||
|
ui->tableKeys->setItem(x, 0, new QTableWidgetItem(acc_keys_t[x].desc));
|
||||||
|
ui->tableKeys->setItem(x, 1, new QTableWidgetItem(acc_keys_t[x].seq));
|
||||||
|
ui->tableKeys->setItem(x, 2, new QTableWidgetItem(acc_keys_t[x].name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsInput::on_tableKeys_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
|
||||||
|
{
|
||||||
|
// Enable/disable bind/clear buttons if user clicked valid row
|
||||||
|
QTableWidgetItem *cell = ui->tableKeys->item(currentRow,1);
|
||||||
|
if (!cell)
|
||||||
|
{
|
||||||
|
ui->pushButtonBind->setEnabled(false);
|
||||||
|
ui->pushButtonClearBind->setEnabled(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->pushButtonBind->setEnabled(true);
|
||||||
|
ui->pushButtonClearBind->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsInput::on_tableKeys_doubleClicked(int row, int col)
|
||||||
|
{
|
||||||
|
// Edit bind
|
||||||
|
QTableWidgetItem *cell = ui->tableKeys->item(row,1);
|
||||||
|
if (!cell) return;
|
||||||
|
|
||||||
|
QKeySequence keyseq = KeyBinder::BindKey(cell->text());
|
||||||
|
if (keyseq != false) {
|
||||||
|
// If no change was made, don't change anything.
|
||||||
|
if (keyseq.toString(QKeySequence::NativeText) == cell->text()) return;
|
||||||
|
|
||||||
|
// Otherwise, check for conflicts.
|
||||||
|
// Check against the *working* copy - NOT the one in use by the app,
|
||||||
|
// so we don't test against shortcuts the user already changed.
|
||||||
|
for(int x=0;x<NUM_ACCELS;x++)
|
||||||
|
{
|
||||||
|
if(QString::fromStdString(acc_keys_t[x].seq) == keyseq.toString(QKeySequence::NativeText))
|
||||||
|
{
|
||||||
|
// That key is already in use
|
||||||
|
main_window->showMessage(MBX_ANSI & MBX_INFO, "Bind conflict", "This key combo is already in use", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we made it here, there were no conflicts.
|
||||||
|
// Go ahead and apply the bind.
|
||||||
|
|
||||||
|
// Find the correct accelerator key entry
|
||||||
|
int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(row,2)->text()));
|
||||||
|
if (!accKeyID) return; // this should never happen
|
||||||
|
|
||||||
|
// Make the change
|
||||||
|
cell->setText(keyseq.toString(QKeySequence::NativeText));
|
||||||
|
strcpy(acc_keys_t[accKeyID].seq, qPrintable(keyseq.toString(QKeySequence::NativeText)));
|
||||||
|
|
||||||
|
refreshInputList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsInput::on_pushButtonBind_Clicked()
|
||||||
|
{
|
||||||
|
// Edit bind
|
||||||
|
QTableWidgetItem *cell = ui->tableKeys->currentItem();
|
||||||
|
if (!cell) return;
|
||||||
|
|
||||||
|
on_tableKeys_doubleClicked(cell->row(), cell->column());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsInput::on_pushButtonClearBind_Clicked()
|
||||||
|
{
|
||||||
|
// Wipe bind
|
||||||
|
QTableWidgetItem *cell = ui->tableKeys->currentItem();
|
||||||
|
if (!cell) return;
|
||||||
|
|
||||||
|
cell->setText("");
|
||||||
|
// Find the correct accelerator key entry
|
||||||
|
int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(cell->row(),2)->text()));
|
||||||
|
if (!accKeyID) return; // this should never happen
|
||||||
|
|
||||||
|
// Make the change
|
||||||
|
cell->setText("");
|
||||||
|
strcpy(acc_keys_t[accKeyID].seq, "");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SettingsInput::on_comboBoxMouse_currentIndexChanged(int index)
|
SettingsInput::on_comboBoxMouse_currentIndexChanged(int index)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
#define QT_SETTINGSINPUT_HPP
|
#define QT_SETTINGSINPUT_HPP
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QtGui/QStandardItemModel>
|
||||||
|
#include <QtGui/QStandardItem>
|
||||||
|
#include <QItemDelegate>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QTableWidget>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class SettingsInput;
|
class SettingsInput;
|
||||||
@@ -27,10 +33,15 @@ private slots:
|
|||||||
void on_pushButtonJoystick2_clicked();
|
void on_pushButtonJoystick2_clicked();
|
||||||
void on_pushButtonJoystick3_clicked();
|
void on_pushButtonJoystick3_clicked();
|
||||||
void on_pushButtonJoystick4_clicked();
|
void on_pushButtonJoystick4_clicked();
|
||||||
|
void on_tableKeys_doubleClicked(int row, int col);
|
||||||
|
void on_tableKeys_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn);
|
||||||
|
void on_pushButtonBind_Clicked();
|
||||||
|
void on_pushButtonClearBind_Clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::SettingsInput *ui;
|
Ui::SettingsInput *ui;
|
||||||
int machineId = 0;
|
int machineId = 0;
|
||||||
|
void refreshInputList();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QT_SETTINGSINPUT_HPP
|
#endif // QT_SETTINGSINPUT_HPP
|
||||||
|
|||||||
@@ -23,17 +23,16 @@
|
|||||||
<property name="rightMargin">
|
<property name="rightMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="2" column="1">
|
<item row="0" column="1" colspan="2">
|
||||||
<widget class="QPushButton" name="pushButtonJoystick2">
|
<widget class="QComboBox" name="comboBoxMouse">
|
||||||
<property name="text">
|
<property name="sizePolicy">
|
||||||
<string>Joystick 2...</string>
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="maxVisibleItems">
|
||||||
</item>
|
<number>30</number>
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Joystick:</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -44,13 +43,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Mouse:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="2">
|
<item row="2" column="2">
|
||||||
<widget class="QPushButton" name="pushButtonJoystick3">
|
<widget class="QPushButton" name="pushButtonJoystick3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -58,21 +50,15 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="5" column="3">
|
||||||
<spacer name="verticalSpacer">
|
<widget class="QPushButton" name="pushButtonBind">
|
||||||
<property name="orientation">
|
<property name="enabled">
|
||||||
<enum>Qt::Vertical</enum>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeType">
|
<property name="text">
|
||||||
<enum>QSizePolicy::Expanding</enum>
|
<string>Bind</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
</widget>
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QPushButton" name="pushButtonJoystick1">
|
<widget class="QPushButton" name="pushButtonJoystick1">
|
||||||
@@ -81,6 +67,44 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="1" colspan="2">
|
||||||
|
<widget class="QComboBox" name="comboBoxJoystick">
|
||||||
|
<property name="maxVisibleItems">
|
||||||
|
<number>30</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mouse:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="2">
|
||||||
|
<widget class="QPushButton" name="pushButtonClearBind">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear binding</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Joystick:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="pushButtonJoystick2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Joystick 2...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="3">
|
<item row="0" column="3">
|
||||||
<widget class="QPushButton" name="pushButtonConfigureMouse">
|
<widget class="QPushButton" name="pushButtonConfigureMouse">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@@ -94,23 +118,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1" colspan="2">
|
<item row="3" column="0">
|
||||||
<widget class="QComboBox" name="comboBoxMouse">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="maxVisibleItems">
|
<property name="text">
|
||||||
<number>30</number>
|
<string>Key Bindings:</string>
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1" colspan="2">
|
<item row="4" column="0" colspan="4">
|
||||||
<widget class="QComboBox" name="comboBoxJoystick">
|
<widget class="QTableWidget" name="tableKeys">
|
||||||
<property name="maxVisibleItems">
|
<property name="editTriggers">
|
||||||
<number>30</number>
|
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="tabKeyNavigation">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="showDropIndicator" stdset="0">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user