Actually handle more than 3 mouse buttons

The code in input_server was pretty much all set for this, but there was
no way to configure the extra buttons. Add them to the mouse view in
Input preferences (up to 5 buttons are handled now)

Define a new B_MOUSE_BUTTON(n) macro to generate the bitmask for a given
button (numbered from 1).

Change-Id: I9091082277937d89b08464ff474e7bbb5db82401
Reviewed-on: https://review.haiku-os.org/c/haiku/+/180
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Adrien Destugues 2020-02-05 13:37:57 +01:00 committed by waddlesplash
parent 6ae1da352b
commit 5bbf7f1be0
8 changed files with 122 additions and 110 deletions

View File

@ -29,6 +29,11 @@
\var B_PRIMARY_MOUSE_BUTTON
\brief Primary mouse button mask parameter.
The primary mouse button should be used for main operations (selecting,
dragging, or opening objects).
This maps to B_MOUSE_BUTTON(1).
\since BeOS R3
*/
@ -37,6 +42,11 @@
\var B_SECONDARY_MOUSE_BUTTON
\brief Secondary mouse button mask parameter.
The secondary button should be used for additional operations on the
pointed objects, such as popup menus.
This maps to B_MOUSE_BUTTON(2).
\since BeOS R3
*/
@ -45,10 +55,27 @@
\var B_TERTIARY_MOUSE_BUTTON
\brief Tertiary mouse button mask parameter.
The tertiary button should be used for clipboard paste.
This maps to B_MOUSE_BUTTON(3).
\since BeOS R3
*/
/*!
\var B_MOUSE_BUTTON(n)
\brief Compute mouse button mask for button n
Buttons are numbered from 1 to 32.
Some mice may not have more than 2 buttons, so the extra buttons should
only be used as shortcuts for actions that can be done in alternative ways.
\since Haiku R1
*/
// mouse transit

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2019 Haiku, Inc. All rights reserved.
* Copyright 2001-2020 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _VIEW_H
@ -16,10 +16,13 @@
// mouse button
#define B_MOUSE_BUTTON(n) (1 << ((n) - 1))
// Legacy BeOS R5 mouse button definitions
enum {
B_PRIMARY_MOUSE_BUTTON = 0x01,
B_SECONDARY_MOUSE_BUTTON = 0x02,
B_TERTIARY_MOUSE_BUTTON = 0x04
B_PRIMARY_MOUSE_BUTTON = B_MOUSE_BUTTON(1),
B_SECONDARY_MOUSE_BUTTON = B_MOUSE_BUTTON(2),
B_TERTIARY_MOUSE_BUTTON = B_MOUSE_BUTTON(3)
};
// mouse transit
@ -41,10 +44,11 @@ enum {
B_LOCK_WINDOW_FOCUS = 0x00000001,
B_SUSPEND_VIEW_FOCUS = 0x00000002,
B_NO_POINTER_HISTORY = 0x00000004,
// NOTE: New in Haiku (unless this flag is
// specified, both BWindow and BView::GetMouse()
// will filter out older mouse moved messages)
// NOTE: This is the default behavior in Haiku, unlike in BeOS
B_FULL_POINTER_HISTORY = 0x00000008
// NOTE: New in Haiku (unless this flag is
// specified, both BWindow and BView::GetMouse()
// will filter out older mouse moved messages)
};
enum {
@ -76,11 +80,11 @@ const uint32 B_FRAME_EVENTS = 0x04000000UL; /* 26 */
const uint32 B_NAVIGABLE = 0x02000000UL; /* 25 */
const uint32 B_SUBPIXEL_PRECISE = 0x01000000UL; /* 24 */
const uint32 B_DRAW_ON_CHILDREN = 0x00800000UL; /* 23 */
const uint32 B_INPUT_METHOD_AWARE = 0x00400000UL; /* 23 */
const uint32 B_SCROLL_VIEW_AWARE = 0x00200000UL; /* 22 */
const uint32 B_SUPPORTS_LAYOUT = 0x00100000UL; /* 21 */
const uint32 B_INVALIDATE_AFTER_LAYOUT = 0x00080000UL; /* 20 */
const uint32 B_TRANSPARENT_BACKGROUND = 0x00040000UL; /* 19 */
const uint32 B_INPUT_METHOD_AWARE = 0x00400000UL; /* 22 */
const uint32 B_SCROLL_VIEW_AWARE = 0x00200000UL; /* 21 */
const uint32 B_SUPPORTS_LAYOUT = 0x00100000UL; /* 20 */
const uint32 B_INVALIDATE_AFTER_LAYOUT = 0x00080000UL; /* 19 */
const uint32 B_TRANSPARENT_BACKGROUND = 0x00040000UL; /* 18 */
#define _RESIZE_MASK_ (0xffff)

View File

@ -183,9 +183,8 @@ MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath)
fDeviceRef.cookie = this;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON;
fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON;
fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON;
for (int i = 0; i < B_MAX_MOUSE_BUTTONS; i++)
fSettings.map.button[i] = B_MOUSE_BUTTON(i + 1);
#endif
};

View File

@ -97,8 +97,8 @@ InputMouse::MessageReceived(BMessage* message)
case kMsgMouseType:
{
int32 type;
if (message->FindInt32("index", &type) == B_OK) {
fSettings.SetMouseType(++type);
if (message->FindInt32("be:value", &type) == B_OK) {
fSettings.SetMouseType(type);
fSettingsView->SetMouseType(type);
fDefaultsButton->SetEnabled(fSettings.IsDefaultable());
fRevertButton->SetEnabled(fSettings.IsRevertable());
@ -196,16 +196,7 @@ InputMouse::MessageReceived(BMessage* message)
int32 button;
if (message->FindInt32("index", &index) == B_OK
&& message->FindInt32("button", &button) == B_OK) {
int32 mapping = B_PRIMARY_MOUSE_BUTTON;
switch (index) {
case 1:
mapping = B_SECONDARY_MOUSE_BUTTON;
break;
case 2:
mapping = B_TERTIARY_MOUSE_BUTTON;
break;
}
int32 mapping = B_MOUSE_BUTTON(index + 1);
fSettings.SetMapping(button, mapping);
fDefaultsButton->SetEnabled(fSettings.IsDefaultable());
fRevertButton->SetEnabled(fSettings.IsRevertable());
@ -214,4 +205,4 @@ InputMouse::MessageReceived(BMessage* message)
break;
}
}
}
}

View File

@ -134,8 +134,7 @@ InputWindow::Show()
{
CenterOnScreen();
BWindow::Show();
status_t x = watch_input_devices(this, true);
puts(strerror(x));
watch_input_devices(this, true);
}

View File

@ -35,12 +35,15 @@ static const int32 kButtonTop = 3;
static const int32 kMouseDownWidth = 72;
static const int32 kMouseDownHeight = 35;
static const int32 kOneButtonOffsets[4]
= { 0, kMouseDownWidth };
static const int32 kTwoButtonOffsets[4]
= { 0, kMouseDownWidth / 2, kMouseDownWidth };
static const int32 kThreeButtonOffsets[4]
= { 0, kMouseDownWidth / 3 + 1, kMouseDownWidth / 3 * 2, kMouseDownWidth };
#define W kMouseDownWidth / 100
static const int32 kButtonOffsets[][6] = {
{ 0, 100 * W },
{ 0, 50 * W, 100 * W },
{ 0, 35 * W, 65 * W, 100 * W },
{ 0, 27 * W, 54 * W, 81 * W, 100 * W },
{ 0, 23 * W, 46 * W, 69 * W, 84 * W, 100 * W }
};
#undef W
static const rgb_color kButtonTextColor = { 0, 0, 0, 255 };
static const rgb_color kMouseShadowColor = { 100, 100, 100, 128 };
@ -54,30 +57,23 @@ static const rgb_color kButtonPressedColor = { 110, 110, 110, 110 };
static const int32*
getButtonOffsets(int32 type)
{
switch (type) {
case 1:
return kOneButtonOffsets;
case 2:
return kTwoButtonOffsets;
case 3:
default:
return kThreeButtonOffsets;
}
if ((type - 1) >= (int32)B_COUNT_OF(kButtonOffsets))
return kButtonOffsets[2];
return kButtonOffsets[type - 1];
}
static uint32
getMappingNumber(int32 mapping)
{
switch (mapping) {
case B_PRIMARY_MOUSE_BUTTON:
return 0;
case B_SECONDARY_MOUSE_BUTTON:
return 1;
case B_TERTIARY_MOUSE_BUTTON:
return 2;
}
return 0;
if (mapping == 0)
return 0;
int i;
for (i = 0; mapping != 1; i++)
mapping >>= 1;
return i;
}
MouseView::MouseView(const MouseSettings &settings)
@ -89,7 +85,7 @@ MouseView::MouseView(const MouseSettings &settings)
fOldButtons(0)
{
SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
fScaling = std::max(1.0f, be_plain_font->Size() / 12.0f);
fScaling = std::max(1.0f, be_plain_font->Size() / 7.0f);
}
@ -195,9 +191,11 @@ MouseView::MouseDown(BPoint where)
BMessage message(kMsgMouseMap);
message.AddInt32("button", button);
menu.AddItem(new BMenuItem("1", new BMessage(message)));
menu.AddItem(new BMenuItem("2", new BMessage(message)));
menu.AddItem(new BMenuItem("3", new BMessage(message)));
for (int i = 1; i < 6; i++) {
char tmp[2];
sprintf(tmp, "%d", i);
menu.AddItem(new BMenuItem(tmp, new BMessage(message)));
}
menu.ItemAt(getMappingNumber(fSettings.Mapping(button)))
->SetMarked(true);
@ -261,6 +259,15 @@ MouseView::Draw(BRect updateFrame)
SetScale(1);
SetOrigin(0, 0);
mouse_map map;
fSettings.Mapping(map);
SetDrawingMode(B_OP_OVER);
// All button drawing is clipped to the outline of the buttons area,
// simplifying the code below as it can overdraw things.
ClipToPicture(&fButtonsPicture, B_ORIGIN, false);
// Separator between the buttons
const int32* offset = getButtonOffsets(fType);
for (int32 i = 1; i < fType; i++) {
@ -268,14 +275,6 @@ MouseView::Draw(BRect updateFrame)
StrokeLine(buttonRect.LeftTop(), buttonRect.LeftBottom());
}
mouse_map map;
fSettings.Mapping(map);
SetDrawingMode(B_OP_OVER);
if (fButtons != 0)
ClipToPicture(&fButtonsPicture, B_ORIGIN, false);
for (int32 i = 0; i < fType; i++) {
// draw mapping number centered over the button
@ -307,8 +306,7 @@ MouseView::Draw(BRect updateFrame)
+ (border.IntegerHeight() - fDigitHeight) / 2));
}
if (fButtons != 0)
ClipToPicture(NULL);
ClipToPicture(NULL);
}
@ -329,6 +327,8 @@ MouseView::_ButtonRect(const int32* offsets, int index) const
}
/** The buttons on a mouse are normally 1 (left), 2 (right), 3 (middle) so
* we need to reorder them */
int32
MouseView::_ConvertFromVisualOrder(int32 i)
{
@ -337,12 +337,13 @@ MouseView::_ConvertFromVisualOrder(int32 i)
switch (i) {
case 0:
default:
return 0;
case 1:
return 2;
case 2:
return 1;
default:
return i;
}
}
@ -376,4 +377,4 @@ MouseView::_CreateButtonsPicture()
EndPicture();
SetScale(1);
}
}

View File

@ -72,17 +72,13 @@ SettingsView::SettingsView(MouseSettings& settings)
fSettings(settings)
{
// Add the "Mouse Type" pop up menu
fTypeMenu = new BPopUpMenu("unknown");
fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("1-Button"),
new BMessage(kMsgMouseType)));
fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("2-Button"),
new BMessage(kMsgMouseType)));
fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("3-Button"),
new BMessage(kMsgMouseType)));
BMenuField* typeField = new BMenuField(B_TRANSLATE("Mouse type:"),
fTypeMenu);
typeField->SetAlignment(B_ALIGN_LEFT);
fTypeMenu = new BOptionPopUp("type", B_TRANSLATE("Mouse type:"),
new BMessage(kMsgMouseType));
fTypeMenu->AddOption(B_TRANSLATE("1-Button"), 1);
fTypeMenu->AddOption(B_TRANSLATE("2-Button"), 2);
fTypeMenu->AddOption(B_TRANSLATE("3-Button"), 3);
fTypeMenu->AddOption(B_TRANSLATE("4-Button"), 4);
fTypeMenu->AddOption(B_TRANSLATE("5-Button"), 5);
// Create the "Double-click speed slider...
fClickSpeedSlider = new BSlider("double_click_speed",
@ -174,12 +170,7 @@ SettingsView::SettingsView(MouseSettings& settings)
// Vertical block A: mouse type/view/test
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
.AddGroup(B_HORIZONTAL, 0)
.AddGlue()
.Add(typeField)
.AddGlue()
.End()
.AddGlue()
.Add(fTypeMenu)
.AddGroup(B_HORIZONTAL, 0)
.AddGlue()
.Add(fMouseView)
@ -260,13 +251,11 @@ SettingsView::UpdateFromSettings()
// slow = 0, fast = 262144
fAccelerationSlider->SetValue(value);
BMenuItem* item = fTypeMenu->ItemAt(fSettings.MouseType() - 1);
if (item != NULL)
item->SetMarked(true);
fTypeMenu->SelectOptionFor(fSettings.MouseType());
fMouseView->SetMouseType(fSettings.MouseType());
item = fFocusMenu->ItemAt(mouse_mode_to_index(fSettings.MouseMode()));
BMenuItem* item = fFocusMenu->ItemAt(
mouse_mode_to_index(fSettings.MouseMode()));
if (item != NULL)
item->SetMarked(true);
@ -282,4 +271,4 @@ SettingsView::UpdateFromSettings()
? B_CONTROL_ON : B_CONTROL_OFF);
fAcceptFirstClickBox->SetEnabled(fSettings.MouseMode()
!= B_FOCUS_FOLLOWS_MOUSE);
}
}

View File

@ -15,6 +15,7 @@
#include <Bitmap.h>
#include <Button.h>
#include <CheckBox.h>
#include <OptionPopUp.h>
#include <PopUpMenu.h>
#include <Slider.h>
@ -25,30 +26,31 @@ class MouseView;
class SettingsView : public BBox {
public:
SettingsView(MouseSettings &settings);
virtual ~SettingsView();
SettingsView(MouseSettings &settings);
virtual ~SettingsView();
virtual void AttachedToWindow();
virtual void AttachedToWindow();
void SetMouseType(int32 type);
void MouseMapUpdated();
void UpdateFromSettings();
void SetMouseType(int32 type);
void MouseMapUpdated();
void UpdateFromSettings();
BPopUpMenu* fFocusFollowsMouseMenu;
BCheckBox* fAcceptFirstClickBox;
public:
// FIXME use proper getters/setters for this?
BPopUpMenu* fFocusFollowsMouseMenu;
BCheckBox* fAcceptFirstClickBox;
private:
typedef BBox inherited;
typedef BBox inherited;
const MouseSettings& fSettings;
const MouseSettings &fSettings;
BPopUpMenu* fTypeMenu;
BPopUpMenu* fFocusMenu;
MouseView* fMouseView;
BSlider* fClickSpeedSlider;
BSlider* fMouseSpeedSlider;
BSlider* fAccelerationSlider;
BOptionPopUp* fTypeMenu;
BPopUpMenu* fFocusMenu;
MouseView* fMouseView;
BSlider* fClickSpeedSlider;
BSlider* fMouseSpeedSlider;
BSlider* fAccelerationSlider;
};
#endif /* SETTINGS_VIEW_H */