Merge pull request #80231 from romlok/input-key-location
Support detecting and mapping ctrl/alt/shift/meta by their left/right physical location
This commit is contained in:
commit
f220d46cdc
|
@ -507,6 +507,10 @@ void register_global_constants() {
|
|||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, KPAD);
|
||||
BIND_CORE_BITFIELD_CLASS_FLAG(KeyModifierMask, KEY_MASK, GROUP_SWITCH);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, UNSPECIFIED);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(KeyLocation, KEY_LOCATION, RIGHT);
|
||||
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, NONE);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, LEFT);
|
||||
BIND_CORE_ENUM_CLASS_CONSTANT(MouseButton, MOUSE_BUTTON, RIGHT);
|
||||
|
|
|
@ -364,6 +364,15 @@ char32_t InputEventKey::get_unicode() const {
|
|||
return unicode;
|
||||
}
|
||||
|
||||
void InputEventKey::set_location(KeyLocation p_key_location) {
|
||||
location = p_key_location;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
KeyLocation InputEventKey::get_location() const {
|
||||
return location;
|
||||
}
|
||||
|
||||
void InputEventKey::set_echo(bool p_enable) {
|
||||
echo = p_enable;
|
||||
emit_changed();
|
||||
|
@ -436,6 +445,23 @@ String InputEventKey::as_text_key_label() const {
|
|||
return mods_text.is_empty() ? kc : mods_text + "+" + kc;
|
||||
}
|
||||
|
||||
String InputEventKey::as_text_location() const {
|
||||
String loc;
|
||||
|
||||
switch (location) {
|
||||
case KeyLocation::LEFT:
|
||||
loc = "left";
|
||||
break;
|
||||
case KeyLocation::RIGHT:
|
||||
loc = "right";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
String InputEventKey::as_text() const {
|
||||
String kc;
|
||||
|
||||
|
@ -464,6 +490,11 @@ String InputEventKey::to_string() {
|
|||
String kc = "";
|
||||
String physical = "false";
|
||||
|
||||
String loc = as_text_location();
|
||||
if (loc.is_empty()) {
|
||||
loc = "unspecified";
|
||||
}
|
||||
|
||||
if (keycode == Key::NONE && physical_keycode == Key::NONE && unicode != 0) {
|
||||
kc = "U+" + String::num_uint64(unicode, 16) + " (" + String::chr(unicode) + ")";
|
||||
} else if (keycode != Key::NONE) {
|
||||
|
@ -478,7 +509,7 @@ String InputEventKey::to_string() {
|
|||
String mods = InputEventWithModifiers::as_text();
|
||||
mods = mods.is_empty() ? "none" : mods;
|
||||
|
||||
return vformat("InputEventKey: keycode=%s, mods=%s, physical=%s, pressed=%s, echo=%s", kc, mods, physical, p, e);
|
||||
return vformat("InputEventKey: keycode=%s, mods=%s, physical=%s, location=%s, pressed=%s, echo=%s", kc, mods, physical, loc, p, e);
|
||||
}
|
||||
|
||||
Ref<InputEventKey> InputEventKey::create_reference(Key p_keycode, bool p_physical) {
|
||||
|
@ -531,6 +562,9 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool p_exact_ma
|
|||
match = keycode == key->keycode;
|
||||
} else if (physical_keycode != Key::NONE) {
|
||||
match = physical_keycode == key->physical_keycode;
|
||||
if (location != KeyLocation::UNSPECIFIED) {
|
||||
match &= location == key->location;
|
||||
}
|
||||
} else {
|
||||
match = false;
|
||||
}
|
||||
|
@ -572,6 +606,9 @@ bool InputEventKey::is_match(const Ref<InputEvent> &p_event, bool p_exact_match)
|
|||
return (keycode == key->keycode) &&
|
||||
(!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask());
|
||||
} else if (physical_keycode != Key::NONE) {
|
||||
if (location != KeyLocation::UNSPECIFIED && location != key->location) {
|
||||
return false;
|
||||
}
|
||||
return (physical_keycode == key->physical_keycode) &&
|
||||
(!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask());
|
||||
} else {
|
||||
|
@ -594,6 +631,9 @@ void InputEventKey::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_unicode", "unicode"), &InputEventKey::set_unicode);
|
||||
ClassDB::bind_method(D_METHOD("get_unicode"), &InputEventKey::get_unicode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_location", "location"), &InputEventKey::set_location);
|
||||
ClassDB::bind_method(D_METHOD("get_location"), &InputEventKey::get_location);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_echo", "echo"), &InputEventKey::set_echo);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_keycode_with_modifiers"), &InputEventKey::get_keycode_with_modifiers);
|
||||
|
@ -603,12 +643,14 @@ void InputEventKey::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("as_text_keycode"), &InputEventKey::as_text_keycode);
|
||||
ClassDB::bind_method(D_METHOD("as_text_physical_keycode"), &InputEventKey::as_text_physical_keycode);
|
||||
ClassDB::bind_method(D_METHOD("as_text_key_label"), &InputEventKey::as_text_key_label);
|
||||
ClassDB::bind_method(D_METHOD("as_text_location"), &InputEventKey::as_text_location);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "keycode"), "set_keycode", "get_keycode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "physical_keycode"), "set_physical_keycode", "get_physical_keycode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "key_label"), "set_key_label", "get_key_label");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "unicode"), "set_unicode", "get_unicode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "location", PROPERTY_HINT_ENUM, "Unspecified,Left,Right"), "set_location", "get_location");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "echo"), "set_echo", "is_echo");
|
||||
}
|
||||
|
||||
|
|
|
@ -157,6 +157,7 @@ class InputEventKey : public InputEventWithModifiers {
|
|||
Key physical_keycode = Key::NONE;
|
||||
Key key_label = Key::NONE;
|
||||
uint32_t unicode = 0; ///unicode
|
||||
KeyLocation location = KeyLocation::UNSPECIFIED;
|
||||
|
||||
bool echo = false; /// true if this is an echo key
|
||||
|
||||
|
@ -178,6 +179,9 @@ public:
|
|||
void set_unicode(char32_t p_unicode);
|
||||
char32_t get_unicode() const;
|
||||
|
||||
void set_location(KeyLocation p_key_location);
|
||||
KeyLocation get_location() const;
|
||||
|
||||
void set_echo(bool p_enable);
|
||||
virtual bool is_echo() const override;
|
||||
|
||||
|
@ -193,6 +197,7 @@ public:
|
|||
virtual String as_text_physical_keycode() const;
|
||||
virtual String as_text_keycode() const;
|
||||
virtual String as_text_key_label() const;
|
||||
virtual String as_text_location() const;
|
||||
virtual String as_text() const override;
|
||||
virtual String to_string() override;
|
||||
|
||||
|
|
|
@ -260,6 +260,12 @@ enum class KeyModifierMask {
|
|||
GROUP_SWITCH = (1 << 30)
|
||||
};
|
||||
|
||||
enum class KeyLocation {
|
||||
UNSPECIFIED,
|
||||
LEFT,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
// To avoid having unnecessary operators, only define the ones that are needed.
|
||||
|
||||
constexpr Key operator-(uint32_t a, Key b) {
|
||||
|
|
|
@ -176,6 +176,7 @@ VARIANT_ENUM_CAST(Variant::Operator);
|
|||
|
||||
VARIANT_ENUM_CAST(Key);
|
||||
VARIANT_BITFIELD_CAST(KeyModifierMask);
|
||||
VARIANT_ENUM_CAST(KeyLocation);
|
||||
|
||||
static inline Key &operator|=(Key &a, BitField<KeyModifierMask> b) {
|
||||
a = static_cast<Key>(static_cast<int>(a) | static_cast<int>(b.operator int64_t()));
|
||||
|
|
|
@ -502,6 +502,7 @@ public:
|
|||
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyAxis)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyButton)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(Key)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(KeyLocation)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(MIDIMessage)
|
||||
VARIANT_ENUM_CLASS_CONSTRUCTOR(MouseButton)
|
||||
|
||||
|
|
|
@ -2374,6 +2374,16 @@
|
|||
<constant name="KEY_MASK_GROUP_SWITCH" value="1073741824" enum="KeyModifierMask" is_bitfield="true">
|
||||
Group Switch key mask.
|
||||
</constant>
|
||||
<constant name="KEY_LOCATION_UNSPECIFIED" value="0" enum="KeyLocation">
|
||||
Used for keys which only appear once, or when a comparison doesn't need to differentiate the [code]LEFT[/code] and [code]RIGHT[/code] versions.
|
||||
For example, when using [method InputEvent.is_match], an event which has [constant KEY_LOCATION_UNSPECIFIED] will match any [enum KeyLocation] on the passed event.
|
||||
</constant>
|
||||
<constant name="KEY_LOCATION_LEFT" value="1" enum="KeyLocation">
|
||||
A key which is to the left of its twin.
|
||||
</constant>
|
||||
<constant name="KEY_LOCATION_RIGHT" value="2" enum="KeyLocation">
|
||||
A key which is to the right of its twin.
|
||||
</constant>
|
||||
<constant name="MOUSE_BUTTON_NONE" value="0" enum="MouseButton">
|
||||
Enum value which doesn't correspond to any mouse button. This is used to initialize [enum MouseButton] properties with a generic state.
|
||||
</constant>
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
Returns a [String] representation of the event's [member keycode] and modifiers.
|
||||
</description>
|
||||
</method>
|
||||
<method name="as_text_location" qualifiers="const">
|
||||
<return type="String" />
|
||||
<description>
|
||||
Returns a [String] representation of the event's [member location]. This will be a blank string if the event is not specific to a location.
|
||||
</description>
|
||||
</method>
|
||||
<method name="as_text_physical_keycode" qualifiers="const">
|
||||
<return type="String" />
|
||||
<description>
|
||||
|
@ -77,6 +83,9 @@
|
|||
+-----+ +-----+
|
||||
[/codeblock]
|
||||
</member>
|
||||
<member name="location" type="int" setter="set_location" getter="get_location" enum="KeyLocation" default="0">
|
||||
Represents the location of a key which has both left and right versions, such as [kbd]Shift[/kbd] or [kbd]Alt[/kbd].
|
||||
</member>
|
||||
<member name="physical_keycode" type="int" setter="set_physical_keycode" getter="get_physical_keycode" enum="Key" default="0">
|
||||
Represents the physical location of a key on the 101/102-key US QWERTY keyboard, which corresponds to one of the [enum Key] constants.
|
||||
To get a human-readable representation of the [InputEventKey], use [method OS.get_keycode_string] in combination with [method DisplayServer.keyboard_get_keycode_from_physical]:
|
||||
|
|
|
@ -79,7 +79,11 @@ String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, boo
|
|||
if (!text.is_empty()) {
|
||||
text += " " + TTR("or") + " ";
|
||||
}
|
||||
text += mods_text + keycode_get_string(key->get_physical_keycode()) + " (" + TTR("Physical") + ")";
|
||||
text += mods_text + keycode_get_string(key->get_physical_keycode()) + " (" + TTR("Physical");
|
||||
if (key->get_location() != KeyLocation::UNSPECIFIED) {
|
||||
text += " " + key->as_text_location();
|
||||
}
|
||||
text += ")";
|
||||
}
|
||||
if (key->get_key_label() != Key::NONE) {
|
||||
if (!text.is_empty()) {
|
||||
|
|
|
@ -64,6 +64,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c
|
|||
bool show_mods = false;
|
||||
bool show_device = false;
|
||||
bool show_key = false;
|
||||
bool show_location = false;
|
||||
|
||||
if (mod.is_valid()) {
|
||||
show_mods = true;
|
||||
|
@ -77,12 +78,17 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c
|
|||
|
||||
if (k.is_valid()) {
|
||||
show_key = true;
|
||||
if (k->get_keycode() == Key::NONE && k->get_physical_keycode() == Key::NONE && k->get_key_label() != Key::NONE) {
|
||||
Key phys_key = k->get_physical_keycode();
|
||||
if (k->get_keycode() == Key::NONE && phys_key == Key::NONE && k->get_key_label() != Key::NONE) {
|
||||
key_mode->select(KEYMODE_UNICODE);
|
||||
} else if (k->get_keycode() != Key::NONE) {
|
||||
key_mode->select(KEYMODE_KEYCODE);
|
||||
} else if (k->get_physical_keycode() != Key::NONE) {
|
||||
} else if (phys_key != Key::NONE) {
|
||||
key_mode->select(KEYMODE_PHY_KEYCODE);
|
||||
if (phys_key == Key::SHIFT || phys_key == Key::CTRL || phys_key == Key::ALT || phys_key == Key::META) {
|
||||
key_location->select((int)k->get_location());
|
||||
show_location = true;
|
||||
}
|
||||
} else {
|
||||
// Invalid key.
|
||||
event = Ref<InputEvent>();
|
||||
|
@ -103,6 +109,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c
|
|||
mod_container->set_visible(show_mods);
|
||||
device_container->set_visible(show_device);
|
||||
key_mode->set_visible(show_key);
|
||||
location_container->set_visible(show_location);
|
||||
additional_options_container->show();
|
||||
|
||||
// Update mode selector based on original key event.
|
||||
|
@ -240,6 +247,9 @@ void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEven
|
|||
k->set_physical_keycode(Key::NONE);
|
||||
k->set_keycode(Key::NONE);
|
||||
}
|
||||
if (key_location->get_selected_id() == (int)KeyLocation::UNSPECIFIED) {
|
||||
k->set_location(KeyLocation::UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventWithModifiers> mod = received_event;
|
||||
|
@ -433,6 +443,17 @@ void InputEventConfigurationDialog::_key_mode_selected(int p_mode) {
|
|||
_set_event(k, original_event);
|
||||
}
|
||||
|
||||
void InputEventConfigurationDialog::_key_location_selected(int p_location) {
|
||||
Ref<InputEventKey> k = event;
|
||||
if (k.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
k->set_location((KeyLocation)p_location);
|
||||
|
||||
_set_event(k, original_event);
|
||||
}
|
||||
|
||||
void InputEventConfigurationDialog::_input_list_item_selected() {
|
||||
TreeItem *selected = input_list_tree->get_selected();
|
||||
|
||||
|
@ -594,6 +615,8 @@ void InputEventConfigurationDialog::popup_and_configure(const Ref<InputEvent> &p
|
|||
|
||||
// Select "All Devices" by default.
|
||||
device_id_option->select(0);
|
||||
// Also "all locations".
|
||||
key_location->select(0);
|
||||
}
|
||||
|
||||
if (!p_current_action_name.is_empty()) {
|
||||
|
@ -726,5 +749,24 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
|
|||
key_mode->hide();
|
||||
additional_options_container->add_child(key_mode);
|
||||
|
||||
// Key Location Selection
|
||||
|
||||
location_container = memnew(HBoxContainer);
|
||||
location_container->hide();
|
||||
|
||||
Label *location_label = memnew(Label);
|
||||
location_label->set_text(TTR("Physical location"));
|
||||
location_container->add_child(location_label);
|
||||
|
||||
key_location = memnew(OptionButton);
|
||||
key_location->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
key_location->add_item(TTR("Any"), (int)KeyLocation::UNSPECIFIED);
|
||||
key_location->add_item(TTR("Left"), (int)KeyLocation::LEFT);
|
||||
key_location->add_item(TTR("Right"), (int)KeyLocation::RIGHT);
|
||||
key_location->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_key_location_selected));
|
||||
|
||||
location_container->add_child(key_location);
|
||||
additional_options_container->add_child(location_container);
|
||||
|
||||
main_vbox->add_child(additional_options_container);
|
||||
}
|
||||
|
|
|
@ -99,6 +99,9 @@ private:
|
|||
|
||||
OptionButton *key_mode = nullptr;
|
||||
|
||||
HBoxContainer *location_container = nullptr;
|
||||
OptionButton *key_location = nullptr;
|
||||
|
||||
void _set_event(const Ref<InputEvent> &p_event, const Ref<InputEvent> &p_original_event, bool p_update_input_list_selection = true);
|
||||
void _on_listen_input_changed(const Ref<InputEvent> &p_event);
|
||||
void _on_listen_focus_changed();
|
||||
|
@ -110,6 +113,7 @@ private:
|
|||
void _mod_toggled(bool p_checked, int p_index);
|
||||
void _autoremap_command_or_control_toggled(bool p_checked);
|
||||
void _key_mode_selected(int p_mode);
|
||||
void _key_location_selected(int p_location);
|
||||
|
||||
void _device_selection_changed(int p_option_button_index);
|
||||
void _set_current_device(int p_device);
|
||||
|
|
|
@ -124,6 +124,7 @@ void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicod
|
|||
ev->set_physical_keycode(physical_keycode);
|
||||
ev->set_key_label(fix_key_label(p_key_label, keycode));
|
||||
ev->set_unicode(fix_unicode(unicode));
|
||||
ev->set_location(godot_location_from_android_code(p_physical_keycode));
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_echo(p_echo);
|
||||
|
||||
|
|
|
@ -38,3 +38,12 @@ Key godot_code_from_android_code(unsigned int p_code) {
|
|||
}
|
||||
return Key::UNKNOWN;
|
||||
}
|
||||
|
||||
KeyLocation godot_location_from_android_code(unsigned int p_code) {
|
||||
for (int i = 0; android_godot_location_pairs[i].android_code != AKEYCODE_MAX; i++) {
|
||||
if (android_godot_location_pairs[i].android_code == p_code) {
|
||||
return android_godot_location_pairs[i].godot_code;
|
||||
}
|
||||
}
|
||||
return KeyLocation::UNSPECIFIED;
|
||||
}
|
||||
|
|
|
@ -177,4 +177,24 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
|
|||
|
||||
Key godot_code_from_android_code(unsigned int p_code);
|
||||
|
||||
// Key location determination.
|
||||
struct AndroidGodotLocationPair {
|
||||
unsigned int android_code = 0;
|
||||
KeyLocation godot_code = KeyLocation::UNSPECIFIED;
|
||||
};
|
||||
|
||||
static AndroidGodotLocationPair android_godot_location_pairs[] = {
|
||||
{ AKEYCODE_ALT_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_ALT_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_SHIFT_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_SHIFT_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_CTRL_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_CTRL_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_META_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_META_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_MAX, KeyLocation::UNSPECIFIED }
|
||||
};
|
||||
|
||||
KeyLocation godot_location_from_android_code(unsigned int p_code);
|
||||
|
||||
#endif // ANDROID_KEYS_UTILS_H
|
||||
|
|
|
@ -119,7 +119,7 @@ public:
|
|||
|
||||
// MARK: Keyboard
|
||||
|
||||
void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed);
|
||||
void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location);
|
||||
bool is_keyboard_active() const;
|
||||
|
||||
// MARK: Motion
|
||||
|
|
|
@ -247,7 +247,7 @@ void DisplayServerIOS::touches_canceled(int p_idx) {
|
|||
|
||||
// MARK: Keyboard
|
||||
|
||||
void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed) {
|
||||
void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location) {
|
||||
Ref<InputEventKey> ev;
|
||||
ev.instantiate();
|
||||
ev->set_echo(false);
|
||||
|
@ -270,6 +270,7 @@ void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_ph
|
|||
ev->set_key_label(p_unshifted);
|
||||
ev->set_physical_keycode(p_physical);
|
||||
ev->set_unicode(fix_unicode(p_char));
|
||||
ev->set_location(p_location);
|
||||
perform_event(ev);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ class KeyMappingIOS {
|
|||
public:
|
||||
static void initialize();
|
||||
static Key remap_key(CFIndex p_keycode);
|
||||
static KeyLocation key_location(CFIndex p_keycode);
|
||||
};
|
||||
|
||||
#endif // KEY_MAPPING_IOS_H
|
||||
|
|
|
@ -38,6 +38,7 @@ struct HashMapHasherKeys {
|
|||
};
|
||||
|
||||
HashMap<CFIndex, Key, HashMapHasherKeys> keyusage_map;
|
||||
HashMap<CFIndex, KeyLocation, HashMapHasherKeys> location_map;
|
||||
|
||||
void KeyMappingIOS::initialize() {
|
||||
if (@available(iOS 13.4, *)) {
|
||||
|
@ -172,6 +173,15 @@ void KeyMappingIOS::initialize() {
|
|||
keyusage_map[0x029D] = Key::GLOBE; // "Globe" key on smart connector / Mac keyboard.
|
||||
keyusage_map[UIKeyboardHIDUsageKeyboardLANG1] = Key::JIS_EISU;
|
||||
keyusage_map[UIKeyboardHIDUsageKeyboardLANG2] = Key::JIS_KANA;
|
||||
|
||||
location_map[UIKeyboardHIDUsageKeyboardLeftAlt] = KeyLocation::LEFT;
|
||||
location_map[UIKeyboardHIDUsageKeyboardRightAlt] = KeyLocation::RIGHT;
|
||||
location_map[UIKeyboardHIDUsageKeyboardLeftControl] = KeyLocation::LEFT;
|
||||
location_map[UIKeyboardHIDUsageKeyboardRightControl] = KeyLocation::RIGHT;
|
||||
location_map[UIKeyboardHIDUsageKeyboardLeftShift] = KeyLocation::LEFT;
|
||||
location_map[UIKeyboardHIDUsageKeyboardRightShift] = KeyLocation::RIGHT;
|
||||
location_map[UIKeyboardHIDUsageKeyboardLeftGUI] = KeyLocation::LEFT;
|
||||
location_map[UIKeyboardHIDUsageKeyboardRightGUI] = KeyLocation::RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,3 +194,13 @@ Key KeyMappingIOS::remap_key(CFIndex p_keycode) {
|
|||
}
|
||||
return Key::NONE;
|
||||
}
|
||||
|
||||
KeyLocation KeyMappingIOS::key_location(CFIndex p_keycode) {
|
||||
if (@available(iOS 13.4, *)) {
|
||||
const KeyLocation *location = location_map.getptr(p_keycode);
|
||||
if (location) {
|
||||
return *location;
|
||||
}
|
||||
}
|
||||
return KeyLocation::UNSPECIFIED;
|
||||
}
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
|
||||
- (void)deleteText:(NSInteger)charactersToDelete {
|
||||
for (int i = 0; i < charactersToDelete; i++) {
|
||||
DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, true);
|
||||
DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, false);
|
||||
DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,8 +137,8 @@
|
|||
key = Key::SPACE;
|
||||
}
|
||||
|
||||
DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, true);
|
||||
DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, false);
|
||||
DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,13 +78,15 @@
|
|||
us = u32lbl[0];
|
||||
}
|
||||
|
||||
KeyLocation location = KeyMappingIOS::key_location(press.key.keyCode);
|
||||
|
||||
if (!u32text.is_empty() && !u32text.begins_with("UIKey")) {
|
||||
for (int i = 0; i < u32text.length(); i++) {
|
||||
const char32_t c = u32text[i];
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true);
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
|
||||
}
|
||||
} else {
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true);
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +112,9 @@
|
|||
us = u32lbl[0];
|
||||
}
|
||||
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false);
|
||||
KeyLocation location = KeyMappingIOS::key_location(press.key.keyCode);
|
||||
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3512,6 +3512,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
|
|||
bool keypress = xkeyevent->type == KeyPress;
|
||||
Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
|
||||
Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
|
||||
KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);
|
||||
|
||||
if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
|
||||
keycode -= 'a' - 'A';
|
||||
|
@ -3549,6 +3550,8 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
|
|||
k->set_unicode(fix_unicode(tmp[i]));
|
||||
}
|
||||
|
||||
k->set_location(key_location);
|
||||
|
||||
k->set_echo(false);
|
||||
|
||||
if (k->get_keycode() == Key::BACKTAB) {
|
||||
|
@ -3574,6 +3577,8 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
|
|||
Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
|
||||
Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
|
||||
|
||||
KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);
|
||||
|
||||
/* Phase 3, obtain a unicode character from the keysym */
|
||||
|
||||
// KeyMappingX11 also translates keysym to unicode.
|
||||
|
@ -3673,6 +3678,9 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
|
|||
if (keypress) {
|
||||
k->set_unicode(fix_unicode(unicode));
|
||||
}
|
||||
|
||||
k->set_location(key_location);
|
||||
|
||||
k->set_echo(p_echo);
|
||||
|
||||
if (k->get_keycode() == Key::BACKTAB) {
|
||||
|
|
|
@ -1113,6 +1113,20 @@ void KeyMappingX11::initialize() {
|
|||
xkeysym_unicode_map[0x13BD] = 0x0153;
|
||||
xkeysym_unicode_map[0x13BE] = 0x0178;
|
||||
xkeysym_unicode_map[0x20AC] = 0x20AC;
|
||||
|
||||
// Scancode to physical location map.
|
||||
// Ctrl.
|
||||
location_map[0x25] = KeyLocation::LEFT;
|
||||
location_map[0x69] = KeyLocation::RIGHT;
|
||||
// Shift.
|
||||
location_map[0x32] = KeyLocation::LEFT;
|
||||
location_map[0x3E] = KeyLocation::RIGHT;
|
||||
// Alt.
|
||||
location_map[0x40] = KeyLocation::LEFT;
|
||||
location_map[0x6C] = KeyLocation::RIGHT;
|
||||
// Meta.
|
||||
location_map[0x85] = KeyLocation::LEFT;
|
||||
location_map[0x86] = KeyLocation::RIGHT;
|
||||
}
|
||||
|
||||
Key KeyMappingX11::get_keycode(KeySym p_keysym) {
|
||||
|
@ -1173,3 +1187,11 @@ char32_t KeyMappingX11::get_unicode_from_keysym(KeySym p_keysym) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
KeyLocation KeyMappingX11::get_location(unsigned int p_code) {
|
||||
const KeyLocation *location = location_map.getptr(p_code);
|
||||
if (location) {
|
||||
return *location;
|
||||
}
|
||||
return KeyLocation::UNSPECIFIED;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ class KeyMappingX11 {
|
|||
static inline HashMap<unsigned int, Key, HashMapHasherKeys> scancode_map;
|
||||
static inline HashMap<Key, unsigned int, HashMapHasherKeys> scancode_map_inv;
|
||||
static inline HashMap<KeySym, char32_t, HashMapHasherKeys> xkeysym_unicode_map;
|
||||
static inline HashMap<unsigned int, KeyLocation, HashMapHasherKeys> location_map;
|
||||
|
||||
KeyMappingX11() {}
|
||||
|
||||
|
@ -64,6 +65,7 @@ public:
|
|||
static unsigned int get_xlibcode(Key p_keysym);
|
||||
static Key get_scancode(unsigned int p_code);
|
||||
static char32_t get_unicode_from_keysym(KeySym p_keysym);
|
||||
static KeyLocation get_location(unsigned int p_code);
|
||||
};
|
||||
|
||||
#endif // KEY_MAPPING_X11_H
|
||||
|
|
|
@ -75,6 +75,7 @@ public:
|
|||
Key physical_keycode = Key::NONE;
|
||||
Key key_label = Key::NONE;
|
||||
uint32_t unicode = 0;
|
||||
KeyLocation location = KeyLocation::UNSPECIFIED;
|
||||
};
|
||||
|
||||
struct WindowData {
|
||||
|
|
|
@ -478,6 +478,7 @@ void DisplayServerMacOS::_process_key_events() {
|
|||
k->set_physical_keycode(ke.physical_keycode);
|
||||
k->set_key_label(ke.key_label);
|
||||
k->set_unicode(ke.unicode);
|
||||
k->set_location(ke.location);
|
||||
|
||||
_push_input(k);
|
||||
} else {
|
||||
|
@ -506,6 +507,7 @@ void DisplayServerMacOS::_process_key_events() {
|
|||
k->set_keycode(ke.keycode);
|
||||
k->set_physical_keycode(ke.physical_keycode);
|
||||
k->set_key_label(ke.key_label);
|
||||
k->set_location(ke.location);
|
||||
|
||||
if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == Key::NONE) {
|
||||
k->set_unicode(key_event_buffer[i + 1].unicode);
|
||||
|
|
|
@ -606,6 +606,7 @@
|
|||
ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
|
||||
ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
|
||||
ke.unicode = 0;
|
||||
ke.location = KeyMappingMacOS::translate_location([event keyCode]);
|
||||
ke.raw = false;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
|
@ -671,6 +672,7 @@
|
|||
ke.physical_keycode = KeyMappingMacOS::translate_key(key);
|
||||
ke.key_label = KeyMappingMacOS::remap_key(key, mod, true);
|
||||
ke.unicode = 0;
|
||||
ke.location = KeyMappingMacOS::translate_location(key);
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
}
|
||||
|
@ -698,6 +700,7 @@
|
|||
ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
|
||||
ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
|
||||
ke.unicode = 0;
|
||||
ke.location = KeyMappingMacOS::translate_location([event keyCode]);
|
||||
ke.raw = true;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
static Key translate_key(unsigned int p_key);
|
||||
static unsigned int unmap_key(Key p_key);
|
||||
static Key remap_key(unsigned int p_key, unsigned int p_state, bool p_unicode);
|
||||
static KeyLocation translate_location(unsigned int p_key);
|
||||
|
||||
// Mapping for menu shortcuts.
|
||||
static String keycode_get_native_string(Key p_keycode);
|
||||
|
|
|
@ -46,6 +46,7 @@ HashSet<unsigned int> numpad_keys;
|
|||
HashMap<unsigned int, Key, HashMapHasherKeys> keysym_map;
|
||||
HashMap<Key, unsigned int, HashMapHasherKeys> keysym_map_inv;
|
||||
HashMap<Key, char32_t, HashMapHasherKeys> keycode_map;
|
||||
HashMap<unsigned int, KeyLocation, HashMapHasherKeys> location_map;
|
||||
|
||||
void KeyMappingMacOS::initialize() {
|
||||
numpad_keys.insert(0x41); //kVK_ANSI_KeypadDecimal
|
||||
|
@ -321,6 +322,20 @@ void KeyMappingMacOS::initialize() {
|
|||
keycode_map[Key::BAR] = '|';
|
||||
keycode_map[Key::BRACERIGHT] = '}';
|
||||
keycode_map[Key::ASCIITILDE] = '~';
|
||||
|
||||
// Keysym -> physical location.
|
||||
// Ctrl.
|
||||
location_map[0x3b] = KeyLocation::LEFT;
|
||||
location_map[0x3e] = KeyLocation::RIGHT;
|
||||
// Shift.
|
||||
location_map[0x38] = KeyLocation::LEFT;
|
||||
location_map[0x3c] = KeyLocation::RIGHT;
|
||||
// Alt/Option.
|
||||
location_map[0x3a] = KeyLocation::LEFT;
|
||||
location_map[0x3d] = KeyLocation::RIGHT;
|
||||
// Meta/Command (yes, right < left).
|
||||
location_map[0x36] = KeyLocation::RIGHT;
|
||||
location_map[0x37] = KeyLocation::LEFT;
|
||||
}
|
||||
|
||||
bool KeyMappingMacOS::is_numpad_key(unsigned int p_key) {
|
||||
|
@ -396,6 +411,15 @@ Key KeyMappingMacOS::remap_key(unsigned int p_key, unsigned int p_state, bool p_
|
|||
}
|
||||
}
|
||||
|
||||
// Translates a macOS keycode to a Godot key location.
|
||||
KeyLocation KeyMappingMacOS::translate_location(unsigned int p_key) {
|
||||
const KeyLocation *location = location_map.getptr(p_key);
|
||||
if (location) {
|
||||
return *location;
|
||||
}
|
||||
return KeyLocation::UNSPECIFIED;
|
||||
}
|
||||
|
||||
String KeyMappingMacOS::keycode_get_native_string(Key p_keycode) {
|
||||
const char32_t *key = keycode_map.getptr(p_keycode);
|
||||
if (key) {
|
||||
|
|
|
@ -187,6 +187,7 @@ void DisplayServerWeb::_key_callback(const String &p_key_event_code, const Strin
|
|||
|
||||
Key keycode = dom_code2godot_scancode(p_key_event_code.utf8().get_data(), p_key_event_key.utf8().get_data(), false);
|
||||
Key scancode = dom_code2godot_scancode(p_key_event_code.utf8().get_data(), p_key_event_key.utf8().get_data(), true);
|
||||
KeyLocation location = dom_code2godot_key_location(p_key_event_code.utf8().get_data());
|
||||
|
||||
DisplayServerWeb::KeyEvent ke;
|
||||
|
||||
|
@ -197,6 +198,7 @@ void DisplayServerWeb::_key_callback(const String &p_key_event_code, const Strin
|
|||
ke.physical_keycode = scancode;
|
||||
ke.key_label = fix_key_label(c, keycode);
|
||||
ke.unicode = fix_unicode(c);
|
||||
ke.location = location;
|
||||
ke.mod = p_modifiers;
|
||||
|
||||
if (ds->key_event_pos >= ds->key_event_buffer.size()) {
|
||||
|
@ -1383,6 +1385,7 @@ void DisplayServerWeb::process_events() {
|
|||
ev->set_physical_keycode(ke.physical_keycode);
|
||||
ev->set_key_label(ke.key_label);
|
||||
ev->set_unicode(ke.unicode);
|
||||
ev->set_location(ke.location);
|
||||
if (ke.raw) {
|
||||
dom2godot_mod(ev, ke.mod, ke.keycode);
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ private:
|
|||
Key physical_keycode = Key::NONE;
|
||||
Key key_label = Key::NONE;
|
||||
uint32_t unicode = 0;
|
||||
KeyLocation location = KeyLocation::UNSPECIFIED;
|
||||
int mod = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -223,3 +223,24 @@ Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
|
|||
return Key::NONE;
|
||||
#undef DOM2GODOT
|
||||
}
|
||||
|
||||
KeyLocation dom_code2godot_key_location(EM_UTF8 const p_code[32]) {
|
||||
#define DOM2GODOT(m_str, m_godot_code) \
|
||||
if (memcmp((const void *)m_str, (void *)p_code, strlen(m_str) + 1) == 0) { \
|
||||
return KeyLocation::m_godot_code; \
|
||||
}
|
||||
|
||||
DOM2GODOT("AltLeft", LEFT);
|
||||
DOM2GODOT("AltRight", RIGHT);
|
||||
DOM2GODOT("ControlLeft", LEFT);
|
||||
DOM2GODOT("ControlRight", RIGHT);
|
||||
DOM2GODOT("MetaLeft", LEFT);
|
||||
DOM2GODOT("MetaRight", RIGHT);
|
||||
DOM2GODOT("OSLeft", LEFT);
|
||||
DOM2GODOT("OSRight", RIGHT);
|
||||
DOM2GODOT("ShiftLeft", LEFT);
|
||||
DOM2GODOT("ShiftRight", RIGHT);
|
||||
|
||||
return KeyLocation::UNSPECIFIED;
|
||||
#undef DOM2GODOT
|
||||
}
|
||||
|
|
|
@ -169,20 +169,26 @@ DisplayServer::WindowID DisplayServerWindows::_get_focused_window_or_popup() con
|
|||
void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) {
|
||||
use_raw_input = true;
|
||||
|
||||
RAWINPUTDEVICE rid[1] = {};
|
||||
rid[0].usUsagePage = 0x01;
|
||||
rid[0].usUsage = 0x02;
|
||||
RAWINPUTDEVICE rid[2] = {};
|
||||
rid[0].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
|
||||
rid[0].usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
|
||||
rid[0].dwFlags = 0;
|
||||
|
||||
rid[1].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
|
||||
rid[1].usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD
|
||||
rid[1].dwFlags = 0;
|
||||
|
||||
if (p_target_window != INVALID_WINDOW_ID && windows.has(p_target_window)) {
|
||||
// Follow the defined window
|
||||
rid[0].hwndTarget = windows[p_target_window].hWnd;
|
||||
rid[1].hwndTarget = windows[p_target_window].hWnd;
|
||||
} else {
|
||||
// Follow the keyboard focus
|
||||
rid[0].hwndTarget = 0;
|
||||
rid[1].hwndTarget = 0;
|
||||
}
|
||||
|
||||
if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
|
||||
if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE) {
|
||||
// Registration failed.
|
||||
use_raw_input = false;
|
||||
}
|
||||
|
@ -3348,7 +3354,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
|
|||
|
||||
} break;
|
||||
case WM_INPUT: {
|
||||
if (mouse_mode != MOUSE_MODE_CAPTURED || !use_raw_input) {
|
||||
if (!use_raw_input) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3366,7 +3372,32 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
|
|||
|
||||
RAWINPUT *raw = (RAWINPUT *)lpb;
|
||||
|
||||
if (raw->header.dwType == RIM_TYPEMOUSE) {
|
||||
if (raw->header.dwType == RIM_TYPEKEYBOARD) {
|
||||
if (raw->data.keyboard.VKey == VK_SHIFT) {
|
||||
// If multiple Shifts are held down at the same time,
|
||||
// Windows natively only sends a KEYUP for the last one to be released.
|
||||
if (raw->data.keyboard.Flags & RI_KEY_BREAK) {
|
||||
if (GetAsyncKeyState(VK_SHIFT) < 0) {
|
||||
// A Shift is released, but another Shift is still held
|
||||
ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
|
||||
|
||||
KeyEvent ke;
|
||||
ke.shift = false;
|
||||
ke.alt = alt_mem;
|
||||
ke.control = control_mem;
|
||||
ke.meta = meta_mem;
|
||||
ke.uMsg = WM_KEYUP;
|
||||
ke.window_id = window_id;
|
||||
|
||||
ke.wParam = VK_SHIFT;
|
||||
// data.keyboard.MakeCode -> 0x2A - left shift, 0x36 - right shift.
|
||||
// Bit 30 -> key was previously down, bit 31 -> key is being released.
|
||||
ke.lParam = raw->data.keyboard.MakeCode << 16 | 1 << 30 | 1 << 31;
|
||||
key_event_buffer[key_event_pos++] = ke;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mouse_mode == MOUSE_MODE_CAPTURED && raw->header.dwType == RIM_TYPEMOUSE) {
|
||||
Ref<InputEventMouseMotion> mm;
|
||||
mm.instantiate();
|
||||
|
||||
|
@ -4371,6 +4402,7 @@ void DisplayServerWindows::_process_key_events() {
|
|||
}
|
||||
Key key_label = keycode;
|
||||
Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
|
||||
KeyLocation location = KeyMappingWindows::get_location((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
|
||||
|
||||
static BYTE keyboard_state[256];
|
||||
memset(keyboard_state, 0, 256);
|
||||
|
@ -4397,6 +4429,7 @@ void DisplayServerWindows::_process_key_events() {
|
|||
}
|
||||
k->set_keycode(keycode);
|
||||
k->set_physical_keycode(physical_keycode);
|
||||
k->set_location(location);
|
||||
k->set_key_label(key_label);
|
||||
|
||||
if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
|
||||
|
|
|
@ -46,6 +46,7 @@ HashMap<unsigned int, Key, HashMapHasherKeys> vk_map;
|
|||
HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map;
|
||||
HashMap<Key, unsigned int, HashMapHasherKeys> scansym_map_inv;
|
||||
HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map_ext;
|
||||
HashMap<unsigned int, KeyLocation, HashMapHasherKeys> location_map;
|
||||
|
||||
void KeyMappingWindows::initialize() {
|
||||
// VK_LBUTTON (0x01)
|
||||
|
@ -380,6 +381,15 @@ void KeyMappingWindows::initialize() {
|
|||
scansym_map_ext[0x6C] = Key::LAUNCHMAIL;
|
||||
scansym_map_ext[0x6D] = Key::LAUNCHMEDIA;
|
||||
scansym_map_ext[0x78] = Key::MEDIARECORD;
|
||||
|
||||
// Scancode to physical location map.
|
||||
// Shift.
|
||||
location_map[0x2A] = KeyLocation::LEFT;
|
||||
location_map[0x36] = KeyLocation::RIGHT;
|
||||
// Meta.
|
||||
location_map[0x5B] = KeyLocation::LEFT;
|
||||
location_map[0x5C] = KeyLocation::RIGHT;
|
||||
// Ctrl and Alt must be handled differently.
|
||||
}
|
||||
|
||||
Key KeyMappingWindows::get_keysym(unsigned int p_code) {
|
||||
|
@ -424,3 +434,16 @@ bool KeyMappingWindows::is_extended_key(unsigned int p_code) {
|
|||
p_code == VK_RIGHT ||
|
||||
p_code == VK_DOWN;
|
||||
}
|
||||
|
||||
KeyLocation KeyMappingWindows::get_location(unsigned int p_code, bool p_extended) {
|
||||
// Right- ctrl and alt have the same scancode as left, but are in the extended keys.
|
||||
const Key *key = scansym_map.getptr(p_code);
|
||||
if (key && (*key == Key::CTRL || *key == Key::ALT)) {
|
||||
return p_extended ? KeyLocation::RIGHT : KeyLocation::LEFT;
|
||||
}
|
||||
const KeyLocation *location = location_map.getptr(p_code);
|
||||
if (location) {
|
||||
return *location;
|
||||
}
|
||||
return KeyLocation::UNSPECIFIED;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
static unsigned int get_scancode(Key p_keycode);
|
||||
static Key get_scansym(unsigned int p_code, bool p_extended);
|
||||
static bool is_extended_key(unsigned int p_code);
|
||||
static KeyLocation get_location(unsigned int p_code, bool p_extended);
|
||||
};
|
||||
|
||||
#endif // KEY_MAPPING_WINDOWS_H
|
||||
|
|
|
@ -85,6 +85,16 @@ TEST_CASE("[InputEventKey] Key correctly stores and retrieves unicode") {
|
|||
CHECK(key.get_unicode() != 'y');
|
||||
}
|
||||
|
||||
TEST_CASE("[InputEventKey] Key correctly stores and retrieves location") {
|
||||
InputEventKey key;
|
||||
|
||||
CHECK(key.get_location() == KeyLocation::UNSPECIFIED);
|
||||
|
||||
key.set_location(KeyLocation::LEFT);
|
||||
CHECK(key.get_location() == KeyLocation::LEFT);
|
||||
CHECK(key.get_location() != KeyLocation::RIGHT);
|
||||
}
|
||||
|
||||
TEST_CASE("[InputEventKey] Key correctly stores and checks echo") {
|
||||
InputEventKey key;
|
||||
|
||||
|
@ -144,32 +154,36 @@ TEST_CASE("[InputEventKey] Key correctly converts itself to text") {
|
|||
TEST_CASE("[InputEventKey] Key correctly converts its state to a string representation") {
|
||||
InputEventKey none_key;
|
||||
|
||||
CHECK(none_key.to_string() == "InputEventKey: keycode=(Unset), mods=none, physical=false, pressed=false, echo=false");
|
||||
CHECK(none_key.to_string() == "InputEventKey: keycode=(Unset), mods=none, physical=false, location=unspecified, pressed=false, echo=false");
|
||||
// Set physical key to Escape.
|
||||
none_key.set_physical_keycode(Key::ESCAPE);
|
||||
CHECK(none_key.to_string() == "InputEventKey: keycode=4194305 (Escape), mods=none, physical=true, pressed=false, echo=false");
|
||||
CHECK(none_key.to_string() == "InputEventKey: keycode=4194305 (Escape), mods=none, physical=true, location=unspecified, pressed=false, echo=false");
|
||||
|
||||
InputEventKey key;
|
||||
|
||||
// Set physical to None, set keycode to Space.
|
||||
key.set_keycode(Key::SPACE);
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=false, echo=false");
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=unspecified, pressed=false, echo=false");
|
||||
|
||||
// Set location
|
||||
key.set_location(KeyLocation::RIGHT);
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=right, pressed=false, echo=false");
|
||||
|
||||
// Set pressed to true.
|
||||
key.set_pressed(true);
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=true, echo=false");
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=right, pressed=true, echo=false");
|
||||
|
||||
// set echo to true.
|
||||
key.set_echo(true);
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=true, echo=true");
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=right, pressed=true, echo=true");
|
||||
|
||||
// Press Ctrl and Alt.
|
||||
key.set_ctrl_pressed(true);
|
||||
key.set_alt_pressed(true);
|
||||
#ifdef MACOS_ENABLED
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Option, physical=false, pressed=true, echo=true");
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Option, physical=false, location=right, pressed=true, echo=true");
|
||||
#else
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Alt, physical=false, pressed=true, echo=true");
|
||||
CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Alt, physical=false, location=right, pressed=true, echo=true");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -291,6 +305,34 @@ TEST_CASE("[IsMatch] Keys are correctly matched") {
|
|||
|
||||
CHECK(key2.is_match(match, true) == true);
|
||||
CHECK(key2.is_match(no_match, true) == false);
|
||||
|
||||
// Physical key with location.
|
||||
InputEventKey key3;
|
||||
key3.set_keycode(Key::NONE);
|
||||
key3.set_physical_keycode(Key::SHIFT);
|
||||
|
||||
Ref<InputEventKey> loc_ref = key.create_reference(Key::NONE);
|
||||
|
||||
loc_ref->set_keycode(Key::SHIFT);
|
||||
loc_ref->set_physical_keycode(Key::SHIFT);
|
||||
|
||||
CHECK(key3.is_match(loc_ref, false) == true);
|
||||
key3.set_location(KeyLocation::UNSPECIFIED);
|
||||
CHECK(key3.is_match(loc_ref, false) == true);
|
||||
|
||||
loc_ref->set_location(KeyLocation::LEFT);
|
||||
CHECK(key3.is_match(loc_ref, false) == true);
|
||||
|
||||
key3.set_location(KeyLocation::LEFT);
|
||||
CHECK(key3.is_match(loc_ref, false) == true);
|
||||
|
||||
key3.set_location(KeyLocation::RIGHT);
|
||||
CHECK(key3.is_match(loc_ref, false) == false);
|
||||
|
||||
// Keycode key with location.
|
||||
key3.set_physical_keycode(Key::NONE);
|
||||
key3.set_keycode(Key::SHIFT);
|
||||
CHECK(key3.is_match(loc_ref, false) == true);
|
||||
}
|
||||
} // namespace TestInputEventKey
|
||||
|
||||
|
|
Loading…
Reference in New Issue