152 lines
4.9 KiB
C++
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);
|
|
}
|
|
}
|