From f44235f7e5548a450e3ea936183f5b97bf248906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Rodr=C3=ADguez=20P=C3=A9rez?= Date: Mon, 24 Nov 2025 17:55:00 +0000 Subject: [PATCH] input: Implement software button areas (disabled by default) input touchpad settings header: - software button areas (enabled by default) - Emulation of buttons clicks based on which small area assinged by each button is pressed. For instance, a software button area on the bottom of the touchpad could be divided on 3 subareas one for each button. This new feature is useful for clickpads that are input devices lacking a separated set of buttons from the touch area. However, we may prefer to make the GUI better suppot "single button" devices. Disabled by default as we don't currently have a way to adjust the default settings according to the presence of physical buttons, and having this disabled yields an OK experience on all machines. Having the soft buttons in addition to physical buttons would just be too strange. input preflet: - Implement software button areas input mouse: - Handle and provide new settings for software button areas input mouse mm: - Implement software button areas in the user space - At the moment only a bottom located software button area simulating 3 different buttons is enabled. There is a working implementation 2 buttons only but not enabled in the code base. TODO for other type of software button areas is there. Change-Id: I255cb1a7eac0d18064c63a2a0d4b158be7370a17 Reviewed-on: https://review.haiku-os.org/c/haiku/+/9922 Reviewed-by: Adrien Destugues --- headers/private/input/touchpad_settings.h | 5 +- .../devices/mouse/MouseInputDevice.cpp | 2 + .../devices/mouse/movement_maker.cpp | 69 ++++++++++++++++--- .../devices/mouse/movement_maker.h | 4 +- src/preferences/input/InputTouchpadPref.cpp | 4 ++ .../input/InputTouchpadPrefView.cpp | 13 ++++ src/preferences/input/InputTouchpadPrefView.h | 2 + 7 files changed, 89 insertions(+), 10 deletions(-) diff --git a/headers/private/input/touchpad_settings.h b/headers/private/input/touchpad_settings.h index b6d5b27d5a..8fc38e60da 100644 --- a/headers/private/input/touchpad_settings.h +++ b/headers/private/input/touchpad_settings.h @@ -33,6 +33,8 @@ typedef struct { // 0x02: edge motion on tap drag // 0x04: edge motion on button click move // 0x08: edge motion on button click drag + + bool software_button_areas; } touchpad_settings; @@ -50,7 +52,8 @@ const static touchpad_settings kDefaultTouchpadSettings = { 65536, false, true, - 0x02 + 0x02, + false }; #define TOUCHPAD_SETTINGS_FILE "Touchpad_settings" diff --git a/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp b/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp index 4874fa8f8e..8ae0be1af7 100644 --- a/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp +++ b/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp @@ -608,6 +608,8 @@ MouseDevice::_UpdateTouchpadSettings(BMessage* message) &settings.scroll_twofinger_natural_scrolling); message->FindInt8("edge_motion", (int8*)&settings.edge_motion); + message->FindBool("software_button_areas", + &settings.software_button_areas); if (fIsTouchpad) fTouchpadMovementMaker.SetSettings(settings); diff --git a/src/add-ons/input_server/devices/mouse/movement_maker.cpp b/src/add-ons/input_server/devices/mouse/movement_maker.cpp index adcba132e5..aaebc2e138 100644 --- a/src/add-ons/input_server/devices/mouse/movement_maker.cpp +++ b/src/add-ons/input_server/devices/mouse/movement_maker.cpp @@ -307,7 +307,7 @@ TouchpadMovement::~TouchpadMovement() { status_t -TouchpadMovement::EventToMovement(const touchpad_movement* event, mouse_movement* movement, +TouchpadMovement::EventToMovement(const touchpad_movement* _event, mouse_movement* movement, bigtime_t& repeatTimeout) { CALLED(); @@ -317,13 +317,13 @@ TouchpadMovement::EventToMovement(const touchpad_movement* event, mouse_movement TRACE("TM_EVENT: b:0x%" B_PRIx8 " nf:%" B_PRId8 " f:0x%" B_PRIx8 " x:%" B_PRIu32 " y:%" B_PRIu32 " p:%" B_PRIu8 " w:%" B_PRIu8 "\n", - event->buttons, - count_set_bits(event->fingers), - event->fingers, - event->xPosition, - event->yPosition, - event->zPressure, - event->fingerWidth + _event->buttons, + count_set_bits(_event->fingers), + _event->fingers, + _event->xPosition, + _event->yPosition, + _event->zPressure, + _event->fingerWidth ); TRACE("TM_STATUS: b:0x%" B_PRIx8 " %c%c%c%c%c%c" " dx:%" B_PRId32 " dy:%" B_PRId32 @@ -352,6 +352,10 @@ TouchpadMovement::EventToMovement(const touchpad_movement* event, mouse_movement movement->clicks = 0; movement->timestamp = system_time(); + touchpad_movement event2 = *_event; + _SoftwareButtonAreas(&event2); + const touchpad_movement* event = &event2; + if ((movement->timestamp - fTapTime) > fTapTimeOUT) { if (fTapStarted) TRACE("TouchpadMovement: tap gesture timed out\n"); @@ -394,6 +398,55 @@ TouchpadMovement::EventToMovement(const touchpad_movement* event, mouse_movement } +void +TouchpadMovement::_SoftwareButtonAreas(touchpad_movement *event) { + CALLED(); + + // Software button areas. + // - Emulation of button areas as clickpads do not have separated physical buttons from the one + // overlapping the touch area. + // - Pretend the the same button is still pressed if the finger hasn't been released regardless + // of its current possition. + // TODO: + // - Implement top button area. + // - Implement trackpoint emulator in an area. + // i.e.: small centered square on the top of the clickpad. + // - Make the areas configurable from settings and Input preference app. + // i.e.: to allow switch left and right buttons, etc. + if (event->buttons != 0) { + if (fSettings.software_button_areas) { + if (fButtonsState == 0) { + uint32 evaluatePositionX = (event->xPosition == 0) ? fPreviousX : event->xPosition; + uint32 evaluatePositionY = (event->yPosition == 0) ? fPreviousY : event->yPosition; + if (evaluatePositionY > 0 && evaluatePositionY < (uint32) fSpecs.areaEndY / 5) { + #if 0 + // 2 software buttons: + // - Emulates right buttom hardcoded to half left side of the touchpad, + // otherwise left button. + if (evaluatePositionX > (uint32) fSpecs.areaEndX / 2) { + event->buttons = 2; + } else { + event->buttons = 1; + } + #else + // 3 software buttons where the the middle button uses 1/6 of the area. + if (evaluatePositionX > (uint32) fSpecs.areaEndX / 12 * 7) { + event->buttons = 2; + } else if (evaluatePositionX > (uint32) fSpecs.areaEndX / 12 * 5) { + // Middle button area smaller than left and right buttons' area. + event->buttons = 4; + } else { + event->buttons = 1; + } + #endif + } + } else { + event->buttons = fButtonsState; + } + } + } +} + // in pixel per second const int32 kEdgeMotionSpeed = 200; diff --git a/src/add-ons/input_server/devices/mouse/movement_maker.h b/src/add-ons/input_server/devices/mouse/movement_maker.h index c33f726b7d..70d3364023 100644 --- a/src/add-ons/input_server/devices/mouse/movement_maker.h +++ b/src/add-ons/input_server/devices/mouse/movement_maker.h @@ -42,10 +42,11 @@ private: bool fMovementMakerStarted; -private: +protected: uint32 fPreviousX; uint32 fPreviousY; +private: float fDeltaSumX; float fDeltaSumY; @@ -75,6 +76,7 @@ private: void _UpdateButtons(mouse_movement *movement); bool _EdgeMotion(const touchpad_movement *event, mouse_movement *movement, bool validStart); + inline void _SoftwareButtonAreas(touchpad_movement *event); inline void _NoTouchToMovement(const touchpad_movement *event, mouse_movement *movement); inline void _MoveToMovement(const touchpad_movement *event, diff --git a/src/preferences/input/InputTouchpadPref.cpp b/src/preferences/input/InputTouchpadPref.cpp index 5ece53632e..40649e09ef 100644 --- a/src/preferences/input/InputTouchpadPref.cpp +++ b/src/preferences/input/InputTouchpadPref.cpp @@ -72,6 +72,7 @@ TouchpadPref::BuildSettingsMessage() msg.AddInt32("trackpad_acceleration", fSettings.trackpad_acceleration); msg.AddBool("scroll_twofinger_natural_scrolling", fSettings.scroll_twofinger_natural_scrolling); msg.AddInt8("edge_motion", fSettings.edge_motion); + msg.AddBool("software_button_areas", fSettings.software_button_areas); return msg; } @@ -160,6 +161,9 @@ TouchpadPref::LoadSettings() fSettings.edge_motion = settingsMsg.GetInt8( "edge_motion", kDefaultTouchpadSettings.edge_motion); + fSettings.software_button_areas = settingsMsg.GetBool( + "software_button_areas", + kDefaultTouchpadSettings.software_button_areas); return B_OK; } diff --git a/src/preferences/input/InputTouchpadPrefView.cpp b/src/preferences/input/InputTouchpadPrefView.cpp index a934c86942..459d0b51ad 100644 --- a/src/preferences/input/InputTouchpadPrefView.cpp +++ b/src/preferences/input/InputTouchpadPrefView.cpp @@ -315,6 +315,12 @@ TouchpadPrefView::MessageReceived(BMessage* message) fTouchpadPref.UpdateRunningSettings(); break; + case SOFTWARE_BUTTON_AREAS_CHANGED: + settings.software_button_areas = fSoftwareButtonAreasBox->Value() == B_CONTROL_ON; + fRevertButton->SetEnabled(true); + fTouchpadPref.UpdateRunningSettings(); + break; + case TAP_CONTROL_CHANGED: settings.tapgesture_sensibility = fTapSlider->Value(); fRevertButton->SetEnabled(true); @@ -376,6 +382,7 @@ TouchpadPrefView::AttachedToWindow() fScrollAccelSlider->SetTarget(this); fEdgeMotionOptionPopUp->SetTarget(this); + fSoftwareButtonAreasBox->SetTarget(this); fPadBlockerSlider->SetTarget(this); fTapSlider->SetTarget(this); @@ -472,6 +479,10 @@ TouchpadPrefView::SetupView() B_EDGE_MOTION_ON_MOVE | B_EDGE_MOTION_ON_TAP_DRAG | B_EDGE_MOTION_ON_BUTTON_CLICK_MOVE | B_EDGE_MOTION_ON_BUTTON_CLICK_DRAG); + fSoftwareButtonAreasBox = new BCheckBox(B_TRANSLATE("Software button areas"), + new BMessage(SOFTWARE_BUTTON_AREAS_CHANGED)); + + float spacing = be_control_look->DefaultItemSpacing(); BView* scrollPrefLeftLayout @@ -534,6 +545,7 @@ TouchpadPrefView::SetupView() .SetInsets(B_USE_WINDOW_SPACING) .Add(scrollBox) .Add(fEdgeMotionOptionPopUp) + .Add(fSoftwareButtonAreasBox) .Add(new BSeparatorView(B_HORIZONTAL)) .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING) .AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING) @@ -568,6 +580,7 @@ TouchpadPrefView::SetValues(touchpad_settings* settings) fTwoFingerNaturalScrollingBox->SetValue( settings->scroll_twofinger_natural_scrolling ? B_CONTROL_ON : B_CONTROL_OFF); fTwoFingerNaturalScrollingBox->SetEnabled(settings->scroll_twofinger); + fSoftwareButtonAreasBox->SetValue(settings->software_button_areas); fEdgeMotionOptionPopUp->SetValue(settings->edge_motion); fScrollStepXSlider->SetValue(20 - settings->scroll_xstepsize / 2); fScrollStepYSlider->SetValue(20 - settings->scroll_ystepsize / 2); diff --git a/src/preferences/input/InputTouchpadPrefView.h b/src/preferences/input/InputTouchpadPrefView.h index d7831b07eb..2cfe7814d5 100644 --- a/src/preferences/input/InputTouchpadPrefView.h +++ b/src/preferences/input/InputTouchpadPrefView.h @@ -41,6 +41,7 @@ const uint PADBLOCK_TIME_CHANGED = '&ptc'; const uint PAD_SPEED_CHANGED = '&psc'; const uint PAD_ACCELERATION_CHANGED = '&pac'; const uint EDGE_MOTION_CHANGED = '&emc'; +const uint SOFTWARE_BUTTON_AREAS_CHANGED = '&sbc'; class DeviceListView; @@ -101,6 +102,7 @@ private: BCheckBox* fTwoFingerBox; BCheckBox* fTwoFingerHorizontalBox; BCheckBox* fTwoFingerNaturalScrollingBox; + BCheckBox* fSoftwareButtonAreasBox; BSlider* fScrollStepXSlider; BSlider* fScrollStepYSlider; BSlider* fScrollAccelSlider;