MacroBinds/qmacrokeysmanager.cpp
2024-09-17 04:05:32 -04:00

152 lines
4.9 KiB
C++

#include "qmacrokeysmanager.h"
#include <codecvt>
#include <locale>
QMacroKeysManager::QMacroKeysManager(QObject *parent)
: QObject{parent}
{}
void QMacroKeysManager::initDevices()
{
hid_device_info *deviceInfo = hid_enumerate(MACROKEYS_VID, MACROKEYS_PID);
if (!deviceInfo) {
return;
}
for (hid_device_info *di = deviceInfo; di != nullptr; di = di->next) {
QDeviceHandler *deviceHandler = new QDeviceHandler();
this->mDevices[di->path] = deviceHandler;
QObject::connect(deviceHandler,
&QDeviceHandler::deviceInitialised,
this,
&QMacroKeysManager::getDeviceInitStatus);
deviceHandler->initDevice(di);
}
}
void QMacroKeysManager::getDeviceInitStatus(const HIDDevice &device)
{
QDeviceHandler *dh = this->mDevices[device.sPath];
QObject::connect(dh,
&QDeviceHandler::buttonStateChanged,
this,
&QMacroKeysManager::handleNewButtonState);
QObject::connect(dh,
&QDeviceHandler::encoderRotationChanged,
this,
&QMacroKeysManager::handleNewEncoderRotation);
emit this->newDeviceFound(device.sPath);
dh->runDevice();
}
void QMacroKeysManager::handleNewButtonState(const quint8 &row,
const quint8 &column,
const bool &state)
{
emit this->newButtonState(row, column, state);
}
void QMacroKeysManager::handleNewEncoderRotation(const quint8 &column,
const EncoderRotation &direction)
{
emit this->newEncoderRotation(column, direction);
}
void QMacroKeysManager::uninitDevices() {}
QDeviceHandler::QDeviceHandler(QObject *parent)
: QObject{parent}
{
this->moveToThread(&this->threadButtonReader);
this->threadButtonReader.start();
}
QDeviceHandler::~QDeviceHandler()
{
hid_close(this->hidDevice.hidDevice);
this->threadButtonReader.quit();
this->threadButtonReader.wait();
}
void QDeviceHandler::initDevice(const hid_device_info *di)
{
hid_device_info *deviceInfo = hid_enumerate(MACROKEYS_VID, MACROKEYS_PID);
if (!deviceInfo) {
return;
}
HIDDevice device;
device.hidInfo = di;
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
device.sManufacturer = utf8_conv.to_bytes(di->manufacturer_string).c_str();
device.sProduct = utf8_conv.to_bytes(di->product_string).c_str();
device.sPath = di->path;
hid_device *handle = hid_open(MACROKEYS_VID, MACROKEYS_PID, deviceInfo->serial_number);
device.hidDevice = handle;
hid_set_nonblocking(device.hidDevice, 0);
ButtonStateRow buttonStatesRow;
buttonStatesRow.fill(false, NUM_BUTTON_COLUMNS);
QVector<ButtonStateRow> buttonStates;
buttonStates.fill(buttonStatesRow, NUM_BUTTON_ROWS);
this->vCurrentButtonStates = buttonStates;
this->hidDevice = device;
emit this->deviceInitialised(this->hidDevice);
}
void QDeviceHandler::runDevice()
{
QMetaObject::invokeMethod(this, "buttonReadLoop");
}
void QDeviceHandler::buttonReadLoop()
{
while (this->threadButtonReader.isRunning()) {
const ButtonStateVector &previousState = ButtonStateVector(this->vCurrentButtonStates);
unsigned char buffer[NUM_HID_BYTES];
hid_read(this->hidDevice.hidDevice, buffer, NUM_HID_BYTES);
for (int column = 0; column < NUM_BUTTON_COLUMNS; column++) {
for (int row = 0; row < NUM_BUTTON_ROWS; row++) {
// Convert bit position in each byte into a row/column value.
// Bits are read from left to right, as though they were one
// little endian value, but with bit order reversed as well.
// Each successive byte counts down the row number, and then
// rolls over to the next column for each row.
//
// Examples:
// - Bit 7 in byte 0 (1000 0000 | 0000 0000) is row 0, column 0
// - Bit 6 in byte 0 (0100 0000 | 0000 0000) is row 1, column 0
// - Bit 2 in byte 1 (0000 0000 | 0100 0000) is row 2, column 1
// - Bit 0 in byte 1 (0000 0000 | 0000 0001) is row 8, column 1
const quint8 buttonBit = (column * NUM_BUTTON_ROWS) + row;
const quint8 byte = buttonBit / 8;
const quint8 byteBit = buttonBit % 8;
const bool buttonState = (buffer[byte] >> (8 - (byteBit + 1))) & 0b00000001;
this->vCurrentButtonStates[row][column] = buttonState;
if (previousState[row][column] != buttonState) {
emit this->buttonStateChanged(row, column, buttonState);
}
}
}
const char &encoderDirectionBytes = buffer[NUM_HID_BYTES - 1];
if (encoderDirectionBytes & ENC1_CCW) emit encoderRotationChanged(0, EncoderRotation::CCW);
if (encoderDirectionBytes & ENC1_CW) emit encoderRotationChanged(0, EncoderRotation::CW);
if (encoderDirectionBytes & ENC2_CCW) emit encoderRotationChanged(1, EncoderRotation::CCW);
if (encoderDirectionBytes & ENC2_CW) emit encoderRotationChanged(1, EncoderRotation::CW);
if (encoderDirectionBytes & ENC3_CCW) emit encoderRotationChanged(2, EncoderRotation::CCW);
if (encoderDirectionBytes & ENC3_CW) emit encoderRotationChanged(2, EncoderRotation::CW);
if (encoderDirectionBytes & ENC4_CCW) emit encoderRotationChanged(3, EncoderRotation::CCW);
if (encoderDirectionBytes & ENC4_CW) emit encoderRotationChanged(3, EncoderRotation::CW);
}
}