diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c948f71
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+bin/*
+lib/*
+.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..5ef5d45
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,19 @@
+# g810-led CONTRIBUTING
+
+## Share your profile or make dump :
+* [https://github.com/MatMoul/g810-led-resources](https://github.com/MatMoul/g810-led-resources)
+
+## Contributing :
+* Open an issue before work to hard
+* Work on the develop branch
+
+## Tasks (Help wanted) :
+* (0%) AVERAGE: Add selection of multiple keyboards by index
+* (0%) AVERAGE: Improve INSTALL.md to support more distributions (And CentOS with hidapi)
+* (10%) AVERAGE: Make distributions ready package
+* (0%) IMAGINATION: Use a more generic name for project, config dir and systemd units ([issue 29](https://github.com/MatMoul/g810-led/issues/29))
+
+## Possible enhancements :
+* Add deamon mode for custom effects (Add G Keys handler [issue 39](https://github.com/MatMoul/g810-led/issues/39), [CReimer](https://github.com/CReimer/g910-gkey-uinput)))
+* Support country based keybord ([issue 16](https://github.com/MatMoul/g810-led/issues/16) but very hard)
+* Support of new G Mouse like the G403 ([issue 40](https://github.com/MatMoul/g810-led/issues/40))
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
new file mode 100644
index 0000000..93320bf
--- /dev/null
+++ b/CONTRIBUTORS.md
@@ -0,0 +1,55 @@
+# g810-led - CONTRIBUTORS (alpha order) :
+
+## [andreast1990](https://github.com/andreast1990) :
+* Add Wireshark dump for g910
+
+## [barul42](https://github.com/barul42) :
+* Improve INSTALL.MD
+
+## [carlba](https://github.com/carlba) :
+* Improve install file
+
+## [CReimer](https://github.com/CReimer) :
+* Add Wireshark dump for g910 M and G keys
+* Debug hidapi missing keys on certain computer
+
+## [dkolosa](https://github.com/dkolosa) :
+* Provide alternative productid for g910
+
+## [francoisfreitag](https://github.com/francoisfreitag) :
+* Refactor makefile (hard work)
+
+## [hschreck](https://github.com/hschreck) :
+* Fix typo
+
+## [jdagerbo](https://github.com/jdagerbo) :
+* Refactor many of the code (very hard work)
+
+## [Landrovan](https://github.com/Landrovan) :
+* Improve support of G410 (two times)
+
+## [larsnaesbye](https://github.com/larsnaesbye) :
+* Fix typo
+
+## [lynix](https://github.com/lynix) :
+* Improve makefile
+
+## [matthunz](https://github.com/matthunz) :
+* Improve INSTALL.MD for ArchLinux
+
+## [MohamadSaada](https://github.com/MohamadSaada) :
+* Add poweron effect bytes for g910
+* Debug setKeys (hard work)
+
+## [noisycat](https://github.com/noisycat) :
+* Add wireshark dump effects
+* Improve makefile
+
+## [pearsonk](https://github.com/pearsonk) :
+* Add g213 protocol (very hard work)
+* Add support of g213
+* Implement underlying device IO as a shared library
+* Add multiple keyboard support (very hard work)
+
+## [wextia](https://github.com/wextia) :
+* Fixed incorrect markdown formatting in README.md
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000..02c9786
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,59 @@
+# Installation :
+
+## Build dependencies :
+* git
+* g++
+* make
+
+## Dependencies :
+* hidapi or libusb
+
+## hidapi vs libusb :
+hidapi is a newer implementation but needs more testing.
+hidapi is more responsive than libusb (~20ms vs ~150ms).
+hidapi seems to not work on CentOS, writing to hidraw is not allowed.
+hidapi is recommended but if you encounter a problem on your system, switch to libusb.
+
+
+## Installation using repos :
+ArchLinux (aur) :
+`yaourt -S g810-led-git` # with yaourt
+`pacaur -S g810-led-git` # with pacaur
+
+
+## Installation of dependencies :
+ArchLinux :
+`sudo pacman -S git gcc make hidapi` # for hidapi
+`sudo pacman -S git gcc make libusb` # for libusb
+Debian :
+`sudo apt-get install git g++ make libhidapi-dev` # for hidapi
+`sudo apt-get install git g++ make libusb-1.0-0-dev` # for libusb
+Fedora :
+`sudo dnf install git make gcc-c++ hidapi-devel` # for hidapi
+`sudo dnf install git make gcc-c++ libusbx-devel` # for libusb
+
+## Installation :
+`git clone https://github.com/MatMoul/g810-led.git`
+`cd g810-led`
+`make bin` # for hidapi
+`make bin LIB=libusb` # for libusb
+`sudo make install`
+
+## Installation of the library (For developers) :
+`make lib` # for hidapi
+`make lib LIB=libusb` # for libusb
+`sudo make install-lib` to install the libg810-led library.
+`sudo make install-dev` to install the libg810-led library and headers for development.
+
+## Update :
+Same as install, but your profile and reboot files are preserved.
+
+## Uninstall :
+`sudo make uninstall`
+
+## Boot profiles :
+On boot, the keyboard is set with the udev file /etc/udev/rules.d/g810-led.rules
+This file launches the profile stored in /etc/g810-led/profile
+To prevent your keyboard flashing 3 times when you reboot use the systemd unit (g810-led-reboot).
+
+Samples can be found in /etc/g810-led/samples.
diff --git a/README.md b/README.md
index cf1e9e3..9d653d4 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,55 @@
-# g810-led
+# g810-led
-Linux LED controller for the Logitech G810 Orion Spectrum Keyboard
+Linux led controller for Logitech G213, G410, G413, G512, G513, G610, G810, G910 and GPRO Keyboards.
-Other compatible keyboard :
-G410 Atlas Spectrum
-G610 Orion
-G910 Orion Spark
-G910 Orion Spectrum
+## Compatible keyboards :
+- **G213 Prodigy**
+- **G410 Atlas Spectrum**
+- **G413 Carbon**
+- **G512 Carbon**
+- **G513 Carbon**
+- **G610 Orion Brown**
+- **G610 Orion Red**
+- **G810 Orion Spectrum**
+- **G910 Orion Spark**
+- **G910 Orion Spectrum**
+- **GPRO**
-![jj](https://raw.githubusercontent.com/MatMoul/g810-led/master/pictures/logitech_g810-2.jpg)
+## Contribute and evolution :
+* [CONTRIBUTING.md](https://github.com/MatMoul/g810-led/blob/master/CONTRIBUTING.md)
-Install and use :
-- look at the wiki : https://github.com/MatMoul/g810-led/wiki
+## Install :
+* [INSTALL.md](https://github.com/MatMoul/g810-led/blob/master/INSTALL.md)
-Samples :
-`g810-led -p /etc/g810/profile # Set a profile`
+## Help :
+`g213-led --help`
+`g410-led --help`
+`g413-led --help`
+`g512-led --help`
+`g513-led --help`
+`g610-led --help`
+`g810-led --help`
+`g910-led --help`
+`gpro-led --help`
+
+`g810-led --help-keys`
+`g810-led --help-effects`
+`g810-led --help-samples`
+
+## Samples :
+`g810-led -p /etc/g810/profile # Load a profile`
`g810-led -k logo ff0000 # Set color of a key`
`g810-led -a 00ff00 # Set color of all keys`
`g810-led -g fkeys ff00ff # Set color of a group of keys`
`g810-led -s color # Set keyboard power on effect`
+`g810-led -fx color keys 00ff00 # Set fixed color effect`
+`g810-led -fx breathing logo 00ff00 0a # Set breathing effect`
+`g810-led -fx cycle all 0a # Set color cycle effect`
+`g810-led -fx hwave keys 0a # Set horizontal wave effect`
+`g810-led -fx vwave keys 0a # Set vertical wave effect`
+`g810-led -fx cwave keys 0a # Set center wave effect`
-Samples with no commit :
+## Samples with no commit :
`g810-led -an 000000 # Set color of all key with no action`
`g810-led -gn modifiers ff0000 # Set color of a group with no action`
`g810-led -kn w ff0000 # Set color of a key with no action`
@@ -28,3 +57,43 @@ Samples with no commit :
`g810-led -kn s ff0000 # Set color of a key with no action`
`g810-led -kn d ff0000 # Set color of a key with no action`
`g810-led -c # Commit all changes`
+
+## Samples for G610 :
+`g610-led -a 60 # Set intensity of all keys`
+`g610-led -k logo ff # Set intensity of a key`
+`g610-led -g fkeys aa # Set intensity of a group of keys`
+
+## Samples for G213 :
+`g213-led -a 00ff00 # Set all keys green`
+`g213-led -r 1 ff0000 # Set region 1 red`
+
+## Samples with pipe (for effects) :
+`g810-led -pp < profilefile # Load a profile`
+`echo -e "k w ff0000\nk a ff0000\nk s ff0000\nk d ff0000\nc" | g810-led -pp # Set multiple keys`
+
+## Testing unsuported keyboards :
+Start by retrieving the VendorID and the ProductID of your keyboard using lsusb.
+`lsusb`
+Sample return :
+`Bus 001 Device 001: ID 046d:c331 Logitech, Inc.`
+In this sample VendorID is 046d and ProductID is c331. Now test your keyboard with all supported protocol :
+`g810-led -dv 046d -dp c331 -tuk 1 -a 000000`
+If your keyboard set all key to off you have found the protocol (1), if not continue.
+`g810-led -dv 046d -dp c331 -tuk 2 -a 000000`
+If your keyboard set all key to off you have found the protocol (2), if not continue.
+`g810-led -dv 046d -dp c331 -tuk 3 -a 000000`
+If your keyboard set all key to off you have found the protocol (3), if not, need new dump.
+
+## Building and linking against the libg810-led library :
+Include in implementing source files.
+```cpp
+#include
+```
+To link, simply provide `-lg810-led` to the build flags.
+
+To build the g810-led application as a dynamically-linked variant, run the target:
+`make bin-linked`
+
+## Dumps :
+Dumps of keyboards are now stored in a separate project to preserve a small download size of this project.
+You can find them here : [https://github.com/MatMoul/g810-led-resources](https://github.com/MatMoul/g810-led-resources)
diff --git a/makefile b/makefile
index 24826e8..3741c14 100644
--- a/makefile
+++ b/makefile
@@ -1,20 +1,120 @@
-CC=g++
-CFLAGS=-Wall -O2 -std=gnu++11
-LIBUSB_INC?=-I/usr/include/libusb-1.0
-LDFLAGS=-lusb-1.0
+CXX?=g++
+CXXFLAGS?=-Wall -O2
+LIB?=hidapi
+ifeq ($(LIB),libusb)
+ CPPFLAGS=-Dlibusb
+ LIBS=-lusb-1.0
+else
+ CPPFLAGS=-Dhidapi
+ LIBS=-lhidapi-hidraw
+endif
+SYSTEMDDIR?=/usr/lib/systemd
+
+PREFIX?=$(DESTDIR)/usr
+libdir?=$(PREFIX)/lib
+includedir?=$(PREFIX)/include
+
+# Program & versioning information
PROGN=g810-led
+MAJOR=0
+MINOR=2
+MICRO=8
-.PHONY: all debug clean
+CXXFLAGS+=-std=gnu++11 -DVERSION=\"$(MAJOR).$(MINOR).$(MICRO)\"
+APPSRCS=src/main.cpp src/helpers/*.cpp src/helpers/*.h
+LIBSRCS=src/classes/*.cpp src/classes/*.h
-all: bin/$(PROGN)
+.PHONY: all bin debug clean setup install uninstall lib install-lib install-dev
-bin/$(PROGN): src/main.cpp src/classes/*.cpp src/classes/*.h
+all: lib/lib$(PROGN).so bin/$(PROGN)
+
+bin: bin/$(PROGN)
+
+bin/$(PROGN): $(APPSRCS) $(LIBSRCS)
@mkdir -p bin
- $(CC) $(CFLAGS) $(LIBUSB_INC) -o $@ $^ $(LDFLAGS)
-
-debug: CFLAGS += -g -Wextra -pedantic
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
+
+debug: CXXFLAGS += -g -Wextra -pedantic
debug: bin/$(PROGN)
-clean:
- rm -rf bin
+lib/lib$(PROGN).so: $(LIBSRCS)
+ @mkdir -p lib
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -fPIC -shared -Wl,-soname,lib$(PROGN).so -o lib/lib$(PROGN).so.$(MAJOR).$(MINOR).$(MICRO) $^ $(LIBS)
+ @ln -sf lib$(PROGN).so.$(MAJOR).$(MINOR).$(MICRO) lib/lib$(PROGN).so
+bin-linked: lib/lib$(PROGN).so
+ @mkdir -p bin
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $(APPSRCS) -o bin/$(PROGN) $(LIBS) -L./lib -l$(PROGN)
+
+lib: lib/lib$(PROGN).so
+
+clean:
+ @rm -rf bin
+ @rm -rf lib
+
+setup:
+ @install -m 755 -d \
+ $(DESTDIR)/usr/bin \
+ $(DESTDIR)/etc/$(PROGN)/samples \
+ $(DESTDIR)/etc/udev/rules.d
+ @cp bin/$(PROGN) $(DESTDIR)/usr/bin
+ @test -s $(DESTDIR)/usr/bin/g213-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g213-led
+ @test -s $(DESTDIR)/usr/bin/g410-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g410-led
+ @test -s $(DESTDIR)/usr/bin/g413-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g413-led
+ @test -s $(DESTDIR)/usr/bin/g512-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g512-led
+ @test -s $(DESTDIR)/usr/bin/g513-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g513-led
+ @test -s $(DESTDIR)/usr/bin/g610-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g610-led
+ @test -s $(DESTDIR)/usr/bin/g910-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g910-led
+ @test -s $(DESTDIR)/usr/bin/gpro-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/gpro-led
+ @cp sample_profiles/* $(DESTDIR)/etc/$(PROGN)/samples
+ @cp udev/$(PROGN).rules $(DESTDIR)/etc/udev/rules.d
+ @test -s /usr/bin/systemd-run && \
+ install -m 755 -d $(DESTDIR)$(SYSTEMDDIR)/system && \
+ cp systemd/$(PROGN)-reboot.service $(DESTDIR)$(SYSTEMDDIR)/system
+
+install-lib: lib
+ @install -m 755 -d $(libdir)
+ @install -m 644 lib/lib$(PROGN).so.$(MAJOR).$(MINOR).$(MICRO) $(libdir)/
+ @ln -sf lib$(PROGN).so.$(MAJOR).$(MINOR).$(MICRO) $(libdir)/lib$(PROGN).so
+
+install-dev: install-lib
+ @mkdir -p $(includedir)/$(PROGN)/
+ @install -m 644 src/classes/*.h $(includedir)/$(PROGN)
+
+install: setup
+ @test -s /etc/$(PROGN)/profile || \
+ cp /etc/$(PROGN)/samples/group_keys /etc/$(PROGN)/profile
+ @test -s /etc/$(PROGN)/reboot || \
+ cp /etc/$(PROGN)/samples/all_off /etc/$(PROGN)/reboot
+ @udevadm control --reload-rules
+ @$(PROGN) -p /etc/$(PROGN)/profile
+ @test -s /usr/bin/systemd-run && \
+ systemctl daemon-reload && \
+ systemctl enable $(PROGN)-reboot
+
+uninstall-lib:
+ @rm -f $(libdir)/lib$(PROGN).so*
+
+uninstall-dev:
+ @rm -rf $(includedir)/$(PROGN)
+
+uninstall:
+ @test -s /usr/bin/systemd-run && \
+ systemctl disable $(PROGN)-reboot && \
+ rm $(SYSTEMDDIR)/system/$(PROGN)-reboot.service && \
+ systemctl daemon-reload && \
+ rm -R /etc/$(PROGN)
+
+ @rm /usr/bin/g213-led
+ @rm /usr/bin/g410-led
+ @rm /usr/bin/g413-led
+ @rm /usr/bin/g413-led
+ @rm /usr/bin/g512-led
+ @rm /usr/bin/g513-led
+ @rm /usr/bin/g610-led
+ @rm /usr/bin/g910-led
+ @rm /usr/bin/gpro-led
+ @rm /usr/bin/$(PROGN)
+
+ @rm /etc/udev/rules.d/$(PROGN).rules
+ @udevadm control --reload-rules
diff --git a/makerelease b/makerelease
new file mode 100755
index 0000000..148e1bf
--- /dev/null
+++ b/makerelease
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+if [ "$1" == "" ]; then
+ echo "Error: No version provided"
+ echo "./makerelease 0.0.1"
+ exit 1
+fi
+
+ssh -T git@github.com
+if [ ! "$?" = "1" ]; then
+ echo "No Github ssh key loaded exiting..."
+ exit 1
+fi
+
+clear
+branch=$(git rev-parse --abbrev-ref HEAD)
+read -p "Current branch is $branch. Continue ? (y/N)" choice
+case "$choice" in
+ n|N|'' )
+ echo "Cancel !"
+ exit 1
+ ;;
+ y|Y ) echo "Make release...";;
+ * )
+ echo "Cancel !"
+ exit 1
+ ;;
+esac
+
+
+
+# Ready to update :
+
+version=$1
+
+sed -i "/string version = /c\\\tstring version = \"$version\";" src/helpers/help.cpp
+IFS='.' read -ra VPART <<< "$version"
+sed -i "/MAJOR=/cMAJOR=${VPART[0]}" makefile
+sed -i "/MINOR=/cMINOR=${VPART[1]}" makefile
+sed -i "/MICRO=/cMICRO=${VPART[2]}" makefile
+
+git commit -m "Version $version" makefile src/*
+git push
+
+git checkout master
+git merge develop
+git push
+
+git tag -a "v$version" -m "Version $version"
+git push --tags
+
+git checkout $branch
+
+#wget https://github.com/MatMoul/g810-led/archive/v$version.zip
+#wget https://github.com/MatMoul/g810-led/archive/v$version.tar.gz
+
+#Publish to aur...
diff --git a/pictures/logitech_g810-2.jpg b/pictures/logitech_g810-2.jpg
deleted file mode 100644
index 0cb5d34..0000000
Binary files a/pictures/logitech_g810-2.jpg and /dev/null differ
diff --git a/sample_effects/bash/k2000 b/sample_effects/bash/k2000
new file mode 100755
index 0000000..c5c85d5
--- /dev/null
+++ b/sample_effects/bash/k2000
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+if [ "$1" == "--help" ]; then
+ echo "k2000 [speed (default:0.01] [colorOff] [colorOn] [colorFade1] [colorFade2]"
+ exit 0
+fi
+
+speed=0.01
+colorOff=000000
+colorOn=ff0000
+colorFade1=aa0000
+colorFade2=550000
+
+if [ "$1" != "" ]; then
+ speed=$1
+fi
+if [ "$2" != "" ]; then
+ colorOff=$2
+fi
+if [ "$3" != "" ]; then
+ colorOn=$3
+ if [ "$4" != "" ]; then
+ colorFade1=$4
+ else
+ colorFade1=$colorOn
+ fi
+ if [ "$5" != "" ]; then
+ colorFade2=$5
+ else
+ colorFade2=$colorOn
+ fi
+fi
+
+setKeys () {
+ cmd=""
+ if [ $1 ] ; then
+ cmd=$cmd"k $1 $colorOn\n"
+ fi
+ if [ $2 ] ; then
+ cmd=$cmd"k $2 $colorFade1\n"
+ fi
+ if [ $3 ] ; then
+ cmd=$cmd"k $3 $colorFade2\n"
+ fi
+ if [ $4 ] ; then
+ cmd=$cmd"k $4 $colorOff\n"
+ fi
+ cmd=$cmd"c"
+ echo -e $cmd | g810-led -pp
+ sleep $speed
+}
+
+g810-led -gn fkeys $colorOff
+
+setKeys F1
+setKeys F2
+setKeys F3
+setKeys F4
+setKeys F5 F1
+setKeys F6 F2 F1
+setKeys F7 F3 F2 F1
+setKeys F8 F4 F3 F2
+setKeys F9 F5 F4 F3
+setKeys F10 F6 F5 F4
+setKeys F11 F7 F6 F5
+setKeys F12 F8 F7 F6
+setKeys F12 F9 F8 F7
+setKeys F12 F10 F9 F8
+setKeys F12 F11 F10 F9
+setKeys F11 F10 F10 F10
+setKeys F10
+setKeys F9
+setKeys F8 F12
+setKeys F7 F11 F12
+setKeys F6 F10 F11 F12
+setKeys F5 F9 F10 F11
+setKeys F4 F8 F9 F10
+setKeys F3 F7 F8 F9
+setKeys F2 F6 F7 F8
+setKeys F1 F5 F6 F7
+setKeys F1 F4 F5 F6
+setKeys F1 F3 F4 F5
+setKeys F1 F2 F3 F4
+setKeys F1 F1 F2 F3
+setKeys F1 F1 F1 F2
+setKeys F1 F1 F1 F1
diff --git a/sample_effects/python/k2000 b/sample_effects/python/k2000
new file mode 100755
index 0000000..ce3c031
--- /dev/null
+++ b/sample_effects/python/k2000
@@ -0,0 +1,96 @@
+#!/usr/bin/python2
+
+import sys
+import subprocess
+import time
+
+
+if len(sys.argv) > 1:
+ if sys.argv[1] == '--help':
+ print 'k2000 [speed (default:0.01] [colorOff] [colorOn] [colorFade1] [colorFade2]'
+ sys.exit()
+
+
+speed = 0.01
+colorOff = '000000'
+colorOn = 'ff0000'
+colorFade1 = 'aa0000'
+colorFade2 = '550000'
+
+if len(sys.argv) > 1:
+ try:
+ speed = float(sys.argv[1])
+ except:
+ print 'Speed arg error'
+if len(sys.argv) > 2:
+ try:
+ colorOff = sys.argv[2]
+ except:
+ print 'colorOff arg error'
+if len(sys.argv) > 3:
+ try:
+ colorOn = sys.argv[3]
+ except:
+ print 'colorOn arg error'
+if len(sys.argv) > 4:
+ try:
+ colorFade1 = sys.argv[4]
+ except:
+ print 'colorFade1 arg error'
+if len(sys.argv) > 5:
+ try:
+ colorFade2 = sys.argv[5]
+ except:
+ print 'colorFade2 arg error'
+
+
+def setKeys(keys):
+ pipeValue = ''
+ for index in range(len(keys)):
+ if index == 0:
+ pipeValue = pipeValue + 'k ' + keys[index] + ' ' + colorOn + '\\n'
+ elif index == 1:
+ pipeValue = pipeValue + 'k ' + keys[index] + ' ' + colorFade1 + '\\n'
+ elif index == 2:
+ pipeValue = pipeValue + 'k ' + keys[index] + ' ' + colorFade2 + '\\n'
+ elif index == 3:
+ pipeValue = pipeValue + 'k ' + keys[index] + ' ' + colorOff + '\\n'
+ pipeValue = pipeValue + 'c'
+ subprocess.call('echo -e "' + pipeValue + '" | g810-led -pp', shell=True)
+ time.sleep(speed)
+
+
+subprocess.call('g810-led -gn fkeys ' + colorOff, shell=True)
+
+setKeys(['F1'])
+setKeys(['F2'])
+setKeys(['F3'])
+setKeys(['F4'])
+setKeys(['F5','F1'])
+setKeys(['F6','F2','F1'])
+setKeys(['F7','F3','F2','F1'])
+setKeys(['F8','F4','F3','F2'])
+setKeys(['F9','F5','F4','F3'])
+setKeys(['F10','F6','F5','F4'])
+setKeys(['F11','F7','F6','F5'])
+setKeys(['F12','F8','F7','F6'])
+setKeys(['F12','F9','F8','F7'])
+setKeys(['F12','F10','F9','F8'])
+setKeys(['F12','F11','F10','F9'])
+setKeys(['F11','F10','F10','F10'])
+setKeys(['F10'])
+setKeys(['F9'])
+setKeys(['F8','F12'])
+setKeys(['F7','F11','F12'])
+setKeys(['F6','F10','F11','F12'])
+setKeys(['F5','F9','F10','F11'])
+setKeys(['F4','F8','F9','F10'])
+setKeys(['F3','F7','F8','F9'])
+setKeys(['F2','F6','F7','F8'])
+setKeys(['F1','F5','F6','F7'])
+setKeys(['F1','F4','F5','F6'])
+setKeys(['F1','F3','F4','F5'])
+setKeys(['F1','F2','F3','F4'])
+setKeys(['F1','F1','F2','F3'])
+setKeys(['F1','F1','F1','F2'])
+setKeys(['F1','F1','F1','F1'])
diff --git a/sample_profiles/all_blue_fxl_breathing_red b/sample_profiles/all_blue_fxl_breathing_red
new file mode 100644
index 0000000..8e8ccf4
--- /dev/null
+++ b/sample_profiles/all_blue_fxl_breathing_red
@@ -0,0 +1,5 @@
+a 0000ff # Set all keys blue
+
+c # Commit changes
+
+fx breathing logo ff0000 10 # Set breathing effect with red color and speed 10
diff --git a/sample_profiles/colors b/sample_profiles/colors
new file mode 100644
index 0000000..d87c950
--- /dev/null
+++ b/sample_profiles/colors
@@ -0,0 +1,28 @@
+# Sample profile using Groups of Keys and Single Characters.
+
+g logo 000096 # Blue
+g indicators ffffff # White
+g multimedia 009600 # Green
+g fkeys ff7700 # Orange
+g modifiers ff7700 # Orange
+g arrows 0000ff # Red
+g numeric 00ff00 # Green
+g functions ffffff # White
+g keys ff00ff # Purple
+g gkeys ffffff # White
+k tilde ff0000 # Red
+k W 0000ff # Blue {
+k A 0000ff
+k S 0000ff
+k D 0000ff # }
+k 1 ff0000 # Red {
+k 2 ff0000
+k 3 ff0000
+k 4 ff0000
+k 5 ff0000
+k 6 ff0000
+k 7 ff0000
+k 8 ff0000
+k 9 ff0000
+k 0 ff0000 # }
+c # Commit changes
diff --git a/sample_profiles/fx_breathing_red b/sample_profiles/fx_breathing_red
new file mode 100644
index 0000000..250349c
--- /dev/null
+++ b/sample_profiles/fx_breathing_red
@@ -0,0 +1,2 @@
+
+fx breathing all ff0000 20 # Set breathing effect with red color and speed 20
diff --git a/sample_profiles/fx_color_green b/sample_profiles/fx_color_green
new file mode 100644
index 0000000..97264a7
--- /dev/null
+++ b/sample_profiles/fx_color_green
@@ -0,0 +1,3 @@
+# Green Profile
+
+fx color all 00ff00 # Set all keys green
diff --git a/sample_profiles/fx_cwave b/sample_profiles/fx_cwave
new file mode 100644
index 0000000..347a1bc
--- /dev/null
+++ b/sample_profiles/fx_cwave
@@ -0,0 +1,2 @@
+
+fx cwave all 20 # Set center wave effect with speed 20
diff --git a/sample_profiles/fx_cycle b/sample_profiles/fx_cycle
new file mode 100644
index 0000000..249adcb
--- /dev/null
+++ b/sample_profiles/fx_cycle
@@ -0,0 +1,2 @@
+
+fx cycle all 20 # Set color cycle effect with speed 20
diff --git a/sample_profiles/fx_hwave b/sample_profiles/fx_hwave
new file mode 100644
index 0000000..cea0f8a
--- /dev/null
+++ b/sample_profiles/fx_hwave
@@ -0,0 +1,2 @@
+
+fx hwave all 20 # Set horizontal wave effect with speed 20
diff --git a/sample_profiles/fx_vwave b/sample_profiles/fx_vwave
new file mode 100644
index 0000000..a52aca2
--- /dev/null
+++ b/sample_profiles/fx_vwave
@@ -0,0 +1,2 @@
+
+fx vwave all 20 # Set vertical wave effect with speed 20
diff --git a/sample_profiles/group_keys b/sample_profiles/group_keys
index 98afb1a..53c92df 100644
--- a/sample_profiles/group_keys
+++ b/sample_profiles/group_keys
@@ -1,7 +1,7 @@
# Sample profile by groups keys
g logo 000096
-g indicators 00ffff
+g indicators ffffff
g multimedia 009600
g fkeys ff00ff
g modifiers ff0000
@@ -9,5 +9,6 @@ g arrows ffff00
g numeric 00ffff
g functions ffffff
g keys 009696
+g gkeys ffffff
c # Commit changes
diff --git a/sample_profiles/keys_v_gradiant_fr_ch-latin1 b/sample_profiles/keys_v_gradiant_fr_ch-latin1
index 0a56625..f22b5f5 100644
--- a/sample_profiles/keys_v_gradiant_fr_ch-latin1
+++ b/sample_profiles/keys_v_gradiant_fr_ch-latin1
@@ -56,7 +56,7 @@ k w $raw3
k e $raw3
k r $raw3
k t $raw3
-k z $raw3
+k y $raw3
k u $raw3
k i $raw3
k o $raw3
@@ -94,7 +94,7 @@ k num_plus $raw4
# Raw 5 :
k shift_left $raw5
k intl_backslash $raw5
-k y $raw5
+k z $raw5
k x $raw5
k c $raw5
k v $raw5
diff --git a/src/classes/Keyboard.cpp b/src/classes/Keyboard.cpp
index 43151f9..9c54f9d 100644
--- a/src/classes/Keyboard.cpp
+++ b/src/classes/Keyboard.cpp
@@ -1,845 +1,897 @@
#include "Keyboard.h"
-#include
+
+#include
#include
-#include
-#include "libusb.h"
+#include
+
+#if defined(hidapi)
+ #include
+ #include "hidapi/hidapi.h"
+#elif defined(libusb)
+ #include "libusb-1.0/libusb.h"
+#endif
-bool Keyboard::isAttached() {
- return m_isAttached;
+using namespace std;
+
+
+
+LedKeyboard::~LedKeyboard() {
+ close();
}
-bool Keyboard::attach() {
- if (m_isAttached == true) return false;
- int r;
- r = libusb_init(&ctx);
- if (r < 0) return false;
-
- libusb_device **devs;
- ssize_t cnt = libusb_get_device_list(ctx, &devs);
- if(cnt < 0) return false;
- int pid = 0;
- for(ssize_t i = 0; i < cnt; i++) {
- libusb_device *device = devs[i];
- libusb_device_descriptor desc = {
- 0, // bLength
- 0, // bDescriptorType
- 0, // bcdUSB
- 0, // bDeviceClass
- 0, // bDeviceSubClass
- 0, // bDeviceProtocol
- 0, // bMaxPacketSize0
- 0, // idVendor
- 0, // idProduct
- 0, // bcdDevice
- 0, // iManufacturer
- 0, // iProduct
- 0, // iSerialNumber
- 0 // bNumConfigurations
- };
- libusb_get_device_descriptor(device, &desc);
- if (desc.idVendor == 0x046d) {
- if (desc.idProduct == 0xc331) { pid = desc.idProduct; break; } // G810 spectrum
- if (desc.idProduct == 0xc337) { pid = desc.idProduct; break; } // G810 spectrum
- if (desc.idProduct == 0xc330) { pid = desc.idProduct; break; } // G410 spectrum
- if (desc.idProduct == 0xc333) { pid = desc.idProduct; break; } // G610 spectrum
- if (desc.idProduct == 0xc32b) { // G910 spark
- pid = desc.idProduct;
- kbdProtocol = KeyboardProtocol::g910;
- break;
- }
- if (desc.idProduct == 0xc335) { // G910 spectrum
- pid = desc.idProduct;
- kbdProtocol = KeyboardProtocol::g910;
- break;
- }
- }
- }
- libusb_free_device_list(devs, 1);
- if (pid == 0) {
- libusb_exit(ctx);
- ctx = NULL;
- return false;
- }
-
- dev_handle = libusb_open_device_with_vid_pid(ctx, 0x046d, pid);
- if (dev_handle == NULL) {
- libusb_exit(ctx);
- ctx = NULL;
- return false;
- }
- if(libusb_kernel_driver_active(dev_handle, 1) == 1) {
- libusb_detach_kernel_driver(dev_handle, 1);
- m_isKernellDetached = true;
- }
- r = libusb_claim_interface(dev_handle, 1);
- if(r < 0) return false;
- m_isAttached = true;
- return true;
-}
-bool Keyboard::detach() {
- if (m_isAttached == false) return false;
- int r;
- r = libusb_release_interface(dev_handle, 1);
- if(r!=0) return false;
- if(m_isKernellDetached==true) {
- libusb_attach_kernel_driver(dev_handle, 1);
- m_isKernellDetached = false;
- }
- libusb_close(dev_handle);
- dev_handle = NULL;
- libusb_exit(ctx);
- ctx = NULL;
- m_isAttached = false;
- return true;
-}
+vector LedKeyboard::listKeyboards() {
+ vector deviceList;
-bool Keyboard::commit() {
- if (m_isAttached == false) return false;
- bool retval = false;
- unsigned char *data = new unsigned char[20];
- switch (kbdProtocol) {
- case KeyboardProtocol::generic:
- data[0] = 0x11;
- data[1] = 0xff;
- data[2] = 0x0c;
- data[3] = 0x5a;
- break;
- case KeyboardProtocol::g910:
- data[0] = 0x11;
- data[1] = 0xff;
- data[2] = 0x0f;
- data[3] = 0x5d;
- break;
- default:
- return false;
- break;
- }
- for(int i = 4; i < 20; i++) data[i] = 0x00;
- retval = sendDataInternal(data, 20);
- delete[] data;
- return retval;
-}
+ #if defined(hidapi)
+ if (hid_init() < 0) return deviceList;
+
+ struct hid_device_info *devs, *dev;
+ devs = hid_enumerate(0x0, 0x0);
+ dev = devs;
+ while (dev) {
+ for (size_t i = 0; i < SupportedKeyboards.size(); i++) {
+ if (dev->vendor_id == SupportedKeyboards[i][0]) {
+ if (dev->product_id == SupportedKeyboards[i][1]) {
+ DeviceInfo deviceInfo;
+ deviceInfo.vendorID=dev->vendor_id;
+ deviceInfo.productID=dev->product_id;
-bool Keyboard::getKeyAddress(Key key, KeyAddress &keyAddress) {
- switch (key) {
- case Key::logo:
- keyAddress.addressGroup = KeyAddressGroup::logo;
- keyAddress.id = 0x01;
- break;
- case Key::logo2:
- keyAddress.addressGroup = KeyAddressGroup::logo;
- keyAddress.id = 0x02;
- break;
- case Key::backlight:
- keyAddress.addressGroup = KeyAddressGroup::indicators;
- keyAddress.id = 0x01;
- break;
- case Key::game:
- keyAddress.addressGroup = KeyAddressGroup::indicators;
- keyAddress.id = 0x02;
- break;
- case Key::caps:
- keyAddress.addressGroup = KeyAddressGroup::indicators;
- keyAddress.id = 0x03;
- break;
- case Key::scroll:
- keyAddress.addressGroup = KeyAddressGroup::indicators;
- keyAddress.id = 0x04;
- break;
- case Key::num:
- keyAddress.addressGroup = KeyAddressGroup::indicators;
- keyAddress.id = 0x05;
- break;
- case Key::next:
- keyAddress.addressGroup = KeyAddressGroup::multimedia;
- keyAddress.id = 0xb5;
- break;
- case Key::prev:
- keyAddress.addressGroup = KeyAddressGroup::multimedia;
- keyAddress.id = 0xb6;
- break;
- case Key::stop:
- keyAddress.addressGroup = KeyAddressGroup::multimedia;
- keyAddress.id = 0xb7;
- break;
- case Key::play:
- keyAddress.addressGroup = KeyAddressGroup::multimedia;
- keyAddress.id = 0xcd;
- break;
- case Key::mute:
- keyAddress.addressGroup = KeyAddressGroup::multimedia;
- keyAddress.id = 0xe2;
- break;
- case Key::g1:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x01;
- break;
- case Key::g2:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x02;
- break;
- case Key::g3:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x03;
- break;
- case Key::g4:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x04;
- break;
- case Key::g5:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x05;
- break;
- case Key::g6:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x06;
- break;
- case Key::g7:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x07;
- break;
- case Key::g8:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x08;
- break;
- case Key::g9:
- keyAddress.addressGroup = KeyAddressGroup::gkeys;
- keyAddress.id = 0x09;
- break;
- default:
- keyAddress.addressGroup = KeyAddressGroup::keys;
- switch (key) {
- case Key::a: keyAddress.id = 0x04; break;
- case Key::b: keyAddress.id = 0x05; break;
- case Key::c: keyAddress.id = 0x06; break;
- case Key::d: keyAddress.id = 0x07; break;
- case Key::e: keyAddress.id = 0x08; break;
- case Key::f: keyAddress.id = 0x09; break;
- case Key::g: keyAddress.id = 0x0a; break;
- case Key::h: keyAddress.id = 0x0b; break;
- case Key::i: keyAddress.id = 0x0c; break;
- case Key::j: keyAddress.id = 0x0d; break;
- case Key::k: keyAddress.id = 0x0e; break;
- case Key::l: keyAddress.id = 0x0f; break;
- case Key::m: keyAddress.id = 0x10; break;
- case Key::n: keyAddress.id = 0x11; break;
- case Key::o: keyAddress.id = 0x12; break;
- case Key::p: keyAddress.id = 0x13; break;
- case Key::q: keyAddress.id = 0x14; break;
- case Key::r: keyAddress.id = 0x15; break;
- case Key::s: keyAddress.id = 0x16; break;
- case Key::t: keyAddress.id = 0x17; break;
- case Key::u: keyAddress.id = 0x18; break;
- case Key::v: keyAddress.id = 0x19; break;
- case Key::w: keyAddress.id = 0x1a; break;
- case Key::x: keyAddress.id = 0x1b; break;
- case Key::z: keyAddress.id = 0x1c; break;
- case Key::y: keyAddress.id = 0x1d; break;
- case Key::n1: keyAddress.id = 0x1e; break;
- case Key::n2: keyAddress.id = 0x1f; break;
- case Key::n3: keyAddress.id = 0x20; break;
- case Key::n4: keyAddress.id = 0x21; break;
- case Key::n5: keyAddress.id = 0x22; break;
- case Key::n6: keyAddress.id = 0x23; break;
- case Key::n7: keyAddress.id = 0x24; break;
- case Key::n8: keyAddress.id = 0x25; break;
- case Key::n9: keyAddress.id = 0x26; break;
- case Key::n0: keyAddress.id = 0x27; break;
- case Key::enter: keyAddress.id = 0x28; break;
- case Key::esc: keyAddress.id = 0x29; break;
- case Key::backspace: keyAddress.id = 0x2a; break;
- case Key::tab: keyAddress.id = 0x2b; break;
- case Key::space: keyAddress.id = 0x2c; break;
- case Key::minus: keyAddress.id = 0x2d; break;
- case Key::equal: keyAddress.id = 0x2e; break;
- case Key::open_bracket: keyAddress.id = 0x2f; break;
- case Key::close_bracket: keyAddress.id = 0x30; break;
- case Key::backslash: keyAddress.id = 0x31; break;
- case Key::dollar: keyAddress.id = 0x32; break;
- case Key::semicolon: keyAddress.id = 0x33; break;
- case Key::quote: keyAddress.id = 0x34; break;
- case Key::tilde: keyAddress.id = 0x35; break;
- case Key::comma: keyAddress.id = 0x36; break;
- case Key::period: keyAddress.id = 0x37; break;
- case Key::slash: keyAddress.id = 0x38; break;
- case Key::caps_lock: keyAddress.id = 0x39; break;
- case Key::f1: keyAddress.id = 0x3a; break;
- case Key::f2: keyAddress.id = 0x3b; break;
- case Key::f3: keyAddress.id = 0x3c; break;
- case Key::f4: keyAddress.id = 0x3d; break;
- case Key::f5: keyAddress.id = 0x3e; break;
- case Key::f6: keyAddress.id = 0x3f; break;
- case Key::f7: keyAddress.id = 0x40; break;
- case Key::f8: keyAddress.id = 0x41; break;
- case Key::f9: keyAddress.id = 0x42; break;
- case Key::f10: keyAddress.id = 0x43; break;
- case Key::f11: keyAddress.id = 0x44; break;
- case Key::f12: keyAddress.id = 0x45; break;
- case Key::print_screen: keyAddress.id = 0x46; break;
- case Key::scroll_lock: keyAddress.id = 0x47; break;
- case Key::pause_break: keyAddress.id = 0x48; break;
- case Key::insert: keyAddress.id = 0x49; break;
- case Key::home: keyAddress.id = 0x4a; break;
- case Key::page_up: keyAddress.id = 0x4b; break;
- case Key::del: keyAddress.id = 0x4c; break;
- case Key::end: keyAddress.id = 0x4d; break;
- case Key::page_down: keyAddress.id = 0x4e; break;
- case Key::arrow_right: keyAddress.id = 0x4f; break;
- case Key::arrow_left: keyAddress.id = 0x50; break;
- case Key::arrow_bottom: keyAddress.id = 0x51; break;
- case Key::arrow_top: keyAddress.id = 0x52; break;
- case Key::num_lock: keyAddress.id = 0x53; break;
- case Key::num_slash: keyAddress.id = 0x54; break;
- case Key::num_asterisk: keyAddress.id = 0x55; break;
- case Key::num_minus: keyAddress.id = 0x56; break;
- case Key::num_plus: keyAddress.id = 0x57; break;
- case Key::num_enter: keyAddress.id = 0x58; break;
- case Key::num_1: keyAddress.id = 0x59; break;
- case Key::num_2: keyAddress.id = 0x5a; break;
- case Key::num_3: keyAddress.id = 0x5b; break;
- case Key::num_4: keyAddress.id = 0x5c; break;
- case Key::num_5: keyAddress.id = 0x5d; break;
- case Key::num_6: keyAddress.id = 0x5e; break;
- case Key::num_7: keyAddress.id = 0x5f; break;
- case Key::num_8: keyAddress.id = 0x60; break;
- case Key::num_9: keyAddress.id = 0x61; break;
- case Key::num_0: keyAddress.id = 0x62; break;
- case Key::num_dot: keyAddress.id = 0x63; break;
- case Key::intl_backslash: keyAddress.id = 0x64; break;
- case Key::menu: keyAddress.id = 0x65; break;
- case Key::ctrl_left: keyAddress.id = 0xe0; break;
- case Key::shift_left: keyAddress.id = 0xe1; break;
- case Key::alt_left: keyAddress.id = 0xe2; break;
- case Key::win_left: keyAddress.id = 0xe3; break;
- case Key::ctrl_right: keyAddress.id = 0xe4; break;
- case Key::shift_right: keyAddress.id = 0xe5; break;
- case Key::alt_right: keyAddress.id = 0xe6; break;
- case Key::win_right: keyAddress.id = 0xe7; break;
- default: break;
- }
- break;
- }
- return true;
-}
+ if (dev->serial_number != NULL) {
+ char buf[256];
+ wcstombs(buf, dev->serial_number, 256);
+ deviceInfo.serialNumber = string(buf);
+ }
-bool Keyboard::parsePowerOnEffect(std::string effect, PowerOnEffect &powerOnEffect) {
- if (effect == "rainbow") powerOnEffect = PowerOnEffect::rainbow;
- else if (effect == "color") powerOnEffect = PowerOnEffect::color;
- else return false;
- return true;
-}
+ if (dev->manufacturer_string != NULL)
+ {
+ char buf[256];
+ wcstombs(buf, dev->manufacturer_string, 256);
+ deviceInfo.manufacturer = string(buf);
+ }
-bool Keyboard::parseKey(std::string key, KeyAddress &keyAddress) {
- std::transform(key.begin(), key.end(), key.begin(), ::tolower);
- Key parsedKey;
- if (key == "logo") parsedKey = Key::logo;
- else if (key == "logo2") parsedKey = Key::logo2;
- else if (key == "back_light" || key == "backlight" || key == "light") parsedKey = Key::backlight;
- else if (key == "game_mode" || key == "gamemode" || key == "game") parsedKey = Key::game;
- else if (key == "caps_indicator" || key == "capsindicator" || key == "caps") parsedKey = Key::caps;
- else if (key == "scroll_indicator" || key == "scrollindicator" || key == "scroll") parsedKey = Key::scroll;
- else if (key == "num_indicator" || key == "numindicator" || key == "num") parsedKey = Key::num;
- else if (key == "next") parsedKey = Key::next;
- else if (key == "prev" || key == "previous") parsedKey = Key::prev;
- else if (key == "stop") parsedKey = Key::stop;
- else if (key == "play_pause" || key == "playpause" || key == "play") parsedKey = Key::play;
- else if (key == "mute") parsedKey = Key::mute;
- else if (key == "a") parsedKey = Key::a;
- else if (key == "b") parsedKey = Key::b;
- else if (key == "c") parsedKey = Key::c;
- else if (key == "d") parsedKey = Key::d;
- else if (key == "e") parsedKey = Key::e;
- else if (key == "f") parsedKey = Key::f;
- else if (key == "g") parsedKey = Key::g;
- else if (key == "h") parsedKey = Key::h;
- else if (key == "i") parsedKey = Key::i;
- else if (key == "j") parsedKey = Key::j;
- else if (key == "k") parsedKey = Key::k;
- else if (key == "l") parsedKey = Key::l;
- else if (key == "m") parsedKey = Key::m;
- else if (key == "n") parsedKey = Key::n;
- else if (key == "o") parsedKey = Key::o;
- else if (key == "p") parsedKey = Key::p;
- else if (key == "q") parsedKey = Key::q;
- else if (key == "r") parsedKey = Key::r;
- else if (key == "s") parsedKey = Key::s;
- else if (key == "t") parsedKey = Key::t;
- else if (key == "u") parsedKey = Key::u;
- else if (key == "v") parsedKey = Key::v;
- else if (key == "w") parsedKey = Key::w;
- else if (key == "x") parsedKey = Key::x;
- else if (key == "z") parsedKey = Key::z;
- else if (key == "y") parsedKey = Key::y;
- else if (key == "1" || key == "one") parsedKey = Key::n1;
- else if (key == "2" || key == "two") parsedKey = Key::n2;
- else if (key == "3" || key == "three") parsedKey = Key::n3;
- else if (key == "4" || key == "four") parsedKey = Key::n4;
- else if (key == "5" || key == "five") parsedKey = Key::n5;
- else if (key == "6" || key == "six") parsedKey = Key::n6;
- else if (key == "7" || key == "seven") parsedKey = Key::n7;
- else if (key == "8" || key == "eight") parsedKey = Key::n8;
- else if (key == "9" || key == "nine") parsedKey = Key::n9;
- else if (key == "0" || key == "zero") parsedKey = Key::n0;
- else if (key == "enter") parsedKey = Key::enter;
- else if (key == "esc" || key == "escape") parsedKey = Key::esc;
- else if (key == "back" || key == "backspace") parsedKey = Key::backspace;
- else if (key == "tab") parsedKey = Key::tab;
- else if (key == "space") parsedKey = Key::space;
- else if (key == "tilde" || key == "~") parsedKey = Key::tilde;
- else if (key == "minus" || key == "-") parsedKey = Key::minus;
- else if (key == "equal" || key == "=") parsedKey = Key::equal;
- else if (key == "open_bracket" || key == "[") parsedKey = Key::open_bracket;
- else if (key == "close_bracket" || key == "]") parsedKey = Key::close_bracket;
- else if (key == "backslash" || key == "\\") parsedKey = Key::backslash;
- else if (key == "semicolon" || key == ";") parsedKey = Key::semicolon;
- else if (key == "quote" || key == "\"") parsedKey = Key::quote;
- else if (key == "dollar" || key == "$") parsedKey = Key::dollar;
- else if (key == "comma" || key == ",") parsedKey = Key::comma;
- else if (key == "period" || key == ".") parsedKey = Key::period;
- else if (key == "slash" || key == "/") parsedKey = Key::slash;
- else if (key == "caps_lock" || key == "capslock") parsedKey = Key::caps_lock;
- else if (key == "f1") parsedKey = Key::f1;
- else if (key == "f2") parsedKey = Key::f2;
- else if (key == "f3") parsedKey = Key::f3;
- else if (key == "f4") parsedKey = Key::f4;
- else if (key == "f5") parsedKey = Key::f5;
- else if (key == "f6") parsedKey = Key::f6;
- else if (key == "f7") parsedKey = Key::f7;
- else if (key == "f8") parsedKey = Key::f8;
- else if (key == "f9") parsedKey = Key::f9;
- else if (key == "f10") parsedKey = Key::f10;
- else if (key == "f11") parsedKey = Key::f11;
- else if (key == "f12") parsedKey = Key::f12;
- else if (key == "print_screen" || key == "printscreen" || key == "printscr" || key == "print") parsedKey = Key::print_screen;
- else if (key == "scroll_lock" || key == "scrolllock") parsedKey = Key::scroll_lock;
- else if (key == "pause_break" || key == "pausebreak" || key == "pause" || key == "break") parsedKey = Key::pause_break;
- else if (key == "insert" || key == "ins") parsedKey = Key::insert;
- else if (key == "home") parsedKey = Key::home;
- else if (key == "page_up" || key == "pageup") parsedKey = Key::page_up;
- else if (key == "delete" || key == "del") parsedKey = Key::del;
- else if (key == "end") parsedKey = Key::end;
- else if (key == "page_down" || key == "pagedown") parsedKey = Key::page_down;
- else if (key == "arrow_right" || key == "arrowright" || key == "right") parsedKey = Key::arrow_right;
- else if (key == "arrow_left" || key == "arrowleft" || key == "left") parsedKey = Key::arrow_left;
- else if (key == "arrow_bottom" || key == "arrowbottom" || key == "bottom") parsedKey = Key::arrow_bottom;
- else if (key == "arrow_top" || key == "arrowtop" || key == "top") parsedKey = Key::arrow_top;
- else if (key == "num_lock" || key == "numlock") parsedKey = Key::num_lock;
- else if (key == "num/" || key == "num_slash" || key == "numslash") parsedKey = Key::num_slash;
- else if (key == "num*" || key == "num_asterisk" || key == "numasterisk") parsedKey = Key::num_asterisk;
- else if (key == "num-" || key == "num_minus" || key == "numminus") parsedKey = Key::num_minus;
- else if (key == "num+" || key == "num_plus" || key == "numplus") parsedKey = Key::num_plus;
- else if (key == "numenter") parsedKey = Key::num_enter;
- else if (key == "num1") parsedKey = Key::num_1;
- else if (key == "num2") parsedKey = Key::num_2;
- else if (key == "num3") parsedKey = Key::num_3;
- else if (key == "num4") parsedKey = Key::num_4;
- else if (key == "num5") parsedKey = Key::num_5;
- else if (key == "num6") parsedKey = Key::num_6;
- else if (key == "num7") parsedKey = Key::num_7;
- else if (key == "num8") parsedKey = Key::num_8;
- else if (key == "num9") parsedKey = Key::num_9;
- else if (key == "num0") parsedKey = Key::num_0;
- else if (key == "num." || key == "num_period" || key == "numperiod") parsedKey = Key::num_dot;
- else if (key == "intl_backslash" || key == "<") parsedKey = Key::intl_backslash;
- else if (key == "menu") parsedKey = Key::menu;
- else if (key == "ctrl_left" || key == "ctrlleft" || key == "ctrll") parsedKey = Key::ctrl_left;
- else if (key == "shift_left" || key == "shiftleft" || key == "shiftl") parsedKey = Key::shift_left;
- else if (key == "alt_left" || key == "altleft" || key == "altl") parsedKey = Key::alt_left;
- else if (key == "win_left" || key == "winleft" || key == "winl") parsedKey = Key::win_left;
- else if (key == "meta_left" || key == "metaleft" || key == "metal") parsedKey = Key::win_left;
- else if (key == "ctrl_right" || key == "ctrlright" || key == "ctrlr") parsedKey = Key::ctrl_right;
- else if (key == "shift_right" || key == "shiftright" || key == "shiftr") parsedKey = Key::shift_right;
- else if (key == "alt_right" || key == "altright" || key == "altr" || key == "altgr") parsedKey = Key::alt_right;
- else if (key == "win_right" || key == "winright" || key == "winr") parsedKey = Key::win_right;
- else if (key == "meta_right" || key == "metaright" || key == "metar") parsedKey = Key::win_right;
- else if (key == "g1") parsedKey = Key::g1;
- else if (key == "g2") parsedKey = Key::g2;
- else if (key == "g3") parsedKey = Key::g3;
- else if (key == "g4") parsedKey = Key::g4;
- else if (key == "g5") parsedKey = Key::g5;
- else if (key == "g6") parsedKey = Key::g6;
- else if (key == "g7") parsedKey = Key::g7;
- else if (key == "g8") parsedKey = Key::g8;
- else if (key == "g9") parsedKey = Key::g9;
- else return false;
- return getKeyAddress(parsedKey, keyAddress);
-}
+ if (dev->product_string != NULL)
+ {
+ char buf[256];
+ wcstombs(buf, dev->product_string, 256);
+ deviceInfo.product = string(buf);
+ }
-bool Keyboard::parseKeyGroup(std::string key, KeyGroup &keyGroup) {
- if (key == "logo") keyGroup = KeyGroup::logo;
- else if (key == "indicators") keyGroup = KeyGroup::indicators;
- else if (key == "multimedia") keyGroup = KeyGroup::multimedia;
- else if (key == "fkeys") keyGroup = KeyGroup::fkeys;
- else if (key == "modifiers") keyGroup = KeyGroup::modifiers;
- else if (key == "arrows") keyGroup = KeyGroup::arrows;
- else if (key == "numeric") keyGroup = KeyGroup::numeric;
- else if (key == "functions") keyGroup = KeyGroup::functions;
- else if (key == "keys") keyGroup = KeyGroup::keys;
- else if (key == "gkeys") keyGroup = KeyGroup::gkeys;
- else return false;
- return true;
-}
-
-bool Keyboard::parseColor(std::string color, KeyColors &colors) {
- if (color.length() == 2) color = color + "0000"; // For G610
- if (color.length() != 6) return false;
- colors.red = std::stoul("0x"+color.substr(0,2), nullptr, 16);
- colors.green = std::stoul("0x"+color.substr(2,2), nullptr, 16);
- colors.blue = std::stoul("0x"+color.substr(4,2), nullptr, 16);
- return true;
-}
-
-bool Keyboard::sendDataInternal(unsigned char *data, uint16_t data_size) {
- if (m_isAttached == false) return false;
- int r;
- if (data_size > 20) r = libusb_control_transfer(dev_handle, 0x21, 0x09, 0x0212, 1, data, data_size, 2000);
- else r = libusb_control_transfer(dev_handle, 0x21, 0x09, 0x0211, 1, data, data_size, 2000);
- usleep(1000);
- if (r < 0) return false;
- return true;
-}
-
-bool Keyboard::populateAddressGroupInternal(KeyAddressGroup addressGroup, unsigned char *data) {
- switch (kbdProtocol) {
- case KeyboardProtocol::generic:
- switch (addressGroup) {
- case KeyAddressGroup::logo:
- data[0] = 0x11; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0c; // Base address
- data[3] = 0x3a; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x10; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x01; // Base address
- break;
- case KeyAddressGroup::indicators:
- data[0] = 0x12; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0c; // Base address
- data[3] = 0x3a; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x40; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x05; // Base address
- break;
- case KeyAddressGroup::multimedia:
- data[0] = 0x12; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0c; // Base address
- data[3] = 0x3a; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x02; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x05; // Base address
- break;
- case KeyAddressGroup::keys:
- data[0] = 0x12; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0c; // Base address
- data[3] = 0x3a; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x01; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x0e; // Base address
- break;
- default:
- return false;
- break;
- }
- break;
- case KeyboardProtocol::g910: // gkeys and mkeys seem not changeable
- switch (addressGroup) {
- case KeyAddressGroup::logo:
- data[0] = 0x11; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0f; // Base address
- data[3] = 0x3a; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x10; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x02; // Base address
- break;
- case KeyAddressGroup::indicators:
- data[0] = 0x12; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0c; // Base address
- data[3] = 0x3a; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x40; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x05; // Base address
- break;
- case KeyAddressGroup::keys:
- data[0] = 0x12; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0f; // Base address
- data[3] = 0x3d; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x01; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x0e; // Base address
- break;
- case KeyAddressGroup::gkeys:
- data[0] = 0x12; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0f; // Base address
- data[3] = 0x3e; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x04; // Base address
- data[6] = 0x00; // Base address
- data[7] = 0x09; // Base address
- break;
- default:
- return false;
- break;
- }
- break;
- default:
- return false;
- break;
- }
- return true;
-}
-
-bool Keyboard::setKeysInternal(KeyAddressGroup addressGroup, KeyValue keyValues[], size_t keyValueCount) {
- bool retval = false;
- int data_size;
- if (addressGroup == KeyAddressGroup::logo) data_size = 20;
- else data_size = 64;
- unsigned char *data = new unsigned char[data_size];
- const size_t maxKeyValueCount = (data_size - 8) / 4;
- populateAddressGroupInternal(addressGroup, data);
- for(size_t i = 0; i < maxKeyValueCount; i++) {
- if (i < keyValueCount) {
- data[8 + i * 4 + 0] = keyValues[i].key.id;
- data[8 + i * 4 + 1] = keyValues[i].colors.red;
- data[8 + i * 4 + 2] = keyValues[i].colors.green;
- data[8 + i * 4 + 3] = keyValues[i].colors.blue;
- } else {
- data[8 + i * 4 + 0] = 0x00;
- data[8 + i * 4 + 1] = 0x00;
- data[8 + i * 4 + 2] = 0x00;
- data[8 + i * 4 + 3] = 0x00;
- }
- }
- retval = sendDataInternal(data, data_size);
- delete[] data;
- return retval;
-}
-
-bool Keyboard::setPowerOnEffect(PowerOnEffect powerOnEffect) {
- bool retval = false;
- int data_size = 20;
- unsigned char *data = new unsigned char[data_size];
- data[0] = 0x11; // Base address
- data[1] = 0xff; // Base address
- data[2] = 0x0d; // Base address
- data[3] = 0x5a; // Base address
- data[4] = 0x00; // Base address
- data[5] = 0x01; // Base address
- switch (powerOnEffect) {
- case PowerOnEffect::rainbow:
- data[6] = 0x01;
- break;
- case PowerOnEffect::color:
- data[6] = 0x02;
- break;
- }
- for(int i = 7; i < data_size; i++) data[i] = 0x00;
- retval = sendDataInternal(data, data_size);
- delete[] data;
- return retval;
-}
-
-bool Keyboard::setKey(KeyValue keyValue) {
- bool retval = false;
- unsigned char *data;
- int data_size;
- if (keyValue.key.addressGroup == KeyAddressGroup::logo) {
- data_size = 20;
- data = new unsigned char[data_size];
- populateAddressGroupInternal(keyValue.key.addressGroup, data);
- } else {
- data_size = 64;
- data = new unsigned char[data_size];
- populateAddressGroupInternal(keyValue.key.addressGroup, data);
- }
- data[8] = keyValue.key.id;
- data[9] = keyValue.colors.red;
- data[10] = keyValue.colors.green;
- data[11] = keyValue.colors.blue;
- for(int i = 12; i < data_size; i++) data[i] = 0x00;
- retval = sendDataInternal(data, data_size);
- delete[] data;
- return retval;
-}
-
-bool Keyboard::setKey(Key key, KeyColors colors) {
- KeyValue keyValue;
- getKeyAddress(key, keyValue.key);
- keyValue.colors = colors;
- return setKey(keyValue);
-}
-
-bool Keyboard::setKeys(KeyValue keyValue[], size_t keyValueCount) {
- const size_t maxLogoKeys = 5;
- const size_t maxIndicatorsKeys = 25;
- const size_t maxMultimediaKeys = 25;
- const size_t maxKeys = 200;
- const size_t maxGKeys = 25;
- size_t logoCount = 0;
- size_t indicatorsCount = 0;
- size_t multimediaCount = 0;
- size_t keysCount = 0;
- size_t gkeysCount = 0;
- KeyValue logo[maxLogoKeys];
- KeyValue indicators[maxIndicatorsKeys];
- KeyValue multimedia[maxMultimediaKeys];
- KeyValue keys[maxKeys];
- KeyValue gkeys[maxGKeys];
-
- for (size_t i = 0; i < keyValueCount; i++) {
- if(keyValue[i].key.addressGroup == KeyAddressGroup::logo && logoCount <= maxLogoKeys) {
- logo[logoCount] = keyValue[i];
- logoCount++;
- } else if(keyValue[i].key.addressGroup == KeyAddressGroup::indicators && indicatorsCount <= maxIndicatorsKeys) {
- indicators[indicatorsCount] = keyValue[i];
- indicatorsCount++;
- } else if(keyValue[i].key.addressGroup == KeyAddressGroup::multimedia && multimediaCount <= maxMultimediaKeys) {
- multimedia[multimediaCount] = keyValue[i];
- multimediaCount++;
- } else if(keyValue[i].key.addressGroup == KeyAddressGroup::keys && keysCount <= maxKeys) {
- keys[keysCount] = keyValue[i];
- keysCount++;
- } else if(keyValue[i].key.addressGroup == KeyAddressGroup::gkeys && gkeysCount <= maxGKeys) {
- gkeys[gkeysCount] = keyValue[i];
- gkeysCount++;
- }
- }
-
- if (logoCount > 0) setKeysInternal(KeyAddressGroup::logo, logo, logoCount);
-
- if (indicatorsCount > 0) setKeysInternal(KeyAddressGroup::indicators, indicators, indicatorsCount);
-
- if (multimediaCount > 0) setKeysInternal(KeyAddressGroup::multimedia, multimedia, multimediaCount);
-
- if (keysCount > 0) {
- const size_t maxKeyValueCount = 14;
- for (size_t i = 0; i < keysCount; i = i + maxKeyValueCount) {
- KeyValue keysBlock[maxKeyValueCount];
- size_t keysBlockCount = 0;
- for (size_t j = 0; j < maxKeyValueCount; j++) {
- if((i + j) < keysCount ) {
- keysBlock[j] = keys[i + j];
- keysBlockCount++;
+ deviceList.push_back(deviceInfo);
+ dev = dev->next;
+ break;
+ }
}
}
- setKeysInternal(KeyAddressGroup::keys, keysBlock, keysBlockCount);
+ if (dev != NULL) dev = dev->next;
+ }
+ hid_free_enumeration(devs);
+ hid_exit();
+
+ #elif defined(libusb)
+ libusb_context *ctx = NULL;
+ if(libusb_init(&m_ctx) < 0) return deviceList;
+
+ libusb_device **devs;
+ ssize_t cnt = libusb_get_device_list(ctx, &devs);
+ for(ssize_t i = 0; i < cnt; i++) {
+ libusb_device *device = devs[i];
+ libusb_device_descriptor desc;
+ libusb_get_device_descriptor(device, &desc);
+ for (int i=0; i<(int)SupportedKeyboards.size(); i++) {
+ if (desc.idVendor == SupportedKeyboards[i][0]) {
+ if (desc.idProduct == SupportedKeyboards[i][1]) {
+ unsigned char buf[256];
+ DeviceInfo deviceInfo;
+ deviceInfo.vendorID=desc.idVendor;
+ deviceInfo.productID=desc.idProduct;
+
+ if (libusb_open(device, &m_hidHandle) != 0) continue;
+
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iSerialNumber, buf, 256) >= 1) deviceInfo.serialNumber = string((char*)buf);
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iManufacturer, buf, 256) >= 1) deviceInfo.manufacturer = string((char*)buf);
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iProduct, buf, 256) >= 1) deviceInfo.product = string((char*)buf);
+
+ deviceList.push_back(deviceInfo);
+ libusb_close(m_hidHandle);
+ m_hidHandle = NULL;
+ break;
+ }
+ }
+ }
+ }
+ libusb_free_device_list(devs, 1);
+
+ if (m_hidHandle != NULL) {
+ libusb_close(m_hidHandle);
+ m_hidHandle = NULL;
+ }
+
+ libusb_exit(m_ctx);
+ m_ctx = NULL;
+ #endif
+
+ return deviceList;
+}
+
+
+bool LedKeyboard::isOpen() {
+ return m_isOpen;
+}
+
+bool LedKeyboard::open() {
+ if (m_isOpen) return true;
+
+ return open(0x0, 0x0, "");
+}
+
+bool LedKeyboard::open(uint16_t vendorID, uint16_t productID, string serial) {
+ if (m_isOpen && ! close()) return false;
+ currentDevice.model = KeyboardModel::unknown;
+
+ #if defined(hidapi)
+ if (hid_init() < 0) return false;
+
+ struct hid_device_info *devs, *dev;
+ devs = hid_enumerate(vendorID, productID);
+ dev = devs;
+ wstring wideSerial;
+
+ if (!serial.empty()) {
+ wchar_t tempSerial[256];
+ if (mbstowcs(tempSerial, serial.c_str(), 256) < 1) return false;
+ wideSerial = wstring(tempSerial);
+ }
+
+ while (dev) {
+ for (int i=0; i<(int)SupportedKeyboards.size(); i++) {
+ if (dev->vendor_id == SupportedKeyboards[i][0] && dev->product_id == SupportedKeyboards[i][1]) {
+ if (!serial.empty() && dev->serial_number != NULL && wideSerial.compare(dev->serial_number) != 0) break; //Serial didn't match
+
+ if (dev->serial_number != NULL) {
+ char buf[256];
+ wcstombs(buf,dev->serial_number,256);
+ currentDevice.serialNumber=string(buf);
+ }
+
+ if (dev->manufacturer_string != NULL)
+ {
+ char buf[256];
+ wcstombs(buf,dev->manufacturer_string,256);
+ currentDevice.manufacturer = string(buf);
+ }
+
+ if (dev->product_string != NULL)
+ {
+ char buf[256];
+ wcstombs(buf,dev->product_string,256);
+ currentDevice.product = string(buf);
+ }
+
+ currentDevice.vendorID = dev->vendor_id;
+ currentDevice.productID = dev->product_id;
+ currentDevice.model = (KeyboardModel)SupportedKeyboards[i][2];
+ break;
+ }
+ }
+ if (currentDevice.model != KeyboardModel::unknown) break;
+ dev = dev->next;
+ }
+
+ hid_free_enumeration(devs);
+
+ if (! dev) {
+ currentDevice.model = KeyboardModel::unknown;
+ hid_exit();
+ return false;
+ }
+
+ if (wideSerial.empty()) m_hidHandle = hid_open(currentDevice.vendorID, currentDevice.productID, NULL);
+ else m_hidHandle = hid_open(currentDevice.vendorID, currentDevice.productID, wideSerial.c_str());
+
+ if(m_hidHandle == 0) {
+ hid_exit();
+ return false;
+ }
+
+ m_isOpen = true;
+ return true;
+
+ #elif defined(libusb)
+ if (libusb_init(&m_ctx) < 0) return false;
+
+ libusb_device **devs;
+ libusb_device *dev = NULL;
+ ssize_t cnt = libusb_get_device_list(m_ctx, &devs);
+ if(cnt >= 0) {
+ for(ssize_t i = 0; i < cnt; i++) {
+ libusb_device *device = devs[i];
+ libusb_device_descriptor desc;
+ libusb_get_device_descriptor(device, &desc);
+
+ if (vendorID != 0x0 && desc.idVendor != vendorID) continue;
+ else if (productID != 0x0 && desc.idProduct != productID) continue;
+ else if (! serial.empty()) {
+ if (desc.iSerialNumber <= 0) continue; //Device does not populate serial number
+
+ unsigned char buf[256];
+ if (libusb_open(device, &m_hidHandle) != 0){
+ m_hidHandle = NULL;
+ continue;
+ }
+
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iSerialNumber, buf, 256) >= 1 && serial.compare((char*)buf) == 0) {
+ //Make sure entry is a supported keyboard and get model
+ for (int i=0; i<(int)SupportedKeyboards.size(); i++) {
+ if (desc.idVendor == SupportedKeyboards[i][0]) {
+ if (desc.idProduct == SupportedKeyboards[i][1]) {
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iManufacturer, buf, 256) >= 1) currentDevice.manufacturer = string((char*)buf);
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iProduct, buf, 256) >= 1) currentDevice.product = string((char*)buf);
+ currentDevice.serialNumber = serial;
+ currentDevice.vendorID = desc.idVendor;
+ currentDevice.productID = desc.idProduct;
+ currentDevice.model = (KeyboardModel)SupportedKeyboards[i][2];
+
+ dev = device;
+ libusb_close(m_hidHandle);
+ m_hidHandle = NULL;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ libusb_close(m_hidHandle);
+ m_hidHandle = NULL;
+ continue; //Serial number set but doesn't match
+ }
+ }
+
+ //For the case where serial is not specified, find first supported device
+ for (int i=0; i<(int)SupportedKeyboards.size(); i++) {
+ if (desc.idVendor == SupportedKeyboards[i][0]) {
+ if (desc.idProduct == SupportedKeyboards[i][1]) {
+ unsigned char buf[256];
+ if (libusb_open(device, &m_hidHandle) != 0){
+ m_hidHandle = NULL;
+ continue;
+ }
+ currentDevice.vendorID = desc.idVendor;
+ currentDevice.productID = desc.idProduct;
+ currentDevice.model = (KeyboardModel)SupportedKeyboards[i][2];
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iManufacturer, buf, 256) >= 1) currentDevice.manufacturer = string((char*)buf);
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iProduct, buf, 256) >= 1) currentDevice.product = string((char*)buf);
+ if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iSerialNumber, buf, 256) >= 1) currentDevice.serialNumber = string((char*)buf);
+
+ libusb_close(m_hidHandle);
+ m_hidHandle=NULL;
+ break;
+ }
+ }
+ }
+ if (currentDevice.model != KeyboardModel::unknown) break;
+ }
+ libusb_free_device_list(devs, 1);
+ }
+
+ if (currentDevice.model == KeyboardModel::unknown) {
+ libusb_exit(m_ctx);
+ m_ctx = NULL;
+ return false;
+ }
+
+ if (dev == NULL) m_hidHandle = libusb_open_device_with_vid_pid(m_ctx, currentDevice.vendorID, currentDevice.productID);
+ else libusb_open(dev, &m_hidHandle);
+
+ if(m_hidHandle == NULL) {
+ libusb_exit(m_ctx);
+ m_ctx = NULL;
+ return false;
+ }
+
+ if(libusb_kernel_driver_active(m_hidHandle, 1) == 1) {
+ if(libusb_detach_kernel_driver(m_hidHandle, 1) != 0) {
+ libusb_exit(m_ctx);
+ m_ctx = NULL;
+ return false;
+ }
+ m_isKernellDetached = true;
+ }
+
+ if(libusb_claim_interface(m_hidHandle, 1) < 0) {
+ if(m_isKernellDetached==true) {
+ libusb_attach_kernel_driver(m_hidHandle, 1);
+ m_isKernellDetached = false;
+ }
+ libusb_exit(m_ctx);
+ m_ctx = NULL;
+ return false;
+ }
+
+ m_isOpen = true;
+ return true;
+ #endif
+
+ return false; //In case neither is defined
+}
+
+LedKeyboard::DeviceInfo LedKeyboard::getCurrentDevice() {
+ return currentDevice;
+}
+
+bool LedKeyboard::close() {
+ if (! m_isOpen) return true;
+ m_isOpen = false;
+
+ #if defined(hidapi)
+ hid_close(m_hidHandle);
+ m_hidHandle = NULL;
+ hid_exit();
+ return true;
+ #elif defined(libusb)
+ if (m_hidHandle == NULL) return true;
+ if(libusb_release_interface(m_hidHandle, 1) != 0) return false;
+ if(m_isKernellDetached==true) {
+ libusb_attach_kernel_driver(m_hidHandle, 1);
+ m_isKernellDetached = false;
+ }
+ libusb_close(m_hidHandle);
+ m_hidHandle = NULL;
+ libusb_exit(m_ctx);
+ m_ctx = NULL;
+ return true;
+ #endif
+
+ return false;
+}
+
+
+LedKeyboard::KeyboardModel LedKeyboard::getKeyboardModel() {
+ return currentDevice.model;
+}
+
+bool LedKeyboard::commit() {
+ byte_buffer_t data;
+ switch (currentDevice.model) {
+ case KeyboardModel::g213:
+ case KeyboardModel::g413:
+ return true; // Keyboard is non-transactional
+ case KeyboardModel::g410:
+ case KeyboardModel::g513:
+ case KeyboardModel::g610:
+ case KeyboardModel::g810:
+ case KeyboardModel::gpro:
+ data = { 0x11, 0xff, 0x0c, 0x5a };
+ break;
+ case KeyboardModel::g910:
+ data = { 0x11, 0xff, 0x0f, 0x5d };
+ break;
+ default:
+ return false;
+ }
+ data.resize(20, 0x00);
+ return sendDataInternal(data);
+}
+
+bool LedKeyboard::setKey(LedKeyboard::KeyValue keyValue) {
+ return setKeys(KeyValueArray {keyValue});
+}
+
+bool LedKeyboard::setKeys(KeyValueArray keyValues) {
+ if (keyValues.empty()) return false;
+
+ bool retval = true;
+
+ vector> SortedKeys = {
+ {}, // Logo AddressGroup
+ {}, // Indicators AddressGroup
+ {}, // Multimedia AddressGroup
+ {}, // GKeys AddressGroup
+ {} // Keys AddressGroup
+ };
+
+ for (uint8_t i = 0; i < keyValues.size(); i++) {
+ switch(static_cast(static_cast(keyValues[i].key) >> 8 )) {
+ case LedKeyboard::KeyAddressGroup::logo:
+ switch (currentDevice.model) {
+ case LedKeyboard::KeyboardModel::g610:
+ case LedKeyboard::KeyboardModel::g810:
+ case LedKeyboard::KeyboardModel::gpro:
+ if (SortedKeys[0].size() <= 1 && keyValues[i].key == LedKeyboard::Key::logo)
+ SortedKeys[0].push_back(keyValues[i]);
+ break;
+ case LedKeyboard::KeyboardModel::g910:
+ if (SortedKeys[0].size() <= 2) SortedKeys[0].push_back(keyValues[i]);
+ break;
+ default:
+ break;
+ }
+ break;
+ case LedKeyboard::KeyAddressGroup::indicators:
+ if (SortedKeys[1].size() <= 5) SortedKeys[1].push_back(keyValues[i]);
+ break;
+ case LedKeyboard::KeyAddressGroup::multimedia:
+ switch (currentDevice.model) {
+ case LedKeyboard::KeyboardModel::g610:
+ case LedKeyboard::KeyboardModel::g810:
+ case LedKeyboard::KeyboardModel::gpro:
+ if (SortedKeys[2].size() <= 5) SortedKeys[2].push_back(keyValues[i]);
+ break;
+ default:
+ break;
+ }
+ break;
+ case LedKeyboard::KeyAddressGroup::gkeys:
+ switch (currentDevice.model) {
+ case LedKeyboard::KeyboardModel::g910:
+ if (SortedKeys[3].size() <= 9) SortedKeys[3].push_back(keyValues[i]);
+ break;
+ default:
+ break;
+ }
+ break;
+ case LedKeyboard::KeyAddressGroup::keys:
+ switch (currentDevice.model) {
+ case LedKeyboard::KeyboardModel::g610:
+ case LedKeyboard::KeyboardModel::g810:
+ case LedKeyboard::KeyboardModel::g910:
+ case LedKeyboard::KeyboardModel::gpro:
+ if (SortedKeys[4].size() <= 120) SortedKeys[4].push_back(keyValues[i]);
+ break;
+ case LedKeyboard::KeyboardModel::g410:
+ if (SortedKeys[4].size() <= 120)
+ if (keyValues[i].key < LedKeyboard::Key::num_lock ||
+ keyValues[i].key > LedKeyboard::Key::num_dot)
+ SortedKeys[4].push_back(keyValues[i]);
+ break;
+ default:
+ break;
+ }
+ break;
}
}
- if (gkeysCount > 0) setKeysInternal(KeyAddressGroup::gkeys, gkeys, gkeysCount);
-
- return true;
-}
-
-bool Keyboard::setAllKeys(KeyColors colors) {
- KeyValue keyValues[127];
- for (int i = 0; i < 127; i++) {
- getKeyAddress((Key)i, keyValues[i].key);
- keyValues[i].colors = colors;
+ for (uint8_t kag = 0; kag < 5; kag++) {
+
+ if (SortedKeys[kag].size() > 0) {
+
+ uint8_t gi = 0;
+ while (gi < SortedKeys[kag].size()) {
+
+ size_t data_size = 0;
+ byte_buffer_t data = {};
+
+ switch (kag) {
+ case 0:
+ data_size = 20;
+ data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::logo);
+ break;
+ case 1:
+ data_size = 64;
+ data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::indicators);
+ break;
+ case 2:
+ data_size = 64;
+ data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::multimedia);
+ break;
+ case 3:
+ data_size = 64;
+ data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::gkeys);
+ break;
+ case 4:
+ data_size = 64;
+ data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::keys);
+ break;
+ }
+
+ const uint8_t maxKeyCount = (data_size - 8) / 4;
+
+ if (data.size() > 0) {
+
+ for (uint8_t i = 0; i < maxKeyCount; i++) {
+ if (gi + i < SortedKeys[kag].size()) {
+ data.push_back(static_cast(
+ static_cast(SortedKeys[kag][gi+i].key) & 0x00ff));
+ data.push_back(SortedKeys[kag][gi+i].color.red);
+ data.push_back(SortedKeys[kag][gi+i].color.green);
+ data.push_back(SortedKeys[kag][gi+i].color.blue);
+ }
+ }
+
+ data.resize(data_size, 0x00);
+
+ if (retval) retval = sendDataInternal(data);
+ else sendDataInternal(data);
+
+ }
+
+ gi = gi + maxKeyCount;
+ }
+
+ }
}
- setKeys(keyValues, 127);
- return true;
+ return retval;
}
-bool Keyboard::setGroupKeys(KeyGroup keyGroup, KeyColors colors) {
- KeyValue keyValues[54];
- int keyValuesCount = 0;
+bool LedKeyboard::setGroupKeys(KeyGroup keyGroup, LedKeyboard::Color color) {
+ KeyValueArray keyValues;
+
+ KeyArray keyArray;
+
switch (keyGroup) {
case KeyGroup::logo:
- for (int i = 0; i < 2; i++) {
- getKeyAddress((Key)i, keyValues[i].key);
- keyValues[i].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
+ keyArray = keyGroupLogo;
break;
case KeyGroup::indicators:
- for (int i = 2; i < 7; i++) {
- getKeyAddress((Key)i, keyValues[i - 2].key);
- keyValues[i - 2].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
- break;
- case KeyGroup::multimedia:
- for (int i = 7; i < 12; i++) {
- getKeyAddress((Key)i, keyValues[i - 7].key);
- keyValues[i - 7].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
- break;
- case KeyGroup::fkeys:
- for (int i = 12; i < 24; i++) {
- getKeyAddress((Key)i, keyValues[i - 12].key);
- keyValues[i - 12].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
- break;
- case KeyGroup::modifiers:
- for (int i = 24; i < 33; i++) {
- getKeyAddress((Key)i, keyValues[i - 24].key);
- keyValues[i - 24].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
- break;
- case KeyGroup::arrows:
- for (int i = 33; i < 37; i++) {
- getKeyAddress((Key)i, keyValues[i - 33].key);
- keyValues[i - 33].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
- break;
- case KeyGroup::numeric:
- for (int i = 37; i < 54; i++) {
- getKeyAddress((Key)i, keyValues[i - 37].key);
- keyValues[i - 37].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
- break;
- case KeyGroup::functions:
- for (int i = 54; i < 64; i++) {
- getKeyAddress((Key)i, keyValues[i - 54].key);
- keyValues[i - 54].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
- break;
- case KeyGroup::keys:
- for (int i = 64; i < 118; i++) {
- getKeyAddress((Key)i, keyValues[i - 64].key);
- keyValues[i - 64].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
+ keyArray = keyGroupIndicators;
break;
case KeyGroup::gkeys:
- for (int i = 118; i < 127; i++) {
- getKeyAddress((Key)i, keyValues[i - 118].key);
- keyValues[i - 118].colors = colors;
- keyValuesCount++;
- }
- setKeys(keyValues, keyValuesCount);
+ keyArray = keyGroupGKeys;
+ break;
+ case KeyGroup::multimedia:
+ keyArray = keyGroupMultimedia;
+ break;
+ case KeyGroup::fkeys:
+ keyArray = keyGroupFKeys;
+ break;
+ case KeyGroup::modifiers:
+ keyArray = keyGroupModifiers;
+ break;
+ case KeyGroup::arrows:
+ keyArray = keyGroupArrows;
+ break;
+ case KeyGroup::numeric:
+ keyArray = keyGroupNumeric;
+ break;
+ case KeyGroup::functions:
+ keyArray = keyGroupFunctions;
+ break;
+ case KeyGroup::keys:
+ keyArray = keyGroupKeys;
+ break;
+ default:
break;
}
- return true;
+
+ for (uint8_t i = 0; i < keyArray.size(); i++) keyValues.push_back({keyArray[i], color});
+
+ return setKeys(keyValues);
+}
+
+bool LedKeyboard::setAllKeys(LedKeyboard::Color color) {
+ KeyValueArray keyValues;
+
+ switch (currentDevice.model) {
+ case KeyboardModel::g213:
+ for (uint8_t rIndex=0x01; rIndex <= 0x05; rIndex++) if (! setRegion(rIndex, color)) return false;
+ return true;
+ case KeyboardModel::g413:
+ setNativeEffect(NativeEffect::color, NativeEffectPart::keys, 0, color);
+ return true;
+ case KeyboardModel::g410:
+ case KeyboardModel::g513:
+ case KeyboardModel::g610:
+ case KeyboardModel::g810:
+ case KeyboardModel::g910:
+ case KeyboardModel::gpro:
+ for (uint8_t i = 0; i < keyGroupLogo.size(); i++) keyValues.push_back({keyGroupLogo[i], color});
+ for (uint8_t i = 0; i < keyGroupIndicators.size(); i++) keyValues.push_back({keyGroupIndicators[i], color});
+ for (uint8_t i = 0; i < keyGroupMultimedia.size(); i++) keyValues.push_back({keyGroupMultimedia[i], color});
+ for (uint8_t i = 0; i < keyGroupGKeys.size(); i++) keyValues.push_back({keyGroupGKeys[i], color});
+ for (uint8_t i = 0; i < keyGroupFKeys.size(); i++) keyValues.push_back({keyGroupFKeys[i], color});
+ for (uint8_t i = 0; i < keyGroupFunctions.size(); i++) keyValues.push_back({keyGroupFunctions[i], color});
+ for (uint8_t i = 0; i < keyGroupArrows.size(); i++) keyValues.push_back({keyGroupArrows[i], color});
+ for (uint8_t i = 0; i < keyGroupNumeric.size(); i++) keyValues.push_back({keyGroupNumeric[i], color});
+ for (uint8_t i = 0; i < keyGroupModifiers.size(); i++) keyValues.push_back({keyGroupModifiers[i], color});
+ for (uint8_t i = 0; i < keyGroupKeys.size(); i++) keyValues.push_back({keyGroupKeys[i], color});
+ return setKeys(keyValues);
+ default:
+ return false;
+ }
+ return false;
+}
+
+
+bool LedKeyboard::setMRKey(uint8_t value) {
+ LedKeyboard::byte_buffer_t data;
+ switch (currentDevice.model) {
+ case KeyboardModel::g910:
+ switch (value) {
+ case 0x00:
+ case 0x01:
+ data = { 0x11, 0xff, 0x0a, 0x0e, value };
+ data.resize(20, 0x00);
+ return sendDataInternal(data);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool LedKeyboard::setMNKey(uint8_t value) {
+ LedKeyboard::byte_buffer_t data;
+ switch (currentDevice.model) {
+ case KeyboardModel::g910:
+ switch (value) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ data = { 0x11, 0xff, 0x09, 0x1e, value };
+ data.resize(20, 0x00);
+ return sendDataInternal(data);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool LedKeyboard::setGKeysMode(uint8_t value) {
+ LedKeyboard::byte_buffer_t data;
+ switch (currentDevice.model) {
+ case KeyboardModel::g910:
+ switch (value) {
+ case 0x00:
+ case 0x01:
+ data = { 0x11, 0xff, 0x08, 0x2e, value };
+ data.resize(20, 0x00);
+ return sendDataInternal(data);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool LedKeyboard::setRegion(uint8_t region, LedKeyboard::Color color) {
+ LedKeyboard::byte_buffer_t data;
+ switch (currentDevice.model) {
+ case KeyboardModel::g213:
+ data = { 0x11, 0xff, 0x0c, 0x3a, region, 0x01, color.red, color.green, color.blue };
+ data.resize(20,0x00);
+ return sendDataInternal(data);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool LedKeyboard::setStartupMode(StartupMode startupMode) {
+ byte_buffer_t data;
+ switch (currentDevice.model) {
+ case KeyboardModel::g213:
+ case KeyboardModel::g410:
+ case KeyboardModel::g610:
+ case KeyboardModel::g810:
+ case KeyboardModel::gpro:
+ data = { 0x11, 0xff, 0x0d, 0x5a, 0x00, 0x01 };
+ break;
+ case KeyboardModel::g910:
+ data = { 0x11, 0xff, 0x10, 0x5e, 0x00, 0x01 };
+ break;
+ default:
+ return false;
+ }
+ data.push_back((unsigned char)startupMode);
+ data.resize(20, 0x00);
+ return sendDataInternal(data);
+}
+
+
+bool LedKeyboard::setNativeEffect(NativeEffect effect, NativeEffectPart part, uint8_t speed, Color color) {
+ uint8_t protocolByte = 0;
+
+ // NativeEffectPart::all is not in the device protocol, but an alias for both keys and logo, plus indicators
+ if (part == LedKeyboard::NativeEffectPart::all) {
+ switch (effect) {
+ case LedKeyboard::NativeEffect::color:
+ if (! setGroupKeys(LedKeyboard::KeyGroup::indicators, color)) return false;
+ if (! commit()) return false;
+ break;
+ case LedKeyboard::NativeEffect::breathing:
+ if (! setGroupKeys(LedKeyboard::KeyGroup::indicators, color)) return false;;
+ if (! commit()) return false;;
+ break;
+ case LedKeyboard::NativeEffect::cycle:
+ case LedKeyboard::NativeEffect::hwave:
+ case LedKeyboard::NativeEffect::vwave:
+ case LedKeyboard::NativeEffect::cwave:
+ if (! setGroupKeys(
+ LedKeyboard::KeyGroup::indicators,
+ LedKeyboard::Color({0xff, 0xff, 0xff}))
+ ) return false;
+ if (! commit()) return false;
+ break;
+ }
+ return (
+ setNativeEffect(effect, LedKeyboard::NativeEffectPart::keys, speed, color) &&
+ setNativeEffect(effect, LedKeyboard::NativeEffectPart::logo, speed, color));
+ }
+
+ switch (currentDevice.model) {
+ case KeyboardModel::g213:
+ case KeyboardModel::g413:
+ protocolByte = 0x0c;
+ if (part == NativeEffectPart::logo) return true; //Does not have logo component
+ break;
+ case KeyboardModel::g410:
+ case KeyboardModel::g513:
+ case KeyboardModel::g610: // Unconfirmed
+ case KeyboardModel::g810:
+ case KeyboardModel::gpro:
+ protocolByte = 0x0d;
+ break;
+ case KeyboardModel::g910:
+ protocolByte = 0x10;
+ break;
+ default:
+ return false;
+ }
+
+ byte_buffer_t data;
+
+ switch (effect) {
+
+ case NativeEffect::color:
+ data = { 0x11, 0xff, protocolByte, 0x3c, (uint8_t)part, 0x01, color.red, color.green, color.blue, 0x02 };
+ break;
+ case NativeEffect::breathing:
+ data = {
+ 0x11, 0xff, protocolByte, 0x3c, (uint8_t)part, 0x02,
+ color.red, color.green, color.blue, speed,
+ 0x10, 0x00, 0x64
+ };
+ break;
+ case NativeEffect::cycle:
+ data = {
+ 0x11, 0xff, protocolByte, 0x3c, (uint8_t)part, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, speed, 0x00, 0x00, 0x64
+ };
+ break;
+ case NativeEffect::hwave:
+ switch (part) {
+ case NativeEffectPart::logo:
+ setNativeEffect(NativeEffect::color, part, 0, Color({0x00, 0xff, 0xff}));
+ break;
+ default:
+ data = {
+ 0x11, 0xff, protocolByte, 0x3c, (uint8_t)part, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x64, speed
+ };
+ break;
+ }
+ break;
+ case NativeEffect::vwave:
+ switch (part) {
+ case NativeEffectPart::logo:
+ setNativeEffect(NativeEffect::color, part, 0, Color({0x00, 0xff, 0xff}));
+ break;
+ default:
+ data = {
+ 0x11, 0xff, protocolByte, 0x3c, (uint8_t)part, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0x64, speed
+ };
+ break;
+ }
+ break;
+ case NativeEffect::cwave:
+ switch (part) {
+ case NativeEffectPart::logo:
+ setNativeEffect(NativeEffect::color, part, 0, Color({0x00, 0xff, 0xff}));
+ break;
+ default:
+ data = {
+ 0x11, 0xff, protocolByte, 0x3c, (uint8_t)part, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x03, 0x64, speed
+ };
+ break;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ data.resize(20, 0x00);
+ return sendDataInternal(data);
+}
+
+
+bool LedKeyboard::sendDataInternal(byte_buffer_t &data) {
+ if (data.size() > 0) {
+ #if defined(hidapi)
+ if (! open(currentDevice.vendorID, currentDevice.productID, currentDevice.serialNumber)) return false;
+ data.insert(data.begin(), 0x00);
+ if (hid_write(m_hidHandle, const_cast(data.data()), data.size()) < 0) {
+ std::cout<<"Error: Can not write to hidraw, try with the libusb version"<(data2.data()), data2.size(), 1);
+ */
+ return true;
+ #elif defined(libusb)
+ if (! m_isOpen) return false;
+ if (data.size() > 20) {
+ if(libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0212, 1,
+ const_cast(data.data()), data.size(), 2000) < 0)
+ return false;
+ } else {
+ if(libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0211, 1,
+ const_cast(data.data()), data.size(), 2000) < 0)
+ return false;
+ }
+ usleep(1000);
+ unsigned char buffer[64];
+ int len = 0;
+ libusb_interrupt_transfer(m_hidHandle, 0x82, buffer, sizeof(buffer), &len, 1);
+ return true;
+ #endif
+ }
+
+ return false;
+}
+
+LedKeyboard::byte_buffer_t LedKeyboard::getKeyGroupAddress(LedKeyboard::KeyAddressGroup keyAddressGroup) {
+ switch (currentDevice.model) {
+ case KeyboardModel::g213:
+ case KeyboardModel::g413:
+ return {}; // Device doesn't support per-key setting
+ case KeyboardModel::g410:
+ case KeyboardModel::g513:
+ case KeyboardModel::g610:
+ case KeyboardModel::g810:
+ case KeyboardModel::gpro:
+ switch (keyAddressGroup) {
+ case LedKeyboard::KeyAddressGroup::logo:
+ return { 0x11, 0xff, 0x0c, 0x3a, 0x00, 0x10, 0x00, 0x01 };
+ case LedKeyboard::KeyAddressGroup::indicators:
+ return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x40, 0x00, 0x05 };
+ case LedKeyboard::KeyAddressGroup::gkeys:
+ return {};
+ case LedKeyboard::KeyAddressGroup::multimedia:
+ return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x02, 0x00, 0x05 };
+ case LedKeyboard::KeyAddressGroup::keys:
+ return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x01, 0x00, 0x0e };
+ }
+ break;
+ case KeyboardModel::g910:
+ switch (keyAddressGroup) {
+ case LedKeyboard::KeyAddressGroup::logo:
+ return { 0x11, 0xff, 0x0f, 0x3a, 0x00, 0x10, 0x00, 0x02 };
+ case LedKeyboard::KeyAddressGroup::indicators:
+ return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x40, 0x00, 0x05 };
+ case LedKeyboard::KeyAddressGroup::gkeys:
+ return { 0x12, 0xff, 0x0f, 0x3e, 0x00, 0x04, 0x00, 0x09 };
+ case LedKeyboard::KeyAddressGroup::multimedia:
+ return {};
+ case LedKeyboard::KeyAddressGroup::keys:
+ return { 0x12, 0xff, 0x0f, 0x3d, 0x00, 0x01, 0x00, 0x0e };
+ }
+ break;
+ default:
+ break;
+ }
+ return {};
}
diff --git a/src/classes/Keyboard.h b/src/classes/Keyboard.h
index a2b563e..76e178f 100644
--- a/src/classes/Keyboard.h
+++ b/src/classes/Keyboard.h
@@ -1,70 +1,223 @@
-#ifndef DEF_KEYBOARD
-#define DEF_KEYBOARD
+#ifndef KEYBOARD_CLASS
+#define KEYBOARD_CLASS
#include
-#include
+#include
-class Keyboard {
+#if defined(hidapi)
+ #include "hidapi/hidapi.h"
+#elif defined(libusb)
+ #include "libusb-1.0/libusb.h"
+#endif
+
+
+class LedKeyboard {
+
+ private:
+
+ enum class KeyAddressGroup : uint8_t {
+ logo = 0x00,
+ indicators,
+ multimedia,
+ gkeys,
+ keys
+ };
+
+
public:
- enum class KeyboardProtocol { generic, g910 };
- enum class PowerOnEffect { rainbow, color };
- enum class KeyAddressGroup { logo, indicators, multimedia, keys, gkeys };
- enum class Key { // 127 items
- logo, logo2,
- caps, num, scroll, game, backlight,
- mute, play, stop, prev, next,
- f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
- shift_left, ctrl_left, win_left, alt_left, alt_right, win_right, ctrl_right, shift_right, menu,
- arrow_top, arrow_left, arrow_bottom, arrow_right,
- num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0, num_dot, num_enter, num_plus, num_minus, num_asterisk, num_slash, num_lock,
- esc, scroll_lock,
- insert, del, home, end, page_up, page_down, print_screen, pause_break,
- n1, n2, n3, n4, n5, n6, n7, n8, n9, n0,
- tab, caps_lock, space, backspace, enter,
- a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,
- tilde, minus, equal,
- open_bracket, close_bracket, backslash,
- semicolon, quote, dollar,
- intl_backslash, comma, period, slash,
- g1, g2, g3, g4, g5, g6, g7, g8, g9
+ std::vector> SupportedKeyboards = {
+ { 0x46d, 0xc336, (u_int16_t)KeyboardModel::g213 },
+ { 0x46d, 0xc330, (u_int16_t)KeyboardModel::g410 },
+ { 0x46d, 0xc33a, (u_int16_t)KeyboardModel::g413 },
+ { 0x46d, 0xc33c, (u_int16_t)KeyboardModel::g513 },
+ { 0x46d, 0xc333, (u_int16_t)KeyboardModel::g610 },
+ { 0x46d, 0xc338, (u_int16_t)KeyboardModel::g610 },
+ { 0x46d, 0xc331, (u_int16_t)KeyboardModel::g810 },
+ { 0x46d, 0xc337, (u_int16_t)KeyboardModel::g810 },
+ { 0x46d, 0xc32b, (u_int16_t)KeyboardModel::g910 },
+ { 0x46d, 0xc335, (u_int16_t)KeyboardModel::g910 },
+ { 0x46d, 0xc339, (u_int16_t)KeyboardModel::gpro }
};
- enum class KeyGroup { logo, indicators, multimedia, fkeys, modifiers, arrows, numeric, functions, keys, gkeys};
- struct KeyColors { uint8_t red; uint8_t green; uint8_t blue; };
- struct KeyAddress { KeyAddressGroup addressGroup; uint8_t id; };
- struct KeyValue { KeyAddress key; KeyColors colors; };
+ enum class KeyboardModel : uint8_t {
+ unknown = 0x00,
+ g213,
+ g410,
+ g413,
+ g513,
+ g610,
+ g810,
+ g910,
+ gpro
+ };
+ enum class StartupMode : uint8_t {
+ wave = 0x01,
+ color
+ };
+ enum class NativeEffect : uint8_t {
+ color = 0x01,
+ breathing,
+ cycle,
+ hwave,
+ vwave,
+ cwave
+ };
+ enum class NativeEffectPart : uint8_t {
+ all = 0xff,
+ keys = 0x00,
+ logo
+ };
+ enum class KeyGroup : uint8_t {
+ logo = 0x00,
+ indicators,
+ multimedia,
+ gkeys,
+ fkeys,
+ modifiers,
+ functions,
+ arrows,
+ numeric,
+ keys
+ };
+ enum class Key : uint16_t { // 127 items
+
+ logo = static_cast(KeyAddressGroup::logo) << 8 | 0x01,
+ logo2,
+
+ backlight = static_cast(KeyAddressGroup::indicators) << 8| 0x01,
+ game, caps, scroll, num,
+
+ next = static_cast(KeyAddressGroup::multimedia) << 8 | 0xb5,
+ prev, stop,
+ play = static_cast(KeyAddressGroup::multimedia) << 8 | 0xcd,
+ mute = static_cast(KeyAddressGroup::multimedia) << 8 | 0xe2,
+
+ g1 = static_cast(KeyAddressGroup::gkeys) << 8 | 0x01,
+ g2, g3, g4, g5, g6, g7, g8, g9,
+
+ a = static_cast(KeyAddressGroup::keys) << 8 | 0x04,
+ b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,
+ n1, n2, n3, n4, n5, n6, n7, n8, n9, n0,
+ enter, esc, backspace, tab, space, minus, equal, open_bracket, close_bracket,
+ backslash, dollar, semicolon, quote, tilde, comma, period, slash, caps_lock,
+ f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
+ print_screen, scroll_lock, pause_break, insert, home, page_up, del, end, page_down,
+ arrow_right, arrow_left, arrow_bottom, arrow_top, num_lock, num_slash, num_asterisk,
+ num_minus, num_plus, num_enter,
+ num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0,
+ num_dot, intl_backslash, menu,
+
+ ctrl_left = static_cast(KeyAddressGroup::keys) << 8 | 0xe0,
+ shift_left, alt_left, win_left,
+ ctrl_right, shift_right, alt_right, win_right
+
+ };
+
+ typedef struct {
+ uint16_t vendorID = 0x0;
+ uint16_t productID = 0x0;
+ std::string manufacturer = "";
+ std::string product = "";
+ std::string serialNumber = "";
+ KeyboardModel model;
+ } DeviceInfo;
+
+ struct Color {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+ };
+ struct KeyValue {
+ LedKeyboard::Key key;
+ LedKeyboard::Color color;
+ };
+
+ typedef std::vector KeyValueArray;
+
+
+ ~LedKeyboard();
+
+
+ std::vector listKeyboards();
+
+ bool isOpen();
+ bool open();
+ bool open(uint16_t vendorID, uint16_t productID, std::string serial);
+ DeviceInfo getCurrentDevice();
+ bool close();
+
+ KeyboardModel getKeyboardModel();
- bool isAttached();
- bool attach();
- bool detach();
bool commit();
- bool getKeyAddress(Key key, KeyAddress &keyAddress);
- bool parsePowerOnEffect(std::string effect, PowerOnEffect &powerOnEffect);
- bool parseKey(std::string key, KeyAddress &keyAddress);
- bool parseKeyGroup(std::string key, KeyGroup &keyGroup);
- bool parseColor(std::string color, KeyColors &colors);
- bool setPowerOnEffect(PowerOnEffect powerOnEffect);
+
bool setKey(KeyValue keyValue);
- bool setKey(Key key, KeyColors colors);
- bool setKeys(KeyValue keyValue[], size_t keyValueCount);
- bool setAllKeys(KeyColors colors);
- bool setGroupKeys(KeyGroup keyGroup, KeyColors colors);
+ bool setKeys(KeyValueArray keyValues);
+ bool setGroupKeys(KeyGroup keyGroup, Color color);
+ bool setAllKeys(Color color);
+
+ bool setMRKey(uint8_t value);
+ bool setMNKey(uint8_t value);
+ bool setGKeysMode(uint8_t value);
+
+ bool setRegion(uint8_t region, Color color);
+ bool setStartupMode(StartupMode startupMode);
+
+ bool setNativeEffect(NativeEffect effect, NativeEffectPart part, uint8_t speed, Color color);
private:
- bool m_isAttached = false;
- bool m_isKernellDetached = false;
- KeyboardProtocol kbdProtocol = KeyboardProtocol::generic;
- libusb_device **devs;
- libusb_device_handle *dev_handle;
- libusb_context *ctx = NULL;
+ typedef std::vector byte_buffer_t;
+ typedef std::vector KeyArray;
- bool populateAddressGroupInternal(KeyAddressGroup addressGroup, unsigned char *data);
- bool sendDataInternal(unsigned char *data, uint16_t data_size);
- bool setKeysInternal(KeyAddressGroup addressGroup, KeyValue keyValues[], size_t keyValueCount);
+
+ const KeyArray keyGroupLogo = { Key::logo, Key::logo2 };
+ const KeyArray keyGroupIndicators = { Key::caps, Key::num, Key::scroll, Key::game, Key::backlight };
+ const KeyArray keyGroupMultimedia = { Key::next, Key::prev, Key::stop, Key::play, Key::mute };
+ const KeyArray keyGroupGKeys = { Key::g1, Key::g2, Key::g3, Key::g4, Key::g5, Key::g6, Key::g7, Key::g8, Key::g9 };
+ const KeyArray keyGroupFKeys = {
+ Key::f1, Key::f2, Key::f3, Key::f4, Key::f5, Key::f6,
+ Key::f7, Key::f8, Key::f9, Key::f10, Key::f11, Key::f12
+ };
+ const KeyArray keyGroupModifiers = {
+ Key::shift_left, Key::ctrl_left, Key::win_left, Key::alt_left,
+ Key::alt_right, Key::win_right, Key::ctrl_right, Key::shift_right, Key::menu };
+ const KeyArray keyGroupFunctions = {
+ Key::esc, Key::print_screen, Key::scroll_lock, Key::pause_break,
+ Key::insert, Key::del, Key::home, Key::end, Key::page_up, Key::page_down
+ };
+ const KeyArray keyGroupArrows = { Key::arrow_top, Key::arrow_left, Key::arrow_bottom, Key::arrow_right };
+ const KeyArray keyGroupNumeric = {
+ Key::num_1, Key::num_2, Key::num_3, Key::num_4, Key::num_5,
+ Key::num_6, Key::num_7, Key::num_8, Key::num_9, Key::num_0,
+ Key::num_dot, Key::num_enter, Key::num_plus, Key::num_minus,
+ Key::num_asterisk, Key::num_slash, Key::num_lock
+ };
+ const KeyArray keyGroupKeys = {
+ Key::a, Key::b, Key::c, Key::d, Key::e, Key::f, Key::g, Key::h, Key::i, Key::j, Key::k, Key::l, Key::m,
+ Key::n, Key::o, Key::p, Key::q, Key::r, Key::s, Key::t, Key::u, Key::v, Key::w, Key::x, Key::y, Key::z,
+ Key::n1, Key::n2, Key::n3, Key::n4, Key::n5, Key::n6, Key::n7, Key::n8, Key::n9, Key::n0,
+ Key::enter, Key::backspace, Key::tab, Key::space, Key::minus, Key::equal,
+ Key::open_bracket, Key::close_bracket, Key::backslash, Key::dollar, Key::semicolon, Key::quote, Key::tilde,
+ Key::comma, Key::period, Key::slash, Key::caps_lock, Key::intl_backslash
+ };
+
+ bool m_isOpen = false;
+ DeviceInfo currentDevice;
+
+ #if defined(hidapi)
+ hid_device *m_hidHandle;
+ #elif defined(libusb)
+ bool m_isKernellDetached = false;
+ libusb_device_handle *m_hidHandle;
+ libusb_context *m_ctx = NULL;
+ #endif
+
+
+ bool sendDataInternal(byte_buffer_t &data);
+ byte_buffer_t getKeyGroupAddress(KeyAddressGroup keyAddressGroup);
};
diff --git a/src/helpers/help.cpp b/src/helpers/help.cpp
new file mode 100644
index 0000000..eb95f87
--- /dev/null
+++ b/src/helpers/help.cpp
@@ -0,0 +1,330 @@
+#include "help.h"
+
+#include
+#include "utils.h"
+
+
+using namespace std;
+
+namespace help {
+
+ inline KeyboardFeatures operator|(KeyboardFeatures a, KeyboardFeatures b) {
+ return static_cast(static_cast(a) | static_cast(b));
+ }
+
+ KeyboardFeatures getKeyboardFeatures(string cmdName) {
+ if(cmdName == "g213-led") return KeyboardFeatures::g213;
+ else if(cmdName == "g410-led") return KeyboardFeatures::g410;
+ else if(cmdName == "g413-led") return KeyboardFeatures::g413;
+ else if(cmdName == "g610-led") return KeyboardFeatures::g610;
+ else if(cmdName == "g810-led") return KeyboardFeatures::g810;
+ else if(cmdName == "g910-led") return KeyboardFeatures::g910;
+ else if(cmdName == "gpro-led") return KeyboardFeatures::gpro;
+ return KeyboardFeatures::all;
+ }
+
+
+ void usage(char *arg0) {
+ string cmdName = utils::getCmdName(arg0);
+ KeyboardFeatures features = getKeyboardFeatures(cmdName);
+ cout<
+
+namespace help {
+
+ enum class KeyboardFeatures : uint16_t {
+ none = 0,
+ rgb = 1,
+ intensity = 2,
+ commit = 4,
+ logo1 = 8,
+ logo2 = 16,
+ numpad = 32,
+ multimedia = 64,
+ gkeys = 128,
+ setall = 256,
+ setgroup = 512,
+ setkey = 1024,
+ setregion = 2048,
+ setindicators = 4096,
+ poweronfx = 8192,
+ // fx features
+
+ all = rgb | intensity | commit | logo1 | logo2 | numpad | multimedia | gkeys |
+ setall | setgroup | setkey | setregion | setindicators | poweronfx,
+
+ g213 = rgb | logo1 | numpad | multimedia | setall | setregion | setindicators | poweronfx,
+ g410 = rgb | commit | setall | setgroup | setkey | poweronfx,
+ g413 = intensity | setall,
+ g610 = intensity | commit | logo1 | numpad | multimedia | setall | setgroup | setkey | setindicators | poweronfx,
+ g810 = rgb | commit | logo1 | numpad | multimedia | setall | setgroup | setkey | setindicators | poweronfx,
+ g910 = rgb | commit | logo1 | logo2 | numpad | multimedia | gkeys | setall | setgroup | setkey | setindicators | poweronfx,
+ gpro = rgb | commit | logo1 | multimedia | setall | setgroup | setkey | setindicators | poweronfx
+ };
+ inline KeyboardFeatures operator|(KeyboardFeatures a, KeyboardFeatures b);
+
+ KeyboardFeatures getKeyboardFeatures(std::string cmdName);
+
+ void usage(char *arg0);
+ void keys(char *arg0);
+ void effects(char *arg0);
+ void samples(char *arg0);
+
+}
+
+#ifndef VERSION
+#define VERSION "unspecified"
+#endif
+
+#endif
diff --git a/src/helpers/utils.cpp b/src/helpers/utils.cpp
new file mode 100644
index 0000000..5398838
--- /dev/null
+++ b/src/helpers/utils.cpp
@@ -0,0 +1,228 @@
+#include "utils.h"
+
+#include
+#include
+
+#include "../classes/Keyboard.h"
+
+
+namespace utils {
+
+ std::string getCmdName(std::string cmd) {
+ return cmd.substr(cmd.find_last_of("/\\") + 1);
+ }
+
+
+
+ bool parseStartupMode(std::string val, LedKeyboard::StartupMode &startupMode) {
+ if (val == "wave") startupMode = LedKeyboard::StartupMode::wave;
+ else if (val == "color") startupMode = LedKeyboard::StartupMode::color;
+ else return false;
+ return true;
+ }
+
+ bool parseNativeEffect(std::string val, LedKeyboard::NativeEffect &nativeEffect) {
+ if (val == "color") nativeEffect = LedKeyboard::NativeEffect::color;
+ else if (val == "cycle") nativeEffect = LedKeyboard::NativeEffect::cycle;
+ else if (val == "breathing") nativeEffect = LedKeyboard::NativeEffect::breathing;
+ else if (val == "hwave") nativeEffect = LedKeyboard::NativeEffect::hwave;
+ else if (val == "vwave") nativeEffect = LedKeyboard::NativeEffect::vwave;
+ else if (val == "cwave") nativeEffect = LedKeyboard::NativeEffect::cwave;
+ else return false;
+ return true;
+ }
+
+ bool parseNativeEffectPart(std::string val, LedKeyboard::NativeEffectPart &nativeEffectPart) {
+ if (val == "all") nativeEffectPart = LedKeyboard::NativeEffectPart::all;
+ else if (val == "keys") nativeEffectPart = LedKeyboard::NativeEffectPart::keys;
+ else if (val == "logo") nativeEffectPart = LedKeyboard::NativeEffectPart::logo;
+ else return false;
+ return true;
+ }
+
+ bool parseKey(std::string val, LedKeyboard::Key &key) {
+ std::transform(val.begin(), val.end(), val.begin(), ::tolower);
+ if (val == "logo") key = LedKeyboard::Key::logo;
+ else if (val == "logo2") key = LedKeyboard::Key::logo2;
+ else if (val == "back_light" || val == "backlight" || val == "light") key = LedKeyboard::Key::backlight;
+ else if (val == "game_mode" || val == "gamemode" || val == "game") key = LedKeyboard::Key::game;
+ else if (val == "caps_indicator" || val == "capsindicator" || val == "caps") key = LedKeyboard::Key::caps;
+ else if (val == "scroll_indicator" || val == "scrollindicator" || val == "scroll") key = LedKeyboard::Key::scroll;
+ else if (val == "num_indicator" || val == "numindicator" || val == "num") key = LedKeyboard::Key::num;
+ else if (val == "next") key = LedKeyboard::Key::next;
+ else if (val == "prev" || val == "previous") key = LedKeyboard::Key::prev;
+ else if (val == "stop") key = LedKeyboard::Key::stop;
+ else if (val == "play_pause" || val == "playpause" || val == "play") key = LedKeyboard::Key::play;
+ else if (val == "mute") key = LedKeyboard::Key::mute;
+ else if (val == "a") key = LedKeyboard::Key::a;
+ else if (val == "b") key = LedKeyboard::Key::b;
+ else if (val == "c") key = LedKeyboard::Key::c;
+ else if (val == "d") key = LedKeyboard::Key::d;
+ else if (val == "e") key = LedKeyboard::Key::e;
+ else if (val == "f") key = LedKeyboard::Key::f;
+ else if (val == "g") key = LedKeyboard::Key::g;
+ else if (val == "h") key = LedKeyboard::Key::h;
+ else if (val == "i") key = LedKeyboard::Key::i;
+ else if (val == "j") key = LedKeyboard::Key::j;
+ else if (val == "k") key = LedKeyboard::Key::k;
+ else if (val == "l") key = LedKeyboard::Key::l;
+ else if (val == "m") key = LedKeyboard::Key::m;
+ else if (val == "n") key = LedKeyboard::Key::n;
+ else if (val == "o") key = LedKeyboard::Key::o;
+ else if (val == "p") key = LedKeyboard::Key::p;
+ else if (val == "q") key = LedKeyboard::Key::q;
+ else if (val == "r") key = LedKeyboard::Key::r;
+ else if (val == "s") key = LedKeyboard::Key::s;
+ else if (val == "t") key = LedKeyboard::Key::t;
+ else if (val == "u") key = LedKeyboard::Key::u;
+ else if (val == "v") key = LedKeyboard::Key::v;
+ else if (val == "w") key = LedKeyboard::Key::w;
+ else if (val == "x") key = LedKeyboard::Key::x;
+ else if (val == "z") key = LedKeyboard::Key::z;
+ else if (val == "y") key = LedKeyboard::Key::y;
+ else if (val == "1" || val == "one") key = LedKeyboard::Key::n1;
+ else if (val == "2" || val == "two") key = LedKeyboard::Key::n2;
+ else if (val == "3" || val == "three") key = LedKeyboard::Key::n3;
+ else if (val == "4" || val == "four") key = LedKeyboard::Key::n4;
+ else if (val == "5" || val == "five") key = LedKeyboard::Key::n5;
+ else if (val == "6" || val == "six") key = LedKeyboard::Key::n6;
+ else if (val == "7" || val == "seven") key = LedKeyboard::Key::n7;
+ else if (val == "8" || val == "eight") key = LedKeyboard::Key::n8;
+ else if (val == "9" || val == "nine") key = LedKeyboard::Key::n9;
+ else if (val == "0" || val == "zero") key = LedKeyboard::Key::n0;
+ else if (val == "enter") key = LedKeyboard::Key::enter;
+ else if (val == "esc" || val == "escape") key = LedKeyboard::Key::esc;
+ else if (val == "back" || val == "backspace") key = LedKeyboard::Key::backspace;
+ else if (val == "tab") key = LedKeyboard::Key::tab;
+ else if (val == "space") key = LedKeyboard::Key::space;
+ else if (val == "tilde" || val == "~") key = LedKeyboard::Key::tilde;
+ else if (val == "minus" || val == "-") key = LedKeyboard::Key::minus;
+ else if (val == "equal" || val == "=") key = LedKeyboard::Key::equal;
+ else if (val == "open_bracket" || val == "[") key = LedKeyboard::Key::open_bracket;
+ else if (val == "close_bracket" || val == "]") key = LedKeyboard::Key::close_bracket;
+ else if (val == "backslash" || val == "\\") key = LedKeyboard::Key::backslash;
+ else if (val == "semicolon" || val == ";") key = LedKeyboard::Key::semicolon;
+ else if (val == "quote" || val == "\"") key = LedKeyboard::Key::quote;
+ else if (val == "dollar" || val == "$") key = LedKeyboard::Key::dollar;
+ else if (val == "comma" || val == ",") key = LedKeyboard::Key::comma;
+ else if (val == "period" || val == ".") key = LedKeyboard::Key::period;
+ else if (val == "slash" || val == "/") key = LedKeyboard::Key::slash;
+ else if (val == "caps_lock" || val == "capslock") key = LedKeyboard::Key::caps_lock;
+ else if (val == "f1") key = LedKeyboard::Key::f1;
+ else if (val == "f2") key = LedKeyboard::Key::f2;
+ else if (val == "f3") key = LedKeyboard::Key::f3;
+ else if (val == "f4") key = LedKeyboard::Key::f4;
+ else if (val == "f5") key = LedKeyboard::Key::f5;
+ else if (val == "f6") key = LedKeyboard::Key::f6;
+ else if (val == "f7") key = LedKeyboard::Key::f7;
+ else if (val == "f8") key = LedKeyboard::Key::f8;
+ else if (val == "f9") key = LedKeyboard::Key::f9;
+ else if (val == "f10") key = LedKeyboard::Key::f10;
+ else if (val == "f11") key = LedKeyboard::Key::f11;
+ else if (val == "f12") key = LedKeyboard::Key::f12;
+ else if (val == "print_screen" || val == "printscreen" || val == "printscr" || val == "print")
+ key = LedKeyboard::Key::print_screen;
+ else if (val == "scroll_lock" || val == "scrolllock") key = LedKeyboard::Key::scroll_lock;
+ else if (val == "pause_break" || val == "pausebreak" || val == "pause" || val == "break")
+ key = LedKeyboard::Key::pause_break;
+ else if (val == "insert" || val == "ins") key = LedKeyboard::Key::insert;
+ else if (val == "home") key = LedKeyboard::Key::home;
+ else if (val == "page_up" || val == "pageup") key = LedKeyboard::Key::page_up;
+ else if (val == "delete" || val == "del") key = LedKeyboard::Key::del;
+ else if (val == "end") key = LedKeyboard::Key::end;
+ else if (val == "page_down" || val == "pagedown") key = LedKeyboard::Key::page_down;
+ else if (val == "arrow_right" || val == "arrowright" || val == "right") key = LedKeyboard::Key::arrow_right;
+ else if (val == "arrow_left" || val == "arrowleft" || val == "left") key = LedKeyboard::Key::arrow_left;
+ else if (val == "arrow_bottom" || val == "arrowbottom" || val == "bottom") key = LedKeyboard::Key::arrow_bottom;
+ else if (val == "arrow_top" || val == "arrowtop" || val == "top") key = LedKeyboard::Key::arrow_top;
+ else if (val == "num_lock" || val == "numlock") key = LedKeyboard::Key::num_lock;
+ else if (val == "num/" || val == "num_slash" || val == "numslash") key = LedKeyboard::Key::num_slash;
+ else if (val == "num*" || val == "num_asterisk" || val == "numasterisk") key = LedKeyboard::Key::num_asterisk;
+ else if (val == "num-" || val == "num_minus" || val == "numminus") key = LedKeyboard::Key::num_minus;
+ else if (val == "num+" || val == "num_plus" || val == "numplus") key = LedKeyboard::Key::num_plus;
+ else if (val == "numenter") key = LedKeyboard::Key::num_enter;
+ else if (val == "num1") key = LedKeyboard::Key::num_1;
+ else if (val == "num2") key = LedKeyboard::Key::num_2;
+ else if (val == "num3") key = LedKeyboard::Key::num_3;
+ else if (val == "num4") key = LedKeyboard::Key::num_4;
+ else if (val == "num5") key = LedKeyboard::Key::num_5;
+ else if (val == "num6") key = LedKeyboard::Key::num_6;
+ else if (val == "num7") key = LedKeyboard::Key::num_7;
+ else if (val == "num8") key = LedKeyboard::Key::num_8;
+ else if (val == "num9") key = LedKeyboard::Key::num_9;
+ else if (val == "num0") key = LedKeyboard::Key::num_0;
+ else if (val == "num." || val == "num_period" || val == "numperiod") key = LedKeyboard::Key::num_dot;
+ else if (val == "intl_backslash" || val == "<") key = LedKeyboard::Key::intl_backslash;
+ else if (val == "menu") key = LedKeyboard::Key::menu;
+ else if (val == "ctrl_left" || val == "ctrlleft" || val == "ctrll") key = LedKeyboard::Key::ctrl_left;
+ else if (val == "shift_left" || val == "shiftleft" || val == "shiftl") key = LedKeyboard::Key::shift_left;
+ else if (val == "alt_left" || val == "altleft" || val == "altl") key = LedKeyboard::Key::alt_left;
+ else if (val == "win_left" || val == "winleft" || val == "winl") key = LedKeyboard::Key::win_left;
+ else if (val == "meta_left" || val == "metaleft" || val == "metal") key = LedKeyboard::Key::win_left;
+ else if (val == "ctrl_right" || val == "ctrlright" || val == "ctrlr") key = LedKeyboard::Key::ctrl_right;
+ else if (val == "shift_right" || val == "shiftright" || val == "shiftr") key = LedKeyboard::Key::shift_right;
+ else if (val == "alt_right" || val == "altright" || val == "altr" || val == "altgr")
+ key = LedKeyboard::Key::alt_right;
+ else if (val == "win_right" || val == "winright" || val == "winr") key = LedKeyboard::Key::win_right;
+ else if (val == "meta_right" || val == "metaright" || val == "metar") key = LedKeyboard::Key::win_right;
+ else if (val == "g1") key = LedKeyboard::Key::g1;
+ else if (val == "g2") key = LedKeyboard::Key::g2;
+ else if (val == "g3") key = LedKeyboard::Key::g3;
+ else if (val == "g4") key = LedKeyboard::Key::g4;
+ else if (val == "g5") key = LedKeyboard::Key::g5;
+ else if (val == "g6") key = LedKeyboard::Key::g6;
+ else if (val == "g7") key = LedKeyboard::Key::g7;
+ else if (val == "g8") key = LedKeyboard::Key::g8;
+ else if (val == "g9") key = LedKeyboard::Key::g9;
+ else return false;
+ return true;
+ }
+
+ bool parseKeyGroup(std::string val, LedKeyboard::KeyGroup &keyGroup) {
+ if (val == "logo") keyGroup = LedKeyboard::KeyGroup::logo;
+ else if (val == "indicators") keyGroup = LedKeyboard::KeyGroup::indicators;
+ else if (val == "multimedia") keyGroup = LedKeyboard::KeyGroup::multimedia;
+ else if (val == "fkeys") keyGroup = LedKeyboard::KeyGroup::fkeys;
+ else if (val == "modifiers") keyGroup = LedKeyboard::KeyGroup::modifiers;
+ else if (val == "arrows") keyGroup = LedKeyboard::KeyGroup::arrows;
+ else if (val == "numeric") keyGroup = LedKeyboard::KeyGroup::numeric;
+ else if (val == "functions") keyGroup = LedKeyboard::KeyGroup::functions;
+ else if (val == "keys") keyGroup = LedKeyboard::KeyGroup::keys;
+ else if (val == "gkeys") keyGroup = LedKeyboard::KeyGroup::gkeys;
+ else return false;
+ return true;
+ }
+
+ bool parseColor(std::string val, LedKeyboard::Color &color) {
+ if (val.length() == 2) val = val + "0000"; // For G610
+ if (val.length() != 6) return false;
+ color.red = std::stoul("0x"+val.substr(0,2), nullptr, 16);
+ color.green = std::stoul("0x"+val.substr(2,2), nullptr, 16);
+ color.blue = std::stoul("0x"+val.substr(4,2), nullptr, 16);
+ return true;
+ }
+
+ bool parseSpeed(std::string val, uint8_t &speed) {
+ if (val.length() == 1) val = "0" + val;
+ if (val.length() != 2) return false;
+ speed = std::stoul("0x" + val, nullptr, 16);
+ return true;
+ }
+
+ bool parseUInt8(std::string val, uint8_t &uint8) {
+ if (val.length() == 1) val = "0" + val;
+ if (val.length() != 2) return false;
+ uint8 = std::stoul("0x" + val, nullptr, 16);
+ return true;
+ }
+
+ bool parseUInt16(std::string val, uint16_t &uint16) {
+ if (val.length() == 1) val = "0" + val;
+ if (val.length() == 2) val = "0" + val;
+ if (val.length() == 3) val = "0" + val;
+ if (val.length() != 4) return false;
+ uint16 = std::stoul("0x" + val, nullptr, 16);
+ return true;
+ }
+
+}
diff --git a/src/helpers/utils.h b/src/helpers/utils.h
new file mode 100644
index 0000000..92de26b
--- /dev/null
+++ b/src/helpers/utils.h
@@ -0,0 +1,23 @@
+#ifndef UTILS_HELPER
+#define UTILS_HELPER
+
+#include
+#include "../classes/Keyboard.h"
+
+namespace utils {
+
+ std::string getCmdName(std::string cmd);
+
+ bool parseStartupMode(std::string val, LedKeyboard::StartupMode &startupMode);
+ bool parseNativeEffect(std::string val, LedKeyboard::NativeEffect &nativeEffect);
+ bool parseNativeEffectPart(std::string val, LedKeyboard::NativeEffectPart &nativeEffectPart);
+ bool parseKey(std::string val, LedKeyboard::Key &key);
+ bool parseKeyGroup(std::string val, LedKeyboard::KeyGroup &keyGroup);
+ bool parseColor(std::string val, LedKeyboard::Color &color);
+ bool parseSpeed(std::string val, uint8_t &speed);
+ bool parseUInt8(std::string val, uint8_t &uint8);
+ bool parseUInt16(std::string val, uint16_t &uint16);
+
+}
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
index b7af4eb..467589a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,310 +1,310 @@
-#include