input: Implement click finger behaviour (enabled by default)

input touchpad settings header:
- click finger behaviour (enabled by default)
- Emulation of different button clicks depending on the
  number of fingers that are pressed at the same time on
  any location of the touchable surface of the device.
    - Clicking with 1 finger triggers a primary button click,
      usually left button click.
    - Clicking with 2 fingers triggers a secondary button click,
      usually right button click.
    - Clicking with 3 fingers triggers a terciary button click,
      usually middle button click.

  This feature is useful for clickpads that are input devices
  lacking a separated set of buttons from the touch area.

input preflet:
- Implement clickfinger

input mouse:
- Handle and provide new settings for clickfinger behaviour

input mouse mm:
- Implement clickfinger in the user space
- Enables button emulation based on the number of fingers pressing
  at the same time the touch surface.

  Userful feature for clickpads.

Change-Id: Ibaa06df3887793158093cc08f6281fc080e85c3b
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9923
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Samuel Rodríguez Pérez
2026-01-02 11:01:29 +00:00
committed by Adrien Destugues
parent f44235f7e5
commit a3f6c4d484
7 changed files with 52 additions and 2 deletions
@@ -34,6 +34,10 @@ typedef struct {
// 0x04: edge motion on button click move // 0x04: edge motion on button click move
// 0x08: edge motion on button click drag // 0x08: edge motion on button click drag
bool finger_click; // 1 finger click -> click button id 1
// 2 fingers' click -> click button id 2
// 3 fingers' click -> click button id 3
bool software_button_areas; bool software_button_areas;
} touchpad_settings; } touchpad_settings;
@@ -53,6 +57,7 @@ const static touchpad_settings kDefaultTouchpadSettings = {
false, false,
true, true,
0x02, 0x02,
true,
false false
}; };
@@ -608,6 +608,8 @@ MouseDevice::_UpdateTouchpadSettings(BMessage* message)
&settings.scroll_twofinger_natural_scrolling); &settings.scroll_twofinger_natural_scrolling);
message->FindInt8("edge_motion", message->FindInt8("edge_motion",
(int8*)&settings.edge_motion); (int8*)&settings.edge_motion);
message->FindBool("finger_click",
&settings.finger_click);
message->FindBool("software_button_areas", message->FindBool("software_button_areas",
&settings.software_button_areas); &settings.software_button_areas);
@@ -353,6 +353,7 @@ TouchpadMovement::EventToMovement(const touchpad_movement* _event, mouse_movemen
movement->timestamp = system_time(); movement->timestamp = system_time();
touchpad_movement event2 = *_event; touchpad_movement event2 = *_event;
if (!_ClickFingerButtonEmulator(&event2))
_SoftwareButtonAreas(&event2); _SoftwareButtonAreas(&event2);
const touchpad_movement* event = &event2; const touchpad_movement* event = &event2;
@@ -398,6 +399,27 @@ TouchpadMovement::EventToMovement(const touchpad_movement* _event, mouse_movemen
} }
bool
TouchpadMovement::_ClickFingerButtonEmulator(touchpad_movement *event) {
CALLED();
if (event->buttons != 0) {
// ClickFinger behaviour.
// Simulate with 2 fingers click => right button click
// Simulate with 3 fingers click => middle button click
if (fSettings.finger_click && two_fingers(event)) {
event->buttons = 2;
return true;
} else if (fSettings.finger_click && three_fingers(event)) {
event->buttons = 4;
return true;
}
}
return false;
}
void void
TouchpadMovement::_SoftwareButtonAreas(touchpad_movement *event) { TouchpadMovement::_SoftwareButtonAreas(touchpad_movement *event) {
CALLED(); CALLED();
@@ -76,6 +76,7 @@ private:
void _UpdateButtons(mouse_movement *movement); void _UpdateButtons(mouse_movement *movement);
bool _EdgeMotion(const touchpad_movement *event, bool _EdgeMotion(const touchpad_movement *event,
mouse_movement *movement, bool validStart); mouse_movement *movement, bool validStart);
inline bool _ClickFingerButtonEmulator(touchpad_movement *event);
inline void _SoftwareButtonAreas(touchpad_movement *event); inline void _SoftwareButtonAreas(touchpad_movement *event);
inline void _NoTouchToMovement(const touchpad_movement *event, inline void _NoTouchToMovement(const touchpad_movement *event,
mouse_movement *movement); mouse_movement *movement);
@@ -72,6 +72,7 @@ TouchpadPref::BuildSettingsMessage()
msg.AddInt32("trackpad_acceleration", fSettings.trackpad_acceleration); msg.AddInt32("trackpad_acceleration", fSettings.trackpad_acceleration);
msg.AddBool("scroll_twofinger_natural_scrolling", fSettings.scroll_twofinger_natural_scrolling); msg.AddBool("scroll_twofinger_natural_scrolling", fSettings.scroll_twofinger_natural_scrolling);
msg.AddInt8("edge_motion", fSettings.edge_motion); msg.AddInt8("edge_motion", fSettings.edge_motion);
msg.AddBool("finger_click", fSettings.finger_click);
msg.AddBool("software_button_areas", fSettings.software_button_areas); msg.AddBool("software_button_areas", fSettings.software_button_areas);
return msg; return msg;
@@ -161,6 +162,9 @@ TouchpadPref::LoadSettings()
fSettings.edge_motion = settingsMsg.GetInt8( fSettings.edge_motion = settingsMsg.GetInt8(
"edge_motion", "edge_motion",
kDefaultTouchpadSettings.edge_motion); kDefaultTouchpadSettings.edge_motion);
fSettings.finger_click = settingsMsg.GetBool(
"finger_click",
kDefaultTouchpadSettings.finger_click);
fSettings.software_button_areas = settingsMsg.GetBool( fSettings.software_button_areas = settingsMsg.GetBool(
"software_button_areas", "software_button_areas",
kDefaultTouchpadSettings.software_button_areas); kDefaultTouchpadSettings.software_button_areas);
@@ -315,6 +315,12 @@ TouchpadPrefView::MessageReceived(BMessage* message)
fTouchpadPref.UpdateRunningSettings(); fTouchpadPref.UpdateRunningSettings();
break; break;
case FINGER_CLICK_CHANGED:
settings.finger_click = fFingerClickBox->Value() == B_CONTROL_ON;
fRevertButton->SetEnabled(true);
fTouchpadPref.UpdateRunningSettings();
break;
case SOFTWARE_BUTTON_AREAS_CHANGED: case SOFTWARE_BUTTON_AREAS_CHANGED:
settings.software_button_areas = fSoftwareButtonAreasBox->Value() == B_CONTROL_ON; settings.software_button_areas = fSoftwareButtonAreasBox->Value() == B_CONTROL_ON;
fRevertButton->SetEnabled(true); fRevertButton->SetEnabled(true);
@@ -382,6 +388,7 @@ TouchpadPrefView::AttachedToWindow()
fScrollAccelSlider->SetTarget(this); fScrollAccelSlider->SetTarget(this);
fEdgeMotionOptionPopUp->SetTarget(this); fEdgeMotionOptionPopUp->SetTarget(this);
fFingerClickBox->SetTarget(this);
fSoftwareButtonAreasBox->SetTarget(this); fSoftwareButtonAreasBox->SetTarget(this);
fPadBlockerSlider->SetTarget(this); fPadBlockerSlider->SetTarget(this);
@@ -479,6 +486,8 @@ TouchpadPrefView::SetupView()
B_EDGE_MOTION_ON_MOVE | B_EDGE_MOTION_ON_TAP_DRAG 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); | B_EDGE_MOTION_ON_BUTTON_CLICK_MOVE | B_EDGE_MOTION_ON_BUTTON_CLICK_DRAG);
fFingerClickBox = new BCheckBox(B_TRANSLATE("Finger click"),
new BMessage(FINGER_CLICK_CHANGED));
fSoftwareButtonAreasBox = new BCheckBox(B_TRANSLATE("Software button areas"), fSoftwareButtonAreasBox = new BCheckBox(B_TRANSLATE("Software button areas"),
new BMessage(SOFTWARE_BUTTON_AREAS_CHANGED)); new BMessage(SOFTWARE_BUTTON_AREAS_CHANGED));
@@ -545,7 +554,11 @@ TouchpadPrefView::SetupView()
.SetInsets(B_USE_WINDOW_SPACING) .SetInsets(B_USE_WINDOW_SPACING)
.Add(scrollBox) .Add(scrollBox)
.Add(fEdgeMotionOptionPopUp) .Add(fEdgeMotionOptionPopUp)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
.Add(fFingerClickBox)
.Add(new BSeparatorView(B_VERTICAL))
.Add(fSoftwareButtonAreasBox) .Add(fSoftwareButtonAreasBox)
.End()
.Add(new BSeparatorView(B_HORIZONTAL)) .Add(new BSeparatorView(B_HORIZONTAL))
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING) .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING) .AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
@@ -580,6 +593,7 @@ TouchpadPrefView::SetValues(touchpad_settings* settings)
fTwoFingerNaturalScrollingBox->SetValue( fTwoFingerNaturalScrollingBox->SetValue(
settings->scroll_twofinger_natural_scrolling ? B_CONTROL_ON : B_CONTROL_OFF); settings->scroll_twofinger_natural_scrolling ? B_CONTROL_ON : B_CONTROL_OFF);
fTwoFingerNaturalScrollingBox->SetEnabled(settings->scroll_twofinger); fTwoFingerNaturalScrollingBox->SetEnabled(settings->scroll_twofinger);
fFingerClickBox->SetValue(settings->finger_click);
fSoftwareButtonAreasBox->SetValue(settings->software_button_areas); fSoftwareButtonAreasBox->SetValue(settings->software_button_areas);
fEdgeMotionOptionPopUp->SetValue(settings->edge_motion); fEdgeMotionOptionPopUp->SetValue(settings->edge_motion);
fScrollStepXSlider->SetValue(20 - settings->scroll_xstepsize / 2); fScrollStepXSlider->SetValue(20 - settings->scroll_xstepsize / 2);
@@ -41,6 +41,7 @@ const uint PADBLOCK_TIME_CHANGED = '&ptc';
const uint PAD_SPEED_CHANGED = '&psc'; const uint PAD_SPEED_CHANGED = '&psc';
const uint PAD_ACCELERATION_CHANGED = '&pac'; const uint PAD_ACCELERATION_CHANGED = '&pac';
const uint EDGE_MOTION_CHANGED = '&emc'; const uint EDGE_MOTION_CHANGED = '&emc';
const uint FINGER_CLICK_CHANGED = '&fcc';
const uint SOFTWARE_BUTTON_AREAS_CHANGED = '&sbc'; const uint SOFTWARE_BUTTON_AREAS_CHANGED = '&sbc';
class DeviceListView; class DeviceListView;
@@ -102,6 +103,7 @@ private:
BCheckBox* fTwoFingerBox; BCheckBox* fTwoFingerBox;
BCheckBox* fTwoFingerHorizontalBox; BCheckBox* fTwoFingerHorizontalBox;
BCheckBox* fTwoFingerNaturalScrollingBox; BCheckBox* fTwoFingerNaturalScrollingBox;
BCheckBox* fFingerClickBox;
BCheckBox* fSoftwareButtonAreasBox; BCheckBox* fSoftwareButtonAreasBox;
BSlider* fScrollStepXSlider; BSlider* fScrollStepXSlider;
BSlider* fScrollStepYSlider; BSlider* fScrollStepYSlider;