From 6974bcd79f1f64139b121058886075974644ef83 Mon Sep 17 00:00:00 2001 From: Karl Fleischmann Date: Fri, 8 Jan 2016 14:55:06 +0100 Subject: [PATCH 01/25] Implement CommandLineParser in main.cpp As mentioned in Issue #125 the `ckb` program lacks a way of inspecting the available command line switches. A `--help` option was added to dispaly and elaborate on the available options. To streamline the experience and make the program anticipate further command line options, implement the default QCommandLineParser functionality as documented in http://doc.qt.io/qt-5/qcommandlineparser.html --- src/ckb/main.cpp | 124 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 14 deletions(-) diff --git a/src/ckb/main.cpp b/src/ckb/main.cpp index 236505a..8c8554a 100644 --- a/src/ckb/main.cpp +++ b/src/ckb/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,74 @@ extern "C" void disableAppNap(); #define SHMEM_SIZE 128 * 1024 #define SHMEM_SIZE_V015 16 +// Command line options +enum CommandLineParseResults { + CommandLineOK, + CommandLineError, + CommandLineVersionRequested, + CommandLineHelpRequested, + CommandLineClose, + CommandLineBackground +}; + +/** + * parseCommandLine - Setup options and parse command line arguments. + * + * @param parser parser instance to use for parse the arguments + * @param errorMessage argument parse error message + * + * @return integer, representing the requested argument + */ +CommandLineParseResults parseCommandLine(QCommandLineParser &parser, QString *errorMessage) { + // setup parser to interpret -abc as -a -b -c + parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsCompactedShortOptions); + + /* add command line options */ + // add -v, --version + const QCommandLineOption versionOption = parser.addVersionOption(); + // add -h, --help (/? on windows) + const QCommandLineOption helpOption = parser.addHelpOption(); + // add -b, --background + const QCommandLineOption backgroundOption(QStringList() << "b" << "background", + "Starts in background, without displaying the main window."); + parser.addOption(backgroundOption); + // add -c, --close + const QCommandLineOption closeOption(QStringList() << "c" << "close", + "Causes already running instance (if any) to exit."); + parser.addOption(closeOption); + + /* parse arguments */ + if (!parser.parse(QCoreApplication::arguments())) { + // set error, if there already are some + *errorMessage = parser.errorText(); + return CommandLineError; + } + + /* return requested operation/setup */ + if (parser.isSet(versionOption)) { + // print version and exit + return CommandLineVersionRequested; + } + + if (parser.isSet(helpOption)) { + // print help and exit + return CommandLineHelpRequested; + } + + if (parser.isSet(backgroundOption)) { + // open application in background + return CommandLineBackground; + } + + if (parser.isSet(closeOption)) { + // close already running application instances, if any + return CommandLineClose; + } + + /* no explicit argument was passed */ + return CommandLineOK; +}; + // Scan shared memory for an active PID static bool pidActive(const QStringList& lines){ foreach(const QString& line, lines){ @@ -77,8 +146,19 @@ static bool isRunning(const char* command){ } int main(int argc, char *argv[]){ + // Setup main application QApplication a(argc, argv); + + // Setup names and versions QCoreApplication::setOrganizationName("ckb"); + QCoreApplication::setApplicationVersion(CKB_VERSION_STR); + QCoreApplication::setApplicationName("ckb"); + + // Setup argument parser + QCommandLineParser parser; + QString errorMessage; + parser.setApplicationDescription("Open Source Corsair Input Device Driver for Linux and OSX."); + bool background = 0; // Seed the RNG for UsbIds qsrand(QDateTime::currentMSecsSinceEpoch()); @@ -90,23 +170,39 @@ int main(int argc, char *argv[]){ qApp->setAttribute(Qt::AA_UseHighDpiPixmaps); #endif - // If launched with --version, print version info and then quit - if(qApp->arguments().contains("--version")){ - printf("ckb %s\n", CKB_VERSION_STR); - return 0; - } - - // Kill existing app when launched with --close - if(qApp->arguments().contains("--close")){ - if(isRunning("Close")) - printf("Asking existing instance to close.\n"); - else - printf("ckb is not running.\n"); - return 0; + // Parse arguments + switch (parseCommandLine(parser, &errorMessage)) { + case CommandLineOK: + // If launched with no argument + break; + case CommandLineError: + fputs(qPrintable(errorMessage), stderr); + fputs("\n\n", stderr); + fputs(qPrintable(parser.helpText()), stderr); + return 1; + case CommandLineVersionRequested: + // If launched with --version, print version info and then quit + printf("%s %s\n", qPrintable(QCoreApplication::applicationName()), + qPrintable(QCoreApplication::applicationVersion())); + return 0; + case CommandLineHelpRequested: + // If launched with --help, print help and then quit + parser.showHelp(); + return 0; + case CommandLineClose: + // If launched with --close, kill existing app + if (isRunning("Close")) + printf("Asking existing instance to close.\n"); + else + printf("ckb is not running.\n"); + return 0; + case CommandLineBackground: + // If launched with --background, launch in background + background = 1; + break; } // Launch in background if requested - bool background = qApp->arguments().contains("--background"); if(isRunning(background ? 0 : "Open")){ printf("ckb is already running. Exiting.\n"); return 0; From 938e95a6746fec3e685e43e5cae5a638670b422e Mon Sep 17 00:00:00 2001 From: frickler24 Date: Sun, 3 Jan 2016 19:32:40 +0100 Subject: [PATCH 02/25] Setup first UI for managing macro key defs (G1..18) This is a new development branch for treating the Macro keys G1-18 on the K95 RGB keyboard. The branch depends on the newfx branch. This first version is based on the BINDING-Tab and includes a new tab (macro). The tab is visible when on the binding site a G-button is selected. The text box on the left (macro key actions) can be edited. When you click Apply, the contents of the text window output in the console and delete the text box. This doesn't use anything, but is a start. --- src/ckb/keyaction.cpp | 15 ++- src/ckb/keyaction.h | 4 +- src/ckb/rebindwidget.cpp | 14 +++ src/ckb/rebindwidget.h | 3 +- src/ckb/rebindwidget.ui | 197 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 228 insertions(+), 5 deletions(-) diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 2fef6b6..93b697a 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -9,6 +9,7 @@ #ifdef USE_LIBX11 #include #endif +#include // lae. KeyAction::Type KeyAction::type() const { if(_value.isEmpty()) @@ -42,7 +43,9 @@ KeyAction::~KeyAction(){ QString KeyAction::defaultAction(const QString& key){ // G1-G18 are unbound by default - if(key.length() >= 2 && key[0] == 'g' && key[1] >= '0' && key[1] <= '9') + if(key.length() >= 2 && key[0] == 'g' + && ((key.length() == 2 && key[1] >= '0' && key[1] <= '9') + || (key.length() == 3 && key[1] == '1' && key[2] >= '0' && key[2] <= '8'))) return ""; // So are thumbgrid buttons if(key.startsWith("thumb")) @@ -368,6 +371,8 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ } else if(stopOnRelease){ // Key released - stop animation anim->stop(); + } else if (prefix == "$macro") { + qDebug ("ToDo: keyEvent with Macro"); } } else if(prefix == "$program"){ // Launch program @@ -466,3 +471,11 @@ void KeyAction::adjustDisplay(){ XCloseDisplay(display); #endif } + +// Changes made by lae. concerning G-Key macro definition user interface +QString KeyAction::macroAction(QString macroDef) { + qWarning() << "______\n[" << macroDef << "]\n_______\n"; + qWarning() << "Length of QString in pteMacroKeys = " << macroDef.length() << "\n"; + return QString ("$macro:%1").arg(macroDef); +} + diff --git a/src/ckb/keyaction.h b/src/ckb/keyaction.h index 6a77f35..f95e8f0 100644 --- a/src/ckb/keyaction.h +++ b/src/ckb/keyaction.h @@ -53,6 +53,7 @@ class KeyAction : public QObject static QString programAction(const QString& onPress, const QString& onRelease, int stop); // Key to start an animation static QString animAction(const QUuid& guid, bool onlyOnce, bool stopOnRelease); + static QString macroAction(QString macroDef); // Action type enum Type { @@ -66,9 +67,10 @@ class KeyAction : public QObject inline bool isSpecial() const { return type() == SPECIAL; } // Media is a type of normal key inline bool isMedia() const { return _value == "mute" || _value == "volup" || _value == "voldn" || _value == "stop" || _value == "prev" || _value == "play" || _value == "next"; } - // Program and animation are types of special key + // Macro, program and animation are types of special key inline bool isProgram() const { return _value.startsWith("$program:"); } inline bool isAnim() const { return _value.startsWith("$anim:"); } + inline bool isMacro() const { return _value.startsWith("$macro:"); } // Mouse is some normal keys plus DPI inline bool isDPI() const { return _value.startsWith("$dpi:"); } inline bool isMouse() const { return (isNormal() && (_value.startsWith("mouse") || _value.startsWith("wheel"))) || isDPI(); } diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index e9c12bc..e29beda 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -1,6 +1,7 @@ #include #include "rebindwidget.h" #include "ui_rebindwidget.h" +#include // lae. static const int DPI_OFFSET = -KeyAction::DPI_UP + 1; static const int DPI_CUST_IDX = KeyAction::DPI_CUSTOM + DPI_OFFSET; @@ -283,6 +284,8 @@ void RebindWidget::setSelection(const QStringList& newSelection, bool applyPrevi else // 0 -> "", 1 -> Prev, 2 -> Next, 3 -> Mode 1 ui->modeBox->setCurrentIndex(3); + } else if (sAction == "macro") { + ui->tabWidget->setCurrentIndex(TAB_MACRO); } else ui->modeBox->setCurrentIndex(0); // Brightness control. Also check wrap @@ -354,6 +357,8 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ krStop = KeyAction::PROGRAM_RE_KPSTOP; } bind->setAction(keys, KeyAction::programAction(ui->programKpBox->text(), ui->programKrBox->text(), kpStop | krStop)); + } else if (ui->pteMacroBox->toPlainText().length() > 0) { + bind->setAction(keys, KeyAction::macroAction(ui->pteMacroBox->toPlainText())); // lae.: does not work } else if(doUnbind) bind->noAction(keys); } @@ -400,6 +405,9 @@ void RebindWidget::setBox(QWidget* box){ ui->programKpButton->setChecked(false); ui->programKrButton->setChecked(false); } + // lae.: Macro pane clear input window on start up + if (box != ui->pteMacroBox) + ui->pteMacroBox->setPlainText(""); } void RebindWidget::on_typingBox_currentIndexChanged(int index){ @@ -411,6 +419,12 @@ void RebindWidget::on_typingBox_currentIndexChanged(int index){ } } +void RebindWidget::on_pteMacroBox_textChanged() { + if (ui->pteMacroBox->toPlainText().length() > 0) { + setBox(ui->pteMacroBox); + } +} + void RebindWidget::on_modBox_currentIndexChanged(int index){ if(index == 0) ui->modButton->setChecked(false); diff --git a/src/ckb/rebindwidget.h b/src/ckb/rebindwidget.h index a7a1369..33a1065 100644 --- a/src/ckb/rebindwidget.h +++ b/src/ckb/rebindwidget.h @@ -64,12 +64,13 @@ private slots: void on_programKpSIBox_clicked(bool checked); void on_programKrSIBox_clicked(bool checked); void on_animButton_clicked(bool checked); + void on_pteMacroBox_textChanged(); private: Ui::RebindWidget *ui; // Tab indices - const static int TAB_KB = 0, TAB_MOUSE = 1, TAB_ANIM = 2, TAB_SPECIAL = 3, TAB_PROGRAM = 4; + const static int TAB_KB = 0, TAB_MOUSE = 1, TAB_ANIM = 2, TAB_SPECIAL = 3, TAB_PROGRAM = 4, TAB_MACRO = 5; void setBox(QWidget* box); diff --git a/src/ckb/rebindwidget.ui b/src/ckb/rebindwidget.ui index 36efb96..1493066 100644 --- a/src/ckb/rebindwidget.ui +++ b/src/ckb/rebindwidget.ui @@ -6,7 +6,7 @@ 0 0 - 687 + 837 342 @@ -1229,6 +1229,134 @@ + + + Macro + + + + + 40 + 12 + 241 + 171 + + + + + + + Macro Key Actions + + + + + + + + + + + + 306 + 120 + 291 + 65 + + + + + + + Control macro recording + + + + + + + + + Start + + + + + + + Stop + + + + + + + Clear + + + + + + + + + + + 303 + 13 + 85 + 28 + + + + Macro Text + + + + + false + + + + 303 + 47 + 421 + 55 + + + + Qt::NoFocus + + + Qt::NoContextMenu + + + false + + + Qt::ImhNoAutoUppercase + + + + + + false + + + true + + + + + + 1 + + + groupBox_3 + pte_MacroText + layoutWidget1 + layoutWidget + @@ -1282,5 +1410,70 @@ - + + + btnClearMacro + clicked() + pteMacroBox + clear() + + + 566 + 200 + + + 277 + 176 + + + + + cancelButton + clicked() + btnClearMacro + click() + + + 735 + 331 + + + 594 + 202 + + + + + cancelButton + clicked() + pteMacroBox + clear() + + + 735 + 331 + + + 252 + 201 + + + + + btnClearMacro + clicked() + pte_MacroText + clear() + + + 588 + 198 + + + 408 + 140 + + + + From ee6b04039b857c4f14287fe6dc85b3183f718bb9 Mon Sep 17 00:00:00 2001 From: frickler24 Date: Tue, 5 Jan 2016 16:30:04 +0100 Subject: [PATCH 03/25] Enable G-Key macro: Sending definitions is working This is the second development step for treating the Macro keys G1-18 on the K95 RGB keyboard. If you type a valid key sequence in the Macro Tab -> Macro Key Actions, select at least one G-Key and click Apply, the macro definiton ist sent to the keyboard and active. The Macro definition is saved like all other bindings, so with restart of ckb the macro definitions are re-sent to the keyboard, but you can't see the older definitions in the ckb-panel yet. Reset and Unbind are working properly, Reset to Default is not tested in that commit. Some debug outputs are still active (qDebug) and some ToDos are marked in the source. --- src/ckb/kbbind.cpp | 20 +++++++++++++++++++- src/ckb/keyaction.cpp | 30 ++++++++++++++++++++++++------ src/ckb/keyaction.h | 1 + src/ckb/rebindwidget.cpp | 8 ++++++-- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/ckb/kbbind.cpp b/src/ckb/kbbind.cpp index 6bd7d63..47f2f58 100644 --- a/src/ckb/kbbind.cpp +++ b/src/ckb/kbbind.cpp @@ -178,7 +178,12 @@ void KbBind::update(QFile& cmd, bool force){ if(!_bind.contains("ralt")) bind["ralt"] = 0; if(!_bind.contains("fn")) bind["fn"] = 0; QHashIterator i(bind); - // Write out rebound keys + + // Initialize String buffer for macro Key definitions (G-keys) + // "macro clear" is neccessary, if an older definition is unbound. + QString macros = "\nmacro clear\n"; + + // Write out rebound keys and collect infos for macro definitions while(i.hasNext()){ i.next(); QString key = i.key(); @@ -192,6 +197,14 @@ void KbBind::update(QFile& cmd, bool force){ // If the key is unbound or is a special action, unbind it cmd.write(" unbind "); cmd.write(key.toLatin1()); + // if a macro definiton for the key is given, + // add the converted string to key-buffer "macro" + if (act->isMacro()) { + QString mac = act->macroContent(); // macroContent assures start of String with "macro" or "" + if (mac.length() > 0) { + macros.append("macro " + key.toLatin1() + ":" + mac.right(mac.length()-6).toLatin1() + "\n"); + } + } } else { // Otherwise, write the binding cmd.write(" bind "); @@ -203,6 +216,11 @@ void KbBind::update(QFile& cmd, bool force){ // If win lock is enabled, unbind windows keys if(_winLock) cmd.write(" unbind lwin rwin"); + + // At last, send Macro definitions if avalilable. + // If no definitions are made, clear macro will be sent only to reset all macros. + qDebug(macros.toLatin1()); + cmd.write(macros.toLatin1()); } void KbBind::keyEvent(const QString& key, bool down){ diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 93b697a..c9b7dfa 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -140,6 +140,8 @@ QString KeyAction::friendlyName(const KeyMap& map) const { return "Start animation"; } else if(prefix == "$program"){ return "Launch program"; + } else if(prefix == "$macro"){ + return "Send G-key macro"; } return "(Unknown)"; } @@ -231,6 +233,14 @@ QString KeyAction::driverName() const { return _value; } +// If a macro definition exists for the given key , +// return the string except the leading "$" +// (it may confuse an other function) +// If no definition exists, return "" +QString KeyAction::macroContent() const { + return isMacro() ? _value.right(_value.length()-1) : ""; +} + void KeyAction::keyEvent(KbBind* bind, bool down){ // No need to respond to standard actions if(!isSpecial()) @@ -371,9 +381,7 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ } else if(stopOnRelease){ // Key released - stop animation anim->stop(); - } else if (prefix == "$macro") { - qDebug ("ToDo: keyEvent with Macro"); - } + } } else if(prefix == "$program"){ // Launch program QString onPress, onRelease; @@ -424,6 +432,11 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ else relProgram = process; } + } else if (prefix == "$macro") { + // Do nothing, because all work is done by the keyboard itself. + // For now, there is no reason to react on G-key press or release. + // If u find some reason, then here is the place for it. + // qDebug ("keyEvent with Macro"); } } @@ -472,10 +485,15 @@ void KeyAction::adjustDisplay(){ #endif } -// Changes made by lae. concerning G-Key macro definition user interface +// G-Key macro definition +// macroAction ist called, while being in the macro pane +// and clicking apply with something in the text boxes. +// Tag that input with $macro: for further recognition. +// ToDo: The input should be read from both text panes +// and concatted. QString KeyAction::macroAction(QString macroDef) { - qWarning() << "______\n[" << macroDef << "]\n_______\n"; - qWarning() << "Length of QString in pteMacroKeys = " << macroDef.length() << "\n"; + qDebug() << "______\n[" << macroDef << "]\n"; + qDebug() << "Length of QString in pteMacroKeys = " << macroDef.length() << "\n"; return QString ("$macro:%1").arg(macroDef); } diff --git a/src/ckb/keyaction.h b/src/ckb/keyaction.h index f95e8f0..a6d2afe 100644 --- a/src/ckb/keyaction.h +++ b/src/ckb/keyaction.h @@ -30,6 +30,7 @@ class KeyAction : public QObject QString friendlyName(const KeyMap& map) const; // Name to send to driver (empty string for unbind) QString driverName() const; + QString macroContent() const; // Mode-switch action. // 0 for first mode, 1 for second, etc. Constants below for movement options diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index e29beda..d65777d 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -358,7 +358,10 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ } bind->setAction(keys, KeyAction::programAction(ui->programKpBox->text(), ui->programKrBox->text(), kpStop | krStop)); } else if (ui->pteMacroBox->toPlainText().length() > 0) { - bind->setAction(keys, KeyAction::macroAction(ui->pteMacroBox->toPlainText())); // lae.: does not work + // G-key macro handling: + // Set the macro definiton for all keys selected (indeed, it may be multiple keys). + // ToDo: We need more than pteMacroBox for later display what has been typed + bind->setAction(keys, KeyAction::macroAction(ui->pteMacroBox->toPlainText())); // lae. } else if(doUnbind) bind->noAction(keys); } @@ -405,7 +408,7 @@ void RebindWidget::setBox(QWidget* box){ ui->programKpButton->setChecked(false); ui->programKrButton->setChecked(false); } - // lae.: Macro pane clear input window on start up + // lae. ToDo: Clear macro pane, so update will not occure in applyChanges() (it's too simple) if (box != ui->pteMacroBox) ui->pteMacroBox->setPlainText(""); } @@ -663,3 +666,4 @@ void RebindWidget::on_animButton_clicked(bool checked){ if(checked && ui->animBox->currentIndex() == 0) ui->animBox->setCurrentIndex(1); } + From de5808b2989fa9595518579ca2ca19fdc2d09445 Mon Sep 17 00:00:00 2001 From: frickler24 Date: Wed, 6 Jan 2016 11:00:26 +0100 Subject: [PATCH 04/25] Combine multiple infos in the Key definition In addition to the Macro Key Definition of panel "Macro Key Actions" also the readable form of panel "Macro Text" will now be processed. In this version, the contents of Macro Text is still a sample text. --- src/ckb/kbbind.cpp | 7 +++--- src/ckb/keyaction.cpp | 17 +++++++------- src/ckb/keyaction.h | 51 +++++++++++++++++++++++++++++++++++++++- src/ckb/rebindwidget.cpp | 25 ++++++++++++++++---- src/ckb/rebindwidget.ui | 6 ++--- 5 files changed, 86 insertions(+), 20 deletions(-) diff --git a/src/ckb/kbbind.cpp b/src/ckb/kbbind.cpp index 47f2f58..3e4d694 100644 --- a/src/ckb/kbbind.cpp +++ b/src/ckb/kbbind.cpp @@ -199,10 +199,9 @@ void KbBind::update(QFile& cmd, bool force){ cmd.write(key.toLatin1()); // if a macro definiton for the key is given, // add the converted string to key-buffer "macro" - if (act->isMacro()) { - QString mac = act->macroContent(); // macroContent assures start of String with "macro" or "" - if (mac.length() > 0) { - macros.append("macro " + key.toLatin1() + ":" + mac.right(mac.length()-6).toLatin1() + "\n"); + if (act->isValidMacro()) { + if (act->macroContent().length() > 0) { + macros.append("macro " + key.toLatin1() + ":" + act->macroContent().toLatin1() + "\n"); } } } else { diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index c9b7dfa..1214254 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -233,14 +233,6 @@ QString KeyAction::driverName() const { return _value; } -// If a macro definition exists for the given key , -// return the string except the leading "$" -// (it may confuse an other function) -// If no definition exists, return "" -QString KeyAction::macroContent() const { - return isMacro() ? _value.right(_value.length()-1) : ""; -} - void KeyAction::keyEvent(KbBind* bind, bool down){ // No need to respond to standard actions if(!isSpecial()) @@ -440,6 +432,15 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ } } +// Just for debugging +void KeyAction::macroDisplay() { + qDebug() << "isMacro returns" << (isMacro() ? "true" : "false"); + qDebug() << "isValidMacro returns" << (isValidMacro() ? "true" : "false"); + QStringList ret =_value.split(":"); + qDebug() << "Macro definition conains" << ret.count() << "elements"; + qDebug() << "Macro definition is" << _value; +} + void KeyAction::adjustDisplay(){ #ifdef USE_LIBX11 char* display_name = XDisplayName(NULL); diff --git a/src/ckb/keyaction.h b/src/ckb/keyaction.h index a6d2afe..b4b5d76 100644 --- a/src/ckb/keyaction.h +++ b/src/ckb/keyaction.h @@ -30,7 +30,56 @@ class KeyAction : public QObject QString friendlyName(const KeyMap& map) const; // Name to send to driver (empty string for unbind) QString driverName() const; - QString macroContent() const; + + // Three inline functions for macros. + // This helps QSting mengling with the macro-action string: + // That string consists of 3 elements: + // 1. "$macro:" + // 2. Macro Key Definition (coming from pteMacroBox) + // This sequence will program the keyboard, + // is hardly readable and is delimited by ":" + // 3. Readable Macro String + // This is displayed in pteMacroText + // + // If a macro definition exists for the given key, + // returns the string except the leading "$" + // (the $ may confuse some caller). + // All 3 parts are returned in one QString . + // If no definition exists, return "" + inline QString macroFullLine() const { + return isMacro() ? _value.right(_value.length()-1) : ""; + } + + // isValidMacro returns true, iff the macro definition + // contains exactly all three elements. + inline bool isValidMacro() const { + if (isMacro()) { + QStringList ret; + ret =_value.split(":"); + return (ret.count() == 3); + } else { + return false; + } + } + + // Return Macro Key Definition and + // Readble Macro String as QStringList. + inline QStringList macroLine() const { + if (isValidMacro()) { + QStringList ret =_value.split(":"); + ret.removeFirst(); + return ret; + } else return QStringList(); + } + + // Return the macro key definition only + // (the second part of the macro definition) + inline QString macroContent() const { + return isValidMacro() ? _value.split(":")[1] : ""; + } + + // Debug output for invalid macro Definitions + void macroDisplay(); // Mode-switch action. // 0 for first mode, 1 for second, etc. Constants below for movement options diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index d65777d..2c54fc9 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -188,6 +188,9 @@ void RebindWidget::setSelection(const QStringList& newSelection, bool applyPrevi ui->programKrModeBox->setCurrentIndex(0); ui->programKpModeBox->setEnabled(false); ui->programKrModeBox->setEnabled(false); + // Clear neu UI elements in MacroTab + ui->pteMacroBox->setPlainText(""); + ui->pteMacroText->setPlainText(""); // Fill in field and select tab according to action type bool mouse = act.isMouse(); if(mouse){ @@ -286,6 +289,13 @@ void RebindWidget::setSelection(const QStringList& newSelection, bool applyPrevi ui->modeBox->setCurrentIndex(3); } else if (sAction == "macro") { ui->tabWidget->setCurrentIndex(TAB_MACRO); + if (act.isValidMacro()) { + ui->pteMacroBox->setPlainText(act.macroContent()); + ui->pteMacroText->setPlainText(act.macroLine()[1].replace("&das_IST_31N_col0n;", ":")); + } else { + qDebug("RebindWidget::setSelection found invalid macro definition."); + act.macroDisplay(); + } } else ui->modeBox->setCurrentIndex(0); // Brightness control. Also check wrap @@ -360,8 +370,13 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ } else if (ui->pteMacroBox->toPlainText().length() > 0) { // G-key macro handling: // Set the macro definiton for all keys selected (indeed, it may be multiple keys). - // ToDo: We need more than pteMacroBox for later display what has been typed - bind->setAction(keys, KeyAction::macroAction(ui->pteMacroBox->toPlainText())); // lae. + // First, concat the Macro Key Definion and the Macro plain text + // after escaping possible colos in the Macro Plain Text. + ui->pteMacroText->setPlainText("Das ist ein Beispieltext mit vielen Doppelpunkten < < >> ::: und einem : zwischendrin haha, geht : doch! : ! :::"); + QString mac; + mac = ui->pteMacroText->toPlainText().replace(":", "&das_IST_31N_col0n;"); + mac = ui->pteMacroBox->toPlainText() + ":" + mac; + bind->setAction(keys, KeyAction::macroAction(mac)); } else if(doUnbind) bind->noAction(keys); } @@ -408,9 +423,11 @@ void RebindWidget::setBox(QWidget* box){ ui->programKpButton->setChecked(false); ui->programKrButton->setChecked(false); } - // lae. ToDo: Clear macro pane, so update will not occure in applyChanges() (it's too simple) - if (box != ui->pteMacroBox) + // Clear macro panel + if (box != ui->pteMacroBox) { ui->pteMacroBox->setPlainText(""); + ui->pteMacroText->setPlainText(""); + } } void RebindWidget::on_typingBox_currentIndexChanged(int index){ diff --git a/src/ckb/rebindwidget.ui b/src/ckb/rebindwidget.ui index 1493066..825fb49 100644 --- a/src/ckb/rebindwidget.ui +++ b/src/ckb/rebindwidget.ui @@ -1312,7 +1312,7 @@ Macro Text - + false @@ -1353,7 +1353,7 @@ groupBox_3 - pte_MacroText + pteMacroText layoutWidget1 layoutWidget @@ -1462,7 +1462,7 @@ btnClearMacro clicked() - pte_MacroText + pteMacroText clear() From 13ac15b315205ee2c14b3bc0ddb0884a39a7885c Mon Sep 17 00:00:00 2001 From: frickler24 Date: Wed, 6 Jan 2016 17:06:16 +0100 Subject: [PATCH 05/25] get some additions to macro UI - Added textpane for Macro Comment - Changes Tab sequence - new class macroreader added - added some signals to handle clear, start, stop --- src/ckb/ckb.pro | 6 +- src/ckb/kbbind.cpp | 1 - src/ckb/rebindwidget.cpp | 12 ++ src/ckb/rebindwidget.h | 5 + src/ckb/rebindwidget.ui | 305 ++++++++++++++++++++++++++++----------- 5 files changed, 241 insertions(+), 88 deletions(-) diff --git a/src/ckb/ckb.pro b/src/ckb/ckb.pro index a4d339e..1a6ea11 100644 --- a/src/ckb/ckb.pro +++ b/src/ckb/ckb.pro @@ -100,7 +100,8 @@ SOURCES += main.cpp\ layoutdialog.cpp \ extrasettingswidget.cpp \ kbmanager.cpp \ - colormap.cpp + colormap.cpp \ + macroreader.cpp HEADERS += mainwindow.h \ kbwidget.h \ @@ -157,7 +158,8 @@ HEADERS += mainwindow.h \ layoutdialog.h \ extrasettingswidget.h \ kbmanager.h \ - colormap.h + colormap.h \ + macroreader.h FORMS += mainwindow.ui \ kbwidget.ui \ diff --git a/src/ckb/kbbind.cpp b/src/ckb/kbbind.cpp index 3e4d694..75c4856 100644 --- a/src/ckb/kbbind.cpp +++ b/src/ckb/kbbind.cpp @@ -218,7 +218,6 @@ void KbBind::update(QFile& cmd, bool force){ // At last, send Macro definitions if avalilable. // If no definitions are made, clear macro will be sent only to reset all macros. - qDebug(macros.toLatin1()); cmd.write(macros.toLatin1()); } diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index 2c54fc9..fec24fb 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -684,3 +684,15 @@ void RebindWidget::on_animButton_clicked(bool checked){ ui->animBox->setCurrentIndex(1); } + +void RebindWidget::on_btnStartMacro_clicked() +{ + if (!macReader) + macReader = new MacroReader; +} + +void RebindWidget::on_btnStopMacro_clicked() +{ + if (macReader) delete macReader; + macReader = 0; +} diff --git a/src/ckb/rebindwidget.h b/src/ckb/rebindwidget.h index 33a1065..da70609 100644 --- a/src/ckb/rebindwidget.h +++ b/src/ckb/rebindwidget.h @@ -4,6 +4,7 @@ #include #include "kbbind.h" #include "kbprofile.h" +#include "macroreader.h" // Key rebinding widget @@ -65,6 +66,8 @@ private slots: void on_programKrSIBox_clicked(bool checked); void on_animButton_clicked(bool checked); void on_pteMacroBox_textChanged(); + void on_btnStartMacro_clicked(); + void on_btnStopMacro_clicked(); private: Ui::RebindWidget *ui; @@ -86,6 +89,8 @@ private slots: QStringList mouseKeys; QStringList mouseExtKeys; QStringList wheelKeys; + + MacroReader* macReader = 0; }; #endif // BINDDIALOG_H diff --git a/src/ckb/rebindwidget.ui b/src/ckb/rebindwidget.ui index 825fb49..03c1338 100644 --- a/src/ckb/rebindwidget.ui +++ b/src/ckb/rebindwidget.ui @@ -20,7 +20,7 @@ - 0 + 5 @@ -1251,81 +1251,80 @@ - - - - - - - - 306 - 120 - 291 - 65 - - - - - - - Control macro recording + + + Qt::WheelFocus + + + true - - - - - - Start - - - - - - - Stop - - - - - - - Clear - - - - - - + + + true + - 303 - 13 - 85 - 28 + 420 + 20 + 311 + 31 - - Macro Text + + Qt::WheelFocus - - - + + Qt::NoContextMenu + + + true + + + What is this macro for? + + + 1 + + + Qt::ImhNone + + + Qt::ScrollBarAlwaysOff + + + true + + + + + + true + + false + + + + + 1 + + + - 303 - 47 - 421 - 55 + 420 + 60 + 311 + 61 - Qt::NoFocus + Qt::StrongFocus Qt::NoContextMenu @@ -1343,7 +1342,7 @@ false - true + false @@ -1352,10 +1351,77 @@ 1 - groupBox_3 - pteMacroText + + + + 300 + 20 + 119 + 81 + + + + + + + Macro Comment + + + + + + + Macro Text + + + + + + + + + 300 + 150 + 436 + 30 + + + + + + + Macro recording + + + + + + + Stop + + + + + + + Start + + + + + + + Clear + + + + + + pteMacroComment layoutWidget1 layoutWidget + pteMacroText + layoutWidget_2 @@ -1409,69 +1475,138 @@ + + tabWidget + pteMacroComment + btnStartMacro + btnStopMacro + btnClearMacro + applyButton + cancelButton + resetButton + unbindButton + pteMacroBox + dpiButton + mb2Box + dpiBox + fnBox + dpiCustYBox + mbBox + wheelBox + mbButton + dpiCustXBox + wheelButton + mb2Button + animBox + animKrBox + animOnceBox + animButton + modeButton + modeWrapBox + lightWrapBox + lockButton + lightBox + lockBox + lightButton + modeBox + programKpButton + programKpBox + programKrBox + programKrButton + programKpSIBox + programKpModeBox + programKrSIBox + programKrModeBox + typingBox + numBox + pteMacroText + typingButton + mediaButton + modBox + modButton + fnButton + mediaBox + numButton + - btnClearMacro + cancelButton clicked() pteMacroBox clear() - 566 - 200 + 735 + 331 - 277 - 176 + 252 + 201 - cancelButton + btnClearMacro clicked() - btnClearMacro - click() + pteMacroBox + clear() - 735 - 331 + 702 + 206 - 594 - 202 + 270 + 179 - cancelButton + btnClearMacro clicked() - pteMacroBox + pteMacroText clear() - 735 - 331 + 718 + 206 - 252 - 201 + 705 + 131 btnClearMacro clicked() - pteMacroText + pteMacroComment clear() - 588 - 198 + 723 + 201 + + + 722 + 85 + + + + + btnClearMacro + clicked() + btnStopMacro + animateClick() + + + 671 + 208 - 408 - 140 + 612 + 206 From 5c5710bafb2d9d97e75ff50bfebf1362a764c709 Mon Sep 17 00:00:00 2001 From: frickler24 Date: Thu, 7 Jan 2016 17:28:32 +0100 Subject: [PATCH 06/25] get the first running version of Macro Definition In this version, the following functions are implemented and integrations-tested: - Interface and buttons are stable - Comment field in the user interface is still ingored - Separate thread is implemented for reading the macro keys - The strings read from Keyboard are converted for saving This is currently missing: - Status line / short instructions to use the panel, - The macro comment - More intensive tests - Systematic documentation of the code - Commenting on the modifications to the existing code --- src/ckb/kb.cpp | 25 +++++++++++++-- src/ckb/kb.h | 13 ++++++-- src/ckb/kbbind.cpp | 37 +++++++++++++++++++++ src/ckb/kbbind.h | 9 ++++-- src/ckb/keyaction.cpp | 3 +- src/ckb/macroreader.cpp | 69 ++++++++++++++++++++++++++++++++++++++++ src/ckb/macroreader.h | 57 +++++++++++++++++++++++++++++++++ src/ckb/rebindwidget.cpp | 32 ++++++++++++++----- src/ckb/rebindwidget.h | 3 ++ 9 files changed, 232 insertions(+), 16 deletions(-) create mode 100644 src/ckb/macroreader.cpp create mode 100644 src/ckb/macroreader.h diff --git a/src/ckb/kb.cpp b/src/ckb/kb.cpp index 53e5719..d7e87e9 100644 --- a/src/ckb/kb.cpp +++ b/src/ckb/kb.cpp @@ -18,11 +18,11 @@ bool Kb::_dither = false, Kb::_mouseAccel = true; Kb::Kb(QObject *parent, const QString& path) : QThread(parent), features("N/A"), firmware("N/A"), pollrate("N/A"), monochrome(false), - devpath(path), cmdpath(path + "/cmd"), notifyPath(path + "/notify1"), + devpath(path), cmdpath(path + "/cmd"), notifyPath(path + "/notify1"), macroPath(path + "/notify2"), _currentProfile(0), _currentMode(0), _model(KeyMap::NO_MODEL), lastAutoSave(QDateTime::currentMSecsSinceEpoch()), _hwProfile(0), prevProfile(0), prevMode(0), - cmd(cmdpath), notifyNumber(1), _needsSave(false) + cmd(cmdpath), notifyNumber(1), macroNumber(2), _needsSave(false) { memset(iState, 0, sizeof(iState)); memset(hwLoading, 0, sizeof(hwLoading)); @@ -94,6 +94,21 @@ Kb::Kb(QObject *parent, const QString& path) : } cmd.write(QString("notifyon %1\n").arg(notifyNumber).toLatin1()); cmd.flush(); + + // Again, find an available notification node for macro definition + // (if none is found, take notify2) + { + QMutexLocker locker(¬ifyPathMutex); + for(int i = 1; i < 10; i++){ + QString notify = QString(path + "/notify%1").arg(i); + if(!QFile::exists(notify) && !notifyPaths.contains(notify)){ + macroNumber = i; + macroPath = notify; + break; + } + } + notifyPaths.insert(notifyPath); // ToDo: Neccessary? + } // Activate device, apply settings, and ask for hardware profile cmd.write(QString("fps %1\n").arg(_frameRate).toLatin1()); cmd.write(QString("dither %1\n").arg(static_cast(_dither)).toLatin1()); @@ -125,9 +140,15 @@ Kb::Kb(QObject *parent, const QString& path) : Kb::~Kb(){ // Save settings first save(); + + if(macroNumber > 0) + cmd.write(QString("idle\nnotifyoff %1\n").arg(macroNumber).toLatin1()); + notifyPaths.remove(macroPath); + // Kill notification thread and remove node activeDevices.remove(this); if(!isOpen()){ + // Detach macro notify channel terminate(); wait(1000); return; diff --git a/src/ckb/kb.h b/src/ckb/kb.h index 17acf14..f1a3512 100644 --- a/src/ckb/kb.h +++ b/src/ckb/kb.h @@ -83,6 +83,11 @@ class Kb : public QThread void hwSave(); + // For usage with macro definions, these two params must only be readable. + // So there are no setters. + inline int getMacroNumber (){ return macroNumber; } + inline QString getMacroPath (){ return macroPath; } + ~Kb(); signals: @@ -124,8 +129,10 @@ private slots: inline bool isOpen() const { return cmd.isOpen(); } - // File paths - QString devpath, cmdpath, notifyPath; + // File paths; + // notifyPath is the standard input monitor for general purpose. + // macroPath added for a second thread to read macro input. + QString devpath, cmdpath, notifyPath, macroPath; // Is this the keyboard at the given serial/path? inline bool matches(const QString& path, const QString& serial) { return path.trimmed() == devpath.trimmed() && usbSerial == serial.trimmed().toUpper(); } @@ -164,6 +171,8 @@ private slots: QFile cmd; // Notification number int notifyNumber; + // Macro Numer to notify macro definition events + int macroNumber; // Needs to be saved? bool _needsSave; diff --git a/src/ckb/kbbind.cpp b/src/ckb/kbbind.cpp index 75c4856..6c908b2 100644 --- a/src/ckb/kbbind.cpp +++ b/src/ckb/kbbind.cpp @@ -4,6 +4,7 @@ #include "kbbind.h" #include "kbmode.h" #include "kb.h" +#include "qdebug.h" QHash KbBind::_globalRemap; quint64 KbBind::globalRemapTime = 0; @@ -219,8 +220,44 @@ void KbBind::update(QFile& cmd, bool force){ // At last, send Macro definitions if avalilable. // If no definitions are made, clear macro will be sent only to reset all macros. cmd.write(macros.toLatin1()); + lastCmd = &cmd; } +//////// +/// \brief KbBind::getMacroNumber +/// \return number of notification channel. Use it in combination with notifyon/off-Statement +/// +int KbBind::getMacroNumber() { + return devParent()->getMacroNumber(); +} + +//////// +/// \brief KbBind::getMacroPath +/// \return Filepath of macro notification pipe. If not set, return "" +/// +QString KbBind::getMacroPath() { + return devParent()->getMacroPath(); +} + +//////// +/// \brief handleMacro +/// \param start is boolean. If true, notification channel is opened for all keys, otherwise channel ist closed. +/// send a notify cmd to the keyboard to set or clear notification for reading macro definition +void KbBind::handleNotificationChannel(bool start) { + if (getMacroNumber() > 0 && lastCmd) { + if (start) { + lastCmd->write (QString("\nnotifyon %1\n@%1 notify all:on\n").arg(getMacroNumber()).toLatin1()); + lastCmd->flush(); + qDebug() << (QString("\nnotifyon %1\n@%1 notify all:on\n").arg(getMacroNumber())).toLatin1(); + } else { + lastCmd->write (QString("\n@%1 notify all:off\nnotifyoff %1\n").arg(getMacroNumber()).toLatin1()); + qDebug() << QString("\n@%1 notify all:off\nnotifyoff %1\n").arg(getMacroNumber()).toLatin1(); + } + } else qDebug() << QString("No cmd or valid handle for notification found, macroNumber = %1, lastCmd = %2") + .arg(getMacroNumber()).arg(lastCmd? "set" : "unset"); +} + + void KbBind::keyEvent(const QString& key, bool down){ QString rKey = globalRemap(key); KeyAction* act = bindAction(rKey); diff --git a/src/ckb/kbbind.h b/src/ckb/kbbind.h index 6ac666d..37abfdb 100644 --- a/src/ckb/kbbind.h +++ b/src/ckb/kbbind.h @@ -37,7 +37,6 @@ class KbBind : public QObject inline bool isISO() const { return _map.isISO(); } inline bool isKeyboard() const { return _map.isKeyboard(); } inline bool isMouse() const { return _map.isMouse(); } - // Related objects KbPerf* perf(); KbLight* light(); @@ -78,6 +77,12 @@ class KbBind : public QObject void update(QFile& cmd, bool force = false); inline void setNeedsUpdate() { _needsUpdate = true; } + // For usage with macro definions, these two params must only be readable. + // So there are no setters. + int getMacroNumber(); + QString getMacroPath(); + void handleNotificationChannel(bool start); + public slots: // Callback for a keypress event. void keyEvent(const QString& key, bool down); @@ -98,6 +103,7 @@ public slots: static QHash _globalRemap; static quint64 globalRemapTime; quint64 lastGlobalRemapTime; + QFile* lastCmd; KeyMap _map; // Key -> action map (no entry = default action) @@ -106,7 +112,6 @@ public slots: bool _winLock; bool _needsUpdate; bool _needsSave; - friend class KeyAction; }; diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 1214254..521ef14 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -493,8 +493,7 @@ void KeyAction::adjustDisplay(){ // ToDo: The input should be read from both text panes // and concatted. QString KeyAction::macroAction(QString macroDef) { - qDebug() << "______\n[" << macroDef << "]\n"; - qDebug() << "Length of QString in pteMacroKeys = " << macroDef.length() << "\n"; + qDebug() << "[" << macroDef << "]\n"; return QString ("$macro:%1").arg(macroDef); } diff --git a/src/ckb/macroreader.cpp b/src/ckb/macroreader.cpp new file mode 100644 index 0000000..94b55fd --- /dev/null +++ b/src/ckb/macroreader.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include "macroreader.h" + +MacroReader::MacroReader() { + qDebug() << "Calling MacroReader without params is not allowed."; +} + +MacroReader::MacroReader(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText) { + macText->setFocus(); // we want to see the keys as they appear in the macroText Widget + startWorkInAThread(macroNumber, macroPath, macBox, macText); +} + +MacroReader::~MacroReader() { +} + +void MacroReader::startWorkInAThread(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText) { + macroReaderThread = new MacroReaderThread(macroNumber, macroPath, macBox, macText); + connect(macroReaderThread, &MacroReaderThread::finished, macroReaderThread, &QObject::deleteLater); + macroReaderThread->start(); +} + +////////////////////// +/// \brief MacroReaderThread::readMacro +/// \param line as QString +/// +/// That method ist called wia signal from the worker thread, +/// which reads the keyboard input. +/// Just display the key code in the macroBox Widget +/// without he trailing \n +/// +void MacroReaderThread::readMacro(QString line) { + // we want to see the keys as they appear in the macroText Widget + // Because it is possible to change the Focus via keyboard, + // we must set the focus on each call. + macroText->setFocus(); + macroBox->appendPlainText(line.left(line.size()-1)); +} + +void MacroReaderThread::run() { + qDebug() << "MacroReader::run() started with" << macroNumber << "and" << macroPath << "and" << macroBox << "and" << macroText; + + QFile macroFile(macroPath); + // Wait a small amount of time for the node to open (100ms) (code reused from kb.cpp) + QThread::usleep(100000); + if(!macroFile.open(QIODevice::ReadOnly)){ + // If it's still not open, try again before giving up (1s at a time, 10s total) + QThread::usleep(900000); + for(int i = 1; i < 10; i++){ + if(macroFile.open(QIODevice::ReadOnly)) + break; + QThread::sleep(1); + } + if(!macroFile.isOpen()) { + qDebug() << QString("unable to open macroFile (%1)").arg(macroPath); + return; + } + } + // Read data from notification node macroPath + QByteArray line; + while(macroFile.isOpen() && (line = macroFile.readLine()).length() > 0){ + QString text = QString::fromUtf8(line); + metaObject()->invokeMethod(this, "readMacro", Qt::QueuedConnection, Q_ARG(QString, text)); + } + qDebug() << "MacroReader::run() ends."; + macroFile.close(); + QThread::exit (); +} diff --git a/src/ckb/macroreader.h b/src/ckb/macroreader.h new file mode 100644 index 0000000..0982739 --- /dev/null +++ b/src/ckb/macroreader.h @@ -0,0 +1,57 @@ +#ifndef MACROREADER_H +#define MACROREADER_H + +//#include +#include +#include +#include +#include + +// Class for managing G-key macros + +class MacroReaderThread : public QThread +{ + Q_OBJECT + int macroNumber; + QString macroPath; + QPlainTextEdit *macroBox; + QPlainTextEdit *macroText; + +public: + MacroReaderThread(int macNum, QString macPath, QPlainTextEdit* macBox, QPlainTextEdit* macText) { + macroNumber = macNum; + macroPath = macPath; + macroBox = macBox; + macroText = macText; + } + + // Notification reader, launches as a separate thread and reads from file. + // (QFile doesn't have readyRead() so there's no other way to do this asynchronously) + void run Q_DECL_OVERRIDE (); + +private slots: + void readMacro(QString line); +}; + +class MacroReader : public QThread +{ + Q_OBJECT + +public: + MacroReader(); + MacroReader(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText); + ~MacroReader(); + + void startWorkInAThread(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText); + +signals: + +public slots: + +private slots: + +private: + MacroReaderThread* macroReaderThread; +}; + +#endif // MACROREADER_H diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index fec24fb..bf8860d 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -372,7 +372,6 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ // Set the macro definiton for all keys selected (indeed, it may be multiple keys). // First, concat the Macro Key Definion and the Macro plain text // after escaping possible colos in the Macro Plain Text. - ui->pteMacroText->setPlainText("Das ist ein Beispieltext mit vielen Doppelpunkten < < >> ::: und einem : zwischendrin haha, geht : doch! : ! :::"); QString mac; mac = ui->pteMacroText->toPlainText().replace(":", "&das_IST_31N_col0n;"); mac = ui->pteMacroBox->toPlainText() + ":" + mac; @@ -382,6 +381,11 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ } void RebindWidget::on_applyButton_clicked(){ + // Normally, this should be done via signalling. + // Because there is no serarate thread, we have to call it directly + // (otherwise we could do Key char conversion step by step, + // but so it is more easy to change the key definition): + on_btnStopMacro_clicked(); applyChanges(selection, true); } @@ -685,14 +689,26 @@ void RebindWidget::on_animButton_clicked(bool checked){ } -void RebindWidget::on_btnStartMacro_clicked() -{ +void RebindWidget::on_btnStartMacro_clicked() { if (!macReader) - macReader = new MacroReader; + bind->handleNotificationChannel(true); + macReader = new MacroReader(bind->getMacroNumber(), bind->getMacroPath(), ui->pteMacroBox, ui->pteMacroText); } -void RebindWidget::on_btnStopMacro_clicked() -{ - if (macReader) delete macReader; - macReader = 0; +void RebindWidget::on_btnStopMacro_clicked() { + if (macReader) { + bind->handleNotificationChannel(false); + delete macReader; + macReader = 0; + convertMacroBox(); + } +} + +void RebindWidget::convertMacroBox() { + QString in; + + in = ui->pteMacroBox->toPlainText(); + in.replace (QRegExp("\n"), ","); + in.replace (QRegExp("key "), ""); + ui->pteMacroBox->setPlainText(in); } diff --git a/src/ckb/rebindwidget.h b/src/ckb/rebindwidget.h index da70609..f39f6d5 100644 --- a/src/ckb/rebindwidget.h +++ b/src/ckb/rebindwidget.h @@ -77,6 +77,9 @@ private slots: void setBox(QWidget* box); + // convert keyboard definion into macro definition + void convertMacroBox(); + KbBind* bind; KbProfile* profile; QStringList selection; From 3b016306bd7af727b238e230817fa08e33447bcf Mon Sep 17 00:00:00 2001 From: frickler24 Date: Thu, 7 Jan 2016 17:28:32 +0100 Subject: [PATCH 07/25] get the first running version of Macro Definition In this version, the following functions are implemented and integrations-tested: - Interface and buttons are stable - Comment field in the user interface is still ingored - Separate thread is implemented for reading the macro keys - The strings read from Keyboard are converted for saving This is currently missing: - Status line / short instructions to use the panel, - The macro comment - More intensive tests - Systematic documentation of the code - Commenting on the modifications to the existing code --- src/ckb/keyaction.cpp | 2 -- src/ckb/macroreader.cpp | 1 - src/ckb/macroreader.h | 4 ++-- src/ckb/rebindwidget.cpp | 11 ++++++++++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 521ef14..1b6f007 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -428,7 +428,6 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ // Do nothing, because all work is done by the keyboard itself. // For now, there is no reason to react on G-key press or release. // If u find some reason, then here is the place for it. - // qDebug ("keyEvent with Macro"); } } @@ -493,7 +492,6 @@ void KeyAction::adjustDisplay(){ // ToDo: The input should be read from both text panes // and concatted. QString KeyAction::macroAction(QString macroDef) { - qDebug() << "[" << macroDef << "]\n"; return QString ("$macro:%1").arg(macroDef); } diff --git a/src/ckb/macroreader.cpp b/src/ckb/macroreader.cpp index 94b55fd..0a2249e 100644 --- a/src/ckb/macroreader.cpp +++ b/src/ckb/macroreader.cpp @@ -1,5 +1,4 @@ #include -#include #include #include "macroreader.h" diff --git a/src/ckb/macroreader.h b/src/ckb/macroreader.h index 0982739..05edd9c 100644 --- a/src/ckb/macroreader.h +++ b/src/ckb/macroreader.h @@ -14,8 +14,8 @@ class MacroReaderThread : public QThread Q_OBJECT int macroNumber; QString macroPath; - QPlainTextEdit *macroBox; - QPlainTextEdit *macroText; + QPlainTextEdit* macroBox; + QPlainTextEdit* macroText; public: MacroReaderThread(int macNum, QString macPath, QPlainTextEdit* macBox, QPlainTextEdit* macText) { diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index bf8860d..87257e8 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -690,9 +690,15 @@ void RebindWidget::on_animButton_clicked(bool checked){ void RebindWidget::on_btnStartMacro_clicked() { - if (!macReader) + if (!macReader) { bind->handleNotificationChannel(true); macReader = new MacroReader(bind->getMacroNumber(), bind->getMacroPath(), ui->pteMacroBox, ui->pteMacroText); + // because of the second thread we need to disable three of the four bottom buttons. + // Clicking "Stop" will enable them again. + ui->applyButton->setEnabled(false); + ui->resetButton->setEnabled(false); + ui->unbindButton->setEnabled(false); + } } void RebindWidget::on_btnStopMacro_clicked() { @@ -701,6 +707,9 @@ void RebindWidget::on_btnStopMacro_clicked() { delete macReader; macReader = 0; convertMacroBox(); + ui->applyButton->setEnabled(true); + ui->resetButton->setEnabled(true); + ui->unbindButton->setEnabled(true); } } From 0072195c262240d8b06cbecb74b7520bdc5743d2 Mon Sep 17 00:00:00 2001 From: frickler24 Date: Sat, 9 Jan 2016 01:25:23 +0100 Subject: [PATCH 08/25] get the second running version of Macro Definition In this version, the following functions are implemented and integrations-tested: - Interface and buttons are stable - Comment field in the user interface is implemented - some status line / short instructions to use the panel are integrated - a short video tutorial ist created https://youtu.be/qhrKP03_NrM This is currently missing: - More intensive tests - More systematic documentation of the code - Commenting on the modifications to the existing code --- src/ckb/kbwidget.h | 2 ++ src/ckb/kbwidget.ui | 13 -------- src/ckb/keyaction.cpp | 22 +++++++----- src/ckb/keyaction.h | 72 ++++++++++++++++++++++++++-------------- src/ckb/macroreader.cpp | 3 ++ src/ckb/rebindwidget.cpp | 43 +++++++++++++++++++----- src/ckb/rebindwidget.h | 6 +++- src/ckb/rebindwidget.ui | 37 +++++++++++++++------ 8 files changed, 133 insertions(+), 65 deletions(-) diff --git a/src/ckb/kbwidget.h b/src/ckb/kbwidget.h index e698c94..f77d554 100644 --- a/src/ckb/kbwidget.h +++ b/src/ckb/kbwidget.h @@ -10,6 +10,8 @@ namespace Ui { class KbWidget; +class KbBindWidget; +class RebindWidget; } class KbWidget : public QWidget diff --git a/src/ckb/kbwidget.ui b/src/ckb/kbwidget.ui index b54fa1f..2cd9c87 100644 --- a/src/ckb/kbwidget.ui +++ b/src/ckb/kbwidget.ui @@ -131,19 +131,6 @@ - - - - - 0 - 0 - - - - Tip: Drag+drop items to reorder. Right-click for menu. - - - diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 1b6f007..7553155 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -431,7 +431,11 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ } } -// Just for debugging + +////////// +/// \brief KeyAction::macroDisplay +/// Just for debugging +/// void KeyAction::macroDisplay() { qDebug() << "isMacro returns" << (isMacro() ? "true" : "false"); qDebug() << "isValidMacro returns" << (isValidMacro() ? "true" : "false"); @@ -485,13 +489,15 @@ void KeyAction::adjustDisplay(){ #endif } -// G-Key macro definition -// macroAction ist called, while being in the macro pane -// and clicking apply with something in the text boxes. -// Tag that input with $macro: for further recognition. -// ToDo: The input should be read from both text panes -// and concatted. +////////// +/// \brief KeyAction::macroAction +/// \param macroDef +/// \return QString holding G-Key macro definition +/// +/// macroAction ist called while being in the macro pane +/// and clicking Apply with something in the Macro Text Box. +/// Tag that input with "$macro:" for further recognition. +/// QString KeyAction::macroAction(QString macroDef) { return QString ("$macro:%1").arg(macroDef); } - diff --git a/src/ckb/keyaction.h b/src/ckb/keyaction.h index b4b5d76..53d410f 100644 --- a/src/ckb/keyaction.h +++ b/src/ckb/keyaction.h @@ -31,39 +31,56 @@ class KeyAction : public QObject // Name to send to driver (empty string for unbind) QString driverName() const; - // Three inline functions for macros. - // This helps QSting mengling with the macro-action string: - // That string consists of 3 elements: - // 1. "$macro:" - // 2. Macro Key Definition (coming from pteMacroBox) - // This sequence will program the keyboard, - // is hardly readable and is delimited by ":" - // 3. Readable Macro String - // This is displayed in pteMacroText - // - // If a macro definition exists for the given key, - // returns the string except the leading "$" - // (the $ may confuse some caller). - // All 3 parts are returned in one QString . - // If no definition exists, return "" + ////////// + /// Three inline functions for macros. + /// This helps QSting mengling with the macro-action string: + /// That string consists of 4 elements: + /// 1. "$macro:" + /// 2. Macro Key Definition (coming from pteMacroBox) + /// This sequence will program the keyboard, + /// is hardly readable and is delimited by ":" + /// 3. Readable Macro String + /// This is displayed in pteMacroText + /// 4. Readable Macro Comment + /// This is displayed in pteMacroComment + ////////// + + ////////// + /// \brief macroFullLine + /// \return QString + /// If a macro definition exists for the given key, + /// returns the string except the leading "$" + /// (the $ may confuse some caller). + /// All 4 parts are returned in one QString. + /// If no definition exists, return "" + /// inline QString macroFullLine() const { return isMacro() ? _value.right(_value.length()-1) : ""; } - // isValidMacro returns true, iff the macro definition - // contains exactly all three elements. - inline bool isValidMacro() const { + ////////// + /// \brief isValidMacro + /// \return bool + /// true, iff the macro definition + /// contains exactly all three elements. + /// + inline bool isValidMacro() const { if (isMacro()) { QStringList ret; ret =_value.split(":"); - return (ret.count() == 3); + return (ret.count() == 4); } else { return false; } } - // Return Macro Key Definition and - // Readble Macro String as QStringList. + ////////// + /// \brief macroLine + /// \return QStringList + /// Macro Key Definition, + /// Readble Macro String and + /// Readable Macro Comment as QStringList. + /// inline QStringList macroLine() const { if (isValidMacro()) { QStringList ret =_value.split(":"); @@ -72,13 +89,20 @@ class KeyAction : public QObject } else return QStringList(); } - // Return the macro key definition only - // (the second part of the macro definition) + ////////// + /// \brief macroContent + /// \return QString + /// Return the macro key definition only + /// (the second part of the macro definition) + /// inline QString macroContent() const { return isValidMacro() ? _value.split(":")[1] : ""; } - // Debug output for invalid macro Definitions + ////////// + /// \brief macroDisplay + /// Debug output for invalid macro Definitions + /// void macroDisplay(); // Mode-switch action. diff --git a/src/ckb/macroreader.cpp b/src/ckb/macroreader.cpp index 0a2249e..415d8fd 100644 --- a/src/ckb/macroreader.cpp +++ b/src/ckb/macroreader.cpp @@ -34,6 +34,9 @@ void MacroReaderThread::readMacro(QString line) { // Because it is possible to change the Focus via keyboard, // we must set the focus on each call. macroText->setFocus(); + QTextCursor c = macroText->textCursor(); + c.setPosition(macroText->toPlainText().length()); + macroText->setTextCursor(c); macroBox->appendPlainText(line.left(line.size()-1)); } diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index 87257e8..0bb0ce4 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -9,7 +9,7 @@ static const int DPI_CUST_IDX = KeyAction::DPI_CUSTOM + DPI_OFFSET; RebindWidget::RebindWidget(QWidget *parent) : QWidget(parent), ui(new Ui::RebindWidget), - bind(0), profile(0) + bind(0), profile(0), macReader(0) { ui->setupUi(this); ui->lightWrapBox->hide(); @@ -191,6 +191,7 @@ void RebindWidget::setSelection(const QStringList& newSelection, bool applyPrevi // Clear neu UI elements in MacroTab ui->pteMacroBox->setPlainText(""); ui->pteMacroText->setPlainText(""); + ui->pteMacroComment->setPlainText(""); // Fill in field and select tab according to action type bool mouse = act.isMouse(); if(mouse){ @@ -292,6 +293,7 @@ void RebindWidget::setSelection(const QStringList& newSelection, bool applyPrevi if (act.isValidMacro()) { ui->pteMacroBox->setPlainText(act.macroContent()); ui->pteMacroText->setPlainText(act.macroLine()[1].replace("&das_IST_31N_col0n;", ":")); + ui->pteMacroComment->setPlainText(act.macroLine()[2].replace("&das_IST_31N_col0n;", ":")); } else { qDebug("RebindWidget::setSelection found invalid macro definition."); act.macroDisplay(); @@ -371,9 +373,10 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ // G-key macro handling: // Set the macro definiton for all keys selected (indeed, it may be multiple keys). // First, concat the Macro Key Definion and the Macro plain text - // after escaping possible colos in the Macro Plain Text. + // after escaping possible colos in the parts for Macro Text and Macro Comment. QString mac; - mac = ui->pteMacroText->toPlainText().replace(":", "&das_IST_31N_col0n;"); + mac = ui->pteMacroComment->toPlainText().replace(":", "&das_IST_31N_col0n;"); + mac = ui->pteMacroText->toPlainText().replace(":", "&das_IST_31N_col0n;") + ":" + mac; mac = ui->pteMacroBox->toPlainText() + ":" + mac; bind->setAction(keys, KeyAction::macroAction(mac)); } else if(doUnbind) @@ -381,11 +384,6 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ } void RebindWidget::on_applyButton_clicked(){ - // Normally, this should be done via signalling. - // Because there is no serarate thread, we have to call it directly - // (otherwise we could do Key char conversion step by step, - // but so it is more easy to change the key definition): - on_btnStopMacro_clicked(); applyChanges(selection, true); } @@ -430,7 +428,7 @@ void RebindWidget::setBox(QWidget* box){ // Clear macro panel if (box != ui->pteMacroBox) { ui->pteMacroBox->setPlainText(""); - ui->pteMacroText->setPlainText(""); + helpStatus(1); } } @@ -698,6 +696,9 @@ void RebindWidget::on_btnStartMacro_clicked() { ui->applyButton->setEnabled(false); ui->resetButton->setEnabled(false); ui->unbindButton->setEnabled(false); + ui->btnStartMacro->setEnabled(false); + ui->btnStopMacro->setEnabled(true); + helpStatus(2); } } @@ -710,6 +711,29 @@ void RebindWidget::on_btnStopMacro_clicked() { ui->applyButton->setEnabled(true); ui->resetButton->setEnabled(true); ui->unbindButton->setEnabled(true); + ui->btnStartMacro->setEnabled(true); + ui->btnStopMacro->setEnabled(false); + helpStatus(3); + } +} + +void RebindWidget::on_btnClearMacro_clicked() { + helpStatus(1); +} + +void RebindWidget::helpStatus(int status) { + switch (status) { + case 1: + ui->lbl_macro->setText("Type in a macro name in the comment box and click start."); + break; + case 2: + ui->lbl_macro->setText("Type your macro and click stop when finished."); + break; + case 3: + ui->lbl_macro->setText("Click Apply or change values in Macro Key Actions in advance."); + break; + default: + ui->lbl_macro->setText(QString("Oops: Some magic in RebindWidget::helpStatus (%1)").arg(status)); } } @@ -721,3 +745,4 @@ void RebindWidget::convertMacroBox() { in.replace (QRegExp("key "), ""); ui->pteMacroBox->setPlainText(in); } + diff --git a/src/ckb/rebindwidget.h b/src/ckb/rebindwidget.h index f39f6d5..8c470e3 100644 --- a/src/ckb/rebindwidget.h +++ b/src/ckb/rebindwidget.h @@ -69,6 +69,8 @@ private slots: void on_btnStartMacro_clicked(); void on_btnStopMacro_clicked(); + void on_btnClearMacro_clicked(); + private: Ui::RebindWidget *ui; @@ -79,6 +81,8 @@ private slots: // convert keyboard definion into macro definition void convertMacroBox(); + // Show some help info + void helpStatus(int status); KbBind* bind; KbProfile* profile; @@ -93,7 +97,7 @@ private slots: QStringList mouseExtKeys; QStringList wheelKeys; - MacroReader* macReader = 0; + MacroReader* macReader; }; #endif // BINDDIALOG_H diff --git a/src/ckb/rebindwidget.ui b/src/ckb/rebindwidget.ui index 03c1338..a9a6a87 100644 --- a/src/ckb/rebindwidget.ui +++ b/src/ckb/rebindwidget.ui @@ -1381,7 +1381,7 @@ 300 - 150 + 160 436 30 @@ -1396,6 +1396,9 @@ + + false + Stop @@ -1417,11 +1420,25 @@ + + + + 300 + 130 + 431 + 27 + + + + Comment label for help + + pteMacroComment layoutWidget1 layoutWidget pteMacroText layoutWidget_2 + lbl_macro @@ -1434,7 +1451,7 @@ - 40 + 5 20 @@ -1478,23 +1495,21 @@ tabWidget pteMacroComment - btnStartMacro - btnStopMacro - btnClearMacro - applyButton - cancelButton - resetButton - unbindButton pteMacroBox dpiButton mb2Box - dpiBox + btnStartMacro fnBox dpiCustYBox + dpiBox + applyButton mbBox + cancelButton wheelBox + btnStopMacro mbButton dpiCustXBox + btnClearMacro wheelButton mb2Button animBox @@ -1506,9 +1521,11 @@ lightWrapBox lockButton lightBox + resetButton lockBox lightButton modeBox + unbindButton programKpButton programKpBox programKrBox From 2cffe41c4bd72e4cecbef17ae1ecaa05d2a53759 Mon Sep 17 00:00:00 2001 From: Lutz Eichler Date: Sat, 20 Feb 2016 23:13:50 +0100 Subject: [PATCH 09/25] Remove some qDebugs --- src/ckb/rebindwidget.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index 0bb0ce4..fc3956f 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -384,6 +384,11 @@ void RebindWidget::applyChanges(const QStringList& keys, bool doUnbind){ } void RebindWidget::on_applyButton_clicked(){ + // Normally, this should be done via signalling. + // Because there is no serarate thread, we have to call it directly + // (otherwise we could do Key char conversion step by step, + // but so it is more easy to change the key definition): + on_btnStopMacro_clicked(); applyChanges(selection, true); } From c747a69967a2d4acf404189d7e02076649a9c964 Mon Sep 17 00:00:00 2001 From: frickler24 Date: Sat, 9 Jan 2016 20:14:22 +0100 Subject: [PATCH 10/25] adopt comment style to doxygen --- src/ckb/kbbindwidget.ui | 1 - src/ckb/kbwidget.h | 2 -- src/ckb/keyaction.cpp | 9 +++-- src/ckb/keyaction.h | 57 ++++++++++++++--------------- src/ckb/macroreader.cpp | 33 +++++++++-------- src/ckb/macroreader.h | 79 ++++++++++++++++++++++++++++++++++++++--- 6 files changed, 124 insertions(+), 57 deletions(-) diff --git a/src/ckb/kbbindwidget.ui b/src/ckb/kbbindwidget.ui index 6c35453..797410f 100644 --- a/src/ckb/kbbindwidget.ui +++ b/src/ckb/kbbindwidget.ui @@ -241,7 +241,6 @@ label line - verticalSpacer label_2 line_2 widget diff --git a/src/ckb/kbwidget.h b/src/ckb/kbwidget.h index f77d554..e698c94 100644 --- a/src/ckb/kbwidget.h +++ b/src/ckb/kbwidget.h @@ -10,8 +10,6 @@ namespace Ui { class KbWidget; -class KbBindWidget; -class RebindWidget; } class KbWidget : public QWidget diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 7553155..1073dfb 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -434,7 +434,7 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ ////////// /// \brief KeyAction::macroDisplay -/// Just for debugging +/// Just for debugging. /// void KeyAction::macroDisplay() { qDebug() << "isMacro returns" << (isMacro() ? "true" : "false"); @@ -490,13 +490,12 @@ void KeyAction::adjustDisplay(){ } ////////// -/// \brief KeyAction::macroAction -/// \param macroDef -/// \return QString holding G-Key macro definition -/// +/// \brief KeyAction::macroAction is called when applying changes on a macro definition. /// macroAction ist called while being in the macro pane /// and clicking Apply with something in the Macro Text Box. /// Tag that input with "$macro:" for further recognition. +/// \param macroDef holds the String containing parts 2-4 of a complete macro definition. +/// \return QString holding the complete G-Key macro definition (parts 1-4) /// QString KeyAction::macroAction(QString macroDef) { return QString ("$macro:%1").arg(macroDef); diff --git a/src/ckb/keyaction.h b/src/ckb/keyaction.h index 53d410f..6b0b557 100644 --- a/src/ckb/keyaction.h +++ b/src/ckb/keyaction.h @@ -31,26 +31,12 @@ class KeyAction : public QObject // Name to send to driver (empty string for unbind) QString driverName() const; - ////////// - /// Three inline functions for macros. - /// This helps QSting mengling with the macro-action string: - /// That string consists of 4 elements: - /// 1. "$macro:" - /// 2. Macro Key Definition (coming from pteMacroBox) - /// This sequence will program the keyboard, - /// is hardly readable and is delimited by ":" - /// 3. Readable Macro String - /// This is displayed in pteMacroText - /// 4. Readable Macro Comment - /// This is displayed in pteMacroComment - ////////// - ////////// /// \brief macroFullLine - /// \return QString - /// If a macro definition exists for the given key, - /// returns the string except the leading "$" + /// If a macro command and a macro definition exists for the given key, + /// returns the complete string except the leading "$" /// (the $ may confuse some caller). + /// \return QString /// All 4 parts are returned in one QString. /// If no definition exists, return "" /// @@ -59,10 +45,12 @@ class KeyAction : public QObject } ////////// - /// \brief isValidMacro - /// \return bool - /// true, iff the macro definition - /// contains exactly all three elements. + /// \brief isValidMacro checks whether a keyAction contains a valid macro. + /// This is easy done: If the macro action starts with $macro: + /// and has four elements, delimited by ":", we may assume, + /// thats a structural correct macro action. + /// \return bool is true, iff the macro definition + /// contains all four elements. /// inline bool isValidMacro() const { if (isMacro()) { @@ -75,9 +63,8 @@ class KeyAction : public QObject } ////////// - /// \brief macroLine - /// \return QStringList - /// Macro Key Definition, + /// \brief macroLine returns all interresting content for a macro definition. + /// \return QStringList returns the Macro Key Definition, /// Readble Macro String and /// Readable Macro Comment as QStringList. /// @@ -90,18 +77,28 @@ class KeyAction : public QObject } ////////// - /// \brief macroContent - /// \return QString - /// Return the macro key definition only - /// (the second part of the macro definition) + /// \brief macroContent returns the macro key definition only + /// (the second part of the macro action). + /// \return QString macroContent /// inline QString macroContent() const { return isValidMacro() ? _value.split(":")[1] : ""; } ////////// - /// \brief macroDisplay - /// Debug output for invalid macro Definitions + /// \brief Debug output for invalid macro Definitions + /// + /// General Info on KeyAction::_value for macros: + /// That string consists of 4 elements: + /// 1. Macro command "$macro:" + /// 2. Macro Key Definition (coming from pteMacroBox) + /// This sequence will program the keyboard, + /// is hardly readable and is delimited by ":" + /// 3. Readable Macro String + /// This is displayed in pteMacroText + /// 4. Readable Macro Comment + /// This is displayed in pteMacroComment + /// /// void macroDisplay(); diff --git a/src/ckb/macroreader.cpp b/src/ckb/macroreader.cpp index 415d8fd..9d6e3ca 100644 --- a/src/ckb/macroreader.cpp +++ b/src/ckb/macroreader.cpp @@ -2,17 +2,18 @@ #include #include "macroreader.h" +////////// +/// \class MacroReader +/// + MacroReader::MacroReader() { qDebug() << "Calling MacroReader without params is not allowed."; } MacroReader::MacroReader(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText) { - macText->setFocus(); // we want to see the keys as they appear in the macroText Widget startWorkInAThread(macroNumber, macroPath, macBox, macText); } - -MacroReader::~MacroReader() { -} +MacroReader::~MacroReader() {} void MacroReader::startWorkInAThread(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText) { macroReaderThread = new MacroReaderThread(macroNumber, macroPath, macBox, macText); @@ -20,19 +21,13 @@ void MacroReader::startWorkInAThread(int macroNumber, QString macroPath, QPlainT macroReaderThread->start(); } -////////////////////// -/// \brief MacroReaderThread::readMacro -/// \param line as QString -/// -/// That method ist called wia signal from the worker thread, -/// which reads the keyboard input. -/// Just display the key code in the macroBox Widget -/// without he trailing \n +////////// +/// \class MacroReaderThread /// void MacroReaderThread::readMacro(QString line) { - // we want to see the keys as they appear in the macroText Widget - // Because it is possible to change the Focus via keyboard, - // we must set the focus on each call. + /// \detail We want to see the keys as they appear in the macroText Widget + /// Because it is possible to change the Focus via keyboard, + /// we must set the focus on each call. macroText->setFocus(); QTextCursor c = macroText->textCursor(); c.setPosition(macroText->toPlainText().length()); @@ -40,6 +35,14 @@ void MacroReaderThread::readMacro(QString line) { macroBox->appendPlainText(line.left(line.size()-1)); } +////////// +/// \brief MacroReaderThread::run is the standard main function for a thread. +/// Tries to open a file several times +/// (in this case, it should be possible the first time. The code was recycled from kb.cpp) +/// +/// While the file is open, read lines an signal them via metaObject() to the main thread. +/// When the file is closed by the sender, close it as reader and terminate. +/// void MacroReaderThread::run() { qDebug() << "MacroReader::run() started with" << macroNumber << "and" << macroPath << "and" << macroBox << "and" << macroText; diff --git a/src/ckb/macroreader.h b/src/ckb/macroreader.h index 05edd9c..1e98d9a 100644 --- a/src/ckb/macroreader.h +++ b/src/ckb/macroreader.h @@ -7,17 +7,53 @@ #include #include -// Class for managing G-key macros - +////////// +/// \brief The MacroReaderThread class is responsible for reading Macro Key Values. +/// It is created as a separate thread (worker thread) for reading macro commands from an fresh opened notify channel. +/// Standard notify channel for macro definitions is number 2. +/// +/// While the worker Thread gets input from the keyboard, +/// the lines are sent via signalling (metaobject) to run a member function in the context of the Qt UI manager. +/// (BTW: in this case it is not interesting, but you may have a lot of parallel running worker threads. +/// Just create more than one object from MacroReaderThread). +/// +/// When the notify channel is closed (that's normally done by pressing "Stop"-Button in the UI), +/// the worker thread closes the channelFile and leaves. +/// \sa MacroReaderThread(), ~MacroReaderThread(), readMaco(), run() +/// class MacroReaderThread : public QThread { Q_OBJECT + + ////////// + /// \brief macroNumber + /// Filenames of nofity channels have the structure /ckb1/notify + /// First part is hold in macroPath, the number is hold in macroNumber. + /// macroNumber may range from 0 to 9. int macroNumber; + + ////////// + /// \brief macroPath holds the path for the notify channel + /// \see macroNumber QString macroPath; + + ////////// + /// \brief macroBox will receive the Macro Key Values sent from the keyboard while defining a new macro. QPlainTextEdit* macroBox; + + ////////// + /// \brief macroText is the other textpane used in the UI while typing new macros. + /// That variable is used for setting the focus to that textpane and to set the cursor at EOT. QPlainTextEdit* macroText; public: + ////////// + /// \brief MacroReaderThread saves the four params to local vars with similar varNames. + /// \param macNum + /// \param macPath + /// \param macBox + /// \param macText + /// MacroReaderThread(int macNum, QString macPath, QPlainTextEdit* macBox, QPlainTextEdit* macText) { macroNumber = macNum; macroPath = macPath; @@ -25,23 +61,58 @@ class MacroReaderThread : public QThread macroText = macText; } - // Notification reader, launches as a separate thread and reads from file. - // (QFile doesn't have readyRead() so there's no other way to do this asynchronously) + ////////// + /// \brief run is the notification reader main loop. void run Q_DECL_OVERRIDE (); private slots: + ////////// + /// \brief readMacro is called for each line received by the worker thread. + /// The method ist called via signal (metaobject) from the worker thread, + /// which reads the keyboard input. + /// Just display the key code in the macroBox Widget without he trailing newline + /// and reposition the cursor in the macro pane. + /// + /// This is used, because the worker thread shouldn't get access to the UI elements + /// (and normally has none, because the pointers macroBox and macroText remain on the stack). + /// That mechanism guarantees, that the UI does not freeze if it happens something magic to the reading function. + /// + /// \param line holds the line just got from keyboard + void readMacro(QString line); }; +////////// +/// \brief The MacroReader class creates a worker thread object. +/// It does a connect do delayed deletion of thread local variables in the case the worker thread terminates. +/// class MacroReader : public QThread { Q_OBJECT public: + ////////// + /// \brief MacroReader Calling MacroReader without params is not allowed. + /// MacroReader(); + ////////// + /// \brief MacroReader This is the only allowed constructor. + /// It only calls startWorkInAThread() with the four params. + /// \param macroNumber + /// \param macroPath + /// \param macBox + /// \param macText + /// MacroReader(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText); ~MacroReader(); + ////////// + /// \brief startWorkInAThread This member function creates the new thread object and starts it with the four params. + /// \param macroNumber + /// \param macroPath + /// \param macBox + /// \param macText + /// void startWorkInAThread(int macroNumber, QString macroPath, QPlainTextEdit* macBox, QPlainTextEdit* macText); signals: From 089b88df0477c7488d6136eb85c01c8975a3eabd Mon Sep 17 00:00:00 2001 From: frickler24 Date: Sun, 10 Jan 2016 00:15:54 +0100 Subject: [PATCH 11/25] add comments --- src/ckb/kb.cpp | 8 ++++---- src/ckb/kb.h | 26 ++++++++++++++++++++++---- src/ckb/kbbind.cpp | 15 +++++++-------- src/ckb/kbbind.h | 20 ++++++++++++++++++-- src/ckb/keyaction.cpp | 10 ++++------ src/ckb/keyaction.h | 35 +++++++++++++++-------------------- src/ckb/macroreader.cpp | 6 +++--- src/ckb/macroreader.h | 4 +--- src/ckb/rebindwidget.cpp | 34 ++++++++++++++++++++++++++++++++-- src/ckb/rebindwidget.h | 4 +--- src/ckb/rebindwidget.ui | 6 +++--- 11 files changed, 110 insertions(+), 58 deletions(-) diff --git a/src/ckb/kb.cpp b/src/ckb/kb.cpp index d7e87e9..44b1342 100644 --- a/src/ckb/kb.cpp +++ b/src/ckb/kb.cpp @@ -107,7 +107,7 @@ Kb::Kb(QObject *parent, const QString& path) : break; } } - notifyPaths.insert(notifyPath); // ToDo: Neccessary? + notifyPaths.insert(notifyPath); ///< \todo Is adding notify2 to the notifypaths neccessary? } // Activate device, apply settings, and ask for hardware profile cmd.write(QString("fps %1\n").arg(_frameRate).toLatin1()); @@ -141,14 +141,14 @@ Kb::~Kb(){ // Save settings first save(); - if(macroNumber > 0) - cmd.write(QString("idle\nnotifyoff %1\n").arg(macroNumber).toLatin1()); + // remove the notify channel from the list of notifyPaths. + ///< \todo I don't think, that notifypaths is used somewhere. So why do we have it? + /// If we do not need it, searching for an ununsed notify channel can easy be refactored to a private member function. notifyPaths.remove(macroPath); // Kill notification thread and remove node activeDevices.remove(this); if(!isOpen()){ - // Detach macro notify channel terminate(); wait(1000); return; diff --git a/src/ckb/kb.h b/src/ckb/kb.h index f1a3512..27c0e6e 100644 --- a/src/ckb/kb.h +++ b/src/ckb/kb.h @@ -85,7 +85,21 @@ class Kb : public QThread // For usage with macro definions, these two params must only be readable. // So there are no setters. + ////////// + /// \brief getMacroNumber returns the macroNumber, which we have saved in the constructor. + /// For usage with macro definions, this param must only be readable. + /// So there is no setter. + /// \return The Number is returned as int. + /// inline int getMacroNumber (){ return macroNumber; } + + /// + /// \brief getMacroPath returns the macroPath (e.g. /dev/input/ckb1/notify), + /// which we have saved in the constructor. + /// For usage with macro definions, this param must only be readable. + /// So there is no setter. + /// \return The absolute path as String + /// inline QString getMacroPath (){ return macroPath; } ~Kb(); @@ -129,9 +143,12 @@ private slots: inline bool isOpen() const { return cmd.isOpen(); } - // File paths; - // notifyPath is the standard input monitor for general purpose. - // macroPath added for a second thread to read macro input. + ////////// + /// \brief pathVars + /// devpath is the device root path (e.g. /dev/device/ckb1), + /// cmdpath leads to the daemon input pipe for daemon commands, + /// notifyPath is the standard input monitor for general purpose, + /// macroPath added for a second thread to read macro input. QString devpath, cmdpath, notifyPath, macroPath; // Is this the keyboard at the given serial/path? inline bool matches(const QString& path, const QString& serial) { return path.trimmed() == devpath.trimmed() && usbSerial == serial.trimmed().toUpper(); } @@ -169,7 +186,8 @@ private slots: // cmd and notify file handles QFile cmd; - // Notification number + + /// \brief notifyNumber is the trailing number in the device path. int notifyNumber; // Macro Numer to notify macro definition events int macroNumber; diff --git a/src/ckb/kbbind.cpp b/src/ckb/kbbind.cpp index 6c908b2..4566dc3 100644 --- a/src/ckb/kbbind.cpp +++ b/src/ckb/kbbind.cpp @@ -233,31 +233,30 @@ int KbBind::getMacroNumber() { //////// /// \brief KbBind::getMacroPath -/// \return Filepath of macro notification pipe. If not set, return "" +/// \return Filepath of macro notification pipe. If not set, returns initial value "" /// QString KbBind::getMacroPath() { return devParent()->getMacroPath(); } //////// -/// \brief handleMacro -/// \param start is boolean. If true, notification channel is opened for all keys, otherwise channel ist closed. -/// send a notify cmd to the keyboard to set or clear notification for reading macro definition +/// \brief handleNotificationChannel sends commands to ckb-daemon for (de-) activating the notify channel. +/// Send a notify cmd to the keyboard to set or clear notification for reading macro definition. +/// The file handle for the cmd pipe is stored in lastCmd. +/// \param start If true, notification channel is opened for all keys, otherwise channel ist closed. +/// void KbBind::handleNotificationChannel(bool start) { if (getMacroNumber() > 0 && lastCmd) { if (start) { lastCmd->write (QString("\nnotifyon %1\n@%1 notify all:on\n").arg(getMacroNumber()).toLatin1()); - lastCmd->flush(); - qDebug() << (QString("\nnotifyon %1\n@%1 notify all:on\n").arg(getMacroNumber())).toLatin1(); } else { lastCmd->write (QString("\n@%1 notify all:off\nnotifyoff %1\n").arg(getMacroNumber()).toLatin1()); - qDebug() << QString("\n@%1 notify all:off\nnotifyoff %1\n").arg(getMacroNumber()).toLatin1(); } + lastCmd->flush(); } else qDebug() << QString("No cmd or valid handle for notification found, macroNumber = %1, lastCmd = %2") .arg(getMacroNumber()).arg(lastCmd? "set" : "unset"); } - void KbBind::keyEvent(const QString& key, bool down){ QString rKey = globalRemap(key); KeyAction* act = bindAction(rKey); diff --git a/src/ckb/kbbind.h b/src/ckb/kbbind.h index 37abfdb..b7ec2c5 100644 --- a/src/ckb/kbbind.h +++ b/src/ckb/kbbind.h @@ -77,10 +77,21 @@ class KbBind : public QObject void update(QFile& cmd, bool force = false); inline void setNeedsUpdate() { _needsUpdate = true; } - // For usage with macro definions, these two params must only be readable. - // So there are no setters. + //////// + /// \brief KbBind::getMacroNumber + /// \return number of notification channel. Use it in combination with notifyon/off-Statement int getMacroNumber(); + + //////// + /// \brief KbBind::getMacroPath + /// \return Filepath of macro notification pipe. If not set, returns initial value "" QString getMacroPath(); + + //////// + /// \brief handleNotificationChannel sends commands to ckb-daemon for (de-) activating the notify channel. + /// Send a notify cmd to the keyboard to set or clear notification for reading macro definition. + /// The file handle for the cmd pipe is stored in lastCmd. + /// \param start is boolean. If true, notification channel is opened for all keys, otherwise channel ist closed. void handleNotificationChannel(bool start); public slots: @@ -103,6 +114,11 @@ public slots: static QHash _globalRemap; static quint64 globalRemapTime; quint64 lastGlobalRemapTime; + + ////////// + /// \brief lastCmd is a cache-hack. + /// Because the QFile ist opened in Kb, and we need it in the macro processing functions, + /// we cache the value her in lastCmd. QFile* lastCmd; KeyMap _map; diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 1073dfb..5a888ba 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -373,7 +373,7 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ } else if(stopOnRelease){ // Key released - stop animation anim->stop(); - } + } } else if(prefix == "$program"){ // Launch program QString onPress, onRelease; @@ -431,10 +431,8 @@ void KeyAction::keyEvent(KbBind* bind, bool down){ } } - -////////// -/// \brief KeyAction::macroDisplay -/// Just for debugging. +/// \brief KeyAction::macroDisplay is just for debugging. +/// It shows the content of the key action and some other info. /// void KeyAction::macroDisplay() { qDebug() << "isMacro returns" << (isMacro() ? "true" : "false"); @@ -493,7 +491,7 @@ void KeyAction::adjustDisplay(){ /// \brief KeyAction::macroAction is called when applying changes on a macro definition. /// macroAction ist called while being in the macro pane /// and clicking Apply with something in the Macro Text Box. -/// Tag that input with "$macro:" for further recognition. +/// It tags that input with "$macro:" for further recognition. /// \param macroDef holds the String containing parts 2-4 of a complete macro definition. /// \return QString holding the complete G-Key macro definition (parts 1-4) /// diff --git a/src/ckb/keyaction.h b/src/ckb/keyaction.h index 6b0b557..82c4d82 100644 --- a/src/ckb/keyaction.h +++ b/src/ckb/keyaction.h @@ -33,12 +33,12 @@ class KeyAction : public QObject ////////// /// \brief macroFullLine - /// If a macro command and a macro definition exists for the given key, - /// returns the complete string except the leading "$" - /// (the $ may confuse some caller). + /// If a macro command and a macro definition exists for the given key, + /// returns the complete string except the leading "$" + /// (the $ may confuse some caller). /// \return QString - /// All 4 parts are returned in one QString. - /// If no definition exists, return "" + /// All 4 parts are returned in one QString. + /// If no definition exists, return "" /// inline QString macroFullLine() const { return isMacro() ? _value.right(_value.length()-1) : ""; @@ -46,11 +46,10 @@ class KeyAction : public QObject ////////// /// \brief isValidMacro checks whether a keyAction contains a valid macro. - /// This is easy done: If the macro action starts with $macro: + /// This is done easily: If the macro action starts with $macro: /// and has four elements, delimited by ":", we may assume, - /// thats a structural correct macro action. - /// \return bool is true, iff the macro definition - /// contains all four elements. + /// that is a structural correct macro action. + /// \return bool as true iff the macro definition contains all four elements. /// inline bool isValidMacro() const { if (isMacro()) { @@ -89,16 +88,12 @@ class KeyAction : public QObject /// \brief Debug output for invalid macro Definitions /// /// General Info on KeyAction::_value for macros: - /// That string consists of 4 elements: - /// 1. Macro command "$macro:" - /// 2. Macro Key Definition (coming from pteMacroBox) - /// This sequence will program the keyboard, - /// is hardly readable and is delimited by ":" - /// 3. Readable Macro String - /// This is displayed in pteMacroText - /// 4. Readable Macro Comment - /// This is displayed in pteMacroComment - /// + /// That string consists of 4 elements, all delimited by ":". + /// 1. Macro command indicator "$macro:" + /// 2. Macro Key Definition (coming from pteMacroBox): + /// This sequence will program the keyboard and is hardly readable + /// 3. Readable Macro String: This is displayed in pteMacroText + /// 4. Readable Macro Comment:This is displayed in pteMacroComment /// void macroDisplay(); @@ -124,7 +119,7 @@ class KeyAction : public QObject static QString programAction(const QString& onPress, const QString& onRelease, int stop); // Key to start an animation static QString animAction(const QUuid& guid, bool onlyOnce, bool stopOnRelease); - static QString macroAction(QString macroDef); + static QString macroAction(QString macroDef); ///< \brief well documented in cpp file // Action type enum Type { diff --git a/src/ckb/macroreader.cpp b/src/ckb/macroreader.cpp index 9d6e3ca..a2f38d2 100644 --- a/src/ckb/macroreader.cpp +++ b/src/ckb/macroreader.cpp @@ -1,4 +1,3 @@ -#include #include #include "macroreader.h" @@ -25,7 +24,8 @@ void MacroReader::startWorkInAThread(int macroNumber, QString macroPath, QPlainT /// \class MacroReaderThread /// void MacroReaderThread::readMacro(QString line) { - /// \detail We want to see the keys as they appear in the macroText Widget + /// \detail We want to see the keys as they appear in the macroText Widget. + /// /// Because it is possible to change the Focus via keyboard, /// we must set the focus on each call. macroText->setFocus(); @@ -38,7 +38,7 @@ void MacroReaderThread::readMacro(QString line) { ////////// /// \brief MacroReaderThread::run is the standard main function for a thread. /// Tries to open a file several times -/// (in this case, it should be possible the first time. The code was recycled from kb.cpp) +/// (in this case, it should be possible the first time. (The code was recycled from kb.cpp). /// /// While the file is open, read lines an signal them via metaObject() to the main thread. /// When the file is closed by the sender, close it as reader and terminate. diff --git a/src/ckb/macroreader.h b/src/ckb/macroreader.h index 1e98d9a..231fb11 100644 --- a/src/ckb/macroreader.h +++ b/src/ckb/macroreader.h @@ -14,8 +14,6 @@ /// /// While the worker Thread gets input from the keyboard, /// the lines are sent via signalling (metaobject) to run a member function in the context of the Qt UI manager. -/// (BTW: in this case it is not interesting, but you may have a lot of parallel running worker threads. -/// Just create more than one object from MacroReaderThread). /// /// When the notify channel is closed (that's normally done by pressing "Stop"-Button in the UI), /// the worker thread closes the channelFile and leaves. @@ -68,7 +66,7 @@ class MacroReaderThread : public QThread private slots: ////////// /// \brief readMacro is called for each line received by the worker thread. - /// The method ist called via signal (metaobject) from the worker thread, + /// The method ist called via signal (metaObject) from the worker thread, /// which reads the keyboard input. /// Just display the key code in the macroBox Widget without he trailing newline /// and reposition the cursor in the macro pane. diff --git a/src/ckb/rebindwidget.cpp b/src/ckb/rebindwidget.cpp index fc3956f..ee4e5f1 100644 --- a/src/ckb/rebindwidget.cpp +++ b/src/ckb/rebindwidget.cpp @@ -691,7 +691,15 @@ void RebindWidget::on_animButton_clicked(bool checked){ ui->animBox->setCurrentIndex(1); } - +////////// +/// \brief RebindWidget::on_btnStartMacro_clicked starts macro recording. +/// A new notification channel and MacroReader are created to do the job. +/// +/// The UI is protected against false clicking +/// (e.g. if you type start and than Apply, the channel is closed in wrong order). +/// +/// At this time, all neccessary params like macroNumber, macroPath, cmdFile etc. had been cached. +/// void RebindWidget::on_btnStartMacro_clicked() { if (!macReader) { bind->handleNotificationChannel(true); @@ -707,6 +715,13 @@ void RebindWidget::on_btnStartMacro_clicked() { } } +////////// +/// \brief RebindWidget::on_btnStopMacro_clicked ends the macro recording. +/// Notify channel ist closed, the ReaderThread is deleted if the notification is really down. +/// +/// Afterwards, the characters in the MacroBox are changed from KB-out format to cmd-in format. +/// At last the UI changes to the new state. +/// void RebindWidget::on_btnStopMacro_clicked() { if (macReader) { bind->handleNotificationChannel(false); @@ -722,10 +737,18 @@ void RebindWidget::on_btnStopMacro_clicked() { } } +////////// +/// \brief RebindWidget::on_btnClearMacro_clicked changes the help info an the panel. +/// The job of clearing the input panels is triggerd with signal/slot via the RebindWidget.ui file. +/// void RebindWidget::on_btnClearMacro_clicked() { helpStatus(1); } +////////// +/// \brief RebindWidget::helpStatus shows a help line in the ui. +/// \param status determines what to display. +/// void RebindWidget::helpStatus(int status) { switch (status) { case 1: @@ -742,6 +765,14 @@ void RebindWidget::helpStatus(int status) { } } +////////// +/// \brief RebindWidget::convertMacroBox converts the macroBox content. +/// The KB sends each keypress as "key [+|-]" +/// +/// the ckb-daemon needs a shorter format, only " [+|-]" +/// +/// That function does the conversion. +/// void RebindWidget::convertMacroBox() { QString in; @@ -750,4 +781,3 @@ void RebindWidget::convertMacroBox() { in.replace (QRegExp("key "), ""); ui->pteMacroBox->setPlainText(in); } - diff --git a/src/ckb/rebindwidget.h b/src/ckb/rebindwidget.h index 8c470e3..4fe8495 100644 --- a/src/ckb/rebindwidget.h +++ b/src/ckb/rebindwidget.h @@ -68,7 +68,6 @@ private slots: void on_pteMacroBox_textChanged(); void on_btnStartMacro_clicked(); void on_btnStopMacro_clicked(); - void on_btnClearMacro_clicked(); private: @@ -96,8 +95,7 @@ private slots: QStringList mouseKeys; QStringList mouseExtKeys; QStringList wheelKeys; - - MacroReader* macReader; + MacroReader* macReader; ///< \brief macReader holds the MacroReader when macro recording starts. }; #endif // BINDDIALOG_H diff --git a/src/ckb/rebindwidget.ui b/src/ckb/rebindwidget.ui index a9a6a87..f88c966 100644 --- a/src/ckb/rebindwidget.ui +++ b/src/ckb/rebindwidget.ui @@ -6,7 +6,7 @@ 0 0 - 837 + 687 342 @@ -20,7 +20,7 @@ - 5 + 0 @@ -1451,7 +1451,7 @@ - 5 + 40 20 From 07d5fc69a646eb52d543ba85648e7f7e17483694 Mon Sep 17 00:00:00 2001 From: Lutz Eichler Date: Mon, 11 Jan 2016 23:35:53 +0100 Subject: [PATCH 12/25] setup ckb for client side macro managment (aplha) This branch sets up the ckb client (and one addition in ckb-daemon) for self defined macros at nearly each key. With this enhancement the 18 G-Keys at the K95 can be used. It adds a new tab "macro" to the bind page as user interface and includes all changes and additions to run the new tab or do the communication with the daemon. This version 0.0.1 handles the key macros in their primary layer, so shift, alt, alt-Gr or meta keys are ignored. It it tested with a K95 RGB on linux (mint 17.1 and 17.2) on different machines. --- src/ckb-daemon/input.c | 4 +++- src/ckb/keyaction.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ckb-daemon/input.c b/src/ckb-daemon/input.c index 8d7aeb9..99c5533 100644 --- a/src/ckb-daemon/input.c +++ b/src/ckb-daemon/input.c @@ -32,8 +32,10 @@ static void inputupdate_keys(usbdevice* kb){ macroaction* action = macro->actions + a; if(action->rel_x != 0 || action->rel_y != 0) os_mousemove(kb, action->rel_x, action->rel_y); - else + else { os_keypress(kb, action->scan, action->down); + if (a > 200) usleep (100); else if (a > 20) usleep(30); + } } } } else { diff --git a/src/ckb/keyaction.cpp b/src/ckb/keyaction.cpp index 5a888ba..b4d89f5 100644 --- a/src/ckb/keyaction.cpp +++ b/src/ckb/keyaction.cpp @@ -1,3 +1,4 @@ +#include #include "keyaction.h" #include "kb.h" #include "kbanim.h" @@ -9,7 +10,6 @@ #ifdef USE_LIBX11 #include #endif -#include // lae. KeyAction::Type KeyAction::type() const { if(_value.isEmpty()) From 0ad494d656676ecf6af94fe881914e65824971b8 Mon Sep 17 00:00:00 2001 From: Lutz Eichler Date: Sat, 23 Jan 2016 19:53:20 +0100 Subject: [PATCH 13/25] update UI in extra settings Extra setting menu has got an additional checkbox. While using large macro definitions, some opSystems lose characters. That ist because the call traffic to the virtual keyboard input seems to be too high. Whith this checkbox set, you get a time delay in two stages: - If more than 20 chars are sent, 30 microseconds after the 20th and each following char - If more than 200 chars are sent, 100 microseconds after the 200th and each following char If you don't have any trouble with lost chars, let this checkbox in off-state. --- src/ckb-daemon/command.c | 6 +++++- src/ckb-daemon/command.h | 5 +++-- src/ckb-daemon/input.c | 5 ++++- src/ckb-daemon/structures.h | 2 ++ src/ckb/extrasettingswidget.cpp | 10 ++++++++++ src/ckb/extrasettingswidget.h | 1 + src/ckb/extrasettingswidget.ui | 10 ++++++++++ src/ckb/kb.cpp | 16 +++++++++++++++- src/ckb/kb.h | 13 +++++++++---- src/ckb/kbbind.h | 1 - 10 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/ckb-daemon/command.c b/src/ckb-daemon/command.c index 6829e28..9acffe7 100644 --- a/src/ckb-daemon/command.c +++ b/src/ckb-daemon/command.c @@ -8,6 +8,7 @@ static const char* const cmd_strings[CMD_COUNT - 1] = { // NONE is implicit + "delay", "mode", "switch", "layout", @@ -111,7 +112,7 @@ int readcmd(usbdevice* kb, const char* line){ // Reject unrecognized commands. Reject bind or notify related commands if the keyboard doesn't have the feature enabled. if(command == NONE - || ((!HAS_FEATURES(kb, FEAT_BIND) && (command == BIND || command == UNBIND || command == REBIND || command == MACRO)) + || ((!HAS_FEATURES(kb, FEAT_BIND) && (command == BIND || command == UNBIND || command == REBIND || command == MACRO || command == DELAY)) || (!HAS_FEATURES(kb, FEAT_NOTIFY) && command == NOTIFY))){ next_loop: continue; @@ -197,6 +198,9 @@ int readcmd(usbdevice* kb, const char* line){ } continue; } + case DELAY: + kb->delay = (!strcmp (word, "on")); // independendant from parameter to handle false commands like "delay off" + continue; default:; } diff --git a/src/ckb-daemon/command.h b/src/ckb-daemon/command.h index 1c2d5b2..7ca2ed7 100644 --- a/src/ckb-daemon/command.h +++ b/src/ckb-daemon/command.h @@ -6,8 +6,9 @@ // Command operations typedef enum { // Special - handled by readcmd, no device functions - NONE = -10, - MODE = -9, CMD_FIRST = MODE, + NONE = -11, + DELAY = -10, CMD_FIRST = DELAY, + MODE = -9, SWITCH = -8, LAYOUT = -7, ACCEL = -6, diff --git a/src/ckb-daemon/input.c b/src/ckb-daemon/input.c index 99c5533..594b38e 100644 --- a/src/ckb-daemon/input.c +++ b/src/ckb-daemon/input.c @@ -34,7 +34,10 @@ static void inputupdate_keys(usbdevice* kb){ os_mousemove(kb, action->rel_x, action->rel_y); else { os_keypress(kb, action->scan, action->down); - if (a > 200) usleep (100); else if (a > 20) usleep(30); + if (kb->delay) { + if (a > 200) usleep (100); + else if (a > 20) usleep(30); + } } } } diff --git a/src/ckb-daemon/structures.h b/src/ckb-daemon/structures.h index b85ef7b..7e5b8de 100644 --- a/src/ckb-daemon/structures.h +++ b/src/ckb-daemon/structures.h @@ -233,6 +233,8 @@ typedef struct { uchar hw_ileds, hw_ileds_old, ileds; // Color dithering in use char dither; + // Flag to check, if large macros should be sent delayed + char delay; } usbdevice; #endif // STRUCTURES_H diff --git a/src/ckb/extrasettingswidget.cpp b/src/ckb/extrasettingswidget.cpp index b1ea88c..536142a 100644 --- a/src/ckb/extrasettingswidget.cpp +++ b/src/ckb/extrasettingswidget.cpp @@ -63,6 +63,11 @@ ExtraSettingsWidget::ExtraSettingsWidget(QWidget *parent) : // Update animation info ui->animPathLabel->setText(AnimScript::path()); on_animScanButton_clicked(); + + /// Read Macro Delay setting, update UI and Kb-internal flag + bool macroDelay = settings.value("MacroDelay").toBool(); + Kb::macroDelay(macroDelay); + ui->delayBox->setChecked(macroDelay); } ExtraSettingsWidget::~ExtraSettingsWidget(){ @@ -134,3 +139,8 @@ void ExtraSettingsWidget::on_sSpeedBox_valueChanged(int arg1){ CkbSettings::set("Program/ScrollSpeed", arg1); Kb::scrollSpeed(ui->sAccelBox->isChecked() ? arg1 : 0); } + +void ExtraSettingsWidget::on_delayBox_clicked(bool checked) { + CkbSettings::set("Program/MacroDelay", checked); + Kb::macroDelay(checked); +} diff --git a/src/ckb/extrasettingswidget.h b/src/ckb/extrasettingswidget.h index d5deba6..c6ad936 100644 --- a/src/ckb/extrasettingswidget.h +++ b/src/ckb/extrasettingswidget.h @@ -27,6 +27,7 @@ private slots: void on_mAccelBox_clicked(bool checked); void on_sAccelBox_clicked(bool checked); void on_sSpeedBox_valueChanged(int arg1); + void on_delayBox_clicked(bool checked); private: Ui::ExtraSettingsWidget *ui; diff --git a/src/ckb/extrasettingswidget.ui b/src/ckb/extrasettingswidget.ui index d437df1..b7cf93a 100644 --- a/src/ckb/extrasettingswidget.ui +++ b/src/ckb/extrasettingswidget.ui @@ -406,6 +406,16 @@ + + + + When using macros with strings longer than 25 chars, some OS may lose characters (e.g. Mint 17.2). Select to prevent that bug. + + + Use delay for very long macros + + + diff --git a/src/ckb/kb.cpp b/src/ckb/kb.cpp index 44b1342..22a8b98 100644 --- a/src/ckb/kb.cpp +++ b/src/ckb/kb.cpp @@ -14,7 +14,7 @@ static QMutex notifyPathMutex; int Kb::_frameRate = 30, Kb::_scrollSpeed = 0; KeyMap::Layout Kb::_layout = KeyMap::NO_LAYOUT; -bool Kb::_dither = false, Kb::_mouseAccel = true; +bool Kb::_dither = false, Kb::_mouseAccel = true, Kb::_delay = false; Kb::Kb(QObject *parent, const QString& path) : QThread(parent), features("N/A"), firmware("N/A"), pollrate("N/A"), monochrome(false), @@ -112,6 +112,7 @@ Kb::Kb(QObject *parent, const QString& path) : // Activate device, apply settings, and ask for hardware profile cmd.write(QString("fps %1\n").arg(_frameRate).toLatin1()); cmd.write(QString("dither %1\n").arg(static_cast(_dither)).toLatin1()); + cmd.write(QString("\ndelay %1\n").arg(_delay? "on" : "off").toLatin1()); #ifdef Q_OS_MACX // Write ANSI/ISO flag to daemon (OSX only) cmd.write("layout "); @@ -778,3 +779,16 @@ void Kb::setCurrentMode(KbProfile* profile, KbMode* mode, bool spontaneous){ } } +//// +/// \brief Kb::macroDelay handles the UI-Element macroBox. +/// Sends a command to the keyboard to switch on or off the delay function on very large macros +/// \param flag true: Switch on delay function, else switch off +/// +void Kb::macroDelay(bool flag) { + _delay = flag; + + foreach(Kb* kb, activeDevices){ + kb->cmd.write(QString("\ndelay %1\n").arg(flag? "on" : "off").toLatin1()); + } +} + diff --git a/src/ckb/kb.h b/src/ckb/kb.h index 27c0e6e..f98f77c 100644 --- a/src/ckb/kb.h +++ b/src/ckb/kb.h @@ -32,6 +32,9 @@ class Kb : public QThread // Whether dithering is used (all devices) static inline bool dither() { return _dither; } static void dither(bool newDither); + // Macro Delay setting + static inline bool macroDelay() { return _delay; } + static void macroDelay(bool flag); // OSX: mouse acceleration toggle (all devices) static inline bool mouseAccel() { return _mouseAccel; } static void mouseAccel(bool newAccel); @@ -83,15 +86,15 @@ class Kb : public QThread void hwSave(); - // For usage with macro definions, these two params must only be readable. - // So there are no setters. ////////// + /// For usage with macro definions, these two params must only be readable. + /// So there are no setters. /// \brief getMacroNumber returns the macroNumber, which we have saved in the constructor. /// For usage with macro definions, this param must only be readable. /// So there is no setter. /// \return The Number is returned as int. /// - inline int getMacroNumber (){ return macroNumber; } + inline int getMacroNumber () { return macroNumber; } /// /// \brief getMacroPath returns the macroPath (e.g. /dev/input/ckb1/notify), @@ -100,7 +103,7 @@ class Kb : public QThread /// So there is no setter. /// \return The absolute path as String /// - inline QString getMacroPath (){ return macroPath; } + inline QString getMacroPath () { return macroPath; } ~Kb(); @@ -191,6 +194,8 @@ private slots: int notifyNumber; // Macro Numer to notify macro definition events int macroNumber; + // flag if macro delay hast to be switched on + static bool _delay; // Needs to be saved? bool _needsSave; diff --git a/src/ckb/kbbind.h b/src/ckb/kbbind.h index b7ec2c5..ca10a81 100644 --- a/src/ckb/kbbind.h +++ b/src/ckb/kbbind.h @@ -103,7 +103,6 @@ public slots: void layoutChanged(); void updated(); - private: Kb* _devParent; inline Kb* devParent() const { return _devParent; } From f48cf8bfa703c1ff4242c5ad050a1534e11746ea Mon Sep 17 00:00:00 2001 From: Lutz Eichler Date: Sat, 6 Feb 2016 17:24:15 +0100 Subject: [PATCH 14/25] Fix initialization bug with K95RGB + M65RGB For the combination of an K95RGB keyboard and the M65RGB mouse there was an initialization bug. The ckb client did send a "Macro clear" command to the driver for the mouse. Because that is unneccessary, there ist no function to handle this and the deamon got a SIGSEGV. This patch fixes that bug. The change in ckb client prevents issuing the command. The Patch in ckb-daemon may be activated by setting INIT_ERROR and only does some debug output. --- src/ckb-daemon/command.c | 9 +++++++++ src/ckb/kbbind.cpp | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ckb-daemon/command.c b/src/ckb-daemon/command.c index 9acffe7..8d734a8 100644 --- a/src/ckb-daemon/command.c +++ b/src/ckb-daemon/command.c @@ -6,6 +6,8 @@ #include "profile.h" #include "usb.h" +//#define INIT_ERROR // for debugging purposes. MacroClient sends invalid macro-clear cmd to mouse + static const char* const cmd_strings[CMD_COUNT - 1] = { // NONE is implicit "delay", @@ -272,6 +274,13 @@ int readcmd(usbdevice* kb, const char* line){ } case MACRO: if(!strcmp(word, "clear")){ // Macro has a special clear command +#ifdef INIT_ERROR + if(IS_MOUSE(kb->vendor, kb->product)) { + fprintf (stderr, "Detected MACRO command for mouse. Ignored.\n"); + continue; + } + fprintf (stderr, "Detected MACRO command for keyboard. Handled.\n"); +#endif vt->macro(kb, mode, notifynumber, 0, 0); continue; } diff --git a/src/ckb/kbbind.cpp b/src/ckb/kbbind.cpp index 4566dc3..ab5ce75 100644 --- a/src/ckb/kbbind.cpp +++ b/src/ckb/kbbind.cpp @@ -218,8 +218,9 @@ void KbBind::update(QFile& cmd, bool force){ cmd.write(" unbind lwin rwin"); // At last, send Macro definitions if avalilable. - // If no definitions are made, clear macro will be sent only to reset all macros. - cmd.write(macros.toLatin1()); + // If no definitions are made, clear macro will be sent only to reset all macros, + // but prevent Macro Clear Cmd for mouse devices + if (!isMouse()) cmd.write(macros.toLatin1()); lastCmd = &cmd; } From 6cc62bcb6e03462044a2b98a2268337494a5c931 Mon Sep 17 00:00:00 2001 From: Lutz Eichler Date: Sun, 21 Feb 2016 00:04:10 +0100 Subject: [PATCH 15/25] Fix adressing wrong pipe and g-key + modifiers When adressing a command pipe for the mouse with a macro cmd, the daemon got a null-ptr, because no macro functions are defined yet. This fixes that effect. Using "macro [\+]+[]+:" is now usable, when sending the macro definition "manually" via echo to the command pipe for the keyboard. --- src/ckb-daemon/command.c | 3 ++- src/ckb-daemon/input.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ckb-daemon/command.c b/src/ckb-daemon/command.c index 8d734a8..2a85b6a 100644 --- a/src/ckb-daemon/command.c +++ b/src/ckb-daemon/command.c @@ -298,7 +298,8 @@ int readcmd(usbdevice* kb, const char* line){ // Macros and DPI have a separate left-side handler if(command == MACRO || command == DPI){ word[left] = 0; - vt->do_macro[command](kb, mode, notifynumber, word, right); + if (vt->do_macro[command]) vt->do_macro[command](kb, mode, notifynumber, word, right); + else fprintf (stderr, "Got null-ptr in vt->do_cmd[MACRO]. Did you try to send a macro to mouse (maybe wrong cmd-pipe)?\n"); continue; } // Scan the left side for key names and run the requested command diff --git a/src/ckb-daemon/input.c b/src/ckb-daemon/input.c index 594b38e..30d5314 100644 --- a/src/ckb-daemon/input.c +++ b/src/ckb-daemon/input.c @@ -5,7 +5,8 @@ int macromask(const uchar* key1, const uchar* key2){ // Scan a macro against key input. Return 0 if any of them don't match for(int i = 0; i < N_KEYBYTES_INPUT; i++){ - if((key1[i] & key2[i]) != key2[i]) + // if((key1[i] & key2[i]) != key2[i]) + if(key1[i] != key2[i]) // Changed to detect G-keys + modifiers return 0; } return 1; @@ -38,7 +39,7 @@ static void inputupdate_keys(usbdevice* kb){ if (a > 200) usleep (100); else if (a > 20) usleep(30); } - } + } } } } else { From 938edb22caccab149ab2ad00d759df3d6e7c1179 Mon Sep 17 00:00:00 2001 From: ccMSC Date: Sun, 28 Feb 2016 23:09:07 -0700 Subject: [PATCH 16/25] (ckb) Re-added session workaround after CLI parser --- VERSION | 2 +- src/ckb/main.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index c99cef6..506530d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -beta-v0.2.4 +beta-v0.2.4+t02 diff --git a/src/ckb/main.cpp b/src/ckb/main.cpp index fe2c6fd..cf78909 100644 --- a/src/ckb/main.cpp +++ b/src/ckb/main.cpp @@ -208,7 +208,13 @@ int main(int argc, char *argv[]){ break; } - // Launch in background if requested +#ifdef Q_OS_LINUX + // This isn't technically a command line option, but some WMs will add it when restoring a previous session. + // We don't want to activate the window when that happens. + if(qApp->arguments().contains("-session") || qApp->arguments().contains("--session")) + background = true; +#endif + if(isRunning(background ? 0 : "Open")){ printf("ckb is already running. Exiting.\n"); return 0; From 16c94f5da393a4bdf39716981eb4ffcec1c13b97 Mon Sep 17 00:00:00 2001 From: 0----0 Date: Thu, 3 Mar 2016 01:11:40 -0500 Subject: [PATCH 17/25] (ckb-ripple) Add the option to select a single color at random from the gradient --- src/ckb-ripple/main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ckb-ripple/main.c b/src/ckb-ripple/main.c index 1388ad3..c61258f 100644 --- a/src/ckb-ripple/main.c +++ b/src/ckb-ripple/main.c @@ -1,5 +1,6 @@ #include "../ckb/ckb-anim.h" #include +#include void ckb_info(){ // Plugin info @@ -14,6 +15,7 @@ void ckb_info(){ CKB_PARAM_AGRADIENT("color", "Ripple color:", "", "ffffffff"); CKB_PARAM_DOUBLE("length", "Ring length:", "%", 100, 1, 100); CKB_PARAM_BOOL("symmetric", "Symmetric", 0); + CKB_PARAM_BOOL("randomize", "Randomly select from gradient", 0); // Timing/input parameters CKB_KPMODE(CKB_KP_POSITION); @@ -44,11 +46,12 @@ void ckb_info(){ float kbsize = 0.f; ckb_gradient animcolor = { 0 }; -int symmetric = 0, kprelease = 0; +int symmetric = 0, kprelease = 0, randomize = 0; double animlength = 0.; void ckb_init(ckb_runctx* context){ kbsize = sqrt(context->width * context->width / 4.f + context->height * context->height / 4.f); + srand((unsigned)time(NULL)); } void ckb_parameter(ckb_runctx* context, const char* name, const char* value){ @@ -61,6 +64,7 @@ void ckb_parameter(ckb_runctx* context, const char* name, const char* value){ } CKB_PARSE_BOOL("symmetric", &symmetric){} CKB_PARSE_BOOL("kprelease", &kprelease){} + CKB_PARSE_BOOL("randomize", &randomize){} } #define ANIM_MAX (144 * 2) @@ -69,6 +73,7 @@ struct { float x, y; float maxsize; float cursize; + float choice; } anim[ANIM_MAX] = { }; void anim_add(float x, float y, float width, float height){ @@ -82,6 +87,7 @@ void anim_add(float x, float y, float width, float height){ float sizey = fmax(y, height - y); anim[i].maxsize = sqrt(sizex * sizex + sizey * sizey) + animlength; anim[i].cursize = (symmetric) ? -animlength : 0; + anim[i].choice = (float)rand()/(float)(RAND_MAX); return; } } @@ -140,10 +146,12 @@ int ckb_frame(ckb_runctx* context){ if(distance > 1.f && distance <= 1.005f) // Round values close to 1 distance = 1.f; + // Blend color gradient according to position if(distance >= 0. && distance <= 1.f){ float a, r, g, b; - ckb_grad_color(&a, &r, &g, &b, &animcolor, distance * 100.); + float gradChoice = randomize ? anim[i].choice : distance; + ckb_grad_color(&a, &r, &g, &b, &animcolor, gradChoice * 100.); ckb_alpha_blend(key, a, r, g, b); } } From 80c0805ae58001114c301eea640b82908aa4e94b Mon Sep 17 00:00:00 2001 From: ccMSC Date: Mon, 18 Apr 2016 04:24:53 -0600 Subject: [PATCH 18/25] (ckb) Fixed syntax in macroreader.h --- src/ckb/macroreader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ckb/macroreader.h b/src/ckb/macroreader.h index 231fb11..6b8299b 100644 --- a/src/ckb/macroreader.h +++ b/src/ckb/macroreader.h @@ -61,7 +61,7 @@ class MacroReaderThread : public QThread ////////// /// \brief run is the notification reader main loop. - void run Q_DECL_OVERRIDE (); + void run () Q_DECL_OVERRIDE; private slots: ////////// From 8299703326074b62e8898179d42381f3e2ca4e2e Mon Sep 17 00:00:00 2001 From: Johan Forssell Date: Wed, 27 Apr 2016 20:55:28 +0200 Subject: [PATCH 19/25] Added info on solution to OS X scroll wheel m.i.a. --- README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0badbab..f060fc1 100644 --- a/README.md +++ b/README.md @@ -186,13 +186,18 @@ If you're using **Unity** and the tray icon doesn't appear correctly, run `sudo #### OS X -- **“ckb.pkg” can’t be opened because it is from an unidentified developer.** -- Open `System Preferences > Security & Privacy > General` and click `Open Anyway`. -- **Modifier keys (Shift, Ctrl, etc.) are not rebound correctly.** -- ckb does not recognize modifier keys rebound from System Preferences. You can rebind them again within the application. -- **`~` key prints `§±`** -- Check your keyboard layout on ckb's Settings screen. Choose the layout that matches your physical keyboard. -- **Compile problems** can usually be resolved by rebooting your computer and/or reinstalling Qt. Make sure that Xcode works on its own. If a compile fails, delete the `ckb-master` directory as well as any automatically generated `build-ckb` folders and try again from a new download. +- **“ckb.pkg” can’t be opened because it is from an unidentified developer** + Open `System Preferences > Security & Privacy > General` and click `Open Anyway`. +- **Modifier keys (Shift, Ctrl, etc.) are not rebound correctly** + ckb does not recognize modifier keys rebound from System Preferences. You can rebind them again within the application. +- **`~` key prints `§±`** + Check your keyboard layout on ckb's Settings screen. Choose the layout that matches your physical keyboard. +- **Compile problems** + Can usually be resolved by rebooting your computer and/or reinstalling Qt. Make sure that Xcode works on its own. If a compile fails, delete the `ckb-master` directory as well as any automatically generated `build-ckb` folders and try again from a new download. +- **Scroll wheel does not scroll** + As of #c3474d2 it's now possible to **disable scroll acceleration** from the GUI. You can access it under "OSX tweaks" in the "More settings" screen. Once disabled, the scroll wheel should behave consistently. + + #### General From 153d93ca7e9f9f355cd82886cfdf777c2e6a7dcd Mon Sep 17 00:00:00 2001 From: ccMSC Date: Wed, 27 Apr 2016 23:32:37 -0600 Subject: [PATCH 20/25] (ckb-daemon) Moved SYN events from inputupdate to the actual event functions I noticed the SYN_events were never being posted during macro playback, which is possibly what caused the issue with some of the keys being dropped. It seems to work now even without the delays, but this will need further testing before I remove them. --- VERSION | 2 +- src/ckb-daemon/input.c | 1 - src/ckb-daemon/input.h | 2 -- src/ckb-daemon/input_linux.c | 29 ++++++++++++++++++----------- src/ckb-daemon/input_mac.c | 4 ---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/VERSION b/VERSION index 70eeb6b..6091c70 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -beta-v0.2.5+t02 +beta-v0.2.5+t03 diff --git a/src/ckb-daemon/input.c b/src/ckb-daemon/input.c index 30d5314..78a5c39 100644 --- a/src/ckb-daemon/input.c +++ b/src/ckb-daemon/input.c @@ -136,7 +136,6 @@ void inputupdate(usbdevice* kb){ input->rel_x = input->rel_y = 0; } // Finish up - os_isync(kb); memcpy(input->prevkeys, input->keys, N_KEYBYTES_INPUT); } diff --git a/src/ckb-daemon/input.h b/src/ckb-daemon/input.h index 9544744..7625df5 100644 --- a/src/ckb-daemon/input.h +++ b/src/ckb-daemon/input.h @@ -43,8 +43,6 @@ void cmd_macro(usbdevice* kb, usbmode* mode, const int notifynumber, const char* void os_keypress(usbdevice* kb, int scancode, int down); // Generate mouse movement void os_mousemove(usbdevice* kb, int x, int y); -// Synchronize input (called after sending key presses) -void os_isync(usbdevice* kb); // Perform OS-specific setup for indicator lights. Called when the device is created. Return 0 on success. int os_setupindicators(usbdevice* kb); diff --git a/src/ckb-daemon/input_linux.c b/src/ckb-daemon/input_linux.c index 20598ba..b42347e 100644 --- a/src/ckb-daemon/input_linux.c +++ b/src/ckb-daemon/input_linux.c @@ -97,6 +97,18 @@ void os_inputclose(usbdevice* kb){ kb->uinput_mouse = 0; } +// Generate SYN reports to synchronize device +static void isync(usbdevice* kb){ + struct input_event event; + memset(&event, 0, sizeof(event)); + event.type = EV_SYN; + event.code = SYN_REPORT; + if(write(kb->uinput_kb - 1, &event, sizeof(event)) <= 0) + ckb_warn("uinput write failed: %s\n", strerror(errno)); + if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0) + ckb_warn("uinput write failed: %s\n", strerror(errno)); +} + void os_keypress(usbdevice* kb, int scancode, int down){ struct input_event event; memset(&event, 0, sizeof(event)); @@ -118,6 +130,8 @@ void os_keypress(usbdevice* kb, int scancode, int down){ } if(write((is_mouse ? kb->uinput_mouse : kb->uinput_kb) - 1, &event, sizeof(event)) <= 0) ckb_warn("uinput write failed: %s\n", strerror(errno)); + else + isync(kb); } void os_mousemove(usbdevice* kb, int x, int y){ @@ -129,26 +143,19 @@ void os_mousemove(usbdevice* kb, int x, int y){ event.value = x; if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0) ckb_warn("uinput write failed: %s\n", strerror(errno)); + else + isync(kb); } if(y != 0){ event.code = REL_Y; event.value = y; if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0) ckb_warn("uinput write failed: %s\n", strerror(errno)); + else + isync(kb); } } -void os_isync(usbdevice* kb){ - struct input_event event; - memset(&event, 0, sizeof(event)); - event.type = EV_SYN; - event.code = SYN_REPORT; - if(write(kb->uinput_kb - 1, &event, sizeof(event)) <= 0) - ckb_warn("uinput write failed: %s\n", strerror(errno)); - if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0) - ckb_warn("uinput write failed: %s\n", strerror(errno)); -} - void* _ledthread(void* ctx){ usbdevice* kb = ctx; uchar ileds = 0; diff --git a/src/ckb-daemon/input_mac.c b/src/ckb-daemon/input_mac.c index 22f820e..766424a 100644 --- a/src/ckb-daemon/input_mac.c +++ b/src/ckb-daemon/input_mac.c @@ -400,10 +400,6 @@ void os_mousemove(usbdevice* kb, int x, int y){ postevent_mm(kb->event, x, y, HAS_FEATURES(kb, FEAT_MOUSEACCEL), kb->mousestate); } -void os_isync(usbdevice* kb){ - // OSX doesn't have any equivalent to the SYN_ events -} - int os_setupindicators(usbdevice* kb){ // Set NumLock on permanently kb->hw_ileds = kb->hw_ileds_old = kb->ileds = 1; From 7460697521a904773ee54444a52874adff8a5d16 Mon Sep 17 00:00:00 2001 From: ccMSC Date: Wed, 27 Apr 2016 23:56:25 -0600 Subject: [PATCH 21/25] Added missing macro entry in mouse vtable They should in fact support this command, I'm not sure how it got left out... --- src/ckb-daemon/command.c | 12 +----------- src/ckb-daemon/device_vtable.c | 2 ++ src/ckb/kbbind.cpp | 3 +-- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/ckb-daemon/command.c b/src/ckb-daemon/command.c index 2a85b6a..9acffe7 100644 --- a/src/ckb-daemon/command.c +++ b/src/ckb-daemon/command.c @@ -6,8 +6,6 @@ #include "profile.h" #include "usb.h" -//#define INIT_ERROR // for debugging purposes. MacroClient sends invalid macro-clear cmd to mouse - static const char* const cmd_strings[CMD_COUNT - 1] = { // NONE is implicit "delay", @@ -274,13 +272,6 @@ int readcmd(usbdevice* kb, const char* line){ } case MACRO: if(!strcmp(word, "clear")){ // Macro has a special clear command -#ifdef INIT_ERROR - if(IS_MOUSE(kb->vendor, kb->product)) { - fprintf (stderr, "Detected MACRO command for mouse. Ignored.\n"); - continue; - } - fprintf (stderr, "Detected MACRO command for keyboard. Handled.\n"); -#endif vt->macro(kb, mode, notifynumber, 0, 0); continue; } @@ -298,8 +289,7 @@ int readcmd(usbdevice* kb, const char* line){ // Macros and DPI have a separate left-side handler if(command == MACRO || command == DPI){ word[left] = 0; - if (vt->do_macro[command]) vt->do_macro[command](kb, mode, notifynumber, word, right); - else fprintf (stderr, "Got null-ptr in vt->do_cmd[MACRO]. Did you try to send a macro to mouse (maybe wrong cmd-pipe)?\n"); + vt->do_macro[command](kb, mode, notifynumber, word, right); continue; } // Scan the left side for key names and run the requested command diff --git a/src/ckb-daemon/device_vtable.c b/src/ckb-daemon/device_vtable.c index e13a4e4..58a4239 100644 --- a/src/ckb-daemon/device_vtable.c +++ b/src/ckb-daemon/device_vtable.c @@ -95,6 +95,7 @@ const devcmd vtable_keyboard_nonrgb = { .bind = cmd_bind, .unbind = cmd_unbind, .rebind = cmd_rebind, + .macro = cmd_macro, .dpi = cmd_macro_none, .dpisel = cmd_none, @@ -140,6 +141,7 @@ const devcmd vtable_mouse = { .bind = cmd_bind, .unbind = cmd_unbind, .rebind = cmd_rebind, + .macro = cmd_macro, .dpi = cmd_dpi, .dpisel = cmd_dpisel, diff --git a/src/ckb/kbbind.cpp b/src/ckb/kbbind.cpp index ab5ce75..c1d2b1e 100644 --- a/src/ckb/kbbind.cpp +++ b/src/ckb/kbbind.cpp @@ -219,8 +219,7 @@ void KbBind::update(QFile& cmd, bool force){ // At last, send Macro definitions if avalilable. // If no definitions are made, clear macro will be sent only to reset all macros, - // but prevent Macro Clear Cmd for mouse devices - if (!isMouse()) cmd.write(macros.toLatin1()); + cmd.write(macros.toLatin1()); lastCmd = &cmd; } From fc31ac264884de7edff6daa45128773b025e58e1 Mon Sep 17 00:00:00 2001 From: Ethan Richardson Date: Sun, 1 May 2016 01:03:18 -0500 Subject: [PATCH 22/25] Add brew installed qt5 path to qmake-auto script This will search through the qt install directory created when `brew install qt5` has been run. --- qmake-auto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake-auto b/qmake-auto index a5a1d32..5c91548 100755 --- a/qmake-auto +++ b/qmake-auto @@ -11,7 +11,7 @@ if [[ "$QMAKE" != "" ]]; then fi if [[ "$OSTYPE" == "darwin"* ]]; then # OSX: Look for qmake in standard install locations - QMAKE=`find ~/Qt/*/clang_64/bin ~/Qt5*/*/clang_64/bin ~/Applications/Qt/*/clang_64/bin ~/Applications/Qt5*/*/clang_64/bin /Applications/Qt/*/clang_64/bin /Applications/Qt5*/*/clang_64/bin -name qmake -print -quit 2>/dev/null` + QMAKE=`find /usr/local/opt/qt5/bin ~/Qt/*/clang_64/bin ~/Qt5*/*/clang_64/bin ~/Applications/Qt/*/clang_64/bin ~/Applications/Qt5*/*/clang_64/bin /Applications/Qt/*/clang_64/bin /Applications/Qt5*/*/clang_64/bin -name qmake -print -quit 2>/dev/null` [[ $QMAKE == "" ]] && die else # Linux: Look for system-installed Qt5 From bcb847190689a236d61bf3d2735efb4d99c4f6a9 Mon Sep 17 00:00:00 2001 From: Sigismund Diijkstra Date: Sat, 14 May 2016 22:37:43 +0200 Subject: [PATCH 23/25] Start in background if session is being restored --- src/ckb/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ckb/main.cpp b/src/ckb/main.cpp index 98cb2c1..37cb257 100644 --- a/src/ckb/main.cpp +++ b/src/ckb/main.cpp @@ -112,7 +112,7 @@ int main(int argc, char *argv[]){ } // Launch in background if requested, or if re-launching a previous session - bool background = qApp->arguments().contains("--background") || qApp->arguments().contains("-session") || qApp->arguments().contains("--session"); + bool background = qApp->arguments().contains("--background") || qApp->isSessionRestored(); if(isRunning(background ? 0 : "Open")){ printf("ckb is already running. Exiting.\n"); return 0; From 038dc17a566b0f67e607b7aaada4caa619fb880b Mon Sep 17 00:00:00 2001 From: Chris Gregory Date: Thu, 16 Jun 2016 14:39:43 -0700 Subject: [PATCH 24/25] Fix misleading indentation in ckb/quazip/zip.c --- src/ckb/quazip/zip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ckb/quazip/zip.c b/src/ckb/quazip/zip.c index 9649653..4c9b01d 100644 --- a/src/ckb/quazip/zip.c +++ b/src/ckb/quazip/zip.c @@ -535,8 +535,8 @@ local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f break; } - if (uPosFound!=0) - break; + if (uPosFound!=0) + break; } TRYFREE(buf); return uPosFound; From 34cd4c8920fbd3dc5d8dc4148da24edd515864b1 Mon Sep 17 00:00:00 2001 From: ccMSC Date: Thu, 30 Jun 2016 05:17:11 -0600 Subject: [PATCH 25/25] Lots of fix merges --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 93cca04..27b0395 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -beta-v0.2.6+t03 +beta-v0.2.6+t04