Warning, file /plasma-bigscreen/plasma-remotecontrollers/src/wiimote/wiimote.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2022 Bart Ribbers <bribbers@disroot.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "wiimote.h" 0008 #include "../controllermanager.h" 0009 0010 #include <QLoggingCategory> 0011 #include <QDebug> 0012 #include <KLocalizedString> 0013 0014 #include <xwiimote.h> 0015 #include <linux/input-event-codes.h> 0016 #include <unistd.h> 0017 0018 Wiimote::Wiimote(struct xwii_iface *iface, const QString &sysPath) 0019 { 0020 m_iface = iface; 0021 m_uniqueIdentifier = sysPath; 0022 m_name = i18nc("What Nintendo Wii remote controllers are called", "Wii Remote"); 0023 m_deviceType = DeviceWiimote; 0024 0025 int ret; 0026 char *devtype; 0027 do { 0028 ret = xwii_iface_get_devtype(iface, &devtype); 0029 if (ret) { 0030 qCritical() << "wiimote: ERROR: Failed to read devtype of new Wiimote device, error:" << ret; 0031 return; 0032 } 0033 } while (strcmp(devtype, "pending") == 0); 0034 0035 if (strcmp(devtype, "unknown") == 0) 0036 m_devType = WIIMOTE_DEVTYPE_UNKNOWN; 0037 else if (strcmp(devtype, "generic") == 0) 0038 m_devType = WIIMOTE_DEVTYPE_GENERIC; 0039 else if (strcmp(devtype, "gen10") == 0) 0040 m_devType = WIIMOTE_DEVTYPE_GEN10; 0041 else if (strcmp(devtype, "gen15") == 0) 0042 m_devType = WIIMOTE_DEVTYPE_GEN15; 0043 else if (strcmp(devtype, "gen20") == 0) 0044 m_devType = WIIMOTE_DEVTYPE_GEN20; 0045 else if (strcmp(devtype, "balanceboard") == 0) 0046 m_devType = WIIMOTE_DEVTYPE_BALANCEBOARD; 0047 else if (strcmp(devtype, "procontroller") == 0) 0048 m_devType = WIIMOTE_DEVTYPE_PROCONTROLLER; 0049 0050 free(devtype); 0051 0052 if (m_devType == WIIMOTE_DEVTYPE_UNKNOWN) { 0053 return; 0054 } 0055 0056 QObject::connect(this, &Wiimote::keyPress, 0057 &ControllerManager::instance(), &ControllerManager::emitKey); 0058 0059 ret = xwii_iface_open(m_iface, xwii_iface_available(m_iface) | XWII_IFACE_WRITABLE); 0060 0061 if (ret) { 0062 qCritical() << "wiimote: Error: Cannot open interface " << ret; 0063 } 0064 0065 // We want to watch for hotplug events and adapt our device accordingly 0066 ret = xwii_iface_watch(m_iface, true); 0067 0068 if (ret) { 0069 qCritical() << "wiimote: Error: Cannot initialize hotplug watch descriptor"; 0070 } 0071 0072 memset(m_fds, 0, sizeof(m_fds)); 0073 m_fds[0].fd = 0; 0074 m_fds[0].events = POLLIN; 0075 m_fds[1].fd = xwii_iface_get_fd(m_iface); 0076 m_fds[1].events = POLLIN; 0077 m_fdsNum = 2; 0078 0079 getExtensionType(); 0080 0081 // Let the user know the device is being used by rumbling 0082 xwii_iface_rumble(m_iface, true); 0083 usleep(200 * 1000); // Only rumble for half a second 0084 xwii_iface_rumble(m_iface, false); 0085 } 0086 0087 WiimoteDevtypes Wiimote::getDevType() 0088 { 0089 return m_devType; 0090 } 0091 0092 0093 void Wiimote::watchEvents() 0094 { 0095 struct xwii_event event; 0096 int ret; 0097 0098 ret = poll(m_fds, m_fdsNum, -1); 0099 if (ret < 0) { 0100 qDebug() << "wiimote: Error: Cannot poll fds: " << ret; 0101 return; 0102 } 0103 0104 ret = xwii_iface_dispatch(m_iface, &event, sizeof(event)); 0105 if (ret && ret != -EAGAIN) { 0106 qCritical() << "wiimote: Error: Read failed with err: " << ret; 0107 return; 0108 } 0109 0110 switch (event.type) { 0111 case XWII_EVENT_GONE: 0112 // TODO: we don't always get this event 0113 // https://github.com/dvdhrm/xwiimote/issues/99 0114 emit deviceDisconnected(m_index); 0115 break; 0116 case XWII_EVENT_WATCH: 0117 handleWatch(); 0118 break; 0119 case XWII_EVENT_KEY: 0120 handleKeypress(&event); 0121 break; 0122 case XWII_EVENT_NUNCHUK_KEY: 0123 case XWII_EVENT_NUNCHUK_MOVE: 0124 handleNunchuk(&event); 0125 break; 0126 case XWII_EVENT_ACCEL: 0127 case XWII_EVENT_IR: 0128 case XWII_EVENT_BALANCE_BOARD: 0129 case XWII_EVENT_MOTION_PLUS: 0130 case XWII_EVENT_CLASSIC_CONTROLLER_KEY: 0131 case XWII_EVENT_CLASSIC_CONTROLLER_MOVE: 0132 case XWII_EVENT_PRO_CONTROLLER_KEY: 0133 case XWII_EVENT_PRO_CONTROLLER_MOVE: 0134 case XWII_EVENT_NUM: 0135 case XWII_EVENT_GUITAR_KEY: 0136 case XWII_EVENT_GUITAR_MOVE: 0137 case XWII_EVENT_DRUMS_KEY: 0138 case XWII_EVENT_DRUMS_MOVE: 0139 break; 0140 } 0141 } 0142 0143 void Wiimote::handleWatch() 0144 { 0145 int ret; 0146 0147 // After a hotplug event occurred xwii_iface_open will fail if called too shortly after it happened 0148 // Because of this, just keep calling it till it succeeds 0149 // https://github.com/dvdhrm/xwiimote/issues/97 0150 do { 0151 ret = xwii_iface_open(m_iface, xwii_iface_available(m_iface) | XWII_IFACE_WRITABLE); 0152 } while (ret); 0153 0154 getExtensionType(); 0155 } 0156 0157 void Wiimote::handleKeypress(struct xwii_event *event) 0158 { 0159 static QHash<int, int> keyCodeTranslation = { 0160 { XWII_KEY_A, KEY_ENTER}, 0161 { XWII_KEY_B, KEY_BACK}, 0162 { XWII_KEY_UP, KEY_UP}, 0163 { XWII_KEY_DOWN, KEY_DOWN}, 0164 { XWII_KEY_LEFT, KEY_LEFT}, 0165 { XWII_KEY_RIGHT, KEY_RIGHT}, 0166 { XWII_KEY_ONE, KEY_1}, 0167 { XWII_KEY_TWO, KEY_2}, 0168 { XWII_KEY_PLUS, KEY_VOLUMEUP}, 0169 { XWII_KEY_MINUS, KEY_VOLUMEDOWN}, 0170 { XWII_KEY_HOME, KEY_HOME}, 0171 }; 0172 0173 bool pressed = event->v.key.state; 0174 int nativeKeyCode = keyCodeTranslation.value(event->v.key.code, -1); 0175 0176 if (nativeKeyCode < 0) { 0177 qDebug() << "wiimote: DEBUG: Received a keypress we do not handle!"; 0178 return; 0179 } 0180 0181 emit keyPress(nativeKeyCode, pressed); 0182 } 0183 0184 void Wiimote::handleNunchuk(struct xwii_event *event) 0185 { 0186 double val; 0187 0188 if (event->type == XWII_EVENT_NUNCHUK_MOVE) { 0189 int time_since_previous_event = 0190 event->time.tv_sec - m_previousNunchukAxisTime; 0191 0192 if (time_since_previous_event > 0) { 0193 // pow(val, 1/4) for smoother interpolation around the origin 0194 val = event->v.abs[0].x * 12; 0195 if (val > 1000) { 0196 emit keyPress(KEY_RIGHT, true); 0197 emit keyPress(KEY_RIGHT, false); 0198 m_previousNunchukAxisTime = event->time.tv_sec; 0199 } else if (val < -1000) { 0200 emit keyPress(KEY_LEFT, true); 0201 emit keyPress(KEY_LEFT, false); 0202 m_previousNunchukAxisTime = event->time.tv_sec; 0203 } 0204 0205 val = event->v.abs[0].y * 12; 0206 if (val > 1000) { 0207 emit keyPress(KEY_UP, true); 0208 emit keyPress(KEY_UP, false); 0209 m_previousNunchukAxisTime = event->time.tv_sec; 0210 } else if (val < -1000) { 0211 emit keyPress(KEY_DOWN, true); 0212 emit keyPress(KEY_DOWN, false); 0213 m_previousNunchukAxisTime = event->time.tv_sec; 0214 } 0215 } 0216 } 0217 } 0218 0219 void Wiimote::getExtensionType() 0220 { 0221 char* extensionName; 0222 int ret = xwii_iface_get_extension(m_iface, &extensionName); 0223 0224 if (ret) 0225 qCritical() << "wiimote: ERROR: Failed to read extension type!"; 0226 0227 if (strcmp(extensionName, "none") == 0) 0228 m_extensionType = WIIMOTE_EXTENSION_NONE; 0229 else if (strcmp(extensionName, "unknown") == 0) 0230 m_extensionType = WIIMOTE_EXTENSION_UNKNOWN; 0231 else if (strcmp(extensionName, "nunchuk") == 0) 0232 m_extensionType = WIIMOTE_EXTENSION_NUNCHUK; 0233 else if (strcmp(extensionName, "classic") == 0) 0234 m_extensionType = WIIMOTE_EXTENSION_CLASSIC; 0235 else if (strcmp(extensionName, "balanceboard") == 0) 0236 m_extensionType = WIIMOTE_EXTENSION_CLASSIC; 0237 else if (strcmp(extensionName, "procontroller") == 0) 0238 m_extensionType = WIIMOTE_EXTENSION_PROCONTROLLER; 0239 } 0240 0241 Wiimote::~Wiimote() 0242 { 0243 xwii_iface_unref(m_iface); 0244 }