File indexing completed on 2024-05-12 05:35:40
0001 /* 0002 SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com> 0003 SPDX-FileCopyrightText: 2023 Jeremy Whiting <jpwhiting@kde.org> 0004 SPDX-FileCopyrightText: 2023 Niccolò Venerandi <niccolo@venerandi.com> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "devicemodel.h" 0010 0011 #include <KLocalizedString> 0012 #include <QTimer> 0013 0014 #include <SDL2/SDL.h> 0015 #include <SDL2/SDL_joystick.h> 0016 0017 #include "gamepad.h" 0018 #include "logging.h" 0019 0020 DeviceModel::DeviceModel() 0021 { 0022 auto timer = new QTimer(this); 0023 connect(timer, &QTimer::timeout, this, &DeviceModel::poll); 0024 timer->start(1); 0025 } 0026 0027 Gamepad *DeviceModel::device(int index) const 0028 { 0029 if (index < 0 || index >= m_devices.count()) 0030 return nullptr; 0031 0032 const int sdlIndex = m_devices.keys().at(index); 0033 return m_devices.value(sdlIndex); 0034 } 0035 0036 int DeviceModel::rowCount(const QModelIndex &parent) const 0037 { 0038 Q_UNUSED(parent) 0039 return m_devices.count(); 0040 } 0041 0042 QVariant DeviceModel::data(const QModelIndex &index, int role) const 0043 { 0044 if (!checkIndex(index)) { 0045 return {}; 0046 } 0047 0048 if (role == Qt::DisplayRole) { 0049 const int sdlIndex = m_devices.keys().at(index.row()); 0050 0051 return i18nc("Device name and path", "%1 (%2)", m_devices.value(sdlIndex)->name(), m_devices.value(sdlIndex)->path()); 0052 } 0053 0054 return {}; 0055 } 0056 0057 void DeviceModel::poll() 0058 { 0059 SDL_Event event{}; 0060 while (SDL_PollEvent(&event)) { 0061 switch (event.type) { 0062 case SDL_CONTROLLERDEVICEADDED: 0063 addDevice(event.cdevice.which); 0064 break; 0065 case SDL_CONTROLLERDEVICEREMOVED: 0066 removeDevice(event.cdevice.which); 0067 break; 0068 case SDL_CONTROLLERBUTTONDOWN: 0069 case SDL_CONTROLLERBUTTONUP: 0070 m_devices.value(event.cbutton.which)->onButtonEvent(event.cbutton); 0071 break; 0072 case SDL_CONTROLLERAXISMOTION: 0073 m_devices.value(event.caxis.which)->onAxisEvent(event.caxis); 0074 break; 0075 } 0076 } 0077 } 0078 0079 void DeviceModel::addDevice(const int deviceIndex) 0080 { 0081 const auto joystick = SDL_JoystickOpen(deviceIndex); 0082 const auto id = SDL_JoystickInstanceID(joystick); 0083 0084 if (m_devices.contains(id)) { 0085 qCWarning(KCM_GAMECONTROLLER) << "Got a duplicate add event, ignoring. Index: " << deviceIndex; 0086 return; 0087 } 0088 0089 const auto gamepad = SDL_GameControllerOpen(deviceIndex); 0090 if (SDL_GameControllerTypeForIndex(deviceIndex) == SDL_CONTROLLER_TYPE_VIRTUAL) { 0091 qCWarning(KCM_GAMECONTROLLER) << "Skipping gamepad since it is virtual. Index: " << deviceIndex; 0092 return; 0093 } 0094 0095 beginInsertRows(QModelIndex(), m_devices.count(), m_devices.count()); 0096 m_devices.insert(id, new Gamepad(joystick, gamepad, this)); 0097 endInsertRows(); 0098 0099 Q_EMIT devicesChanged(); 0100 } 0101 0102 void DeviceModel::removeDevice(const int deviceIndex) 0103 { 0104 if (!m_devices.contains(deviceIndex)) { 0105 qCWarning(KCM_GAMECONTROLLER) << "Invalid device index from removal event, ignoring"; 0106 return; 0107 } 0108 0109 const int index = m_devices.keys().indexOf(deviceIndex); 0110 0111 beginRemoveRows(QModelIndex(), index, index); 0112 m_devices.value(deviceIndex)->deleteLater(); 0113 m_devices.remove(deviceIndex); 0114 endRemoveRows(); 0115 0116 Q_EMIT devicesChanged(); 0117 } 0118 0119 int DeviceModel::count() const 0120 { 0121 return m_devices.size(); 0122 } 0123 0124 #include "moc_devicemodel.cpp"