diff --git a/Base/etc/WindowServer.ini b/Base/etc/WindowServer.ini index 8963788f99..8a228c3355 100644 --- a/Base/etc/WindowServer.ini +++ b/Base/etc/WindowServer.ini @@ -20,6 +20,7 @@ Name=Default AccelerationFactor=1.0 ScrollStepSize=4 CursorTheme=Default +ButtonsSwitched=0 [Graphics] OverlayRectShadow=/res/graphics/overlay-rect-shadow.png diff --git a/Base/res/graphics/switch-mouse-buttons.png b/Base/res/graphics/switch-mouse-buttons.png new file mode 100644 index 0000000000..a40d675ead Binary files /dev/null and b/Base/res/graphics/switch-mouse-buttons.png differ diff --git a/Userland/Applications/MouseSettings/Mouse.gml b/Userland/Applications/MouseSettings/Mouse.gml index 1ee8e37b93..1daf2d4be7 100644 --- a/Userland/Applications/MouseSettings/Mouse.gml +++ b/Userland/Applications/MouseSettings/Mouse.gml @@ -158,4 +158,39 @@ } } } + + @GUI::GroupBox { + title: "Button configuration" + fixed_height: 60 + + layout: @GUI::VerticalBoxLayout { + margins: [16, 8, 8] + spacing: 2 + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + fixed_height: 32 + name: "switch_buttons_image_label" + } + + @GUI::Label { + text: "Switch primary and secondary buttons" + fixed_width: 201 + text_alignment: "CenterLeft" + name: "switch_buttons_label" + } + + @GUI::CheckBox { + name: "switch_buttons_input" + fixed_width: 14 + + } + } + } } diff --git a/Userland/Applications/MouseSettings/MouseWidget.cpp b/Userland/Applications/MouseSettings/MouseWidget.cpp index 4dbea84b5f..afae4b45d8 100644 --- a/Userland/Applications/MouseSettings/MouseWidget.cpp +++ b/Userland/Applications/MouseSettings/MouseWidget.cpp @@ -51,6 +51,10 @@ MouseWidget::MouseWidget() m_double_click_speed_label->set_text(String::formatted("{} ms", speed)); }; m_double_click_speed_slider->set_value(GUI::WindowServerConnection::the().get_double_click_speed()); + m_switch_buttons_checkbox = *find_descendant_of_type_named("switch_buttons_input"); + m_switch_buttons_checkbox->set_checked(GUI::WindowServerConnection::the().get_buttons_switched()); + auto& switch_buttons_image_label = *find_descendant_of_type_named("switch_buttons_image_label"); + switch_buttons_image_label.set_icon(Gfx::Bitmap::try_load_from_file("/res/graphics/switch-mouse-buttons.png")); } void MouseWidget::update_window_server() @@ -59,6 +63,7 @@ void MouseWidget::update_window_server() GUI::WindowServerConnection::the().async_set_mouse_acceleration(factor); GUI::WindowServerConnection::the().async_set_scroll_step_size(m_scroll_length_spinbox->value()); GUI::WindowServerConnection::the().async_set_double_click_speed(m_double_click_speed_slider->value()); + GUI::WindowServerConnection::the().async_set_buttons_switched(m_switch_buttons_checkbox->is_checked()); } void MouseWidget::reset_default_values() @@ -66,6 +71,7 @@ void MouseWidget::reset_default_values() m_speed_slider->set_value(speed_slider_scale); m_scroll_length_spinbox->set_value(default_scroll_length); m_double_click_speed_slider->set_value(double_click_speed_default); + m_switch_buttons_checkbox->set_checked(false); update_window_server(); } diff --git a/Userland/Applications/MouseSettings/MouseWidget.h b/Userland/Applications/MouseSettings/MouseWidget.h index 846a70c8f6..967709ae9f 100644 --- a/Userland/Applications/MouseSettings/MouseWidget.h +++ b/Userland/Applications/MouseSettings/MouseWidget.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include "DoubleClickArrowWidget.h" @@ -26,5 +27,6 @@ private: RefPtr m_scroll_length_spinbox; RefPtr m_double_click_speed_slider; RefPtr m_double_click_speed_label; + RefPtr m_switch_buttons_checkbox; RefPtr m_double_click_arrow_widget; }; diff --git a/Userland/Services/WindowServer/ClientConnection.cpp b/Userland/Services/WindowServer/ClientConnection.cpp index 46604f5ce2..5591c3c1cf 100644 --- a/Userland/Services/WindowServer/ClientConnection.cpp +++ b/Userland/Services/WindowServer/ClientConnection.cpp @@ -921,6 +921,16 @@ Messages::WindowServer::GetDoubleClickSpeedResponse ClientConnection::get_double return WindowManager::the().double_click_speed(); } +void ClientConnection::set_buttons_switched(bool switched) +{ + WindowManager::the().set_buttons_switched(switched); +} + +Messages::WindowServer::GetButtonsSwitchedResponse ClientConnection::get_buttons_switched() +{ + return WindowManager::the().get_buttons_switched(); +} + void ClientConnection::set_unresponsive(bool unresponsive) { if (m_unresponsive == unresponsive) diff --git a/Userland/Services/WindowServer/ClientConnection.h b/Userland/Services/WindowServer/ClientConnection.h index 3e7def4af4..51d90777ea 100644 --- a/Userland/Services/WindowServer/ClientConnection.h +++ b/Userland/Services/WindowServer/ClientConnection.h @@ -160,6 +160,8 @@ private: virtual Messages::WindowServer::GetScreenBitmapAroundCursorResponse get_screen_bitmap_around_cursor(Gfx::IntSize const&) override; virtual void set_double_click_speed(i32) override; virtual Messages::WindowServer::GetDoubleClickSpeedResponse get_double_click_speed() override; + virtual void set_buttons_switched(bool) override; + virtual Messages::WindowServer::GetButtonsSwitchedResponse get_buttons_switched() override; virtual void set_window_modified(i32, bool) override; virtual Messages::WindowServer::IsWindowModifiedResponse is_window_modified(i32) override; virtual Messages::WindowServer::GetDesktopDisplayScaleResponse get_desktop_display_scale(u32) override; diff --git a/Userland/Services/WindowServer/EventLoop.cpp b/Userland/Services/WindowServer/EventLoop.cpp index b4b3eeee45..7b21c820a0 100644 --- a/Userland/Services/WindowServer/EventLoop.cpp +++ b/Userland/Services/WindowServer/EventLoop.cpp @@ -106,6 +106,20 @@ void EventLoop::drain_mouse() if (packet.buttons != state.buttons) { state.buttons = packet.buttons; dbgln_if(WSMESSAGELOOP_DEBUG, "EventLoop: Mouse Button Event"); + + // Swap primary (1) and secondary (2) buttons if checked in Settings. + // Doing the swap here avoids all emulator and hardware issues. + if (WindowManager::the().get_buttons_switched()) { + bool has_primary = state.buttons & MousePacket::Button::LeftButton; + bool has_secondary = state.buttons & MousePacket::Button::RightButton; + state.buttons = state.buttons & ~(MousePacket::Button::LeftButton | MousePacket::Button::RightButton); + // Invert the buttons: + if (has_primary) + state.buttons |= MousePacket::Button::RightButton; + if (has_secondary) + state.buttons |= MousePacket::Button::LeftButton; + } + screen_input.on_receive_mouse_data(state); state_is_sent = true; if (state.is_relative) { diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index 8b9853996a..4073b4a8b7 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -71,6 +71,7 @@ void WindowManager::reload_config() apply_virtual_desktop_settings(virtual_desktop_rows, virtual_desktop_columns, false); m_double_click_speed = m_config->read_num_entry("Input", "DoubleClickSpeed", 250); + m_buttons_switched = m_config->read_bool_entry("Mouse", "ButtonsSwitched", false); apply_cursor_theme(m_config->read_entry("Mouse", "CursorTheme", "Default")); auto reload_graphic = [&](RefPtr& bitmap, String const& name) { @@ -274,6 +275,19 @@ int WindowManager::double_click_speed() const return m_double_click_speed; } +void WindowManager::set_buttons_switched(bool switched) +{ + m_buttons_switched = switched; + dbgln("Saving mouse buttons switched state {} to config file at {}", switched, m_config->filename()); + m_config->write_bool_entry("Mouse", "ButtonsSwitched", switched); + m_config->sync(); +} + +bool WindowManager::get_buttons_switched() const +{ + return m_buttons_switched; +} + WindowStack& WindowManager::window_stack_for_window(Window& window) { if (is_stationary_window_type(window.type())) diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index 98dd20ec0f..e2ec2aa050 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -164,6 +164,8 @@ public: void set_scroll_step_size(unsigned); void set_double_click_speed(int); int double_click_speed() const; + void set_buttons_switched(bool); + bool get_buttons_switched() const; Window* set_active_input_window(Window*); void restore_active_input_window(Window*); @@ -409,6 +411,7 @@ private: int m_double_click_speed { 0 }; int m_max_distance_for_double_click { 4 }; bool m_previous_event_was_super_keydown { false }; + bool m_buttons_switched { false }; WeakPtr m_hovered_window; WeakPtr m_highlight_window; diff --git a/Userland/Services/WindowServer/WindowServer.ipc b/Userland/Services/WindowServer/WindowServer.ipc index 4f3d40498b..c2f7fb6e3a 100644 --- a/Userland/Services/WindowServer/WindowServer.ipc +++ b/Userland/Services/WindowServer/WindowServer.ipc @@ -144,6 +144,9 @@ endpoint WindowServer set_double_click_speed(int speed) =| get_double_click_speed() => (int speed) + set_buttons_switched(bool switched) =| + get_buttons_switched() => (bool switched) + get_desktop_display_scale(u32 screen_index) => (int desktop_display_scale) set_flash_flush(bool enabled) =|