swift
inputmanager.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "core/inputmanager.h"
5 
6 #include <limits.h>
7 
8 #include <QtGlobal>
9 
11 #include "misc/range.h"
12 #include "misc/sequence.h"
13 
14 // clazy:excludeall=detaching-member
15 
16 using namespace swift::input;
17 using namespace swift::misc;
18 using namespace swift::misc::input;
19 
20 namespace swift::core
21 {
22  CInputManager::CInputManager(QObject *parent) : QObject(parent) { reloadHotkeySettings(); }
23 
24  void CInputManager::registerAction(const QString &action, CIcons::IconIndex icon)
25  {
26  if (!m_availableActions.contains(action))
27  {
28  m_availableActions.insert(action, icon);
29  emit this->hotkeyActionRegistered({ action });
30  }
31  }
32 
33  void CInputManager::registerRemoteActions(const QStringList &actions)
34  {
35  for (const auto &action : actions)
36  {
37  if (!m_availableActions.contains(action))
38  {
39  m_availableActions.insert(action, {});
40  emit this->hotkeyActionRegistered({ action });
41  }
42  }
43  }
44 
45  void CInputManager::unbind(int index)
46  {
47  auto info = std::find_if(m_boundActions.begin(), m_boundActions.end(),
48  [index](const BindInfo &info) { return info.m_index == index; });
49  if (info != m_boundActions.end()) { m_boundActions.erase(info); }
50  }
51 
52  void CInputManager::reloadHotkeySettings()
53  {
54  m_configuredActions.clear();
55  for (const CActionHotkey &actionHotkey : m_actionHotkeys.getThreadLocal())
56  {
57  if (!actionHotkey.getApplicableMachine().isFromLocalMachine()) { continue; }
58  CHotkeyCombination combination = actionHotkey.getCombination();
59  if (combination.isEmpty()) continue;
60 
61  m_configuredActions.insert(combination, actionHotkey.getAction());
62  }
63  }
64 
65  void CInputManager::processKeyCombinationChanged(const CHotkeyCombination &combination)
66  {
67  // Merge in the joystick part
68  // mixed on purpose, as any joystick keyboard combination is possible
69  CHotkeyCombination copy(combination);
70  copy.setJoystickButtons(m_lastCombination.getJoystickButtons());
71  processCombination(copy);
72  }
73 
74  void CInputManager::processButtonCombinationChanged(const CHotkeyCombination &combination)
75  {
76  // Merge in the keyboard keys
77  // mixed on purpose, as any joystick keyboard combination is possible
78  CHotkeyCombination copy(combination);
79  copy.setKeyboardKeys(m_lastCombination.getKeyboardKeys());
80  processCombination(copy);
81  }
82 
84  {
85  m_captureActive = true;
86  m_capturedCombination = {};
87  m_combinationBeforeCapture = m_lastCombination;
88  }
89 
90  void CInputManager::callFunctionsBy(const QString &action, bool isKeyDown, bool shouldEmit)
91  {
92  if (action.isEmpty()) { return; }
93  if (m_actionRelayingEnabled && shouldEmit) { emit remoteActionFromLocal(action, isKeyDown); }
94 
95  for (const auto &boundAction : std::as_const(m_boundActions))
96  {
97  if (boundAction.m_action == action) { boundAction.m_function(isKeyDown); }
98  }
99  }
100 
101  void CInputManager::triggerKey(const CHotkeyCombination &combination, bool isPressed)
102  {
103  Q_UNUSED(isPressed)
104  QString previousAction = m_configuredActions.value(m_lastCombination);
105  QString action = m_configuredActions.value(combination);
106  callFunctionsBy(previousAction, false);
107  callFunctionsBy(action, true);
108  m_lastCombination = combination;
109  }
110 
112  {
113  m_keyboard = IKeyboard::create(this);
114  m_joystick = IJoystick::create(this);
115  connect(m_keyboard.get(), &IKeyboard::keyCombinationChanged, this, &CInputManager::processKeyCombinationChanged,
116  Qt::QueuedConnection);
117  connect(m_joystick.get(), &IJoystick::buttonCombinationChanged, this,
118  &CInputManager::processButtonCombinationChanged, Qt::QueuedConnection);
119  }
120 
122  {
123  m_keyboard.reset();
124  m_joystick.reset();
125  }
126 
128  {
129  return m_joystick->getAllAvailableJoystickButtons();
130  }
131 
132  int CInputManager::bindImpl(const QString &action, QObject *receiver, std::function<void(bool)> function)
133  {
134  static int index = 0;
135  Q_ASSERT(index < INT_MAX);
136  BindInfo info;
137  info.m_index = index;
138  ++index;
139  info.m_function = function;
140  info.m_action = action;
141  info.m_receiver = receiver;
142  m_boundActions.push_back(info);
143  return info.m_index;
144  }
145 
146  void CInputManager::processCombination(const CHotkeyCombination &currentCombination)
147  {
148  if (m_captureActive)
149  {
150  CHotkeyCombination deltaCombination = currentCombination.getDeltaComparedTo(m_combinationBeforeCapture);
151 
152  // Don't continue if there is no relevant combination yet
153  if (m_capturedCombination.isEmpty() && deltaCombination.isEmpty()) { return; }
154 
155  if (deltaCombination.size() < m_capturedCombination.size())
156  {
157  emit combinationSelectionFinished(m_capturedCombination);
158  m_captureActive = false;
159  }
160  else
161  {
162  emit combinationSelectionChanged(deltaCombination);
163  m_capturedCombination = deltaCombination;
164  }
165  return;
166  }
167 
168  QSet<QString> newActiveActions;
169  for (const auto [combination, action] : makePairsRange(std::as_const(m_configuredActions)))
170  {
171  if (combination.isSubsetOf(currentCombination)) { newActiveActions.insert(action); }
172  }
173 
174  const QSet<QString> pressedActions = newActiveActions - m_activeActions;
175  const QSet<QString> releasedActions = m_activeActions - newActiveActions;
176  m_activeActions = newActiveActions;
177  for (const QString &action : pressedActions) { callFunctionsBy(action, true); }
178  for (const QString &action : releasedActions) { callFunctionsBy(action, false); }
179 
180  // combination
181  m_lastCombination = currentCombination;
182  }
183 } // namespace swift::core
void registerRemoteActions(const QStringList &actions)
Register remote actions.
void callFunctionsBy(const QString &action, bool isKeyDown, bool shouldEmit=true)
Call functions by hotkeyfunction.
void remoteActionFromLocal(const QString &action, bool argument)
Event hotkeyfunction occured.
void registerAction(const QString &action, swift::misc::CIcons::IconIndex icon=swift::misc::CIcons::StandardIconEmpty16)
Register new action.
void combinationSelectionFinished(const swift::misc::input::CHotkeyCombination &combination)
Combination selection has finished.
void combinationSelectionChanged(const swift::misc::input::CHotkeyCombination &combination)
Selected combination has changed.
void startCapture()
Select a key combination as hotkey. This method returns immediatly. Listen for signals combinationSel...
void unbind(int index)
Unbind a slot.
void hotkeyActionRegistered(const QStringList &actions)
New hotkey action is registered.
void triggerKey(const swift::misc::input::CHotkeyCombination &combination, bool isPressed)
Triggers a key event manually and calls the registered functions.
swift::misc::input::CJoystickButtonList getAllAvailableJoystickButtons() const
Get all available joystick buttons.
void createDevices()
Creates low level input devices. Once completed, hotkeys start to be processed.
void releaseDevices()
Releases all devices.
IconIndex
Index for each icon, allows to send them via DBus, efficiently store them, etc.
Definition: icons.h:32
Value object encapsulating a action hotkey.
Definition: actionhotkey.h:25
Value object representing hotkey sequence.
int size() const
Get size of sequence.
CHotkeyCombination getDeltaComparedTo(const CHotkeyCombination &other) const
Returns the delta (removing all keys and buttons contained in other)
bool isSubsetOf(const CHotkeyCombination &other) const
Is sequence a subset of other? E.g. CTRL would be a subset of CTRL+D.
CJoystickButtonList getJoystickButtons() const
Get joystick buttons.
CKeyboardKeyList getKeyboardKeys() const
Get keyboard keys.
bool isEmpty() const
Is sequence empty?
Value object encapsulating a list of joystick buttons.
Backend services of the swift project, like dealing with the network or the simulators.
Definition: actionbind.cpp:7
Free functions in swift::misc.
auto makePairsRange(const T &container)
Returns a const CRange for iterating over the keys and values of a Qt associative container.
Definition: range.h:374