partial
This commit is contained in:
parent
246c35316c
commit
cd8dee2779
@ -342,6 +342,26 @@ public:
|
|||||||
{
|
{
|
||||||
return video::isDriverSupported(driver);
|
return video::isDriverSupported(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a trivial (near-identity) mapping for converting between scancodes and keycodes for devices that do
|
||||||
|
// not implement this.
|
||||||
|
|
||||||
|
//! Get the scancode of the corresponding keycode.
|
||||||
|
virtual u32 getScancodeFromKey(const KeyCode &key) const
|
||||||
|
{
|
||||||
|
return key.index() == 0 ? std::get<EKEY_CODE>(key) : KEY_KEY_CODES_COUNT + std::get<wchar_t>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the keycode of the corresponding scancode.
|
||||||
|
virtual KeyCode getKeyFromScancode(const u32 scancode) const
|
||||||
|
{
|
||||||
|
KeyCode key;
|
||||||
|
if (scancode < KEY_KEY_CODES_COUNT)
|
||||||
|
key.emplace<EKEY_CODE>((EKEY_CODE)scancode);
|
||||||
|
else
|
||||||
|
key.emplace<wchar_t>(scancode - KEY_KEY_CODES_COUNT);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace irr
|
} // end namespace irr
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
@ -182,4 +183,29 @@ enum EKEY_CODE
|
|||||||
KEY_KEY_CODES_COUNT = 0x100 // this is not a key, but the amount of keycodes there are.
|
KEY_KEY_CODES_COUNT = 0x100 // this is not a key, but the amount of keycodes there are.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class KeyCode : public std::variant<EKEY_CODE, wchar_t> {
|
||||||
|
using super = std::variant<EKEY_CODE, wchar_t>;
|
||||||
|
public:
|
||||||
|
KeyCode() : KeyCode(KEY_KEY_CODES_COUNT, L'\0') {}
|
||||||
|
|
||||||
|
KeyCode(EKEY_CODE code, wchar_t ch)
|
||||||
|
{
|
||||||
|
emplace(code, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
using super::emplace;
|
||||||
|
void emplace(EKEY_CODE code, wchar_t ch)
|
||||||
|
{
|
||||||
|
if (isValid(code))
|
||||||
|
emplace<EKEY_CODE>(code);
|
||||||
|
else
|
||||||
|
emplace<wchar_t>(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isValid(EKEY_CODE code)
|
||||||
|
{
|
||||||
|
return code > 0 && code < KEY_KEY_CODES_COUNT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // end namespace irr
|
} // end namespace irr
|
||||||
|
@ -220,6 +220,31 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtK
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 CIrrDeviceSDL::getScancodeFromKey(const KeyCode &key) const
|
||||||
|
{
|
||||||
|
u32 keynum = 0;
|
||||||
|
if (key.index() == 0) {
|
||||||
|
auto keycode = std::get<EKEY_CODE>(key);
|
||||||
|
for (const auto &entry: KeyMap) {
|
||||||
|
if (entry.second == keycode) {
|
||||||
|
keynum = entry.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keynum = std::get<wchar_t>(key);
|
||||||
|
}
|
||||||
|
return SDL_GetScancodeFromKey(keynum);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyCode CIrrDeviceSDL::getKeyFromScancode(const u32 scancode) const
|
||||||
|
{
|
||||||
|
auto keycode = SDL_GetKeyFromScancode((SDL_Scancode)scancode);
|
||||||
|
const auto &keyentry = KeyMap.find(keycode);
|
||||||
|
auto irrcode = keyentry != KeyMap.end() ? keyentry->second : KEY_UNKNOWN;
|
||||||
|
return KeyCode(irrcode, keycode);
|
||||||
|
}
|
||||||
|
|
||||||
void CIrrDeviceSDL::resetReceiveTextInputEvents()
|
void CIrrDeviceSDL::resetReceiveTextInputEvents()
|
||||||
{
|
{
|
||||||
gui::IGUIElement *elem = GUIEnvironment->getFocus();
|
gui::IGUIElement *elem = GUIEnvironment->getFocus();
|
||||||
@ -815,6 +840,21 @@ bool CIrrDeviceSDL::run()
|
|||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
case SDL_KEYUP: {
|
case SDL_KEYUP: {
|
||||||
auto keysym = SDL_event.key.keysym.sym;
|
auto keysym = SDL_event.key.keysym.sym;
|
||||||
|
auto scancode = SDL_event.key.keysym.scancode;
|
||||||
|
|
||||||
|
// Treat AC_BACK as the Escape key
|
||||||
|
if (scancode == SDL_SCANCODE_AC_BACK || scancode == SDL_SCANCODE_ESCAPE)
|
||||||
|
{
|
||||||
|
if (SDL_event.type == SDL_KEYDOWN)
|
||||||
|
escapeKeys.insert(scancode);
|
||||||
|
else
|
||||||
|
escapeKeys.erase(scancode);
|
||||||
|
if (SDL_event.type == SDL_KEYUP && !escapeKeys.empty())
|
||||||
|
break; // avoid sending KEYUP twice if AC_BACK and ESCAPE are both released
|
||||||
|
scancode = SDL_SCANCODE_ESCAPE;
|
||||||
|
keysym = SDLK_ESCAPE;
|
||||||
|
}
|
||||||
|
|
||||||
const auto &entry = KeyMap.find(keysym);
|
const auto &entry = KeyMap.find(keysym);
|
||||||
auto key = entry == KeyMap.end() ? KEY_UNKNOWN : entry->second;
|
auto key = entry == KeyMap.end() ? KEY_UNKNOWN : entry->second;
|
||||||
|
|
||||||
@ -832,6 +872,8 @@ bool CIrrDeviceSDL::run()
|
|||||||
irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0;
|
irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0;
|
||||||
irrevent.KeyInput.Char = findCharToPassToIrrlicht(keysym, key,
|
irrevent.KeyInput.Char = findCharToPassToIrrlicht(keysym, key,
|
||||||
(SDL_event.key.keysym.mod & KMOD_NUM) != 0);
|
(SDL_event.key.keysym.mod & KMOD_NUM) != 0);
|
||||||
|
irrevent.KeyInput.SystemKeyCode = scancode;
|
||||||
|
|
||||||
postEventFromUser(irrevent);
|
postEventFromUser(irrevent);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -1298,9 +1340,6 @@ void CIrrDeviceSDL::createKeyMap()
|
|||||||
|
|
||||||
// buttons missing
|
// buttons missing
|
||||||
|
|
||||||
// Android back button = ESC
|
|
||||||
KeyMap.emplace(SDLK_AC_BACK, KEY_ESCAPE);
|
|
||||||
|
|
||||||
KeyMap.emplace(SDLK_BACKSPACE, KEY_BACK);
|
KeyMap.emplace(SDLK_BACKSPACE, KEY_BACK);
|
||||||
KeyMap.emplace(SDLK_TAB, KEY_TAB);
|
KeyMap.emplace(SDLK_TAB, KEY_TAB);
|
||||||
KeyMap.emplace(SDLK_CLEAR, KEY_CLEAR);
|
KeyMap.emplace(SDLK_CLEAR, KEY_CLEAR);
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include <SDL_syswm.h>
|
#include <SDL_syswm.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
@ -286,6 +288,9 @@ private:
|
|||||||
// Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0).
|
// Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0).
|
||||||
static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock);
|
static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock);
|
||||||
|
|
||||||
|
virtual u32 getScancodeFromKey(const KeyCode &key) const override;
|
||||||
|
virtual KeyCode getKeyFromScancode(const u32 scancode) const override;
|
||||||
|
|
||||||
// Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus.
|
// Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus.
|
||||||
void resetReceiveTextInputEvents();
|
void resetReceiveTextInputEvents();
|
||||||
|
|
||||||
@ -324,6 +329,8 @@ private:
|
|||||||
|
|
||||||
s32 CurrentTouchCount;
|
s32 CurrentTouchCount;
|
||||||
bool IsInBackground;
|
bool IsInBackground;
|
||||||
|
|
||||||
|
std::unordered_set<SDL_Scancode> escapeKeys;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace irr
|
} // end namespace irr
|
||||||
|
@ -143,7 +143,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
|||||||
// Remember whether each key is down or up
|
// Remember whether each key is down or up
|
||||||
if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
|
if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
|
||||||
const KeyPress keyCode(event.KeyInput);
|
const KeyPress keyCode(event.KeyInput);
|
||||||
if (keysListenedFor[keyCode]) {
|
if (keyCode && keysListenedFor[keyCode]) {
|
||||||
if (event.KeyInput.PressedDown) {
|
if (event.KeyInput.PressedDown) {
|
||||||
if (!IsKeyDown(keyCode))
|
if (!IsKeyDown(keyCode))
|
||||||
keyWasPressed.set(keyCode);
|
keyWasPressed.set(keyCode);
|
||||||
|
@ -6,15 +6,17 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "renderingengine.h"
|
||||||
#include "util/hex.h"
|
#include "util/hex.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "util/basic_macros.h"
|
#include "util/basic_macros.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct table_key {
|
struct table_key {
|
||||||
const char *Name;
|
std::string Name;
|
||||||
irr::EKEY_CODE Key;
|
irr::EKEY_CODE Key;
|
||||||
wchar_t Char; // L'\0' means no character assigned
|
wchar_t Char; // L'\0' means no character assigned
|
||||||
const char *LangName; // NULL means it doesn't have a human description
|
std::string LangName; // NULL means it doesn't have a human description
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFINEKEY1(x, lang) /* Irrlicht key without character */ \
|
#define DEFINEKEY1(x, lang) /* Irrlicht key without character */ \
|
||||||
@ -30,7 +32,7 @@ struct table_key {
|
|||||||
|
|
||||||
#define N_(text) text
|
#define N_(text) text
|
||||||
|
|
||||||
static const struct table_key table[] = {
|
static std::vector<table_key> table = {
|
||||||
// Keys that can be reliably mapped between Char and Key
|
// Keys that can be reliably mapped between Char and Key
|
||||||
DEFINEKEY3(0)
|
DEFINEKEY3(0)
|
||||||
DEFINEKEY3(1)
|
DEFINEKEY3(1)
|
||||||
@ -126,7 +128,7 @@ static const struct table_key table[] = {
|
|||||||
DEFINEKEY1(KEY_ADD, N_("Numpad +"))
|
DEFINEKEY1(KEY_ADD, N_("Numpad +"))
|
||||||
DEFINEKEY1(KEY_SEPARATOR, N_("Numpad ."))
|
DEFINEKEY1(KEY_SEPARATOR, N_("Numpad ."))
|
||||||
DEFINEKEY1(KEY_SUBTRACT, N_("Numpad -"))
|
DEFINEKEY1(KEY_SUBTRACT, N_("Numpad -"))
|
||||||
DEFINEKEY1(KEY_DECIMAL, NULL)
|
DEFINEKEY1(KEY_DECIMAL, N_("Numpad ."))
|
||||||
DEFINEKEY1(KEY_DIVIDE, N_("Numpad /"))
|
DEFINEKEY1(KEY_DIVIDE, N_("Numpad /"))
|
||||||
DEFINEKEY4(1)
|
DEFINEKEY4(1)
|
||||||
DEFINEKEY4(2)
|
DEFINEKEY4(2)
|
||||||
@ -221,33 +223,16 @@ static const struct table_key table[] = {
|
|||||||
DEFINEKEY5("_")
|
DEFINEKEY5("_")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const table_key invalid_key = {"", irr::KEY_UNKNOWN, L'\0', ""};
|
||||||
|
|
||||||
#undef N_
|
#undef N_
|
||||||
|
|
||||||
|
|
||||||
static const table_key &lookup_keyname(const char *name)
|
|
||||||
{
|
|
||||||
for (const auto &table_key : table) {
|
|
||||||
if (strcmp(table_key.Name, name) == 0)
|
|
||||||
return table_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw UnknownKeycode(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const table_key &lookup_keykey(irr::EKEY_CODE key)
|
|
||||||
{
|
|
||||||
for (const auto &table_key : table) {
|
|
||||||
if (table_key.Key == key)
|
|
||||||
return table_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostringstream os;
|
|
||||||
os << "<Keycode " << (int) key << ">";
|
|
||||||
throw UnknownKeycode(os.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
static const table_key &lookup_keychar(wchar_t Char)
|
static const table_key &lookup_keychar(wchar_t Char)
|
||||||
{
|
{
|
||||||
|
if (Char == L'\0')
|
||||||
|
return invalid_key;
|
||||||
|
|
||||||
for (const auto &table_key : table) {
|
for (const auto &table_key : table) {
|
||||||
if (table_key.Char == Char)
|
if (table_key.Char == Char)
|
||||||
return table_key;
|
return table_key;
|
||||||
@ -255,88 +240,73 @@ static const table_key &lookup_keychar(wchar_t Char)
|
|||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "<Char " << hex_encode((char*) &Char, sizeof(wchar_t)) << ">";
|
os << "<Char " << hex_encode((char*) &Char, sizeof(wchar_t)) << ">";
|
||||||
throw UnknownKeycode(os.str().c_str());
|
auto newsym = wide_to_utf8(std::wstring_view(&Char, 1));
|
||||||
|
table_key new_key = {newsym, irr::KEY_KEY_CODES_COUNT, Char, newsym};
|
||||||
|
return table.emplace_back(std::move(new_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyPress::KeyPress(const char *name)
|
static const table_key &lookup_keyname(const std::string_view &name)
|
||||||
{
|
{
|
||||||
if (strlen(name) == 0) {
|
if (name.empty())
|
||||||
Key = irr::KEY_KEY_CODES_COUNT;
|
return invalid_key;
|
||||||
Char = L'\0';
|
|
||||||
m_name = "";
|
for (const auto &table_key : table) {
|
||||||
return;
|
if (table_key.Name == name)
|
||||||
|
return table_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(name) <= 4) {
|
auto wname = utf8_to_wide(name);
|
||||||
// Lookup by resulting character
|
if (wname.empty())
|
||||||
int chars_read = mbtowc(&Char, name, 1);
|
return invalid_key;
|
||||||
FATAL_ERROR_IF(chars_read != 1, "Unexpected multibyte character");
|
return lookup_keychar(wname[0]);
|
||||||
try {
|
}
|
||||||
auto &k = lookup_keychar(Char);
|
|
||||||
m_name = k.Name;
|
static const table_key &lookup_keykey(irr::EKEY_CODE key)
|
||||||
Key = k.Key;
|
{
|
||||||
return;
|
if (!KeyCode::isValid(key))
|
||||||
} catch (UnknownKeycode &e) {};
|
return invalid_key;
|
||||||
} else {
|
|
||||||
// Lookup by name
|
for (const auto &table_key : table) {
|
||||||
m_name = name;
|
if (table_key.Key == key)
|
||||||
try {
|
return table_key;
|
||||||
auto &k = lookup_keyname(name);
|
|
||||||
Key = k.Key;
|
|
||||||
Char = k.Char;
|
|
||||||
return;
|
|
||||||
} catch (UnknownKeycode &e) {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's not a known key, complain and try to do something
|
std::ostringstream os;
|
||||||
Key = irr::KEY_KEY_CODES_COUNT;
|
os << "<Keycode " << (int) key << ">";
|
||||||
int chars_read = mbtowc(&Char, name, 1);
|
return invalid_key;
|
||||||
FATAL_ERROR_IF(chars_read != 1, "Unexpected multibyte character");
|
|
||||||
m_name = "";
|
|
||||||
warningstream << "KeyPress: Unknown key '" << name
|
|
||||||
<< "', falling back to first char." << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyPress::KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character)
|
static const table_key &lookup_scancode(const u32 scancode)
|
||||||
{
|
{
|
||||||
if (prefer_character)
|
auto key = RenderingEngine::get_raw_device()->getKeyFromScancode(scancode);
|
||||||
Key = irr::KEY_KEY_CODES_COUNT;
|
return key.index() == 0 ? lookup_keykey(std::get<irr::EKEY_CODE>(key)) : lookup_keychar(std::get<wchar_t>(key));
|
||||||
else
|
|
||||||
Key = in.Key;
|
|
||||||
Char = in.Char;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (valid_kcode(Key))
|
|
||||||
m_name = lookup_keykey(Key).Name;
|
|
||||||
else
|
|
||||||
m_name = lookup_keychar(Char).Name;
|
|
||||||
} catch (UnknownKeycode &e) {
|
|
||||||
m_name.clear();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *KeyPress::sym() const
|
KeyPress::KeyPress(const std::string_view &name)
|
||||||
{
|
{
|
||||||
return m_name.c_str();
|
const auto &key = lookup_keyname(name);
|
||||||
|
KeyCode keycode(key.Key, key.Char);
|
||||||
|
scancode = RenderingEngine::get_raw_device()->getScancodeFromKey(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *KeyPress::name() const
|
std::string KeyPress::sym() const
|
||||||
{
|
{
|
||||||
if (m_name.empty())
|
return lookup_scancode(scancode).Name;
|
||||||
return "";
|
|
||||||
const char *ret;
|
|
||||||
if (valid_kcode(Key))
|
|
||||||
ret = lookup_keykey(Key).LangName;
|
|
||||||
else
|
|
||||||
ret = lookup_keychar(Char).LangName;
|
|
||||||
return ret ? ret : "<Unnamed key>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const KeyPress EscapeKey("KEY_ESCAPE");
|
std::string KeyPress::name() const
|
||||||
|
{
|
||||||
|
return lookup_scancode(scancode).LangName;
|
||||||
|
}
|
||||||
|
|
||||||
const KeyPress LMBKey("KEY_LBUTTON");
|
std::unordered_map<std::string, KeyPress> KeyPress::specialKeyCache;
|
||||||
const KeyPress MMBKey("KEY_MBUTTON");
|
const KeyPress &KeyPress::getSpecialKey(const std::string &name)
|
||||||
const KeyPress RMBKey("KEY_RBUTTON");
|
{
|
||||||
|
auto &key = specialKeyCache[name];
|
||||||
|
if (!key)
|
||||||
|
key = KeyPress(name);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Key config
|
Key config
|
||||||
@ -352,7 +322,7 @@ const KeyPress &getKeySetting(const char *settingname)
|
|||||||
return n->second;
|
return n->second;
|
||||||
|
|
||||||
auto &ref = g_key_setting_cache[settingname];
|
auto &ref = g_key_setting_cache[settingname];
|
||||||
ref = g_settings->get(settingname).c_str();
|
ref = std::string_view(g_settings->get(settingname));
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,57 +4,49 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "exceptions.h"
|
|
||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
#include <Keycodes.h>
|
#include <Keycodes.h>
|
||||||
#include <IEventReceiver.h>
|
#include <IEventReceiver.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class UnknownKeycode : public BaseException
|
/* A key press, consisting of a scancode or a keycode */
|
||||||
{
|
|
||||||
public:
|
|
||||||
UnknownKeycode(const char *s) :
|
|
||||||
BaseException(s) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A key press, consisting of either an Irrlicht keycode
|
|
||||||
or an actual char */
|
|
||||||
|
|
||||||
class KeyPress
|
class KeyPress
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KeyPress() = default;
|
KeyPress() {};
|
||||||
|
|
||||||
KeyPress(const char *name);
|
KeyPress(const std::string_view &name);
|
||||||
|
|
||||||
KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character = false);
|
KeyPress(const irr::SEvent::SKeyInput &in) :
|
||||||
|
scancode(in.SystemKeyCode) {};
|
||||||
|
|
||||||
bool operator==(const KeyPress &o) const
|
std::string sym() const;
|
||||||
{
|
std::string name() const;
|
||||||
return (Char > 0 && Char == o.Char) || (valid_kcode(Key) && Key == o.Key);
|
|
||||||
|
bool operator==(const KeyPress &o) const {
|
||||||
|
return scancode == o.scancode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *sym() const;
|
operator bool() const {
|
||||||
const char *name() const;
|
return scancode != 0;
|
||||||
|
|
||||||
protected:
|
|
||||||
static bool valid_kcode(irr::EKEY_CODE k)
|
|
||||||
{
|
|
||||||
return k > 0 && k < irr::KEY_KEY_CODES_COUNT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
irr::EKEY_CODE Key = irr::KEY_KEY_CODES_COUNT;
|
static const KeyPress &getSpecialKey(const std::string &name);
|
||||||
wchar_t Char = L'\0';
|
|
||||||
std::string m_name = "";
|
private:
|
||||||
|
u32 scancode = 0;
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, KeyPress> specialKeyCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global defines for convenience
|
// Global defines for convenience
|
||||||
|
// This implementation defers creation of the objects to make sure that the
|
||||||
extern const KeyPress EscapeKey;
|
// IrrlichtDevice is initialized.
|
||||||
|
#define EscapeKey KeyPress::getSpecialKey("KEY_ESCAPE")
|
||||||
extern const KeyPress LMBKey;
|
#define LMBKey KeyPress::getSpecialKey("KEY_LBUTTON")
|
||||||
extern const KeyPress MMBKey; // Middle Mouse Button
|
#define MMBKey KeyPress::getSpecialKey("KEY_MBUTTON") // Middle Mouse Button
|
||||||
extern const KeyPress RMBKey;
|
#define RMBKey KeyPress::getSpecialKey("KEY_RBUTTON")
|
||||||
|
|
||||||
// Key configuration getter
|
// Key configuration getter
|
||||||
const KeyPress &getKeySetting(const char *settingname);
|
const KeyPress &getKeySetting(const char *settingname);
|
||||||
|
@ -253,8 +253,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
|||||||
if (event.EventType == EET_KEY_INPUT_EVENT && active_key
|
if (event.EventType == EET_KEY_INPUT_EVENT && active_key
|
||||||
&& event.KeyInput.PressedDown) {
|
&& event.KeyInput.PressedDown) {
|
||||||
|
|
||||||
bool prefer_character = shift_down;
|
KeyPress kp(event.KeyInput);
|
||||||
KeyPress kp(event.KeyInput, prefer_character);
|
|
||||||
|
|
||||||
if (event.KeyInput.Key == irr::KEY_DELETE)
|
if (event.KeyInput.Key == irr::KEY_DELETE)
|
||||||
kp = KeyPress(""); // To erase key settings
|
kp = KeyPress(""); // To erase key settings
|
||||||
@ -270,7 +269,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
|||||||
|
|
||||||
// Display Key already in use message
|
// Display Key already in use message
|
||||||
bool key_in_use = false;
|
bool key_in_use = false;
|
||||||
if (strcmp(kp.sym(), "") != 0) {
|
if (kp) {
|
||||||
for (key_setting *ks : key_settings) {
|
for (key_setting *ks : key_settings) {
|
||||||
if (ks != active_key && ks->key == kp) {
|
if (ks != active_key && ks->key == kp) {
|
||||||
key_in_use = true;
|
key_in_use = true;
|
||||||
|
@ -190,13 +190,7 @@ static EKEY_CODE id_to_keycode(touch_gui_button_id id)
|
|||||||
}
|
}
|
||||||
assert(!key.empty());
|
assert(!key.empty());
|
||||||
std::string resolved = g_settings->get("keymap_" + key);
|
std::string resolved = g_settings->get("keymap_" + key);
|
||||||
try {
|
code = keyname_to_keycode(resolved.c_str());
|
||||||
code = keyname_to_keycode(resolved.c_str());
|
|
||||||
} catch (UnknownKeycode &e) {
|
|
||||||
code = KEY_UNKNOWN;
|
|
||||||
warningstream << "TouchControls: Unknown key '" << resolved
|
|
||||||
<< "' for '" << key << "', hiding button." << std::endl;
|
|
||||||
}
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "client/keycode.h"
|
#include "client/keycode.h"
|
||||||
|
#include "client/renderingengine.h" // scancode<->keycode conversion
|
||||||
|
|
||||||
class TestKeycode : public TestBase {
|
class TestKeycode : public TestBase {
|
||||||
public:
|
public:
|
||||||
@ -24,42 +25,56 @@ static TestKeycode g_test_instance;
|
|||||||
|
|
||||||
void TestKeycode::runTests(IGameDef *gamedef)
|
void TestKeycode::runTests(IGameDef *gamedef)
|
||||||
{
|
{
|
||||||
|
// TODO: How do we test this without an IrrlichtDevice?
|
||||||
|
#if 0
|
||||||
TEST(testCreateFromString);
|
TEST(testCreateFromString);
|
||||||
TEST(testCreateFromSKeyInput);
|
TEST(testCreateFromSKeyInput);
|
||||||
TEST(testCompare);
|
TEST(testCompare);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define UASSERTEQ_STR(one, two) UASSERT(strcmp(one, two) == 0)
|
#define UASSERTEQ_STR(one, two) UASSERT(one == two)
|
||||||
|
#define UASSERT_HAS_NAME(k) UASSERT(!k.name().empty())
|
||||||
|
|
||||||
void TestKeycode::testCreateFromString()
|
void TestKeycode::testCreateFromString()
|
||||||
{
|
{
|
||||||
KeyPress k;
|
KeyPress k;
|
||||||
|
|
||||||
|
k = KeyPress("");
|
||||||
|
UASSERTEQ_STR(k.sym(), "");
|
||||||
|
UASSERTEQ_STR(k.name(), "");
|
||||||
|
|
||||||
// Character key, from char
|
// Character key, from char
|
||||||
k = KeyPress("R");
|
k = KeyPress("R");
|
||||||
UASSERTEQ_STR(k.sym(), "KEY_KEY_R");
|
UASSERTEQ_STR(k.sym(), "KEY_KEY_R");
|
||||||
UASSERTCMP(int, >, strlen(k.name()), 0); // should have human description
|
UASSERT_HAS_NAME(k);
|
||||||
|
|
||||||
// Character key, from identifier
|
// Character key, from identifier
|
||||||
k = KeyPress("KEY_KEY_B");
|
k = KeyPress("KEY_KEY_B");
|
||||||
UASSERTEQ_STR(k.sym(), "KEY_KEY_B");
|
UASSERTEQ_STR(k.sym(), "KEY_KEY_B");
|
||||||
UASSERTCMP(int, >, strlen(k.name()), 0);
|
UASSERT_HAS_NAME(k);
|
||||||
|
|
||||||
// Non-Character key, from identifier
|
// Non-Character key, from identifier
|
||||||
k = KeyPress("KEY_UP");
|
k = KeyPress("KEY_UP");
|
||||||
UASSERTEQ_STR(k.sym(), "KEY_UP");
|
UASSERTEQ_STR(k.sym(), "KEY_UP");
|
||||||
UASSERTCMP(int, >, strlen(k.name()), 0);
|
UASSERT_HAS_NAME(k);
|
||||||
|
|
||||||
k = KeyPress("KEY_F6");
|
k = KeyPress("KEY_F6");
|
||||||
UASSERTEQ_STR(k.sym(), "KEY_F6");
|
UASSERTEQ_STR(k.sym(), "KEY_F6");
|
||||||
UASSERTCMP(int, >, strlen(k.name()), 0);
|
UASSERT_HAS_NAME(k);
|
||||||
|
|
||||||
// Irrlicht-unknown key, from char
|
// Irrlicht-unknown key, from char
|
||||||
k = KeyPress("/");
|
k = KeyPress("/");
|
||||||
UASSERTEQ_STR(k.sym(), "/");
|
UASSERTEQ_STR(k.sym(), "/");
|
||||||
UASSERTCMP(int, >, strlen(k.name()), 0);
|
UASSERT_HAS_NAME(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
static u32 toScancode(Args... args)
|
||||||
|
{
|
||||||
|
return RenderingEngine::get_raw_device()->getScancodeFromKey(KeyCode(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestKeycode::testCreateFromSKeyInput()
|
void TestKeycode::testCreateFromSKeyInput()
|
||||||
@ -68,47 +83,46 @@ void TestKeycode::testCreateFromSKeyInput()
|
|||||||
irr::SEvent::SKeyInput in;
|
irr::SEvent::SKeyInput in;
|
||||||
|
|
||||||
// Character key
|
// Character key
|
||||||
in.Key = irr::KEY_KEY_3;
|
in.SystemKeyCode = toScancode(irr::KEY_KEY_3, L'3');
|
||||||
in.Char = L'3';
|
|
||||||
k = KeyPress(in);
|
k = KeyPress(in);
|
||||||
UASSERTEQ_STR(k.sym(), "KEY_KEY_3");
|
UASSERTEQ_STR(k.sym(), "KEY_KEY_3");
|
||||||
|
UASSERT_HAS_NAME(k);
|
||||||
|
|
||||||
// Non-Character key
|
// Non-Character key
|
||||||
in.Key = irr::KEY_RSHIFT;
|
in.SystemKeyCode = toScancode(irr::KEY_RSHIFT, L'\0');
|
||||||
in.Char = L'\0';
|
|
||||||
k = KeyPress(in);
|
k = KeyPress(in);
|
||||||
UASSERTEQ_STR(k.sym(), "KEY_RSHIFT");
|
UASSERTEQ_STR(k.sym(), "KEY_RSHIFT");
|
||||||
|
UASSERT_HAS_NAME(k);
|
||||||
|
|
||||||
// Irrlicht-unknown key
|
// Irrlicht-unknown key
|
||||||
in.Key = irr::KEY_KEY_CODES_COUNT;
|
in.SystemKeyCode = toScancode(KEY_KEY_CODES_COUNT, L'?');
|
||||||
in.Char = L'?';
|
|
||||||
k = KeyPress(in);
|
k = KeyPress(in);
|
||||||
UASSERTEQ_STR(k.sym(), "?");
|
UASSERTEQ_STR(k.sym(), "?");
|
||||||
|
UASSERT_HAS_NAME(k);
|
||||||
// prefer_character mode
|
|
||||||
in.Key = irr::KEY_COMMA;
|
|
||||||
in.Char = L'G';
|
|
||||||
k = KeyPress(in, true);
|
|
||||||
UASSERTEQ_STR(k.sym(), "KEY_KEY_G");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestKeycode::testCompare()
|
void TestKeycode::testCompare()
|
||||||
{
|
{
|
||||||
|
// "Empty" key
|
||||||
|
UASSERT(KeyPress() == KeyPress(""));
|
||||||
|
|
||||||
// Basic comparison
|
// Basic comparison
|
||||||
UASSERT(KeyPress("5") == KeyPress("KEY_KEY_5"));
|
UASSERT(KeyPress("5") == KeyPress("KEY_KEY_5"));
|
||||||
UASSERT(!(KeyPress("5") == KeyPress("KEY_NUMPAD5")));
|
UASSERT(!(KeyPress("5") == KeyPress("KEY_NUMPAD5")));
|
||||||
|
|
||||||
// Matching char suffices
|
// Matching char suffices
|
||||||
// note: This is a real-world example, Irrlicht maps XK_equal to irr::KEY_PLUS on Linux
|
// note: This is a real-world example, Irrlicht maps XK_equal to irr::KEY_PLUS on Linux
|
||||||
|
// TODO: Is this still relevant for scancodes?
|
||||||
irr::SEvent::SKeyInput in;
|
irr::SEvent::SKeyInput in;
|
||||||
|
/*
|
||||||
in.Key = irr::KEY_PLUS;
|
in.Key = irr::KEY_PLUS;
|
||||||
in.Char = L'=';
|
in.Char = L'=';
|
||||||
UASSERT(KeyPress("=") == KeyPress(in));
|
UASSERT(KeyPress("=") == KeyPress(in));
|
||||||
|
*/
|
||||||
|
|
||||||
// Matching keycode suffices
|
// Matching keycode suffices
|
||||||
irr::SEvent::SKeyInput in2;
|
irr::SEvent::SKeyInput in2;
|
||||||
in.Key = in2.Key = irr::KEY_OEM_CLEAR;
|
in.SystemKeyCode = toScancode(irr::KEY_OEM_CLEAR, L'\0');
|
||||||
in.Char = L'\0';
|
in2.SystemKeyCode = toScancode(irr::KEY_OEM_CLEAR, L';');
|
||||||
in2.Char = L';';
|
|
||||||
UASSERT(KeyPress(in) == KeyPress(in2));
|
UASSERT(KeyPress(in) == KeyPress(in2));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user