This commit is contained in:
y5nw 2024-08-12 01:24:51 +02:00
parent 246c35316c
commit cd8dee2779
10 changed files with 219 additions and 158 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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;
} }

View File

@ -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));
} }