#include "qmacrokeysmanager.h" #include #include 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> 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 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); } }