# HG changeset patch # User František Kučera # Date 1566228439 -7200 # Node ID 4655725186256eb7f47166f2b615fae25046f192 # Parent 148f8dd077e85825aa04dc6599b927e2c9c336fc move sources to a sub-project folder diff -r 148f8dd077e8 -r 465572518625 .hgignore --- a/.hgignore Mon Aug 19 17:21:02 2019 +0200 +++ b/.hgignore Mon Aug 19 17:27:19 2019 +0200 @@ -7,7 +7,6 @@ ^temp/ -^\.dep\.inc -^dist/ -^build/ -^nbproject/private/ +^[^/]+/dist/ +^[^/]+/build/ +^[^/]+/nbproject/private/ diff -r 148f8dd077e8 -r 465572518625 CMakeLists.txt --- a/CMakeLists.txt Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -project (cadMousePro) -cmake_minimum_required(VERSION 2.8) -add_subdirectory (src) diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/CMakeLists.txt Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,3 @@ +project (cadMousePro-daemon) +cmake_minimum_required(VERSION 2.8) +add_subdirectory (src) diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/nbproject/configurations.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/nbproject/configurations.xml Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,136 @@ + + + + + + + cadMousePro.cpp + + + + CMakeLists.txt + build/Debug/Makefile + build/Release/Makefile + + + ^(nbproject|build)$ + + . + + build/Debug/Makefile + + + + default + false + false + + + + + + + + + build/Debug + ${MAKE} -f Makefile + ${MAKE} -f Makefile clean + build/Debug/src/welcome + + + /usr/include/hidapi + build/Debug/src + + + + + build/Debug + ${CMAKE} -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${IDE_CC} -DCMAKE_CXX_COMPILER=${IDE_CXX} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../.. + true + + + + + + + + + + default + false + false + + + + + + + + + build/Release + ${MAKE} -f Makefile + ${MAKE} -f Makefile clean + build/Release/src/welcome + + + build/Release/src + + + NDEBUG + + + + + build/Release + ${CMAKE} -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=${IDE_CC} -DCMAKE_CXX_COMPILER=${IDE_CXX} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../.. + true + + + + + + + + + diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/nbproject/project.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/nbproject/project.xml Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,72 @@ + + + + org.netbeans.modules.cnd.makeproject + + + cadMousePro-daemon + + cpp + h + UTF-8 + + . + + + + . + + + + Debug + 0 + + + Release + 0 + + + + false + + + + diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/CLI.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/CLI.h Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,80 @@ +/** + * cadMousePro + * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +/** + * a common header-only library for CLI programs + */ +class CLI { +public: + + CLI(int argc, char* argv[]) { + setlocale(LC_ALL, ""); + + this->argc = &argc; + this->argv = &argv; + + program = convertor.from_bytes(argv[0]); + + for (int i = 1; i < argc; i++) { + args.insert(args.end(), convertor.from_bytes(argv[i])); + } + + } + + CLI(const CLI& orig) { + } + + virtual ~CLI() { + } + + const std::wstring programName() { + return (const std::wstring) program; + } + + const std::vector arguments() { + return (const std::vector)args; + } + + static const int EXIT_CODE_SUCCESS = 0; + static const int EXIT_CODE_UNEXPECTED_ERROR = 1; + static const int EXIT_CODE_BAD_CLI_ARGUMENTS = 6; + + /** + * std::cin and std::cout are "tied" by default i.e. reading from std::cin causes flush of the std::cout. + * Call this to "untie" them and have less write() calls (better buffering). + */ + static void untieStdIO() { + std::cin.tie(nullptr); + } + +private: + int* argc; + char*** argv; + std::wstring program; + std::vector args; + std::wstring_convert> convertor; // TODO: support also other encodings. +}; diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/CLIConfiguration.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/CLIConfiguration.h Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,30 @@ +/** + * cadMousePro + * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "CadMouseConfig.h" + +class CLIConfiguration { +public: + + + CadMouseConfig cadMouseConfig; + + virtual ~CLIConfiguration() { + } +}; diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/CLIException.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/CLIException.h Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,41 @@ +/** + * cadMousePro + * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#include "CLI.h" + +class CLIException { +private: + std::wstring message; + int exitCode = CLI::EXIT_CODE_UNEXPECTED_ERROR; +public: + + CLIException(std::wstring message, int exitCode) : message(message), exitCode(exitCode) { + } + + std::wstring getMessge() const { + return message; + } + + int getExitCode() const { + return exitCode; + } + +}; diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/CLIParser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/CLIParser.h Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,80 @@ +/** + * cadMousePro + * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#include "CLI.h" +#include "CLIConfiguration.h" +#include "CLIException.h" + +class CLIParser { +private: + + std::wstring readNext(std::vector arguments, int& i) { + if (i < arguments.size()) return arguments[i++]; + else throw CLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); + } + + bool parseBoolean(std::wstring value) { + if (value == L"true") return true; + else if (value == L"false") return false; + else throw CLIException(L"Unable to parse boolean value „" + value + L"“ – expecting „true“ or „false“", CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); + } + + Frequency parseFrequency(std::wstring value) { + if (value == L"125") return Frequency::Hz_0125; + else if (value == L"250") return Frequency::Hz_0250; + else if (value == L"500") return Frequency::Hz_0500; + else if (value == L"1000") return Frequency::Hz_1000; + else throw CLIException(L"Unable to parse frequency value „" + value + L"“ – expecting „125“ or „250“ or „500“ or „1000“", CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); + } + +public: + + static const std::wstring OPTION_FREQUENCY; + static const std::wstring OPTION_SMART_SCROLLING; + static const std::wstring OPTION_LIFT_OFF_DETECTION; + static const std::wstring OPTION_KEEP_FILE; + + CLIConfiguration parse(const std::vector& arguments) { + CLIConfiguration c; + + for (int i = 0; i < arguments.size();) { + std::wstring option = readNext(arguments, i); + + if (option == OPTION_FREQUENCY) { + c.cadMouseConfig.setFrequency(parseFrequency(readNext(arguments, i))); + } else if (option == OPTION_SMART_SCROLLING) { + c.cadMouseConfig.setSmartScrolling(parseBoolean(readNext(arguments, i))); + } else if (option == OPTION_LIFT_OFF_DETECTION) { + c.cadMouseConfig.setLiftOffDetection(parseBoolean(readNext(arguments, i))); + } else throw CLIException(L"Unsupported CLI option: " + option, CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); + } + + return c; + } + + virtual ~CLIParser() { + } +}; + + +const std::wstring CLIParser::OPTION_FREQUENCY = L"--frequency"; +const std::wstring CLIParser::OPTION_SMART_SCROLLING = L"--smart-scrolling"; +const std::wstring CLIParser::OPTION_LIFT_OFF_DETECTION = L"--lift-off-detection"; diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/CMakeLists.txt Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,21 @@ +set(EXECUTABLE_FILE "cadMousePro") + +# USB libraries: +INCLUDE(FindPkgConfig) +pkg_check_modules (USB_LIBS hidapi-hidraw) +include_directories(${USB_LIBS_INCLUDE_DIRS}) +link_directories(${USB_LIBS_LIBRARY_DIRS}) + +# Add ASan AddressSanitizer +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") +set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") + +# Executable output: +add_executable( + ${EXECUTABLE_FILE} + cadMousePro.cpp +) + +# Link libraries: +target_link_libraries(${EXECUTABLE_FILE} ${USB_LIBS_LIBRARIES}) +set_property(TARGET ${EXECUTABLE_FILE} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/CadMouseConfig.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/CadMouseConfig.h Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,99 @@ +/** + * cadMousePro + * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#include "HID.h" + +enum class Frequency : uint8_t { + Hz_0125 = 8, + Hz_0250 = 4, + Hz_0500 = 2, + Hz_1000 = 1 +}; + +using FrequencyType = std::underlying_type::type; + +class CadMouseConfig { +private: + bool liftOffDetection = true; + bool smartScrolling = false; + Frequency frequency = Frequency::Hz_1000; +public: + + void setFrequency(Frequency frequency) { + this->frequency = frequency; + } + + void setLiftOffDetection(bool liftOffDetection) { + this->liftOffDetection = liftOffDetection; + } + + void setSmartScrolling(bool smartScrolling) { + this->smartScrolling = smartScrolling; + } + + Packet serialize() { + Packet data; + data.reserve(32); + + data.push_back(0x10); // report ID + data.push_back(0x00); // option + + data.push_back(0x1c); // speed + + data.push_back(liftOffDetection ? 0x00 : 0x1f); + + if (smartScrolling) { + data.push_back(0x00); + data.push_back(0x00); + data.push_back(0x00); + data.push_back(0x01); + } else { + data.push_back(0x01); + data.push_back(0xff); + data.push_back(0x00); + data.push_back(0x00); + } + + for (int i = 0; i < 8; i++) data.push_back(0x00); // constant padding or magic + + // magic constants or unknown fields + data.push_back(0x00); + data.push_back(0x03); + data.push_back(0x00); + data.push_back(0x0a); + data.push_back(0x0b); + data.push_back(0x0c); + data.push_back(0x0c); + data.push_back(0x0e); + data.push_back(0x0d); + data.push_back(0x2f); + data.push_back(0x00); + data.push_back(0x1e); + + data.push_back(0x00); + data.push_back(0x00); + data.push_back(0x00); + data.push_back(static_cast (frequency)); + + return data; + } + +}; diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/HID.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/HID.h Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,91 @@ +/** + * cadMousePro + * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include + +using Packet = std::vector; +static_assert(sizeof (uint8_t) == sizeof (unsigned char)); // unsigned char is used in the HID API library + +class HIDException { +private: + std::wstring message; +public: + + HIDException(std::wstring message) : message(message) { + } + + virtual ~HIDException() { + } + + const std::wstring getMessage() const { + return message; + } + +}; + +class HIDDevice { +private: + std::shared_ptr handle; + +public: + + HIDDevice(unsigned short vendorId, unsigned short productId, const wchar_t *serialNumber) { + int initError = hid_init(); // TODO: move to HIDContext class? + if (initError) throw HIDException(L"Unable to init HID API."); + handle.reset(hid_open(vendorId, productId, serialNumber), hid_close); + if (handle == nullptr) throw HIDException(L"Unable to open HID device. Are you root? Is the device present?"); + } + + virtual ~HIDDevice() { + hid_exit(); // TODO: move to HIDContext class? + } + + const std::wstring getManufacturerName() const { + std::array buffer; + int error = hid_get_manufacturer_string(handle.get(), buffer.data(), buffer.size()); + if (error) throw HIDException(L"Unable to get manufacturer name."); + return buffer.data(); + } + + const std::wstring getProductName() const { + std::array buffer; + int error = hid_get_product_string(handle.get(), buffer.data(), buffer.size()); + if (error) throw HIDException(L"Unable to get product name."); + return buffer.data(); + } + + const std::wstring getSerialNumber() const { + std::array buffer; + int error = hid_get_serial_number_string(handle.get(), buffer.data(), buffer.size()); + if (error) throw HIDException(L"Unable to get serial number."); + return buffer.data(); + } + + void sendFeatureReport(Packet data) { + int written = hid_send_feature_report(handle.get(), data.data(), data.size()); + if (written < 0) throw HIDException(L"Unable to send feature report."); + } + +}; diff -r 148f8dd077e8 -r 465572518625 cadMousePro-daemon/src/cadMousePro.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cadMousePro-daemon/src/cadMousePro.cpp Mon Aug 19 17:27:19 2019 +0200 @@ -0,0 +1,50 @@ +/** + * cadMousePro + * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +#include "CadMouseConfig.h" +#include "CLI.h" +#include "CLIParser.h" +#include "HID.h" + +int main(int argc, char** argv) { + try { + CLI cli(argc, argv); + + std::wcout << L"cadMousePro" << std::endl; + HIDDevice mouse(0x256f, 0xc652, nullptr); + std::wcout << L"mouse opened" << std::endl; + std::wcout << L"manufacturer: " << mouse.getManufacturerName() << std::endl; + std::wcout << L"product: " << mouse.getProductName() << std::endl; + // std::wcout << L"serial number: " << mouse.getSerialNumber() << std::endl; // throws exception + + CLIParser cliParser; + CLIConfiguration configuration = cliParser.parse(cli.arguments()); + + mouse.sendFeatureReport(configuration.cadMouseConfig.serialize()); + + return CLI::EXIT_CODE_SUCCESS; + } catch (const HIDException& e) { + std::wcout << L"HIDException: " << e.getMessage() << std::endl; + return CLI::EXIT_CODE_UNEXPECTED_ERROR; + } catch (const CLIException& e) { + std::wcout << L"CLIException: " << e.getMessge() << std::endl; + return e.getExitCode(); + } + +} diff -r 148f8dd077e8 -r 465572518625 nbproject/configurations.xml --- a/nbproject/configurations.xml Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ - - - - - - - cadMousePro.cpp - - - - CMakeLists.txt - build/Debug/Makefile - build/Release/Makefile - - - ^(nbproject|build)$ - - . - - build/Debug/Makefile - - - - default - false - false - - - - - - - - - build/Debug - ${MAKE} -f Makefile - ${MAKE} -f Makefile clean - build/Debug/src/welcome - - - /usr/include/hidapi - build/Debug/src - - - - - build/Debug - ${CMAKE} -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${IDE_CC} -DCMAKE_CXX_COMPILER=${IDE_CXX} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../.. - true - - - - - - - - - - default - false - false - - - - - - - - - build/Release - ${MAKE} -f Makefile - ${MAKE} -f Makefile clean - build/Release/src/welcome - - - build/Release/src - - - NDEBUG - - - - - build/Release - ${CMAKE} -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=${IDE_CC} -DCMAKE_CXX_COMPILER=${IDE_CXX} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../.. - true - - - - - - - - - diff -r 148f8dd077e8 -r 465572518625 nbproject/project.xml --- a/nbproject/project.xml Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ - - - - org.netbeans.modules.cnd.makeproject - - - cadMousePro - - cpp - h - UTF-8 - - . - - - - . - - - - Debug - 0 - - - Release - 0 - - - - false - - - - diff -r 148f8dd077e8 -r 465572518625 src/CLI.h --- a/src/CLI.h Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/** - * cadMousePro - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -/** - * a common header-only library for CLI programs - */ -class CLI { -public: - - CLI(int argc, char* argv[]) { - setlocale(LC_ALL, ""); - - this->argc = &argc; - this->argv = &argv; - - program = convertor.from_bytes(argv[0]); - - for (int i = 1; i < argc; i++) { - args.insert(args.end(), convertor.from_bytes(argv[i])); - } - - } - - CLI(const CLI& orig) { - } - - virtual ~CLI() { - } - - const std::wstring programName() { - return (const std::wstring) program; - } - - const std::vector arguments() { - return (const std::vector)args; - } - - static const int EXIT_CODE_SUCCESS = 0; - static const int EXIT_CODE_UNEXPECTED_ERROR = 1; - static const int EXIT_CODE_BAD_CLI_ARGUMENTS = 6; - - /** - * std::cin and std::cout are "tied" by default i.e. reading from std::cin causes flush of the std::cout. - * Call this to "untie" them and have less write() calls (better buffering). - */ - static void untieStdIO() { - std::cin.tie(nullptr); - } - -private: - int* argc; - char*** argv; - std::wstring program; - std::vector args; - std::wstring_convert> convertor; // TODO: support also other encodings. -}; diff -r 148f8dd077e8 -r 465572518625 src/CLIConfiguration.h --- a/src/CLIConfiguration.h Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/** - * cadMousePro - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include "CadMouseConfig.h" - -class CLIConfiguration { -public: - - - CadMouseConfig cadMouseConfig; - - virtual ~CLIConfiguration() { - } -}; diff -r 148f8dd077e8 -r 465572518625 src/CLIException.h --- a/src/CLIException.h Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/** - * cadMousePro - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include - -#include "CLI.h" - -class CLIException { -private: - std::wstring message; - int exitCode = CLI::EXIT_CODE_UNEXPECTED_ERROR; -public: - - CLIException(std::wstring message, int exitCode) : message(message), exitCode(exitCode) { - } - - std::wstring getMessge() const { - return message; - } - - int getExitCode() const { - return exitCode; - } - -}; diff -r 148f8dd077e8 -r 465572518625 src/CLIParser.h --- a/src/CLIParser.h Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/** - * cadMousePro - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include - -#include "CLI.h" -#include "CLIConfiguration.h" -#include "CLIException.h" - -class CLIParser { -private: - - std::wstring readNext(std::vector arguments, int& i) { - if (i < arguments.size()) return arguments[i++]; - else throw CLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); - } - - bool parseBoolean(std::wstring value) { - if (value == L"true") return true; - else if (value == L"false") return false; - else throw CLIException(L"Unable to parse boolean value „" + value + L"“ – expecting „true“ or „false“", CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); - } - - Frequency parseFrequency(std::wstring value) { - if (value == L"125") return Frequency::Hz_0125; - else if (value == L"250") return Frequency::Hz_0250; - else if (value == L"500") return Frequency::Hz_0500; - else if (value == L"1000") return Frequency::Hz_1000; - else throw CLIException(L"Unable to parse frequency value „" + value + L"“ – expecting „125“ or „250“ or „500“ or „1000“", CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); - } - -public: - - static const std::wstring OPTION_FREQUENCY; - static const std::wstring OPTION_SMART_SCROLLING; - static const std::wstring OPTION_LIFT_OFF_DETECTION; - static const std::wstring OPTION_KEEP_FILE; - - CLIConfiguration parse(const std::vector& arguments) { - CLIConfiguration c; - - for (int i = 0; i < arguments.size();) { - std::wstring option = readNext(arguments, i); - - if (option == OPTION_FREQUENCY) { - c.cadMouseConfig.setFrequency(parseFrequency(readNext(arguments, i))); - } else if (option == OPTION_SMART_SCROLLING) { - c.cadMouseConfig.setSmartScrolling(parseBoolean(readNext(arguments, i))); - } else if (option == OPTION_LIFT_OFF_DETECTION) { - c.cadMouseConfig.setLiftOffDetection(parseBoolean(readNext(arguments, i))); - } else throw CLIException(L"Unsupported CLI option: " + option, CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); - } - - return c; - } - - virtual ~CLIParser() { - } -}; - - -const std::wstring CLIParser::OPTION_FREQUENCY = L"--frequency"; -const std::wstring CLIParser::OPTION_SMART_SCROLLING = L"--smart-scrolling"; -const std::wstring CLIParser::OPTION_LIFT_OFF_DETECTION = L"--lift-off-detection"; diff -r 148f8dd077e8 -r 465572518625 src/CMakeLists.txt --- a/src/CMakeLists.txt Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -set(EXECUTABLE_FILE "cadMousePro") - -# USB libraries: -INCLUDE(FindPkgConfig) -pkg_check_modules (USB_LIBS hidapi-hidraw) -include_directories(${USB_LIBS_INCLUDE_DIRS}) -link_directories(${USB_LIBS_LIBRARY_DIRS}) - -# Add ASan AddressSanitizer -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") -set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") - -# Executable output: -add_executable( - ${EXECUTABLE_FILE} - cadMousePro.cpp -) - -# Link libraries: -target_link_libraries(${EXECUTABLE_FILE} ${USB_LIBS_LIBRARIES}) -set_property(TARGET ${EXECUTABLE_FILE} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) diff -r 148f8dd077e8 -r 465572518625 src/CadMouseConfig.h --- a/src/CadMouseConfig.h Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/** - * cadMousePro - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include - -#include "HID.h" - -enum class Frequency : uint8_t { - Hz_0125 = 8, - Hz_0250 = 4, - Hz_0500 = 2, - Hz_1000 = 1 -}; - -using FrequencyType = std::underlying_type::type; - -class CadMouseConfig { -private: - bool liftOffDetection = true; - bool smartScrolling = false; - Frequency frequency = Frequency::Hz_1000; -public: - - void setFrequency(Frequency frequency) { - this->frequency = frequency; - } - - void setLiftOffDetection(bool liftOffDetection) { - this->liftOffDetection = liftOffDetection; - } - - void setSmartScrolling(bool smartScrolling) { - this->smartScrolling = smartScrolling; - } - - Packet serialize() { - Packet data; - data.reserve(32); - - data.push_back(0x10); // report ID - data.push_back(0x00); // option - - data.push_back(0x1c); // speed - - data.push_back(liftOffDetection ? 0x00 : 0x1f); - - if (smartScrolling) { - data.push_back(0x00); - data.push_back(0x00); - data.push_back(0x00); - data.push_back(0x01); - } else { - data.push_back(0x01); - data.push_back(0xff); - data.push_back(0x00); - data.push_back(0x00); - } - - for (int i = 0; i < 8; i++) data.push_back(0x00); // constant padding or magic - - // magic constants or unknown fields - data.push_back(0x00); - data.push_back(0x03); - data.push_back(0x00); - data.push_back(0x0a); - data.push_back(0x0b); - data.push_back(0x0c); - data.push_back(0x0c); - data.push_back(0x0e); - data.push_back(0x0d); - data.push_back(0x2f); - data.push_back(0x00); - data.push_back(0x1e); - - data.push_back(0x00); - data.push_back(0x00); - data.push_back(0x00); - data.push_back(static_cast (frequency)); - - return data; - } - -}; diff -r 148f8dd077e8 -r 465572518625 src/HID.h --- a/src/HID.h Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/** - * cadMousePro - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include - -#include - -using Packet = std::vector; -static_assert(sizeof (uint8_t) == sizeof (unsigned char)); // unsigned char is used in the HID API library - -class HIDException { -private: - std::wstring message; -public: - - HIDException(std::wstring message) : message(message) { - } - - virtual ~HIDException() { - } - - const std::wstring getMessage() const { - return message; - } - -}; - -class HIDDevice { -private: - std::shared_ptr handle; - -public: - - HIDDevice(unsigned short vendorId, unsigned short productId, const wchar_t *serialNumber) { - int initError = hid_init(); // TODO: move to HIDContext class? - if (initError) throw HIDException(L"Unable to init HID API."); - handle.reset(hid_open(vendorId, productId, serialNumber), hid_close); - if (handle == nullptr) throw HIDException(L"Unable to open HID device. Are you root? Is the device present?"); - } - - virtual ~HIDDevice() { - hid_exit(); // TODO: move to HIDContext class? - } - - const std::wstring getManufacturerName() const { - std::array buffer; - int error = hid_get_manufacturer_string(handle.get(), buffer.data(), buffer.size()); - if (error) throw HIDException(L"Unable to get manufacturer name."); - return buffer.data(); - } - - const std::wstring getProductName() const { - std::array buffer; - int error = hid_get_product_string(handle.get(), buffer.data(), buffer.size()); - if (error) throw HIDException(L"Unable to get product name."); - return buffer.data(); - } - - const std::wstring getSerialNumber() const { - std::array buffer; - int error = hid_get_serial_number_string(handle.get(), buffer.data(), buffer.size()); - if (error) throw HIDException(L"Unable to get serial number."); - return buffer.data(); - } - - void sendFeatureReport(Packet data) { - int written = hid_send_feature_report(handle.get(), data.data(), data.size()); - if (written < 0) throw HIDException(L"Unable to send feature report."); - } - -}; diff -r 148f8dd077e8 -r 465572518625 src/cadMousePro.cpp --- a/src/cadMousePro.cpp Mon Aug 19 17:21:02 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/** - * cadMousePro - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include - -#include "CadMouseConfig.h" -#include "CLI.h" -#include "CLIParser.h" -#include "HID.h" - -int main(int argc, char** argv) { - try { - CLI cli(argc, argv); - - std::wcout << L"cadMousePro" << std::endl; - HIDDevice mouse(0x256f, 0xc652, nullptr); - std::wcout << L"mouse opened" << std::endl; - std::wcout << L"manufacturer: " << mouse.getManufacturerName() << std::endl; - std::wcout << L"product: " << mouse.getProductName() << std::endl; - // std::wcout << L"serial number: " << mouse.getSerialNumber() << std::endl; // throws exception - - CLIParser cliParser; - CLIConfiguration configuration = cliParser.parse(cli.arguments()); - - mouse.sendFeatureReport(configuration.cadMouseConfig.serialize()); - - return CLI::EXIT_CODE_SUCCESS; - } catch (const HIDException& e) { - std::wcout << L"HIDException: " << e.getMessage() << std::endl; - return CLI::EXIT_CODE_UNEXPECTED_ERROR; - } catch (const CLIException& e) { - std::wcout << L"CLIException: " << e.getMessge() << std::endl; - return e.getExitCode(); - } - -}