Add files
This commit is contained in:
60
sustain-kbd-config/.gitignore
vendored
Normal file
60
sustain-kbd-config/.gitignore
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/c++
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=c++
|
||||
|
||||
### C++ ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/c++
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/cmake
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake
|
||||
|
||||
### CMake ###
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
### CMake Patch ###
|
||||
# External projects
|
||||
*-prefix/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/cmake
|
74
sustain-kbd-config/CMakeLists.txt
Normal file
74
sustain-kbd-config/CMakeLists.txt
Normal file
@@ -0,0 +1,74 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(sustain-kbd-config VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(LIBUSB REQUIRED libusb-1.0)
|
||||
|
||||
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
|
||||
# Check https://doc.qt.io/qt/deployment-android.html for more information.
|
||||
# They need to be set before the find_package( ...) calls below.
|
||||
|
||||
#if(ANDROID)
|
||||
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
|
||||
# if (ANDROID_ABI STREQUAL "armeabi-v7a")
|
||||
# set(ANDROID_EXTRA_LIBS
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
|
||||
# endif()
|
||||
#endif()
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
main.cpp
|
||||
mainwindow.cpp
|
||||
mainwindow.h
|
||||
mainwindow.ui
|
||||
libusbwrapper.cpp
|
||||
libusbwrapper.h
|
||||
sustainpedalkeyboard.h
|
||||
sustainpedalkeyboard.cpp
|
||||
)
|
||||
|
||||
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||
qt_add_executable(sustain-kbd-config
|
||||
MANUAL_FINALIZATION
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
else()
|
||||
if(ANDROID)
|
||||
add_library(sustain-kbd-config SHARED
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
else()
|
||||
add_executable(sustain-kbd-config
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(sustain-kbd-config PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${LIBUSB_LDFLAGS})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${LIBUSB_INCLUDE_DIRS})
|
||||
|
||||
set_target_properties(sustain-kbd-config PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
CXX_STANDARD 17
|
||||
)
|
||||
|
||||
if(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt_finalize_executable(sustain-kbd-config)
|
||||
endif()
|
137
sustain-kbd-config/libusbwrapper.cpp
Normal file
137
sustain-kbd-config/libusbwrapper.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "libusbwrapper.h"
|
||||
#include <libusb.h>
|
||||
#include <iostream>
|
||||
|
||||
UsbDevice::UsbDevice(libusb_device *device)
|
||||
{
|
||||
int res;
|
||||
|
||||
this->dev = device;
|
||||
res = libusb_get_device_descriptor(device, &this->devdesc);
|
||||
this->device_handle = nullptr;
|
||||
|
||||
if (res == 0) {
|
||||
this->vendor_id = devdesc.idVendor;
|
||||
this->product_id = devdesc.idProduct;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UsbDevice::UsbDevice(UsbDevice &&d)
|
||||
{
|
||||
vendor_id = std::move(d.vendor_id);
|
||||
product_id = std::move(d.product_id);
|
||||
dev = d.dev;
|
||||
devdesc = d.devdesc;
|
||||
device_handle = std::move(d.device_handle);
|
||||
}
|
||||
|
||||
UsbDevice::~UsbDevice()
|
||||
{
|
||||
/* Nothing to do here. Our device handle will be automatically closed once the shared pointer is released */
|
||||
}
|
||||
|
||||
std::vector<UsbDevice> UsbDevice::find_devices(uint16_t vendor_id, uint16_t product_id)
|
||||
{
|
||||
auto ret_vector = std::vector<UsbDevice>();
|
||||
libusb_device **devlist;
|
||||
|
||||
int res = libusb_get_device_list(NULL, &devlist);
|
||||
if (res > 0) {
|
||||
for (int idx = 0; idx < res; idx++) {
|
||||
auto d = UsbDevice(devlist[idx]);
|
||||
if (d.get_product_id() == product_id && d.get_vendor_id() == vendor_id)
|
||||
ret_vector.push_back(std::move(d));
|
||||
}
|
||||
}
|
||||
|
||||
return ret_vector;
|
||||
}
|
||||
|
||||
bool UsbDevice::opened()
|
||||
{
|
||||
return !!(this->device_handle != nullptr);
|
||||
}
|
||||
|
||||
int UsbDevice::open()
|
||||
{
|
||||
int ret;
|
||||
libusb_device_handle *handle;
|
||||
|
||||
if (this->dev) {
|
||||
ret = libusb_open(this->dev, &handle);
|
||||
} else {
|
||||
handle = libusb_open_device_with_vid_pid(NULL, this->vendor_id, this->product_id);
|
||||
if (!handle)
|
||||
ret = -1;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
device_handle = std::make_shared<UsbDeviceHandle>(handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint16_t UsbDevice::get_vendor_id()
|
||||
{
|
||||
return this->vendor_id;
|
||||
}
|
||||
|
||||
uint16_t UsbDevice::get_product_id()
|
||||
{
|
||||
return this->product_id;
|
||||
}
|
||||
|
||||
int UsbDevice::control_transfer(uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout)
|
||||
{
|
||||
if (!opened())
|
||||
return -1000;
|
||||
|
||||
return libusb_control_transfer(this->device_handle->m_handle, request_type, bRequest, wValue, wIndex, data, wLength, timeout);
|
||||
}
|
||||
|
||||
const std::string &UsbDevice::get_serial_number()
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
|
||||
if (!opened())
|
||||
return serial;
|
||||
if (devdesc.iSerialNumber == 0)
|
||||
return serial;
|
||||
|
||||
if (serial.length() > 0) {
|
||||
return serial;
|
||||
}
|
||||
|
||||
int res = libusb_get_string_descriptor_ascii(device_handle->m_handle, devdesc.iSerialNumber, (unsigned char *)buffer, 255);
|
||||
if (res > 0) {
|
||||
serial = std::string(buffer);
|
||||
return serial;
|
||||
} else {
|
||||
return serial;
|
||||
}
|
||||
}
|
||||
|
||||
void LibUsbInit()
|
||||
{
|
||||
libusb_init(NULL);
|
||||
}
|
||||
|
||||
void LibUsbDeInit()
|
||||
{
|
||||
libusb_exit(NULL);
|
||||
}
|
||||
|
||||
UsbDeviceHandle::UsbDeviceHandle(libusb_device_handle *handle)
|
||||
{
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
UsbDeviceHandle::~UsbDeviceHandle()
|
||||
{
|
||||
if (m_handle)
|
||||
libusb_close(m_handle);
|
||||
m_handle = NULL;
|
||||
}
|
47
sustain-kbd-config/libusbwrapper.h
Normal file
47
sustain-kbd-config/libusbwrapper.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef LIBUSBWRAPPER_H
|
||||
#define LIBUSBWRAPPER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <libusb.h>
|
||||
#include <memory>
|
||||
|
||||
void LibUsbInit();
|
||||
void LibUsbDeInit();
|
||||
|
||||
class UsbDeviceHandle {
|
||||
public:
|
||||
UsbDeviceHandle(libusb_device_handle *handle);
|
||||
~UsbDeviceHandle();
|
||||
libusb_device_handle *m_handle;
|
||||
};
|
||||
|
||||
class UsbDevice {
|
||||
public:
|
||||
UsbDevice(libusb_device *device);
|
||||
UsbDevice(const UsbDevice &d) = default;
|
||||
UsbDevice(UsbDevice &&d);
|
||||
~UsbDevice();
|
||||
static std::vector<UsbDevice> find_devices(uint16_t vendor_id, uint16_t product_id);
|
||||
|
||||
bool opened();
|
||||
int open();
|
||||
uint16_t get_vendor_id();
|
||||
uint16_t get_product_id();
|
||||
int control_transfer(uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
|
||||
unsigned char *data, uint16_t wLength, unsigned int timeout);
|
||||
const std::string &get_serial_number();
|
||||
|
||||
private:
|
||||
std::shared_ptr<UsbDeviceHandle> device_handle;
|
||||
libusb_device *dev;
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
std::string serial;
|
||||
struct libusb_device_descriptor devdesc;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // LIBUSBWRAPPER_H
|
23
sustain-kbd-config/main.cpp
Normal file
23
sustain-kbd-config/main.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "mainwindow.h"
|
||||
#include "libusbwrapper.h"
|
||||
#include <iostream>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
|
||||
LibUsbInit();
|
||||
|
||||
w.show();
|
||||
|
||||
ret = a.exec();
|
||||
|
||||
LibUsbDeInit();
|
||||
|
||||
return ret;
|
||||
}
|
228
sustain-kbd-config/mainwindow.cpp
Normal file
228
sustain-kbd-config/mainwindow.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
#include "mainwindow.h"
|
||||
#include "./ui_mainwindow.h"
|
||||
#include "libusbwrapper.h"
|
||||
#include <QMessageBox>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->rescanButton, SIGNAL(clicked()), this, SLOT(rescan_clicked()));
|
||||
connect(this, SIGNAL(close()), this, SLOT(on_close()));
|
||||
connect(ui->deviceComboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(device_changed(QString)));
|
||||
connect(ui->clearKeycodesButton, SIGNAL(clicked()), this, SLOT(clear_keyboard_config()));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::rescan_device_list()
|
||||
{
|
||||
if (this->m_usb_devices.size()) {
|
||||
/* Close old devices */
|
||||
m_usb_devices.clear();
|
||||
}
|
||||
|
||||
auto temp_vector = UsbDevice::find_devices(0xDEAD, 0xBEEF);
|
||||
this->m_usb_devices = std::vector<SustainPedalKeyboard>(temp_vector.begin(), temp_vector.end());
|
||||
|
||||
ui->deviceComboBox->clear();
|
||||
|
||||
/* Update combo box with devices */
|
||||
for (auto &dev : m_usb_devices) {
|
||||
dev.open();
|
||||
auto sn = dev.get_serial_number();
|
||||
ui->deviceComboBox->addItem(QString::fromStdString(sn));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UsbDevice *MainWindow::get_device_from_sn(const std::string &sn)
|
||||
{
|
||||
for (auto &d : m_usb_devices) {
|
||||
if (d.get_serial_number() == sn)
|
||||
return &d;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UsbHidKeyEvent MainWindow::create_key_event_pedal1()
|
||||
{
|
||||
UsbHidKeyEvent event;
|
||||
|
||||
event.left_control = ui->checkBoxLControl_1->isChecked();
|
||||
event.left_shift = ui->checkBoxLShift_1->isChecked();
|
||||
event.left_alt = ui->checkBoxLAlt_1->isChecked();
|
||||
event.left_super = ui->checkBoxLSuper_1->isChecked();
|
||||
event.right_control = ui->checkBoxRControl_1->isChecked();
|
||||
event.right_shift = ui->checkBoxRShift_1->isChecked();
|
||||
event.right_alt = ui->checkBoxRAlt_1->isChecked();
|
||||
event.right_super = ui->checkBoxRSuper_1->isChecked();
|
||||
|
||||
event.keycodes[0] = (uint8_t)ui->keycode1_1->value();
|
||||
event.keycodes[1] = (uint8_t)ui->keycode2_1->value();
|
||||
event.keycodes[2] = (uint8_t)ui->keycode3_1->value();
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
UsbHidKeyEvent MainWindow::create_key_event_pedal2()
|
||||
{
|
||||
UsbHidKeyEvent event;
|
||||
|
||||
event.left_control = ui->checkBoxLControl_2->isChecked();
|
||||
event.left_shift = ui->checkBoxLShift_2->isChecked();
|
||||
event.left_alt = ui->checkBoxLAlt_2->isChecked();
|
||||
event.left_super = ui->checkBoxLSuper_2->isChecked();
|
||||
event.right_control = ui->checkBoxRControl_2->isChecked();
|
||||
event.right_shift = ui->checkBoxRShift_2->isChecked();
|
||||
event.right_alt = ui->checkBoxRAlt_2->isChecked();
|
||||
event.right_super = ui->checkBoxRSuper_2->isChecked();
|
||||
|
||||
event.keycodes[0] = (uint8_t)ui->keycode1_2->value();
|
||||
event.keycodes[1] = (uint8_t)ui->keycode2_2->value();
|
||||
event.keycodes[2] = (uint8_t)ui->keycode3_2->value();
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void MainWindow::rescan_clicked()
|
||||
{
|
||||
rescan_device_list();
|
||||
}
|
||||
|
||||
void MainWindow::device_changed(QString sn)
|
||||
{
|
||||
auto dev = get_device_from_sn(sn.toStdString());
|
||||
if (m_currently_selected_dev.get()) {
|
||||
m_currently_selected_dev->set_active_indicator(false);
|
||||
}
|
||||
m_currently_selected_dev.reset();
|
||||
|
||||
if (dev == NULL) {
|
||||
enable_pedal_gui_elements(false);
|
||||
return;
|
||||
}
|
||||
|
||||
enable_pedal_gui_elements(true);
|
||||
|
||||
m_currently_selected_dev = std::make_unique<SustainPedalKeyboard>(*dev);
|
||||
|
||||
m_currently_selected_dev->set_active_indicator(true);
|
||||
update_gui_from_keyboard();
|
||||
}
|
||||
|
||||
void MainWindow::clear_keyboard_config()
|
||||
{
|
||||
if (!m_currently_selected_dev.get()) {
|
||||
QMessageBox::warning(this, "Error", "No device selected!");
|
||||
return;
|
||||
}
|
||||
|
||||
UsbHidKeyEvent empty_key;
|
||||
|
||||
if (m_currently_selected_dev->program_keyboard_keycode(0, empty_key)) {
|
||||
QMessageBox::warning(this, "Error", "Request to device failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_currently_selected_dev->program_keyboard_keycode(1, empty_key)) {
|
||||
QMessageBox::warning(this, "Error", "Request to device failed!");
|
||||
return;
|
||||
}
|
||||
update_gui_from_keyboard();
|
||||
QMessageBox::information(this, "Device Reset", "All configuration deleted!");
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::update_gui_from_keyboard()
|
||||
{
|
||||
UsbHidKeyEvent pedal1, pedal2;
|
||||
|
||||
if (!m_currently_selected_dev->read_keyboard_config(&pedal1, &pedal2)) {
|
||||
ui->checkBoxLControl_1->setChecked(pedal1.left_control);
|
||||
ui->checkBoxLShift_1->setChecked(pedal1.left_shift);
|
||||
ui->checkBoxLAlt_1->setChecked(pedal1.left_alt);
|
||||
ui->checkBoxLSuper_1->setChecked(pedal1.left_super);
|
||||
ui->checkBoxRControl_1->setChecked(pedal1.right_control);
|
||||
ui->checkBoxRShift_1->setChecked(pedal1.right_shift);
|
||||
ui->checkBoxRAlt_1->setChecked(pedal1.right_alt);
|
||||
ui->checkBoxRSuper_1->setChecked(pedal1.right_super);
|
||||
|
||||
ui->checkBoxLControl_2->setChecked(pedal2.left_control);
|
||||
ui->checkBoxLShift_2->setChecked(pedal2.left_shift);
|
||||
ui->checkBoxLAlt_2->setChecked(pedal2.left_alt);
|
||||
ui->checkBoxLSuper_2->setChecked(pedal2.left_super);
|
||||
ui->checkBoxRControl_2->setChecked(pedal2.right_control);
|
||||
ui->checkBoxRShift_2->setChecked(pedal2.right_shift);
|
||||
ui->checkBoxRAlt_2->setChecked(pedal2.right_alt);
|
||||
ui->checkBoxRSuper_2->setChecked(pedal2.right_super);
|
||||
|
||||
ui->keycode1_1->setValue((int)pedal1.keycodes[0]);
|
||||
ui->keycode2_1->setValue((int)pedal1.keycodes[1]);
|
||||
ui->keycode3_1->setValue((int)pedal1.keycodes[2]);
|
||||
|
||||
ui->keycode1_2->setValue((int)pedal2.keycodes[0]);
|
||||
ui->keycode2_2->setValue((int)pedal2.keycodes[1]);
|
||||
ui->keycode3_2->setValue((int)pedal2.keycodes[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (m_currently_selected_dev)
|
||||
m_currently_selected_dev->set_active_indicator(false);
|
||||
m_usb_devices.clear();
|
||||
m_currently_selected_dev.reset();
|
||||
m_currently_selected_dev = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QMainWindow::showEvent(event);
|
||||
enable_pedal_gui_elements(false);
|
||||
rescan_device_list();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_buttonProgPedal1_clicked()
|
||||
{
|
||||
if (!m_currently_selected_dev.get())
|
||||
return;
|
||||
auto ev = create_key_event_pedal1();
|
||||
m_currently_selected_dev->program_keyboard_keycode(0, ev);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_buttonProgPedal2_clicked()
|
||||
{
|
||||
if (!m_currently_selected_dev.get())
|
||||
return;
|
||||
|
||||
auto ev = create_key_event_pedal2();
|
||||
m_currently_selected_dev->program_keyboard_keycode(1, ev);
|
||||
}
|
||||
|
||||
void MainWindow::enable_pedal_gui_elements(bool enable)
|
||||
{
|
||||
int count1 = ui->verticalLayoutPedal1->count();
|
||||
int count2 = ui->verticalLayoutPedal2->count();
|
||||
|
||||
for (int i = 0; i < count1; i++) {
|
||||
ui->verticalLayoutPedal1->itemAt(i)->widget()->setEnabled(enable);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count2; i++) {
|
||||
ui->verticalLayoutPedal2->itemAt(i)->widget()->setEnabled(enable);
|
||||
}
|
||||
|
||||
ui->clearKeycodesButton->setEnabled(enable);
|
||||
|
||||
}
|
||||
|
47
sustain-kbd-config/mainwindow.h
Normal file
47
sustain-kbd-config/mainwindow.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "sustainpedalkeyboard.h"
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
void rescan_device_list(void);
|
||||
UsbDevice *get_device_from_sn(const std::string &sn);
|
||||
std::vector<SustainPedalKeyboard> m_usb_devices;
|
||||
std::unique_ptr<SustainPedalKeyboard> m_currently_selected_dev;
|
||||
UsbHidKeyEvent create_key_event_pedal1();
|
||||
UsbHidKeyEvent create_key_event_pedal2();
|
||||
|
||||
private slots:
|
||||
void rescan_clicked();
|
||||
void device_changed(QString sn);
|
||||
void clear_keyboard_config();
|
||||
void update_gui_from_keyboard();
|
||||
void on_buttonProgPedal1_clicked();
|
||||
|
||||
void on_buttonProgPedal2_clicked();
|
||||
void enable_pedal_gui_elements(bool enable);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void showEvent(QShowEvent *event);
|
||||
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
251
sustain-kbd-config/mainwindow.ui
Normal file
251
sustain-kbd-config/mainwindow.ui
Normal file
@@ -0,0 +1,251 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Shimatta Sustain Pedal Keyboard Configuration</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<widget class="QWidget" name="verticalLayoutWidget_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>501</width>
|
||||
<height>492</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QComboBox" name="deviceComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rescanButton">
|
||||
<property name="text">
|
||||
<string>Rescan Device List</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBoxVid"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBoxPid"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Program VID:PID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearKeycodesButton">
|
||||
<property name="text">
|
||||
<string>Clear Keycodes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="pedalUiElements">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayoutPedal1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLControl_1">
|
||||
<property name="text">
|
||||
<string>Left Control</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLShift_1">
|
||||
<property name="text">
|
||||
<string>Left Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLAlt_1">
|
||||
<property name="text">
|
||||
<string>Left Alt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLSuper_1">
|
||||
<property name="text">
|
||||
<string>Left Super</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRControl_1">
|
||||
<property name="text">
|
||||
<string>Right Control</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRShift_1">
|
||||
<property name="text">
|
||||
<string>Right Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRAlt_1">
|
||||
<property name="text">
|
||||
<string>Right Alt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRSuper_1">
|
||||
<property name="text">
|
||||
<string>Right Super</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="keycode1_1">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="keycode2_1">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="keycode3_1">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonProgPedal1">
|
||||
<property name="text">
|
||||
<string>Program Pedal 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayoutPedal2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLControl_2">
|
||||
<property name="text">
|
||||
<string>Left Control</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLShift_2">
|
||||
<property name="text">
|
||||
<string>Left Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLAlt_2">
|
||||
<property name="text">
|
||||
<string>Left Alt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxLSuper_2">
|
||||
<property name="text">
|
||||
<string>Left Super</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRControl_2">
|
||||
<property name="text">
|
||||
<string>Right Control</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRShift_2">
|
||||
<property name="text">
|
||||
<string>Right Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRAlt_2">
|
||||
<property name="text">
|
||||
<string>Right Alt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxRSuper_2">
|
||||
<property name="text">
|
||||
<string>Right Super</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="keycode1_2">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="keycode2_2">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="keycode3_2">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonProgPedal2">
|
||||
<property name="text">
|
||||
<string>Program Pedal 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
155
sustain-kbd-config/sustainpedalkeyboard.cpp
Normal file
155
sustain-kbd-config/sustainpedalkeyboard.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#include "sustainpedalkeyboard.h"
|
||||
#include <iostream>
|
||||
|
||||
SustainPedalKeyboard::SustainPedalKeyboard(libusb_device *device) : UsbDevice(device)
|
||||
{
|
||||
m_control_timeout = 500;
|
||||
}
|
||||
|
||||
SustainPedalKeyboard::SustainPedalKeyboard(const UsbDevice &device) : UsbDevice(device)
|
||||
{
|
||||
m_control_timeout = 500;
|
||||
}
|
||||
|
||||
SustainPedalKeyboard::~SustainPedalKeyboard()
|
||||
{
|
||||
}
|
||||
|
||||
int SustainPedalKeyboard::get_control_timeout()
|
||||
{
|
||||
return m_control_timeout;
|
||||
}
|
||||
|
||||
void SustainPedalKeyboard::set_control_timeout(int timeout)
|
||||
{
|
||||
m_control_timeout = timeout;
|
||||
}
|
||||
|
||||
int SustainPedalKeyboard::set_led(uint8_t led, bool state)
|
||||
{
|
||||
int res = this->control_transfer((1<<6), 0x1, state ? 1 : 0, led, NULL, 0, m_control_timeout);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void SustainPedalKeyboard::set_active_indicator(bool state)
|
||||
{
|
||||
(void)set_led(3, state);
|
||||
}
|
||||
|
||||
int SustainPedalKeyboard::program_keyboard_keycode(uint8_t pedal_idx, UsbHidKeyEvent &key)
|
||||
{
|
||||
uint32_t word;
|
||||
uint8_t data[4];
|
||||
|
||||
if (pedal_idx > 1)
|
||||
return -1001;
|
||||
|
||||
word = key.to_eeprom_word();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data[i] = word & 0xFF;
|
||||
word >>= 8;
|
||||
}
|
||||
|
||||
int res = write_eeprom(pedal_idx * 4, data, 4);
|
||||
if (res < 0)
|
||||
return res;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SustainPedalKeyboard::read_keyboard_config(UsbHidKeyEvent *pedal1, UsbHidKeyEvent *pedal2)
|
||||
{
|
||||
unsigned char eeprom_data[8];
|
||||
|
||||
if (!pedal1 || !pedal2)
|
||||
return -1000;
|
||||
|
||||
int res = read_eeprom(0, eeprom_data, sizeof(eeprom_data));
|
||||
if (res != 8) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pedal1->from_eeprom_data(&eeprom_data[0]);
|
||||
pedal2->from_eeprom_data(&eeprom_data[4]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int SustainPedalKeyboard::write_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len)
|
||||
{
|
||||
return this->control_transfer((1<<6), 0x2, 0, offset_addr, data, len, m_control_timeout);
|
||||
}
|
||||
|
||||
int SustainPedalKeyboard::read_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = this->control_transfer(0x80 | (1<<6), 0x2, 0x0, offset_addr, data, len, m_control_timeout);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
UsbHidKeyEvent::UsbHidKeyEvent()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
keycodes[i] = 0;
|
||||
left_control = false;
|
||||
left_alt = false;
|
||||
left_shift = false;
|
||||
left_super = false;
|
||||
right_control = false;
|
||||
right_super = false;
|
||||
right_alt = false;
|
||||
right_shift = false;
|
||||
}
|
||||
|
||||
uint32_t UsbHidKeyEvent::to_eeprom_word()
|
||||
{
|
||||
uint8_t modifiers = 0;
|
||||
uint32_t ret;
|
||||
|
||||
|
||||
if (left_control)
|
||||
modifiers |= 1;
|
||||
if (left_shift)
|
||||
modifiers |= 2;
|
||||
if (left_alt)
|
||||
modifiers |= 4;
|
||||
if (left_super)
|
||||
modifiers |= 8;
|
||||
if (right_control)
|
||||
modifiers |= 16;
|
||||
if (right_shift)
|
||||
modifiers |= 32;
|
||||
if (right_alt)
|
||||
modifiers |= 64;
|
||||
if (right_super)
|
||||
modifiers |= 128;
|
||||
|
||||
ret = (uint32_t)modifiers;
|
||||
ret |= (((uint32_t)keycodes[0]) << 8);
|
||||
ret |= (((uint32_t)keycodes[1]) << 16);
|
||||
ret |= (((uint32_t)keycodes[2]) << 24);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UsbHidKeyEvent::from_eeprom_data(uint8_t data[4])
|
||||
{
|
||||
left_control = !!(data[0] & 1);
|
||||
left_shift = !!(data[0] & 2);
|
||||
left_alt = !!(data[0] & 4);
|
||||
left_super = !!(data[0] & 8);
|
||||
right_control = !!(data[0] & 16);
|
||||
right_shift = !!(data[0] & 32);
|
||||
right_alt = !!(data[0] & 64);
|
||||
right_super = !!(data[0] & 128);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
keycodes[i] = data[i + 1];
|
||||
}
|
||||
}
|
50
sustain-kbd-config/sustainpedalkeyboard.h
Normal file
50
sustain-kbd-config/sustainpedalkeyboard.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef SUSTAINPEDALKEYBOARD_H
|
||||
#define SUSTAINPEDALKEYBOARD_H
|
||||
|
||||
#include "libusbwrapper.h"
|
||||
|
||||
class UsbHidKeyEvent {
|
||||
public:
|
||||
UsbHidKeyEvent();
|
||||
|
||||
bool left_control;
|
||||
bool left_shift;
|
||||
bool left_alt;
|
||||
bool left_super;
|
||||
bool right_control;
|
||||
bool right_shift;
|
||||
bool right_alt;
|
||||
bool right_super;
|
||||
|
||||
uint8_t keycodes[3];
|
||||
|
||||
uint32_t to_eeprom_word();
|
||||
void from_eeprom_data(uint8_t data[4]);
|
||||
};
|
||||
|
||||
class SustainPedalKeyboard : public UsbDevice
|
||||
{
|
||||
public:
|
||||
SustainPedalKeyboard(libusb_device *device);
|
||||
SustainPedalKeyboard(const UsbDevice &device);
|
||||
~SustainPedalKeyboard();
|
||||
|
||||
int get_control_timeout();
|
||||
void set_control_timeout(int timeout);
|
||||
|
||||
int set_led(uint8_t led, bool state);
|
||||
void set_active_indicator(bool state);
|
||||
|
||||
int program_keyboard_keycode(uint8_t pedal_idx, UsbHidKeyEvent &key);
|
||||
|
||||
int read_keyboard_config(UsbHidKeyEvent *pedal1, UsbHidKeyEvent *pedal2);
|
||||
|
||||
private:
|
||||
int write_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len);
|
||||
int read_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len);
|
||||
|
||||
int m_control_timeout;
|
||||
|
||||
};
|
||||
|
||||
#endif // SUSTAINPEDALKEYBOARD_H
|
Reference in New Issue
Block a user