Skip to content

Commit

Permalink
Add mouse motion to input map.
Browse files Browse the repository at this point in the history
Copy Mouse Motion Input Map PR

Hide modifier keys from mouse motion binding menu
  • Loading branch information
addmix committed Aug 21, 2024
1 parent 3b3d622 commit 71fc074
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 22 deletions.
14 changes: 14 additions & 0 deletions core/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,20 @@ void Input::flush_frame_parsed_events() {
}
#endif

void Input::clear_mouse_axes_action_state() {
for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) {
const List<Ref<InputEvent>> *inputs = InputMap::get_singleton()->action_get_events(E.key);
if (inputs) {
for (const Ref<InputEvent> &input : *inputs) {
Ref<InputEventMouseMotion> mm = input;
if (mm.is_valid()) {
action_release(E.key);
}
}
}
}
}

void Input::flush_buffered_events() {
_THREAD_SAFE_METHOD_

Expand Down
1 change: 1 addition & 0 deletions core/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ class Input : public Object {
#ifdef DEBUG_ENABLED
void flush_frame_parsed_events();
#endif
void clear_mouse_axes_action_state();
void flush_buffered_events();
bool is_agile_input_event_flushing();
void set_agile_input_event_flushing(bool p_enable);
Expand Down
34 changes: 34 additions & 0 deletions core/input/input_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,40 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co
return mm;
}

bool InputEventMouseMotion::action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_null()) {
return false;
}

Vector2 action_rel = get_relative();
Vector2 event_rel = mm->get_relative();

if (event_rel.dot(action_rel) <= 0) {
return false;
}

Vector2 action_value = action_rel * event_rel;
float strength = action_value.x + action_value.y;

if (r_pressed != nullptr) {
*r_pressed = strength != 0;
}
if (r_strength != nullptr) {
*r_strength = strength;
}
if (r_raw_strength != nullptr) {
*r_raw_strength = strength;
}

return true;
}

bool InputEventMouseMotion::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const {
Ref<InputEventMouseMotion> mm = p_event;
return mm.is_valid() && mm->get_relative().dot(get_relative()) > 0;
}

String InputEventMouseMotion::as_text() const {
return vformat(RTR("Mouse motion at position (%s) with velocity (%s)"), String(get_position()), String(get_velocity()));
}
Expand Down
4 changes: 4 additions & 0 deletions core/input/input_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ class InputEventMouseMotion : public InputEventMouse {
Vector2 get_screen_velocity() const;

virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;

virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;

virtual String as_text() const override;
virtual String to_string() override;

Expand Down
12 changes: 12 additions & 0 deletions editor/event_listener_line_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, boo

String text;
Ref<InputEventKey> key = p_event;
Ref<InputEventMouseMotion> mouse_motion = p_event;
if (key.is_valid()) {
String mods_text = key->InputEventWithModifiers::as_text();
mods_text = mods_text.is_empty() ? mods_text : mods_text + "+";
Expand Down Expand Up @@ -95,6 +96,17 @@ String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, boo
if (text.is_empty()) {
text = "(" + TTR("Unset") + ")";
}
} else if (mouse_motion.is_valid()) {
Vector2 rel = mouse_motion->get_relative();
if (rel.x < 0){
text = TTR("Mouse X (Left)");
} else if (rel.x > 0){
text = TTR("Mouse X (Right)");
} else if (rel.y < 0){
text = TTR("Mouse Y (Up)");
} else {
text = TTR("Mouse Y (Down)");
}
} else {
text = p_event->as_text();
}
Expand Down
5 changes: 3 additions & 2 deletions editor/event_listener_line_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ enum InputType {
INPUT_KEY = 1,
INPUT_MOUSE_BUTTON = 2,
INPUT_JOY_BUTTON = 4,
INPUT_JOY_MOTION = 8
INPUT_JOY_MOTION = 8,
INPUT_MOUSE_MOTION = 16,
};

class EventListenerLineEdit : public LineEdit {
GDCLASS(EventListenerLineEdit, LineEdit)

int allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;
int allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION | INPUT_MOUSE_MOTION;
bool ignore_next_event = true;
bool share_keycodes = false;
Ref<InputEvent> event;
Expand Down
58 changes: 54 additions & 4 deletions editor/input_event_configuration_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c

Ref<InputEventKey> k = p_event;
Ref<InputEventMouseButton> mb = p_event;
Ref<InputEventMouseMotion> mm = p_event;
Ref<InputEventJoypadButton> joyb = p_event;
Ref<InputEventJoypadMotion> joym = p_event;
Ref<InputEventWithModifiers> mod = p_event;
Expand All @@ -76,6 +77,10 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c
autoremap_command_or_control_checkbox->set_pressed(mod->is_command_or_control_autoremap());
}

if (mm.is_valid()) {
show_mods = false;
}

if (k.is_valid()) {
show_key = true;
Key phys_key = k->get_physical_keycode();
Expand Down Expand Up @@ -110,7 +115,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c
device_container->set_visible(show_device);
key_mode->set_visible(show_key);
location_container->set_visible(show_location);
additional_options_container->show();
additional_options_container->set_visible(show_mods or show_device or show_key or show_location);

// Update mode selector based on original key event.
Ref<InputEventKey> ko = p_original_event;
Expand Down Expand Up @@ -148,7 +153,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c
}

// Update selected item in input list.
if (p_update_input_list_selection && (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid())) {
if (p_update_input_list_selection && (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid() || mm.is_valid())) {
in_tree_update = true;
TreeItem *category = input_list_tree->get_root()->get_first_child();
while (category) {
Expand All @@ -170,7 +175,8 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, c
bool joyb_match = joyb.is_valid() && Variant(joyb->get_button_index()) == input_item->get_meta("__index");
bool joym_match = joym.is_valid() && Variant(joym->get_axis()) == input_item->get_meta("__axis") && joym->get_axis_value() == (float)input_item->get_meta("__value");
bool mb_match = mb.is_valid() && Variant(mb->get_button_index()) == input_item->get_meta("__index");
if (key_match || joyb_match || joym_match || mb_match) {
bool mm_match = mm.is_valid() && mm->get_relative()[input_item->get_meta("__axis")] != 0;
if (key_match || joyb_match || joym_match || mb_match || mm_match) {
category->set_collapsed(false);
input_item->select(0);
input_list_tree->ensure_cursor_is_visible();
Expand Down Expand Up @@ -319,6 +325,35 @@ void InputEventConfigurationDialog::_update_input_list() {
}
}

if (allowed_input_types & INPUT_MOUSE_MOTION) {
TreeItem *mouse_motion_root = input_list_tree->create_item(root);
mouse_motion_root->set_text(0, TTR("Mouse Axes"));
mouse_motion_root->set_icon(0, icon_cache.mouse);
mouse_motion_root->set_collapsed(collapse);
mouse_motion_root->set_meta("__type", INPUT_MOUSE_MOTION);

for (int i = 0; i < 4; i++) {
int axis = i / 2;
int direction = (i & 1) ? 1 : -1;

String desc;
if (axis == 0) {
desc = direction == 1 ? TTR("Mouse X (Right)") : TTR("Mouse X (Left)");
} else {
desc = direction == 1 ? TTR("Mouse Y (Down)") : TTR("Mouse Y (Up)");
}

if (!search_term.is_empty() && desc.findn(search_term) == -1) {
continue;
}

TreeItem *item = input_list_tree->create_item(mouse_motion_root);
item->set_text(0, desc);
item->set_meta("__axis", axis);
item->set_meta("__value", direction);
}
}

if (allowed_input_types & INPUT_JOY_BUTTON) {
TreeItem *joyb_root = input_list_tree->create_item(root);
joyb_root->set_text(0, TTR("Joypad Buttons"));
Expand Down Expand Up @@ -524,6 +559,21 @@ void InputEventConfigurationDialog::_input_list_item_selected() {

_set_event(mb, mb, false);
} break;
case INPUT_MOUSE_MOTION: {
int axis = selected->get_meta("__axis");
int value = selected->get_meta("__value");

Ref<InputEventMouseMotion> mm;
mm.instantiate();
Vector2 rel(0, 0);
rel[axis] = value;
mm->set_relative(rel);

// Maintain selected device.
mm->set_device(_get_current_device());

_set_event(mm, mm, false);
} break;
case INPUT_JOY_BUTTON: {
JoyButton idx = (JoyButton)(int)selected->get_meta("__index");
Ref<InputEventJoypadButton> jb = InputEventJoypadButton::create_reference(idx);
Expand Down Expand Up @@ -635,7 +685,7 @@ void InputEventConfigurationDialog::set_allowed_input_types(int p_type_masks) {
}

InputEventConfigurationDialog::InputEventConfigurationDialog() {
allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;
allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_MOUSE_MOTION | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;

set_min_size(Size2i(550, 0) * EDSCALE);

Expand Down
35 changes: 19 additions & 16 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4317,35 +4317,38 @@ bool Main::iteration() {
}
#endif

if (fixed_fps != -1) {
return exit;
}
if (fixed_fps == -1) {
OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw());

OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw());

#ifdef TOOLS_ENABLED
if (auto_build_solutions) {
auto_build_solutions = false;
// Only relevant when running the editor.
if (!editor) {
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
ERR_FAIL_V_MSG(true,
"Command line option --build-solutions was passed, but no project is being edited. Aborting.");
}
if (!EditorNode::get_singleton()->call_build()) {
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
ERR_FAIL_V_MSG(true,
"Command line option --build-solutions was passed, but the build callback failed. Aborting.");
auto_build_solutions = false;
// Only relevant when running the editor.
if (!editor) {
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
ERR_FAIL_V_MSG(true,
"Command line option --build-solutions was passed, but no project is being edited. Aborting.");
}
if (!EditorNode::get_singleton()->call_build()) {
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
ERR_FAIL_V_MSG(true,
"Command line option --build-solutions was passed, but the build callback failed. Aborting.");
}
}
}
#endif
}

#ifdef TOOLS_ENABLED
if (exit && quit_after_timeout && EditorNode::get_singleton()) {
EditorNode::get_singleton()->unload_editor_addons();
}
#endif

//need to find a better place to put this.
if (! Math::is_equal_approx(Input::get_singleton()->get_last_mouse_velocity().length_squared(), 0.0)) {

Check failure on line 4349 in main/main.cpp

View workflow job for this annotation

GitHub Actions / 🐧 Linux / Editor w/ Mono (target=editor)

ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [-Werror]

Check failure on line 4349 in main/main.cpp

View workflow job for this annotation

GitHub Actions / 🐧 Linux / Editor with clang sanitizers (target=editor, tests=yes, dev_build=yes, use_asan=yes, use_ubsan=yes, use_llvm=yes, linker=lld)

call to 'is_equal_approx' is ambiguous

Check failure on line 4349 in main/main.cpp

View workflow job for this annotation

GitHub Actions / 🐧 Linux / Editor with ThreadSanitizer (target=editor, tests=yes, dev_build=yes, use_tsan=yes, use_llvm=yes, linker=lld)

call to 'is_equal_approx' is ambiguous

Check failure on line 4349 in main/main.cpp

View workflow job for this annotation

GitHub Actions / 🏁 Windows / Editor (target=editor, tests=yes)

'Math::is_equal_approx': overloaded functions have similar conversions

Check failure on line 4349 in main/main.cpp

View workflow job for this annotation

GitHub Actions / 🐧 Linux / Template w/ Mono (target=template_release)

ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [-Werror]

Check failure on line 4349 in main/main.cpp

View workflow job for this annotation

GitHub Actions / 🏁 Windows / Template (target=template_release)

'Math::is_equal_approx': overloaded functions have similar conversions

Check failure on line 4349 in main/main.cpp

View workflow job for this annotation

GitHub Actions / 🐧 Linux / Minimal template (target=template_release, everything disabled)

ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [-Werror]
Input::get_singleton()->clear_mouse_axes_action_state();
}
return exit;
}

Expand Down

0 comments on commit 71fc074

Please sign in to comment.