Skip to content

Commit 8d5bdce

Browse files
committed
joystick: make joystick buttons and axes configurable
Add joystick axis and button mapping to the settings dialog. The mapping enables a small number of initial actions that can be mapped as the user likes, including pan/tilt/zoom for the axes, and selecting previous/next camera or preset, and recalling presets for the buttons. More actions will get added in the future. Fixes: #139 Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
1 parent d3e4180 commit 8d5bdce

File tree

4 files changed

+164
-46
lines changed

4 files changed

+164
-46
lines changed

src/ptz-controls.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ public slots:
151151
void setJoystickAxisAction(size_t axis, ptz_joy_action_id);
152152
void setJoystickButtonAction(size_t button, ptz_joy_action_id);
153153

154+
signals:
155+
void joystickAxisActionChanged(size_t axis, ptz_joy_action_id action);
156+
void joystickButtonActionChanged(size_t button, ptz_joy_action_id action);
157+
154158
#if defined(ENABLE_JOYSTICK)
155159
public:
156160
void joystickSetup();
@@ -171,9 +175,6 @@ protected slots:
171175
void joystickAxisEvent(const QJoystickAxisEvent evt);
172176
void joystickButtonEvent(const QJoystickButtonEvent evt);
173177
void joystickPOVEvent(const QJoystickPOVEvent evt);
174-
signals:
175-
void joystickAxisActionChanged(size_t axis, ptz_joy_action_id action);
176-
void joystickButtonActionChanged(size_t button, ptz_joy_action_id action);
177178
#else
178179
void joystickSetup(){};
179180
#endif /* ENABLE_JOYSTICK */

src/settings.cpp

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ PTZSettings::PTZSettings() : QWidget(nullptr), ui(new Ui_PTZSettings)
109109
SLOT(setChecked(bool)));
110110
connect(ui->livemoveCheckBox, SIGNAL(clicked(bool)), PTZControls::getInstance(),
111111
SLOT(setDisableLiveMoves(bool)));
112+
connect(PTZControls::getInstance(), SIGNAL(joystickAxisActionChanged(size_t, ptz_joy_action_id)), this,
113+
SLOT(joystickAxisMappingChanged(size_t, ptz_joy_action_id)));
114+
connect(PTZControls::getInstance(), SIGNAL(joystickButtonActionChanged(size_t, ptz_joy_action_id)), this,
115+
SLOT(joystickButtonMappingChanged(size_t, ptz_joy_action_id)));
112116

113117
ui->speedRampCheckBox->setChecked(PTZControls::getInstance()->speedRampEnabled());
114118
connect(PTZControls::getInstance(), SIGNAL(speedRampEnabledChanged(bool)), ui->speedRampCheckBox,
@@ -157,6 +161,8 @@ void PTZSettings::joystickSetup()
157161
connect(joysticks, SIGNAL(countChanged()), this, SLOT(joystickUpdate()));
158162
connect(joysticks, SIGNAL(axisEvent(const QJoystickAxisEvent)), this,
159163
SLOT(joystickAxisEvent(const QJoystickAxisEvent)));
164+
connect(joysticks, SIGNAL(buttonEvent(const QJoystickButtonEvent)), this,
165+
SLOT(joystickButtonEvent(const QJoystickButtonEvent)));
160166

161167
auto selectionModel = ui->joystickNamesListView->selectionModel();
162168
connect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)), this,
@@ -180,21 +186,126 @@ void PTZSettings::on_joystickGroupBox_toggled(bool checked)
180186
ui->joystickNamesListView->setEnabled(checked);
181187
}
182188

189+
void PTZSettings::on_joystickAxisActionChanged(int idx)
190+
{
191+
auto controls = PTZControls::getInstance();
192+
auto cb = qobject_cast<QComboBox *>(sender());
193+
if (cb == nullptr)
194+
return;
195+
auto axis = cb->property("axis-id");
196+
ptz_joy_action_id action = cb->itemData(idx).toInt();
197+
if (axis.isValid())
198+
controls->setJoystickAxisAction(axis.toInt(), action);
199+
}
200+
201+
void PTZSettings::on_joystickButtonActionChanged(int idx)
202+
{
203+
auto controls = PTZControls::getInstance();
204+
auto cb = qobject_cast<QComboBox *>(sender());
205+
if (cb == nullptr)
206+
return;
207+
auto axis = cb->property("button-id");
208+
ptz_joy_action_id action = cb->itemData(idx).toInt();
209+
if (axis.isValid())
210+
controls->setJoystickButtonAction(axis.toInt(), action);
211+
}
212+
213+
#define BUTTON_ROW_OFFSET 100
183214
void PTZSettings::joystickUpdate()
184215
{
216+
auto cbAddJoyAction = [](QComboBox *cb, ptz_joy_action_id action) {
217+
cb->addItem(ptz_joy_action_names[action], (int)action);
218+
};
219+
185220
auto joysticks = QJoysticks::getInstance();
186221
auto controls = PTZControls::getInstance();
187222
m_joystickNamesModel.setStringList(joysticks->deviceNames());
188-
auto idx = m_joystickNamesModel.index(controls->joystickId(), 0);
189-
if (idx.isValid())
223+
auto jid = controls->joystickId();
224+
auto idx = m_joystickNamesModel.index(jid, 0);
225+
if (idx.isValid()) {
190226
ui->joystickNamesListView->setCurrentIndex(idx);
227+
for (int i = joystickAxisLabels.count(); i < joysticks->getNumAxes(jid); i++) {
228+
auto label = new QLabel(this);
229+
auto cb = new QComboBox(this);
230+
label->setText(QString("Axis %1").arg(i));
231+
cbAddJoyAction(cb, PTZ_JOY_ACTION_NONE);
232+
cbAddJoyAction(cb, PTZ_JOY_ACTION_PAN);
233+
cbAddJoyAction(cb, PTZ_JOY_ACTION_TILT);
234+
cbAddJoyAction(cb, PTZ_JOY_ACTION_ZOOM);
235+
cb->setProperty("axis-id", i);
236+
joystickAxisLabels.append(label);
237+
joystickAxisCBs.append(cb);
238+
ui->joystickMapGridLayout->addWidget(label, i, 0);
239+
ui->joystickMapGridLayout->addWidget(cb, i, 1);
240+
connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(on_joystickAxisActionChanged(int)));
241+
}
242+
for (int i = joystickButtonLabels.count(); i < joysticks->getNumButtons(jid); i++) {
243+
auto label = new QLabel(this);
244+
auto cb = new QComboBox(this);
245+
label->setText(QString("Button %1").arg(i));
246+
cbAddJoyAction(cb, PTZ_JOY_ACTION_NONE);
247+
cbAddJoyAction(cb, PTZ_JOY_ACTION_CAMERA_PREV);
248+
cbAddJoyAction(cb, PTZ_JOY_ACTION_CAMERA_NEXT);
249+
cbAddJoyAction(cb, PTZ_JOY_ACTION_PRESET_PREV);
250+
cbAddJoyAction(cb, PTZ_JOY_ACTION_PRESET_NEXT);
251+
cbAddJoyAction(cb, PTZ_JOY_ACTION_PRESET_RECALL);
252+
cb->setProperty("button-id", i);
253+
joystickButtonLabels.append(label);
254+
joystickButtonCBs.append(cb);
255+
ui->joystickMapGridLayout->addWidget(label, i + BUTTON_ROW_OFFSET, 0);
256+
ui->joystickMapGridLayout->addWidget(cb, i + BUTTON_ROW_OFFSET, 1);
257+
connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(on_joystickButtonActionChanged(int)));
258+
}
259+
260+
for (int i = 0; i < joystickAxisCBs.size(); i++)
261+
joystickAxisMappingChanged(i, controls->joystickAxisAction(i));
262+
for (int i = 0; i < joystickButtonCBs.size(); i++)
263+
joystickButtonMappingChanged(i, controls->joystickButtonAction(i));
264+
}
265+
}
266+
267+
void PTZSettings::joystickAxisMappingChanged(size_t axis, ptz_joy_action_id action)
268+
{
269+
if (axis >= (size_t)joystickAxisCBs.size())
270+
return;
271+
auto cb = joystickAxisCBs.at(axis);
272+
auto idx = cb->findData(QVariant((int)action));
273+
cb->setCurrentIndex(idx >= 0 ? idx : 0);
274+
}
275+
276+
void PTZSettings::joystickButtonMappingChanged(size_t button, ptz_joy_action_id action)
277+
{
278+
if (button >= (size_t)joystickButtonCBs.size())
279+
return;
280+
auto cb = joystickButtonCBs.at(button);
281+
auto idx = cb->findData(QVariant((int)action));
282+
cb->setCurrentIndex(idx >= 0 ? idx : 0);
191283
}
192284

193285
void PTZSettings::joystickCurrentChanged(QModelIndex current, QModelIndex previous)
194286
{
195287
Q_UNUSED(previous);
196288
PTZControls::getInstance()->setJoystickId(current.row());
197289
}
290+
291+
void PTZSettings::joystickAxisEvent(const QJoystickAxisEvent evt)
292+
{
293+
auto jid = PTZControls::getInstance()->joystickId();
294+
if (evt.joystick->id != jid || evt.axis >= joystickAxisLabels.size())
295+
return;
296+
auto label = joystickAxisLabels.at(evt.axis);
297+
label->setText(QString("Axis %1 [%2]").arg(evt.axis).arg(evt.value));
298+
}
299+
300+
void PTZSettings::joystickButtonEvent(const QJoystickButtonEvent evt)
301+
{
302+
auto jid = PTZControls::getInstance()->joystickId();
303+
if (evt.joystick->id != jid || evt.button >= joystickButtonLabels.size())
304+
return;
305+
auto label = joystickButtonLabels.at(evt.button);
306+
label->setText(QString("Button %1 [%2]").arg(evt.button).arg(evt.pressed));
307+
}
308+
198309
#else
199310
void PTZSettings::joystickSetup()
200311
{

src/settings.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,20 @@ class PTZSettings : public QWidget {
4343
protected:
4444
void joystickSetup();
4545
QStringListModel m_joystickNamesModel;
46+
QList<QLabel *> joystickAxisLabels, joystickButtonLabels;
47+
QList<QComboBox *> joystickAxisCBs, joystickButtonCBs;
4648
protected slots:
4749
void on_joystickGroupBox_toggled(bool checked);
4850
void on_joystickSpeedSlider_doubleValChanged(double val);
4951
void on_joystickDeadzoneSlider_doubleValChanged(double val);
52+
void on_joystickAxisActionChanged(int idx);
53+
void on_joystickButtonActionChanged(int idx);
5054
void joystickUpdate();
55+
void joystickAxisMappingChanged(size_t axis, ptz_joy_action_id action);
56+
void joystickButtonMappingChanged(size_t button, ptz_joy_action_id action);
5157
void joystickCurrentChanged(QModelIndex, QModelIndex);
58+
void joystickAxisEvent(const QJoystickAxisEvent);
59+
void joystickButtonEvent(const QJoystickButtonEvent);
5260
#else /* ENABLE_JOYSTICK */
5361
protected:
5462
void joystickSetup();

src/settings.ui

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -87,27 +87,25 @@
8787
</layout>
8888
</item>
8989
<item>
90-
<widget class="QLabel" name="joystickBindingsLabel">
91-
<property name="text">
92-
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Joysitck Bindings:&lt;/p&gt;
93-
&lt;p&gt;
94-
&lt;table&gt;
95-
&lt;tr&gt;&lt;th&gt;Control&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;
96-
&lt;tr&gt;&lt;td&gt;Left Joystick&lt;/td&gt;&lt;td&gt;Pan/Tilt&lt;/td&gt;&lt;/tr&gt;
97-
&lt;tr&gt;&lt;td&gt;Right Joystick&lt;/td&gt;&lt;td&gt;Zoom&lt;/td&gt;&lt;/tr&gt;
98-
&lt;tr&gt;&lt;td&gt;D-Pad&lt;/td&gt;&lt;td&gt;Select Preset&lt;/td&gt;&lt;/tr&gt;
99-
&lt;tr&gt;&lt;td&gt;Shoulder buttons&lt;/td&gt;&lt;td&gt;Change Camera&lt;/td&gt;&lt;/tr&gt;
100-
&lt;tr&gt;&lt;td&gt;A Button&lt;/td&gt;&lt;td&gt;Activate current preset&lt;/td&gt;&lt;/tr&gt;
101-
&lt;/table&gt;
102-
&lt;/p&gt;
103-
&lt;/body&gt;&lt;/html&gt;</string>
104-
</property>
105-
<property name="alignment">
106-
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
107-
</property>
108-
<property name="wordWrap">
90+
<widget class="QScrollArea" name="scrollArea">
91+
<property name="widgetResizable">
10992
<bool>true</bool>
11093
</property>
94+
<widget class="QWidget" name="scrollAreaWidgetContents_3">
95+
<property name="geometry">
96+
<rect>
97+
<x>0</x>
98+
<y>0</y>
99+
<width>330</width>
100+
<height>338</height>
101+
</rect>
102+
</property>
103+
<layout class="QVBoxLayout" name="verticalLayout_4">
104+
<item>
105+
<layout class="QGridLayout" name="joystickMapGridLayout"/>
106+
</item>
107+
</layout>
108+
</widget>
111109
</widget>
112110
</item>
113111
</layout>
@@ -264,30 +262,30 @@
264262
<property name="sizeConstraint">
265263
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
266264
</property>
265+
<item>
266+
<layout class="QHBoxLayout" name="horizontalLayout_4">
267+
<item>
268+
<spacer name="horizontalSpacer">
269+
<property name="orientation">
270+
<enum>Qt::Orientation::Horizontal</enum>
271+
</property>
272+
<property name="sizeHint" stdset="0">
273+
<size>
274+
<width>40</width>
275+
<height>20</height>
276+
</size>
277+
</property>
278+
</spacer>
279+
</item>
267280
<item>
268-
<layout class="QHBoxLayout" name="horizontalLayout_4">
269-
<item>
270-
<spacer name="horizontalSpacer">
271-
<property name="orientation">
272-
<enum>Qt::Orientation::Horizontal</enum>
273-
</property>
274-
<property name="sizeHint" stdset="0">
275-
<size>
276-
<width>40</width>
277-
<height>20</height>
278-
</size>
279-
</property>
280-
</spacer>
281-
</item>
282-
<item>
283-
<widget class="QPushButton" name="applyButton">
284-
<property name="text">
285-
<string>Apply</string>
286-
</property>
287-
</widget>
288-
</item>
289-
</layout>
281+
<widget class="QPushButton" name="applyButton">
282+
<property name="text">
283+
<string>Apply</string>
284+
</property>
285+
</widget>
290286
</item>
287+
</layout>
288+
</item>
291289
</layout>
292290
</widget>
293291
</widget>

0 commit comments

Comments
 (0)