1/*
2 * Copyright 2019-2020, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Preetpal Kaur <preetpalok123@gmail.com>
7 *		Adrien Destugues <pulkomandy@gmail.com>
8 */
9
10
11#include <Alert.h>
12#include <Alignment.h>
13#include <Application.h>
14#include <Button.h>
15#include <CardLayout.h>
16#include <CardView.h>
17#include <Catalog.h>
18#include <Control.h>
19#include <ControlLook.h>
20#include <LayoutBuilder.h>
21#include <Screen.h>
22#include <SplitView.h>
23
24#include <private/input/InputServerTypes.h>
25
26#include "InputConstants.h"
27#include "InputDeviceView.h"
28#include "InputMouse.h"
29#include "InputTouchpadPref.h"
30#include "InputWindow.h"
31#include "MouseSettings.h"
32#include "SettingsView.h"
33
34#undef B_TRANSLATION_CONTEXT
35#define B_TRANSLATION_CONTEXT "InputWindow"
36
37
38InputWindow::InputWindow(BRect rect)
39	:
40	BWindow(rect, B_TRANSLATE_SYSTEM_NAME("Input"), B_TITLED_WINDOW,
41		B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS
42			| B_AUTO_UPDATE_SIZE_LIMITS | B_QUIT_ON_WINDOW_CLOSE)
43{
44	fDeviceListView = new BListView(B_TRANSLATE("Device List"));
45	fDeviceListView->SetSelectionMessage(new BMessage(ITEM_SELECTED));
46	fDeviceListView->SetExplicitMinSize(
47		BSize(be_control_look->ComposeIconSize(32).Width()
48				+ fDeviceListView->StringWidth("Extended PS/2 Mouse 1"),
49			B_SIZE_UNSET));
50
51	BScrollView* scrollView = new BScrollView(
52		"scrollView", fDeviceListView, 0, false, B_FANCY_BORDER);
53	fCardView = new BCardView();
54
55	BLayoutBuilder::Group<>(this, B_HORIZONTAL, 10)
56		.SetInsets(B_USE_WINDOW_SPACING)
57		.Add(scrollView, 1)
58		.Add(fCardView, 3);
59
60	FindDevice();
61}
62
63
64void
65InputWindow::MessageReceived(BMessage* message)
66{
67	switch (message->what) {
68		case ITEM_SELECTED:
69		{
70			int32 index = message->GetInt32("index", 0);
71			if (index >= 0)
72				fCardView->CardLayout()->SetVisibleItem(index);
73			break;
74		}
75		case kMsgMouseType:
76		case kMsgMouseMap:
77		case kMsgMouseFocusMode:
78		case kMsgFollowsMouseMode:
79		case kMsgAcceptFirstClick:
80		case kMsgDoubleClickSpeed:
81		case kMsgMouseSpeed:
82		case kMsgAccelerationFactor:
83		case kMsgDefaults:
84		case kMsgRevert:
85		{
86			PostMessage(
87				message, fCardView->CardLayout()->VisibleItem()->View());
88			break;
89		}
90		case SCROLL_AREA_CHANGED:
91		case SCROLL_CONTROL_CHANGED:
92		case TAP_CONTROL_CHANGED:
93		case DEFAULT_SETTINGS:
94		case REVERT_SETTINGS:
95		{
96			PostMessage(
97				message, fCardView->CardLayout()->VisibleItem()->View());
98			break;
99		}
100		case kMsgSliderrepeatrate:
101		case kMsgSliderdelayrate:
102		{
103			PostMessage(
104				message, fCardView->CardLayout()->VisibleItem()->View());
105			break;
106		}
107
108		case B_INPUT_DEVICES_CHANGED:
109		{
110			int32 operation = message->FindInt32("be:opcode");
111			BString name = message->FindString("be:device_name");
112
113			if (operation == B_INPUT_DEVICE_ADDED) {
114				BInputDevice* device = find_input_device(name);
115				if (device)
116					AddDevice(device);
117			} else if (operation == B_INPUT_DEVICE_REMOVED) {
118				for (int i = 0; i < fDeviceListView->CountItems(); i++) {
119					DeviceListItemView* item
120						= dynamic_cast<DeviceListItemView*>(
121							fDeviceListView->ItemAt(i));
122					if (item != NULL && item->Label() == name) {
123						fDeviceListView->RemoveItem(i);
124						BView* settings = fCardView->ChildAt(i);
125						fCardView->RemoveChild(settings);
126						delete settings;
127						break;
128					}
129				}
130			}
131
132			break;
133		}
134
135		default:
136			BWindow::MessageReceived(message);
137			break;
138	}
139}
140
141
142void
143InputWindow::Show()
144{
145	CenterOnScreen();
146	BWindow::Show();
147	watch_input_devices(this, true);
148}
149
150
151void
152InputWindow::Hide()
153{
154	BWindow::Hide();
155	watch_input_devices(this, false);
156}
157
158
159status_t
160InputWindow::FindDevice()
161{
162	BList devList;
163	status_t status = get_input_devices(&devList);
164	if (status != B_OK)
165		return status;
166
167	int32 i = 0;
168
169	while (true) {
170		BInputDevice* dev = (BInputDevice*)devList.ItemAt(i);
171		if (dev == NULL)
172			break;
173		i++;
174
175		AddDevice(dev);
176	}
177
178	return B_OK;
179}
180
181
182void
183InputWindow::AddDevice(BInputDevice* dev)
184{
185	BString name = dev->Name();
186
187	if (dev->Type() == B_POINTING_DEVICE && name.FindFirst("Touchpad") >= 0) {
188		TouchpadPrefView* view = new TouchpadPrefView(dev);
189		fCardView->AddChild(view);
190
191		DeviceListItemView* touchpad
192			= new DeviceListItemView(name, TOUCHPAD_TYPE);
193		fDeviceListView->AddItem(touchpad);
194	} else if (dev->Type() == B_POINTING_DEVICE) {
195		MouseSettings* settings;
196		settings = fMultipleMouseSettings.AddMouseSettings(name);
197
198		InputMouse* view = new InputMouse(dev, settings);
199		fCardView->AddChild(view);
200
201		DeviceListItemView* mouse = new DeviceListItemView(name, MOUSE_TYPE);
202		fDeviceListView->AddItem(mouse);
203	} else if (dev->Type() == B_KEYBOARD_DEVICE) {
204		InputKeyboard* view = new InputKeyboard(dev);
205		fCardView->AddChild(view);
206
207		DeviceListItemView* keyboard
208			= new DeviceListItemView(name, KEYBOARD_TYPE);
209		fDeviceListView->AddItem(keyboard);
210	} else
211		delete dev;
212}
213