Repository: JSubelj/g910-gkey-macro-support (language: python)

Issue:
[Misc] Another keyboard driver example with root daemon & user-side settings/actions
I am sorry, I switched my G910 for a Corsair K70, so I won't be involved in this project anymore.

However, the [K70 has also a driver](https://github.com/ckb-next/ckb-next) (written in C) similar to g910-gkey-macro-support.

The interesting point is that this driver uses a design that [I proposed for the G910](https://github.com/JSubelj/g910-gkey-macro-support/issues/13#issuecomment-1308919383): A minimal **root daemon**, which only purpose is the communication between the device and a **user client**. The client is responsible for everything: settings, actions, animations, etc... There is no risk (and no way) to run any code as root with that system.

Maybe such a design for the Logitech keyboards could solve some current issues and reduce security risks ?

Another topic, I wonder if the [`G15` kernel support](https://github.com/torvalds/linux/blob/master/drivers/hid/hid-lg-g15.c) could be of some use here.

Anyway, thanks a lot for the great job for Logitech keyboards !
[Feature] Logitech G915 support?
Hi there,
I use Arch Linux with Logitech G915 keyboard (wireless/lightspeed connection) and I installed your package from AUR, I enabled the service and tried to start it but it fails with the following report:

```
× g910-gkeys.service - Support for Logitech g910 keyboard gkeys
     Loaded: loaded (/usr/lib/systemd/system/g910-gkeys.service; enabled; vendor preset: disabled)
     Active: failed (Result: exit-code) since Tue 2021-11-23 17:51:52 CET; 2s ago
       Docs: https://github.com/JSubelj/g910-gkey-macro-support/wiki
    Process: 3426 ExecStart=/usr/bin/env g910-gkeys (code=exited, status=1/FAILURE)
   Main PID: 3426 (code=exited, status=1/FAILURE)
        CPU: 62ms

stu 23 17:51:52 dalibor-rogstrix env[3426]:     device = uinput.Device(uinput_all_keys.uinput_all_keys)
stu 23 17:51:52 dalibor-rogstrix env[3426]:   File "/usr/lib/python3.9/site-packages/uinput/__init__.py", line 178, in __init__
stu 23 17:51:52 dalibor-rogstrix env[3426]:     self.__uinput_fd = fd or fdopen()
stu 23 17:51:52 dalibor-rogstrix env[3426]:   File "/usr/lib/python3.9/site-packages/uinput/__init__.py", line 84, in fdopen
stu 23 17:51:52 dalibor-rogstrix env[3426]:     return _libsuinput.suinput_open()
stu 23 17:51:52 dalibor-rogstrix env[3426]:   File "/usr/lib/python3.9/site-packages/uinput/__init__.py", line 70, in _open_error_handler
stu 23 17:51:52 dalibor-rogstrix env[3426]:     raise OSError(code, msg)
stu 23 17:51:52 dalibor-rogstrix env[3426]: OSError: [Errno 19] Failed to open the uinput device: No such device
stu 23 17:51:52 dalibor-rogstrix systemd[1]: g910-gkeys.service: Main process exited, code=exited, status=1/FAILURE
stu 23 17:51:52 dalibor-rogstrix systemd[1]: g910-gkeys.service: Failed with result 'exit-code'.
```

Is there anything I should do to make it work w this keyboard - don't know if the wireless part is whats tripping the whole thing. I would really like to use the G keys if I can. The keyboard button layout is essentially the same as on G910... Also does it support HR (hrvatski) layout :D?


Discussion / hints:

@hogar1977 - have you made any inroads on this question? I'm also running a 915 and have the same questions. 
It looks like the uinput device can't get initialized. Can you try the following:
```
ls -l /dev/uinput
crw------- 1 root root 10, 223 Okt 31 10:56 /dev/uinput
```
If you got the same permissions then i you can only init a udev/uinput device with root privileges.

If you don't have that file:
`modprobe uinput` and `sudo systemctl restart udev`
After that check if udev started without errors.
Look what i just stumbled over: [https://github.com/MatMoul/g810-led/blob/master/src/classes/Keyboard.cpp#L793](https://github.com/MatMoul/g810-led/blob/master/src/classes/Keyboard.cpp#L793)  
`data = { 0x11, 0xff, 0x0a, 0x2b, value };`
It looks like there is the byte code to activate gkeys on g915.
I can do the changes, but i need one of you to test it. Is one of you interested?
Did you update the code for this? I will test it
Any updates on this? @suabo @JSubelj 
>= v0.3.0 will support the following keyboards:

- LogitechG915
- LogitechG910OrionSpectrum
- LogitechG910OrionSpark
- LogitechG815
- LogitechG710p
- LogitechG510

Can someone test it and tell me if it works?

Fix patch:
diff --git a/.ON_UPDATE_UPDATE b/.ON_UPDATE_UPDATE
index 6a71d96..4933089 100644
--- a/.ON_UPDATE_UPDATE
+++ b/.ON_UPDATE_UPDATE
@@ -2,7 +2,7 @@ If you are not me, you can ignore this file.
 
 Raise the version number in:
     - reboot and try
-    - PROJECT_INFO.py
+    - pyproject.toml
     - PKGBUILD
 
 Update:
diff --git a/.gitignore b/.gitignore
index 055c05f..3b96129 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,13 +10,15 @@ install_and_run.sh
 wiki/
 g910_gkeys.egg-info/
 g910-gkey-macro-support.wiki/
-/config/
+/docs/
+
 notes
 
 # build
 /build/
 /.pybuild/
 /debian/
+/.pytest_cache/
 
 *.log
 
diff --git a/README.md b/README.md
index 084a3c6..38cc103 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,6 @@ Everything is described in great depth (and actually much better) on [WIKI](http
 To use this project you need:
  - Python >=3.7
  - uinput kernel module (more on this [here](http://tjjr.fi/sw/python-uinput/#Usage))
- - pip requirements are stored in requirements.txt
  
 #### Note: 
 From version 0.2.0 onwards the g810-led controller is no longer required because G-key to F-key mapping is disabled inside the driver.
@@ -28,33 +27,41 @@ From version 0.2.0 onwards the g810-led controller is no longer required because
    wget https://github.com/JSubelj/g910-gkey-macro-support/archive/refs/heads/master.zip; unzip master.zip
    ```
  - move to driver directory: `cd g910-gkey-macro-support`
- - run the installer shell: `chmod +x installer.sh; sudo ./installer.sh`
- - This will install the module, set a command `g910-gkeys`, add a service file to `/usr/lib/systemd/system/g910-gkeys.service` or `/lib/systemd/system/g910-gkeys.service`, install a default configuration file in `/etc/g910-gkeys/config.json` if none exists, and finally enable and start this service.
+ - run the installer script: `chmod +x installer.sh; ./installer.sh`
+ - This will install the module, set a command `g910-gkeys`, add a service file to `$HOME/.config/systemd/user/g910-gkeys.service` or similar, install a default configuration file in `$HOME/.config/g910-gkeys/config.json` if none exists, and finally enable and start this service.
 
-If you do not want to enable g910-gkeys automatically, use the `-n` switch: `sudo ./installer.sh -n`. If you want to enable it later you can use: `sudo systemctl enable --now g910-gkeys.service`. To just start the service one till next reboot use: `sudo systemctl start g910-gkeys`
+If you do not want to enable g910-gkeys automatically, use the `-n` switch: `./installer.sh -n`. If you want to enable it later you can use: `systemctl --user enable --now g910-gkeys.service`. To just start the service till next reboot use: `systemctl --user start g910-gkeys`
  
 ## Update
+### <= v0.3.0
+If you use the installer your old config will be moved to the new location automatically. On manual installations you need to move your old config file to the new location and set the permissions to your username.
+```
+sudo mv /etc/g910-gkeys/config.json "$HOME"/.config/g910-gkeys/config.json
+sudo chown "$USER":"$USER" "$HOME"/.config/g910-gkeys/config.json
+```
+
+You can delete the old log file `sudo rm /var/log/g910-gkeys.log`.
+
+### <= v0.2.4
  If you update from version <= v0.2.4 you will need to make some manual changes to your `/etc/g910-gkeys/config.json` to make use of the new gkey profile feature.
  You don't need to do anything if you don't want to use the profile feature your old config will be loaded as default profile m1.
 
 ## Uninstalling
 ### By script (recommended)
-Run the uninstalling script: `chmod +x uninstall.sh; sudo ./uninstall.sh`. 
+Run the uninstalling script: `chmod +x uninstall.sh; ./uninstall.sh`  
+Run `./uninstall.sh -d` to perform a dry-run (no actual removal will be done, actions will only be displayed).
 
 ### Manual uninstall
 If you prefer to do it manually, these are the commands :
 
- 1. Disable and stop the service: `sudo systemctl disable --now g910-gkeys`
- 2. Remove installed files (list is in files.txt): `sudo xargs --arg-file=files.txt rm -rf`
- 3. List pip packages that include g910-gkeys: `pip (or pip3) list | grep g910-gkeys`
- 4. Remove the ones that concern this driver: `pip (or pip3) uninstall ${pkgs to uninstall}`
- 5. Remove configuration directory if `-a` option is given to uninstall.sh: `rm -rf /etc/g910-gkeys`
-
-If you deleted files.txt you can always run the installer again to create it.   
-Run `uninstall.sh -d` to perform a dry-run (no actual removal will be done, actions will only be displayed).
+ 1. Disable and stop the service: `systemctl --user disable --now g910-gkeys`
+ 2. List pip packages that include g910-gkeys: `pip (or pip3) list | grep g910-gkeys`
+ 3. Remove the ones that concern this driver: `pip (or pip3) uninstall ${pkgs to uninstall}`
+ 4. Optional: Remove configuration directory `rm -rf '$HOME/.config/g910-gkeys`  
+    If you want to reinstall the driver again later consider keeping the config file.
 
 ## Configuration
-Configuration should be located in `/etc/g910-gkeys/config.json` and should be syntactically correct. Example 
+Configuration should be located in `/home/[username]/.config/g910-gkeys/config.json` and should be syntactically correct. Example 
 configuration can be found in docs folder: [ex_config](docs/ex_config/ex_config.json). 
 
 ### Supported languages:
@@ -97,14 +104,12 @@ hotkeys are listed in [supported_keys.txt](docs/supported_keys.txt)):
 There are four profiles you can use and set up different gkey macros in config. Select the profile with M[1-3|R] key on your keyboard.
 If you use the profile feature you can also use the following parameter:
  * `notify` - Send notifications if profile gets changed
- * `username` - Username to send notifications with (required if notify is used)
  * `profiles` - Define a profile which is bound to the matching mkey
 
 The following example shows how to set slovenian layout and define the g1-5 macro keys for profile m1 and m2 and shows an example of every `hotkey_type`.
  ```
 {
     "notify": "True",
-    "username": "<username>",
     "keyboard_mapping": "si",
     "profiles": {
         "MEMORY_1": {
@@ -122,7 +127,7 @@ The following example shows how to set slovenian layout and define the g1-5 macr
             },
             "MACRO_4": {
                 "hotkey_type": "run",
-                "do": "/path/script_run_by_root"
+                "do": "/path/to/bash/script"
             },
             "MACRO_5": {
                 "hotkey_type": "python",
@@ -144,7 +149,7 @@ The following example shows how to set slovenian layout and define the g1-5 macr
             },
             "MACRO_4": {
                 "hotkey_type": "run",
-                "do": "su <username> -c 'DISPLAY=:0 nohup firefox' & 2>&1 > /dev/null"
+                "do": "DISPLAY=:0 nohup firefox & 2>&1 > /dev/null"
             },
             "MACRO_5": {
                 "hotkey_type": "python",
@@ -154,7 +159,13 @@ The following example shows how to set slovenian layout and define the g1-5 macr
     }
 }
  ```
-To run an app like firefox, chrome or similar you need to replace **\<username\>** with your username. The DISPLAY variable defines the screen to open the app on a multi-screen-setup.
+The DISPLAY variable defines the screen to open the app on a multi-screen-setup.
+
+## Troubleshooting
+To see a log of the running service use:
+```sehll
+journalctl --user --user-unit=g910-gkeys
+```
 
 The code is tested on Logitech G910 keyboard with
 - OS: Ubuntu 20.04.6 LTS, Linux 5.4.0-159-generic, GNOME: 3.36.9
diff --git a/cli_entry_point.py b/cli_entry_point.py
index ab37c35..aab0805 100644
--- a/cli_entry_point.py
+++ b/cli_entry_point.py
@@ -2,30 +2,11 @@
 # -*- coding: utf-8 -*-
 
 import argparse
-from lib import g910_gkey_mapper, PROJECT_INFO
-from lib.misc.config import Config
+from g910_gkeys import g910_gkeys
 
 
 def main():
-    parser = argparse.ArgumentParser(description=PROJECT_INFO.DESCRIPTION)
-    parser.add_argument("--create-config", help="Creates config in /etc/g910-gkeys",
-                        action='store_true', default=False)
-    parser.add_argument("-s", "--set-config", help="Set the config file to use",
-                        default='/etc/g910-gkeys/config.json', dest="config_file")
-    parser.add_argument("-v", "--version", help="Displays the information about the driver",
-                        action='version', version=f"%(prog)s {PROJECT_INFO.VERSION} by {PROJECT_INFO.AUTHOR}")
-    args = parser.parse_args()
-    if args.create_config:
-        from lib.usb_device import USBDevice
-        config = Config()
-        device = USBDevice()  # init usb device and keyboard interface
-        config.create(device.keyboard)  # create config with keyboard interface
-        device.__exit__()  # clean up usb connection
-    elif args.config_file != "/etc/g910-gkeys/config.json":
-        Config.config_path = args.config_file
-        g910_gkey_mapper.main()
-    else:
-        g910_gkey_mapper.main()
+    g910_gkeys.main()
 
 
 if __name__ == "__main__":
diff --git a/cli_layout_config_helpers.py b/cli_layout_config_helpers.py
new file mode 100644
index 0000000..5344570
--- /dev/null
+++ b/cli_layout_config_helpers.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import argparse
+from g910_gkeys import layout_config_helpers
+
+
+def main():
+    layout_config_helpers.main()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/docs/Changelog.md b/docs/Changelog.md
deleted file mode 100644
index 89f516c..0000000
--- a/docs/Changelog.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# Current:
-**RELEASE-0.2.5:**
-  - Four profiles (Mkeys to switch profiles, up to 28 GKey bindings)
-  - New hotkey_type python (execute simple one-line python code on a Gkey press)
-  - New argument -c PATH or --set-config PATH to load a different config on startup
-  - Remove uinput device on exit consequently (reworked exit strategy)
-  - Detecting JSONDecodeError helps on syntax problems in config.json with better error messages
-  - Added uninstall script and improved install script
-  - Keyboard layouts:
-    - Fixed 'w' char in fr
-    - Added '?' character in en
-
-# Older:
-
-**RELEASE-0.2.4:**
-  - Changed logger levet to INFO
-  - g910-gkeys.service is now platform independant (no more /usr/local/bin vs /usr/bin)
-  - Updated Troubleshooting wiki
-  - Bugfix:
-    - Changed 'is' keyword with '==' with string literals
-
-**RELEASE-0.2.3:**
-  - Updated readme and wiki
-  - When running now prints PID
-  - Bugfix:
-    - Fixed a bug causing the driver not shutting down
-
-**RELEASE-0.2.2:**
-  - Versioning fix
-  - Added -v and --version flags to display version
-  - Flags -v, --version and --help can now be executed as normal user
-  - Project is now consistently named g910-gkeys (GitHub repo name stays the same)
-
-**RELEASE-0.2.1:**
-  - Hotfix: The driver could not find the keyboard on boot.
-
-**RELEASE-0.2.0:**
-  - New features: 
-    - GKeys can now be used as modifiers
-    - Disabling the GKey to FKey mapping is now done in the driver (g810-leds controller is no longer needed)
-    - G910 Spark is now supported without any modification
-    - New types of keys supported
-  - Bugfixes:
-    - Minor bugfixes
\ No newline at end of file
diff --git a/docs/Configuration-strict-user-environment.org b/docs/Configuration-strict-user-environment.org
deleted file mode 100644
index 33717b1..0000000
--- a/docs/Configuration-strict-user-environment.org
+++ /dev/null
@@ -1,251 +0,0 @@
-* Alternative settings for g910-gkeys
-*Important: This document is for Xorg only (not Wayland).*
-
-This document will explain how to setup g910-gkeys by limiting as much as possible the usage of a global config, the idea being to setup global mapping in a static manner, and let the user set the actions in his/her own environment.
-
-** Preamble
-~g910-gkeys-macro-support~ allows different actions, mainly: ~typeout~, ~shortcut~, ~run~, and ~python~.
-
-There are some drawbacks with that:
-- All of these actions will be performed within the process environment, that is ~root~. This is problematic with ~run~ and ~python~ actions.
-- These actions are global.
-- The actions (especially ~run~ and ~python~) will be performed even when the user is not logged-on.
-- It is impossible to use the G-keys as all other keys (for example different actions with different modifiers, for example ~Shift-G1~ or ~Control-Meta-G1~).
-- The ~typeout~ action depends on keyboard localization.
-- The ~typeout~ does not allow any UTF-8 string.
-
-** g910-gkeys configuration file (/etc/g910-gkeys/config.json)
-The configuration chosen will be basic: assign each ~G-key~ to a key which does not exist on physical keyboard. Any key could be used, like specific localized keys which do not exist on your keyboard (example: Japanese keys for an English keyboard), or function keys above F12.
-
-We will choose to map them to Function keys ~F13~ to ~F21~.
-
-My ~config.json~ is:
-
-#+BEGIN_SRC json
-{
-    "__comment": "I was sometimes unable to use F20, even xev did not show the keycode (It just muted/unmuted sound, same as the G910's <mute> button). If it is the case for you, just skip F20 and use F22 instead.",
-    "keyboard_mapping": "en",
-    "g1": { "hotkey_type": "shortcut", "do": "F13" },
-    "g2": { "hotkey_type": "shortcut", "do": "F14" },
-    "g3": { "hotkey_type": "shortcut", "do": "F15" },
-    "g4": { "hotkey_type": "shortcut", "do": "F16" },
-    "g5": { "hotkey_type": "shortcut", "do": "F17" },
-    "g6": { "hotkey_type": "shortcut", "do": "F18" },
-    "g7": { "hotkey_type": "shortcut", "do": "F19" },
-    "g8": { "hotkey_type": "shortcut", "do": "F20" },
-    "g9": { "hotkey_type": "shortcut", "do": "F21" }
-}
-#+END_SRC
-
-** X11 keyboard mapping
-*Note*: Below, I configure also ~F22~ (which looks un-necessary), because I had trouble with ~F20~ at some point, and used ~F22~ as fallback.
-
-By default, the F13-F22 keys may be mapped to some defaults. For example, ~F13~ could return ~XF86Tools~.
-This is not what we want: Instead we want F13-F22 to return themselves.
-
-It could be possible to keep the default mappings, but it makes less sense, and it would probably clash with the keyboard Media keys.
-
-You can check if this mapping is done on your system with the following command:
-
-*Correct F-keys mapping:*
-#+BEGIN_SRC
-$ xmodmap -pke | grep -E 'keycode (19[1-9]|200)'
-keycode 191 = F13 F13 F13 F13 F13 F13 F13
-keycode 192 = F14 F14 F14 F14 F14 F14 F14
-keycode 193 = F15 F15 F15 F15 F15 F15 F15
-keycode 194 = F16 F16 F16 F16 F16 F16 F16
-...
-keycode 200 = F22 F22 F22 F22 F22 F22 F22
-#+END_SRC
-
-*Incorrect F-keys mapping:*
-#+BEGIN_SRC
-$ xmodmap -pke | grep -E 'keycode (19[1-9]|200)'
-keycode 191 = XF86Tools NoSymbol XF86Tools
-keycode 192 = XF86Launch5 NoSymbol XF86Launch5
-keycode 193 = XF86Launch6 NoSymbol XF86Launch6
-...
-keycode 200 = XF86TouchpadOn NoSymbol XF86TouchpadOn
-#+END_SRC
-
-If your configuration is incorrect, you can choose one of the two solutions below (I prefer the first one):
-
-*** Solution 1: Fix F-keys mapping globally
-You will need to find out where the mapping *F-key -> Different key* is done. On my system, it was in ~/usr/share/X11/xkb/symbols/inet~.
-
-To find where the mapping is done on your system, you may run: ~setxkbmap -print -verbose 10~:
-#+BEGIN_SRC
-$ setxkbmap -print -verbose 10
-Setting verbose level to 10
-locale is C
-Trying to load rules file ./rules/evdev...
-Trying to load rules file /usr/share/X11/xkb/rules/evdev...
-Success.
-Applied rules from evdev:
-rules:      evdev
-model:      pc105
-layout:     us
-variant:    altgr-intl
-options:    compose:ralt,grp:ctrls_toggle,lv3:ralt_switch,terminate:ctrl_alt_bksp
-Trying to build keymap using the following components:
-keycodes:   evdev+aliases(qwerty)
-types:      complete
-compat:     complete
-symbols:    pc+us(altgr-intl)+inet(evdev)+group(ctrls_toggle)+level3(ralt_switch)+compose(ralt)+terminate(ctrl_alt_bksp)
-geometry:   pc(pc105)
-xkb_keymap {
-	xkb_keycodes  { include "evdev+aliases(qwerty)"	};
-	xkb_types     { include "complete"	};
-	xkb_compat    { include "complete"	};
-	xkb_symbols   { include "pc+us(altgr-intl)+inet(evdev)+group(ctrls_toggle)+level3(ralt_switch)+compose(ralt)+terminate(ctrl_alt_bksp)"	};
-	xkb_geometry  { include "pc(pc105)"	};
-};
-#+END_SRC
-
-In my case, the faulty configuration was the ~inet(evdev)~ part on ~symbols~ line, meaning in the ~xkb_symbols "evdev" {~ section of ~/usr/share/X11/xkb/symbols/inet~ file. I had to remove the ~FK13-FK22~ lines and add my own. For example, replacing the line:
-#+BEGIN_SRC
-key <FK13>   {      [ XF86Tools         ]       };
-#+END_SRC
-With:
-#+BEGIN_SRC
-key <FK13>   {      [ F13, F13, F13, F13   ]       };
-#+END_SRC
-The full diff with my changes is:
-#+BEGIN_SRC
-$ diff -u0 inet.brsav.2022.11.13 inet
---- inet.brsav.2022.11.13	2022-02-08 18:13:55.000000000 +0100
-+++ inet	2022-11-13 13:09:29.910184100 +0100
-@@ -115,5 +114,0 @@
--    key <FK21>   {      [ XF86TouchpadToggle    ]       };
--    key <FK22>   {      [ XF86TouchpadOn        ]       };
--    key <FK23>   {      [ XF86TouchpadOff       ]       };
--
--    key <FK20>   {      [ XF86AudioMicMute      ]       };
-@@ -204,6 +199,10 @@
--    key <FK13>   {      [ XF86Tools         ]       };
--    key <FK14>   {      [ XF86Launch5       ]       };
--    key <FK15>   {      [ XF86Launch6       ]       };
--    key <FK16>   {      [ XF86Launch7       ]       };
--    key <FK17>   {      [ XF86Launch8       ]       };
--    key <FK18>   {      [ XF86Launch9       ]       };
-+    key <FK13>   {      [ F13, F13, F13, F13   ]       };
-+    key <FK14>   {      [ F14, F14, F14, F14   ]       };
-+    key <FK15>   {      [ F15, F15, F15, F15   ]       };
-+    key <FK16>   {      [ F16, F16, F16, F16   ]       };
-+    key <FK17>   {      [ F17, F17, F17, F17   ]       };
-+    key <FK18>   {      [ F18, F18, F18, F18   ]       };
-+    key <FK19>   {      [ F19, F19, F19, F19   ]       };
-+    key <FK20>   {      [ F20, F20, F20, F20   ]       };
-+    key <FK21>   {      [ F21, F21, F21, F21   ]       };
-+    key <FK22>   {      [ F22, F22, F22, F22   ]       };
-#+END_SRC
-
-*** Solution 2: Fix F-keys mapping with .Xmodmaprc
-If you prefer not to touch system-wide files, you can add in your *~/.Xmodmap*:
-#+BEGIN_SRC
-!!!!!!!!!!!!!! Logitech G910 keyboard
-! Note:
-! F11-F20 have synonyms L1-L10
-! F21-F35 have synonyms R1-R15
-! See: /usr/include/X11/keysymdef.h
-!
-! original F13, F14, etc... mapping on my system:
-! F13 = keycode 191 = XF86Tools NoSymbol XF86Tools
-! F14 = keycode 192 = XF86Launch5 NoSymbol XF86Launch5
-! F15 = keycode 193 = XF86Launch6 NoSymbol XF86Launch6
-! F16 = keycode 194 = XF86Launch7 NoSymbol XF86kLaunch7
-! F17 = keycode 195 = XF86Launch8 NoSymbol XF86Launch8
-! F18 = keycode 196 = XF86Launch9 NoSymbol XF86Launch9
-! F19 = keycode 197 = (nothing)
-! F20 = keycode 198 = XF86AudioMicMute NoSymbol XF86AudioMicMute
-! F21 = keycode 199 = XF86TouchpadToggle NoSymbol XF86TouchpadToggle
-! F22 = keycode 200 = XF86TouchpadOn NoSymbol XF86TouchpadOn
-
-! we map the Gkeys (G1-G9), to F13-F21,
-
-! G1
-keycode 191 = F13 F13 F13 F13 F13 F13
-! G2
-keycode 192 = F14 F14 F14 F14 F14 F14
-! G3
-keycode 193 = F15 F15 F15 F15 F15 F15
-! G4
-keycode 194 = F16 F16 F16 F16 F16 F16
-! G5
-keycode 195 = F17 F17 F17 F17 F17 F17
-! G6
-keycode 196 = F18 F18 F18 F18 F18 F18
-! G7
-keycode 197 = F19 F19 F19 F19 F19 F19
-! G8
-keycode 198 = F20 F20 F20 F20 F20 F20
-! G9
-keycode 199 = F21 F21 F21 F21 F21 F21
-#+END_SRC
-
-** User configuration
-*Note*: Configuration below will make the ~G-keys~ active only when user is logged-on, as any other key.
-
-We will assign the F-keys we defined in ~config.json~ to run any program (this includes graphical programs), or to send a string/command output to active window.
-
-Below are some examples (screenshots from ~Xubuntu 22.10~). We will define the following actions:
-- ~G1~: Activate the *Emacs* main window (whose title is always "*GNU Emacs*").
-- ~Shift-G1~: Launch *Gnome Terminal*.
-- ~G2~ (including with modifiers): Send ~strings~ or ~commands output~ to active window.
-- ~G5~: Assigned to ~Hyper~ modifier: ~G5+a~ will be ~Hyper-a~, as ~Control+a~ is ~Control-a~.
-- ~G6~: Will move the cursor to top-left corner.
-All settings below (except for ~G5~) are configurable in ~Settings/keyboard~, ~Application Shortcuts~ tab, or, for pasting text, via ~autokey~:
-*Xfce keyboard settings:*
-
-[[img/g910-keyboard-settings.png]]
-
-*Autokey:*
-
-[[img/autokey.png]]
-
-*** G1: Activate the *Emacs* main window
-In ~Application Shortcut~ section, click on ~Add~, then set command to ~wmctrl -F -a "GNU Emacs"​~, click ~OK~, then press ~G1~ when asked.
-
-*** Shift-G1: Launch *Gnome Terminal*
-In ~Application Shortcut~ section, click on ~Add~, then set command to ~gnome-terminal~, click ~OK~, then press ~Shift-G1~ when asked.
-
-*** G2: Send different strings to active window
-We can send static/dynamic strings to active window, using ~autokey~ (on Ubuntu 22.10, autokey is provided by ~autokey-gtk~ or ~autokey-qt~ packages).
-
-Note that you can use any combination of modifiers (for example Shift+Meta+G2).
-
-*Example 1*: Insert current date to active window with G2:
-[[img/date.png]]
-
-*Example 2*: Insert Japanese "山" with Control-Shift-G2:
-[[img/yama.png]]
-
-*Note*: The Example 2 looks pretty unstable, when using non US-ASCII strings.
-
-*Example 3*: Use clipboard to insert any UTF-8 string
-A workaround for Example 2 would be to use the clipboard, it looks much more stable. You may use any of:
-- With ~autokey~, create a new script, with the following command to add the string /こんばんは/ to clipboard with ~Super-G2~ shortcut:
-  #+BEGIN_SRC
-  clipboard.fill_clipboard("さよなら")
-  #+END_SRC
-  [[img/sayonara.png]]
-
-- With keyboard manager, use any command which can alter clipboard. For example, to copy /今日は/ to clipboard with ~Control-G2~ shortcut:
-  #+BEGIN_SRC
-  bash -c 'echo "今日は" | xsel -bi'
-  #+END_SRC
-  [[img/konnichiwa.png]]
-Of course, you will have to paste yourself the current clipboard (Control-v, Control-y, Control-Shift-v, depending on application).
-
-*** G5: Assign to /Hyper/ modifier
-In ~$HOME/.Xmodmap~, add the following lines:
-#+CAPTION: Add an Hyper modifier to G5
-#+BEGIN_SRC
-! G5 becomes Hyper_L
-keycode 195 = Hyper_L NoSymbol Hyper_L
-clear mod3
-add mod3 = Hyper_L
-#+END_SRC
-
-*** G6: Move mouse cursor to top-left corner
-In ~Application Shortcut~ section, click on ~Add~, then set command to ~xvkbd -text \\x0\\y0~ (or ~xdotool mousemove 0 0~), click ~OK~, then press ~G6~ when asked.
diff --git a/docs/Configuration.md b/docs/Configuration.md
deleted file mode 100644
index d596471..0000000
--- a/docs/Configuration.md
+++ /dev/null
@@ -1,180 +0,0 @@
-As of version 0.2.5 the default language set in keyboard_mapping is `en`. In earlier versions the default keyboard_mapping was set to `si` for slovene, because the author of this package is from [Slovenia](https://en.wikipedia.org/wiki/Slovenia). If you have another keyboard layout configured in your system you need to change this in the configuration accordingly.
-
-## Location
-Config created on setup is located in: `/etc/g910-gkeys/config.json`
-
-## Config layout
-The driver is set up so that it will work without any data in config (using the default data written in [supported_configs.py](https://github.com/JSubelj/g910-gkey-macro-support/blob/master/lib/data_mappers/supported_configs.py)) so the data written in `config.json` can be `{}` and it will work, but that doesn't really add any functionality at all. So the default config (which the driver writes on first run) is:
-```
-{
-  "__comment" : "following hotkey types are supported: nothing, typeout, shortcut and run; only en, fr, de and si keyboard mappings are currently supported",
-  "keyboard_mapping": "en",
-  "notify": "True",
-  "username": "",
-  "profiles": {
-    "MEMORY_1": {
-      "MACRO_1": {
-        "hotkey_type": "typeout",
-        "do": "This is profile m1"
-      },
-      "MACRO_2": {
-        "hotkey_type": "shortcut",
-        "do": "alt+F4"
-      },
-      "MACRO_3": {
-        "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
-      },
-      "MACRO_4": {
-        "hotkey_type": "nothing"
-      }
-    },
-    "MEMORY_2": {
-      "MACRO_1": {
-        "hotkey_type": "typeout",
-        "do": "This is profile m2"
-      },
-      "MACRO_2": {
-        "hotkey_type": "shortcut",
-        "do": "alt+F4"
-      },
-      "MACRO_3": {
-        "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
-      },
-      "MACRO_4": {
-        "hotkey_type": "nothing"
-      }
-    },
-    "MEMORY_3": {
-      "MACRO_1": {
-        "hotkey_type": "typeout",
-        "do": "This is profile m3"
-      },
-      "MACRO_2": {
-        "hotkey_type": "shortcut",
-        "do": "alt+F4"
-      },
-      "MACRO_3": {
-        "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
-      },
-      "MACRO_4": {
-        "hotkey_type": "nothing"
-      }
-    },
-    "MEMORY_RECORD": {
-      "MACRO_1": {
-        "hotkey_type": "typeout",
-        "do": "This is profile mr"
-      },
-      "MACRO_2": {
-        "hotkey_type": "shortcut",
-        "do": "alt+F4"
-      },
-      "MACRO_3": {
-        "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
-      },
-      "MACRO_4": {
-        "hotkey_type": "nothing"
-      }
-    }
-  }
-}
-```
-
-## Config keys
-`keyboard_mapping` - Keyboard layout, supported languages:  
-   * `"de"` - german
-   * `"en"` - **english (default)**
-   * `"fr"` - french
-   * `"si"` - slovenian
-
-`notify` - Show notifications on profile changed  
-
-`username` - used to show notification (optional)  
-
-`profiles` - use up to 4 profiles, define `MEMORY_[1-3|RECORD]` as entity of profile  
-
-`MEMORY_[1-3|RECORD]` - switch profile (only if you have more than one profile in config.json)  
-
-`MACRO_[1-N]` - G-keys macro definition, defined in root of config if no profiles are needed or as entity of the assigned profile. In each `MACRO_[1-N]` object you have two entities `hotkey_type` and `do` which set what to do when a gkey is pressed.
-
-### Hotkey types
-There are currently 6 hotkey types: `nothing`, `shortcut`, `typeout`, `run` and `python`, `uinput` their functionality is as follows:
-
-#### Type out - `"typeout"`  
-Types out what is written in "do" key by key, as you would on a keyboard. New line is `\n` and tab is `\t`.
-
-#### Shortcuts - `"shortcut"`  
-Press keys that are separated by a comma at the same time. For example copying "ctrl+c", or pasting and writing out: "ctrl+v,i, ,d,i,d, ,i,t"). For characters, only simple ones (without altgr or shift pressing) are supported, so characters like @ can't be typed in shortcut, you'll have to use typeout for that. (Or use `altgr+v` on slovenian layout). If there are no commas (`,`) in the `do` field the driver now releases the pressed keys when you release the GKey bind to it, so you can use them as a modifier.
-
-#### Starting a program - `"run"`  
-If you want to run something that interacts with gnome or your desktop service you need to wrap the call with su and your username:
-   ```bash
-   su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null
-   ```
-
-#### Execute a snippet of Python code - `"python"`  
-A Python one-line script. If output is desired, the script should define a global variable named `output_string` and set it to the string to be output.
-
-#### Map a G-Key to a different key - `"uinput"`
-A key defined by python3-uinput to emit (ex. `KEY_F13` or `KEY_KATAKANA`)  
-A full list of all available keys you can find [here](https://github.com/tuomasjjrasanen/python-uinput/blob/master/src/ev.py).
-
-#### Do nothing - `"nothing"`
-
-Also, not all possible characters and control keys are supported (yeah no emojis!). Supported characters and control keys can be viewed in [char_uinput_mapper.py](https://github.com/JSubelj/g910-gkey-macro-support/blob/master/lib/data_mappers/char_uinput_mapper.py).
-
-
->It is also worth pointing out that Enter and Tab keys are pressed while typing out `\n` and `\t`, so you can use this when controlling a program like vim or terminal without using `shortcut`.
-
-## Example config for writing a test file by pressing gkeys
-```
-{
-    "keyboard_mapping": "si",
-    "profiles": {
-        "MEMORY_1": {
-            "MACRO_1": {
-                "hotkey_type": "shortcut",
-                "do": "ctrl+alt+t"
-            },
-            "MACRO_2": {
-                "hotkey_type": "typeout",
-                "do": "vim /tmp/test-gkey.txt\n"
-            },
-            "MACRO_3": {
-                "hotkey_type": "typeout",
-                "do": "iThis Is a Test \n \t also %$&$\"& characters."
-            },
-            "MACRO_4": {
-                "hotkey_type": "shortcut",
-                "do": "esc"
-            },
-            "MACRO_5": {
-                "hotkey_type": "typeout",
-                "do": ":wq\n"
-            },
-            "MACRO_6": {
-                "hotkey_type": "typeout",
-                "do": "cat /tmp/test-gkey.txt\n"
-            }
-        }
-    }
-}   
-```
-
-## Troubleshooting
-### JSONDecoderError
-So if you have written your config and the daemon doesn't run then you most likely have a syntax error in your config file. Since we parse the file you will get the error message from the parser in the log file:  
-`tail -f /var/log/g910-gkeys.log`
-
-### Other Config Problems
-If the functionality still isn't what you expect, look into the logs: `/var/log/g910-gkey.log`  
-There should be a warning of what is wrong, similar to this:  
-`2018-11-21 19:21:40,576 [WARNING] {lib.data_mappers.config_reader} - Error(s) in config: {'g3': {'hotkey_type': 'typout does not exist!'}, 'g6': {'hotkey_type': 'typout does not exist!'}}`  
-This says that `typout` does not exist for `hotkey_type`. To correct it I had to change `'hotkey_type': 'typout'` to `'hotkey_type': 'typeout`.
-
-### Other Errors
-If you find yourself with an error not listed above please take a look at the [troubleshooting](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Troubleshooting).
\ No newline at end of file
diff --git a/docs/Contributing.md b/docs/Contributing.md
deleted file mode 100644
index 905b161..0000000
--- a/docs/Contributing.md
+++ /dev/null
@@ -1,40 +0,0 @@
-There are many ways you can contribute to this project. But first of all I would like to thank you for using my software, trying to enhance it and giving me the energy to improve it.
-
-# Adding your code
-If you like to improve the driver first check if anyone is already working on that. If not post an Issue and/or assign yourself to it so we can know that you are working on it. If you can also post a deadline when you will probably finish. Then just fork the project (if you fork my code just to have it on your GitHub page you should be ashamed), do your magic and then issue a pull request. I will review your code and if I have any questions I will ask them in the pull request. If you don't answer in a few days I will probably decline the pull request.
-
-If you have any questions on the issue you are currently working on, send me an email or post it in the Issue you are working on and I will be glad to help.
-
-If you think you can greatly enhance the project contact me on my email (at the bottom of this page), we will talk and if I see you are interested and qualified I will add you to the team.
-
-If you don't already have a favourite ide you can try [pycharm community](https://www.jetbrains.com/de-de/pycharm/download/) it is free and has a lot of good features to help you write better code. It's also available via snap: `sudo snap install pycharm-community`
-
-# Requesting additional features
-If you have a bright new feature that you want to see in my driver and don't know how to code it in please write an Issue and if it looks good I will gladly implement it.
-
-# Correcting my grammar mistakes
-Because I am not a native speaker my english is not really good (as you probably saw). So if you like to correct the grammar mistakes please post an issue or email me and we will work this out.
-
-# Saying thanks
-If you just want to thank me for the driver send me an email and I will gladly reply to you. You are the one that keeps me going in developing this driver.
-
-# Logitech employees
-If you work for Logitech and want to use my code for an official Logitech driver for GNU/Linux (and I have to say you should be ashamed to not release it ten years ago) email me and we will work something out.
-
-# Donating
-If you would like to donate to this project please contact me on my email. If there is interest I will also set up a PayPal account or something. (I will be eternally grateful to you).
-
-# List of contributors
-I would like to thank everyone that contributed their code for the driver:
- - Jez Mckinley (https://github.com/tabashir/g910-gkey-macro-support)
-
-# Thanks
-To everyone that opened an Issue, pointing out a bug or an enhancement I am really grateful. I would especially like to thank:
- - [MatMoul](https://github.com/MatMoul) for his [g810-led](https://github.com/MatMoul/g810-led) controller
- - [xShirase](https://github.com/xShirase) for the [code](https://github.com/CReimer/g910-gkey-uinput/issues/3) on which I built this driver
- - [frostworx](https://github.com/frostworx) for contributing his [PKGBUILD script](https://github.com/JSubelj/g910-gkey-macro-support/issues/1)
- 
- # Contact information
- If you would like to send me mail please go for it. I would just like to ask you to add the name of this driver into the subject field.
- 
- My email: jan.subelj010@gmail.com
\ No newline at end of file
diff --git a/docs/Detailed-installation.md b/docs/Detailed-installation.md
deleted file mode 100644
index f9b155c..0000000
--- a/docs/Detailed-installation.md
+++ /dev/null
@@ -1,56 +0,0 @@
-## Requirements
-First check that you have the needed requirements:
- - Python 3.7 (3.6 should work)
- - uinput kernel module (more on this [here](http://tjjr.fi/sw/python-uinput/#Usage))
-
-For Arch based distros: It's live on [AUR](https://aur.archlinux.org/packages/g910-gkeys-git/)
-
-### Preperation
-If that's checked you can prepare for the setup:
- 1. Load uinput kernel module: `modprobe uinput` (on Manjaro should be loaded by default afaik)
- 
-## Installation  
-Download the driver  
-- with git use `git clone https://github.com/JSubelj/g910-gkey-macro-support.git`  
-or
-- download & unzip `wget https://github.com/JSubelj/g910-gkey-macro-support/archive/refs/heads/master.zip; unzip master.zip`  
-
-Open the directory: `cd g910-gkey-macro-support` or `cd g910-gkey-macro-support-master` if you have downloaded the zip.
-
-### Installer (recommended)
-To run the installer you need to make it executable `chmod +x installer.sh` and then execute it with admin privileges `sudo ./installer.sh`. You can do this with in one line `chmod +x installer.sh; sudo ./installer.sh`
-
-### Build package from source
-1. Build and install the package with setuptools: `sudo python3 setup.py install --record files.txt`
-2. Verify a successful build and install by running `sudo g910-gkeys -v`  
-    You should see something like this:
-      ```
-      g910-gkeys
-      
-      Support for Logitech G910 GKeys on GNU/Linux
-      
-      Created by Jan Šubelj
-      Version 0.2.5
-      ```
-3. Install the driver as a system service: `cp g910-gkeys.service /usr/lib/systemd/system; systemctl daemon-reload`
-4. To start the driver now and automatically on every boot run `systemctl enable --now g910-gkeys`
- 
-If you just want to start the driver for this session skip the last step and use: `systemctl start g910-gkeys`. You can also stop the service with `systemctl stop g910-gkeys`.
-
-#### Why running the driver with a service manager is recommended
-These are the plus sides to running the driver with a service manager and I believe there are many more:
-- You don't have to worry about the number of instances spawned. There is only one, and you can't by mistake spawn more of them
-- Service manager takes care of correctly shutting down the program
-- The driver launches as soon as possible (if enabled with `systemctl enable g910-gkeys`), giving you functionality before even the graphical environment starts
-- You can diagnose the driver by running `systemctl status g910-gkeys` and looking at systemd logs with `journalctl -u g910-gkeys`
-
-## First Steps
-The driver should work now and pressing the G1 key should typeout: *This is profile m1*  
-Be sure to enter a text window/field before hitting G1, since the type out use the focus of the cursor.
-
-### Configuring G910 macro keys
-Now that you installed the driver successfully you can configure your Gkeys mapping as described here: [Configuration](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Configuration)
-
-If the driver still doesn't work correctly troubleshoot it as described here: [Troubleshooting](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Troubleshooting)
-
-
diff --git a/docs/Home.md b/docs/Home.md
deleted file mode 100644
index 4d59cc0..0000000
--- a/docs/Home.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Logitech G910 keyboard Gkey support for GNU/Linux
-
-Because I didn't find any Gkey support for Logitech G910 keyboard I decided to create this Gkey mapper. Code is based on an [issue](https://github.com/CReimer/g910-gkey-uinput/issues/3) in [g910-gkey-uinput](https://github.com/CReimer/g910-gkey-uinput) project. I expanded the code, so that it is more user-friendly to add functionality to Gkeys.
-
-## Features
-With this driver run as a service you can bind every Gkeys with four different commands. You can bind shortcuts to it (ex. ctrl+c), type out stuff, run a bash command and execute short python snippets and type out the result.
-
-To see what is coming next look at the [roadmap](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Roadmap).
-
-## Installation
-You can find a detailed installation guide [here](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Detailed-installation).
-
-### Update
-If you have already installed a previous version of the driver and want to upgrade take a look [here](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Upgrading).
-
-### Configuration
-Everything about the configuration you will find [here](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Configuration).  
-For a more advanced configuration limiting the usage of global gkey config, where user set the actions in his/her own environment. See [here](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Configuration-strict-user-environment.md)
-
-### Troubleshooting
-If you have problems installing or running the driver you can have a look [here](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Troubleshooting).
-
-### Uninstall
-Information about how to remove driver from you system are [here](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Uninstalling)
-
-## Contributing
-If you like to contribute to this project please start [here](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Contributing)
-
-The code is tested on Logitech G910 keyboard with
-- OS: Ubuntu 20.04.6 LTS, Linux 5.4.0-159-generic, GNOME: 3.36.9
\ No newline at end of file
diff --git a/docs/Roadmap.md b/docs/Roadmap.md
deleted file mode 100644
index 3c45ddd..0000000
--- a/docs/Roadmap.md
+++ /dev/null
@@ -1,8 +0,0 @@
-This roadmaps contains set goals for the driver.
-
-# 0.2.6
- - Change log level in config.json #67
- - move config to user folder to better support multi-user-systems #63
-
-# 0.3.0
- - Refactor to object-oriented style to better handle circular imports
\ No newline at end of file
diff --git a/docs/Run-graphic-programs.md b/docs/Run-graphic-programs.md
deleted file mode 100644
index 5fd0524..0000000
--- a/docs/Run-graphic-programs.md
+++ /dev/null
@@ -1,29 +0,0 @@
-## Shortcut (recommended)
-If you want to launch graphical programs by pressing g-keys just set a shortcut to run a program in your shortcut manager, assign that shortcut to a GKey and you're good to go! If your not sure how to do it you can take a look at the [advanced How-To](Configuration-strict-user-environment.org).
-
-## Run command (not recommended)
-If you are in a single user environment you can config a run command to start a graphical program with `su <username> -c 'nohub <programm>'`. The use of `nohub` will keep the program open. If the program writes to stdout you need to redirect it to /dev/null. Here is an example how to open the gnome-terminal:
-```
-su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null
-```
-Replace <username> with your username. If the program supports it you can define the DISPLAY variable with the screen you want the program to start up.
-
->**Important:**  
-The keys are always active with the "run" type, even if nobody is logged in, logged in as another user, if the screen is locked, or even when the user is switched to another one (the first session still being active): In the first 2 cases the program will be launched but will fail (the DISPLAY does not exist), but will be successful in the 2 other cases (screen locked or user switched).
->
->If you are in a multi-user-environment you can't use the method explained above since there is only one global config for g-keys. The driver will be available soon after boot and even in none graphical environments you need to keep in mind that the run commands you put in your config will be executed with no limitations. The driver is handled as service by systemd and executed by root. There is a huge difference between a "run" command, with or without su and the simple mapping to another key by shortcut.
-
-~~Well first of all. This driver is, as it is said a driver. It is not meant to run as a normal program that can start graphical processes and what not. There are multiple restrains for that:~~
- - ~~Once again it is a driver and a daemon. It is not designed to be like a Logitech "driver", that pops up, has weird configuration and if you force shut it down your computer won't boot. It is meant to sit between a keyboard and the system (even though it is run in userspace) and work regardless of the environment. It is not dependant on X server and because of that you can use it even in non graphical environment.~~
- - ~~Because it is not dependant of a graphical environment it also does not have any idea what are the DISPLAY variables, which Xorg server is used etc. and so, the graphical programs that would be spawned by the driver also don't have a clue so they cannot start.~~
- - ~~The daemon is also meant to start asap as the system boots, so that all the GKey support is right there even at login, so waiting for an Xorg server to start would be contradictory.~~
-
-~~## But I REALLY want to start programs with it (also why I don't advise to run the driver as a program and not as a systemd service)~~
-~~Ok. I give up. You actually can. But I don't recommend it. You can do that by disabling the service if you enabled it and then in your desktop environment set to autostart it when you log in. Now you can run any program as you would if you run it from command line just set the `hotkey_type` in [config](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Configuration) to `run` and `do` to the command line argument (ex. `firefox`). Hurrah you win! But now listen to my concerns with this kind of abusing the driver:~~
- - ~~Using the driver like that, you can never know if its running or not (you can look for the pid with `pidof python`), the output of the driver is not saved, so you don't know if anything went wrong.~~ 
- - ~~Because of that you have to always check if the driver is already running, and if you by mistake spawn multiple instances of the driver, the actions can be duplicated, logs can be filled by warnings that the driver can't bind to the device and some more possible headaching behaviour.~~
- - ~~The system sometimes shuts this kind of programs correctly (by sending SIGTERM to them and waiting to shut down) or they can not wait for it sending it SIGKILL signal before it can properly shutdown. Because of that you can have problems like computer not even booting to bios, because uinput handler didn't close correctly. (If you do then I found out that unplugging the keyboard and hard resetting the computer does the trick)~~
- - ~~The driver now doesn't work in non graphical environments.~~
- - ~~All programs spawned have Superuser privileges (because the driver also has them) and that can also bring some unwanted problems, to not even touch the security concern.~~
-
-~~So I hope I changed your mind, and you will use the driver as intended. (But if you don't and stumble on a problem that you can't fix yourself feel free to open an [issue](https://github.com/JSubelj/g910-gkey-macro-support/issues), and I'll try to help as much as I can).~~
\ No newline at end of file
diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md
deleted file mode 100644
index ad29998..0000000
--- a/docs/Troubleshooting.md
+++ /dev/null
@@ -1,32 +0,0 @@
-So you stumbled on an issue and you don't know where to look at what went wrong. No problem, I'm here to help.
-
-## Installation Troubleshooting
-
-First you need to make sure that the version of Python is >=3.7 (3.6 should also work) with `python3 --version`.
-If you have the 3.7 installed but the above command returns some other version, try command `python3.7 --version`. Then run `sudo python3.7 setup.py install`.
-
-On some distros there was also problems with not having python devel, pip and gcc installed so try check that you have those packages installed.
-
-There has also been a few reported issues with installing the software on various platforms. Check out the [Issues](https://github.com/JSubelj/g910-gkey-macro-support/issues?q=is%3Aissue+is%3Aclosed+label%3A%22good+first+issue%22) with tag `good first issue`.
-
-
-## Execution Troubleshooting
-
-The main information you can get is systemd logs and driver's log. Systemd status and logs can be found by running:
-
-- status: `systemctl status g910-gkeys`
-- logs: `journalctl -u g910-gkeys`
-
-Those two should give you enough information to figure out why the driver didn't start or why it shut down unexpectedly.
-
-If the driver runs but does not work as you expect it to, then your best place to look is in: `/var/log/g910-gkeys.log`, where the behaviour of the driver is logged. There you can see if there is a problem with your [configuration](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Configuration) or if there are errors (like not finding the device). 
-
-If you want to see exactly if driver catches the GKey or media button event and what the HEX-code is, change logger level to `DEBUG` in [logger.py](https://github.com/JSubelj/g910-gkey-macro-support/blob/5caa954019a835906f80950d1f21877e9b1b7405/lib/misc/logger.py#L13) and rebuild the driver (will probably make it dynamically changeable in the future).
-
-If you still can't figure out why it doesn't work, check that GKey to FKey mapping is disabled (you can do this by pressing G5 in a browser. If the page reloads the mapping is not disabled). If the mapping is not disabled try restarting the driver but if that still doesn't work install [g810-led controller](https://github.com/MatMoul/g810-led) and disable the mapping with `g910-led -gkm 1` then restart the driver. 
- 
-If still nothing then try restarting your computer or plugging the keyboard in and out. 
-
-If still no luck, try reinstalling the software and then if still nothing please post an [issue](https://github.com/JSubelj/g910-gkey-macro-support/issues), describe the problem in detail add the configuration, logs and systemctl log via pastebin (or whatever you prefer) and I will try to help.
- 
-
diff --git a/docs/Uninstalling.md b/docs/Uninstalling.md
deleted file mode 100644
index 6ea4cc5..0000000
--- a/docs/Uninstalling.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Uninstall the package
-To remove the package fully you need to navigate to the directory you installed the driver from.
-
->If you deleted the directory you can [install](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Detailed-installation) the driver once again to run the uninstall script after. It is important to run the installer in the first place, because it will create the files.txt which is needed.
-
-## Uninstaller (recommended)
-Run the uninstalling script from the directory you installed the driver:  
-`chmod +x uninstall.sh; sudo ./uninstall.sh`.
-
-If you won't be reinstalling the program (sad to see you go), you should also remove the configuration, so it doesn't bloat your `/etc/` folder:  
-`sudo ./uninstall.sh -a`
-
-## Remove the package manually (versions below v0.2.5)
- 1. Delete package files from installed system folder: `cat files.txt | sudo xargs rm -rf`
- 2. Remove package from pip: `sudo pip uninstall g910-gkeys`
- 3. Disable service: `systemctl disable g910-gkeys`
-
-If you won't be reinstalling the program (sad to see you go), you should also remove the configuration, so it doesn't bloat your `/etc/` folder: `rm /etc/g910-gkeys -rf`
-
-> For older Versions:  
-> To remove the module from pip you should run `pip list | grep g910` and then `sudo pip uninstall ${names that were returned by the previous command}`. This is because I renamed the driver from "g910-gkey-macro-support" to "g910-gkeys" for shorter and easier understanding.  
-> 
-> Remove the service file with: `rm /usr/lib/systemd/system/g910-gkeys.service`
\ No newline at end of file
diff --git a/docs/Upgrading.md b/docs/Upgrading.md
deleted file mode 100644
index a8a06ff..0000000
--- a/docs/Upgrading.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## Uninstall the old version
-It is recommended to first uninstall the driver (as seen in [Uninstalling](https://github.com/JSubelj/g910-gkey-macro-support/wiki/Uninstalling) section), of course not removing the `/etc/g910-gkeys/config.json`.
-
-## For not an ArchLinux based distro
-After the uninstall run `sudo python setup.py install` and the program should install itself.
- 
-
-## For ArchLinux based distro
-Even though the upper command will work on Arch based distros it is better to install the program by pulling the pkgbuild folder, building the .tar.gz with `makepkg` and installing with pacman: `pacman -U g910-gkeys-git-*.*.*-1-any.pkg.tar.xz` where you fill in the correct version number.
-
-Even better, use the [AUR](https://aur.archlinux.org/packages/g910-gkeys-git/)
-
-### Use profile feature after upgrade to 0.2.4
- If you update from version <= v0.2.4 you will need to make some manual changes to your `/etc/g910-gkeys/config.json` to make use of the new gkey profile feature.
- You don't need to do anything if you don't want to use the profile feature your old config will be loaded as default profile m1.
\ No newline at end of file
diff --git a/docs/img/autokey.png b/docs/img/autokey.png
deleted file mode 100644
index 8056559..0000000
Binary files a/docs/img/autokey.png and /dev/null differ
diff --git a/docs/img/date.png b/docs/img/date.png
deleted file mode 100644
index 14b03bb..0000000
Binary files a/docs/img/date.png and /dev/null differ
diff --git a/docs/img/g910-keyboard-settings.png b/docs/img/g910-keyboard-settings.png
deleted file mode 100644
index eb0407c..0000000
Binary files a/docs/img/g910-keyboard-settings.png and /dev/null differ
diff --git a/docs/img/konnichiwa.png b/docs/img/konnichiwa.png
deleted file mode 100644
index 1443217..0000000
Binary files a/docs/img/konnichiwa.png and /dev/null differ
diff --git a/docs/img/sayonara.png b/docs/img/sayonara.png
deleted file mode 100644
index 946013d..0000000
Binary files a/docs/img/sayonara.png and /dev/null differ
diff --git a/docs/img/yama.png b/docs/img/yama.png
deleted file mode 100644
index 7e347ac..0000000
Binary files a/docs/img/yama.png and /dev/null differ
diff --git a/etc/60-g910-gkeys.rules b/etc/60-g910-gkeys.rules
index 9ea74ac..81786a6 100644
--- a/etc/60-g910-gkeys.rules
+++ b/etc/60-g910-gkeys.rules
@@ -3,5 +3,6 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c33f", TAG+="uacc
 SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c33e", TAG+="uaccess"
 SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c32b", TAG+="uaccess"
 SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c24d", TAG+="uaccess"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c22d", TAG+="uaccess"
 
 KERNEL=="uinput", TAG+="uaccess"
\ No newline at end of file
diff --git a/docs/ex_config/ex_config.json b/etc/config.json
similarity index 83%
rename from docs/ex_config/ex_config.json
rename to etc/config.json
index f11cd00..5bd6fbc 100644
--- a/docs/ex_config/ex_config.json
+++ b/etc/config.json
@@ -2,7 +2,6 @@
   "__comment" : "following hotkey types are supported: nothing, typeout, shortcut and run; only en, fr, de and si keyboard mappings are currently supported",
   "keyboard_mapping": "en",
   "notify": "True",
-  "username": "",
   "profiles": {
     "MEMORY_1": {
       "MACRO_1": {
@@ -15,7 +14,7 @@
       },
       "MACRO_3": {
         "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
+        "do": "DISPLAY=:0 nohup gnome-terminal & 2>&1 > /dev/null"
       },
       "MACRO_4": {
         "hotkey_type": "python",
@@ -33,7 +32,7 @@
       },
       "MACRO_3": {
         "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
+        "do": "DISPLAY=:0 nohup gnome-terminal & 2>&1 > /dev/null"
       },
       "MACRO_4": {
         "hotkey_type": "python",
@@ -51,7 +50,7 @@
       },
       "MACRO_3": {
         "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
+        "do": "DISPLAY=:0 nohup gnome-terminal & 2>&1 > /dev/null"
       },
       "MACRO_4": {
         "hotkey_type": "python",
@@ -69,12 +68,15 @@
       },
       "MACRO_3": {
         "hotkey_type": "run",
-        "do": "su <username> -c 'DISPLAY=:0 nohup gnome-terminal' & 2>&1 > /dev/null"
+        "do": "DISPLAY=:0 nohup gnome-terminal & 2>&1 > /dev/null"
       },
       "MACRO_4": {
         "hotkey_type": "python",
         "do": "import uuid; global output_string; output_string = str(uuid.uuid4());"
       }
     }
-  }
+  },
+  "logging": "True",
+  "log_path": "g910-gkeys.log",
+  "log_level": "INFO"
 }
diff --git a/etc/g910-gkeys.service b/etc/g910-gkeys.service
index 779e800..7b82750 100644
--- a/etc/g910-gkeys.service
+++ b/etc/g910-gkeys.service
@@ -3,9 +3,13 @@ Description=Support for Logitech g910 keyboard gkeys
 Documentation=https://github.com/JSubelj/g910-gkey-macro-support/wiki
 
 [Service]
+Type=simple
 ExecStart=/usr/bin/env g910-gkeys
-TimeoutStopSec=3
+ExecReload=/bin/kill -SIGUSR1 $MAINPID
+TimeoutStopSec=5
+Restart=on-failure
+RestartSec=10
 
 
 [Install]
-WantedBy=multi-user.target
\ No newline at end of file
+WantedBy=default.target
\ No newline at end of file
diff --git a/lib/__init__.py b/g910_gkeys/__init__.py
similarity index 100%
rename from lib/__init__.py
rename to g910_gkeys/__init__.py
diff --git a/lib/data_mappers/__init__.py b/g910_gkeys/data_mappers/__init__.py
similarity index 100%
rename from lib/data_mappers/__init__.py
rename to g910_gkeys/data_mappers/__init__.py
diff --git a/lib/data_mappers/bytearrays.py b/g910_gkeys/data_mappers/bytearrays.py
similarity index 100%
rename from lib/data_mappers/bytearrays.py
rename to g910_gkeys/data_mappers/bytearrays.py
diff --git a/lib/data_mappers/char_uinput_mapper.py b/g910_gkeys/data_mappers/char_uinput_mapper.py
similarity index 100%
rename from lib/data_mappers/char_uinput_mapper.py
rename to g910_gkeys/data_mappers/char_uinput_mapper.py
diff --git a/lib/data_mappers/supported_configs.py b/g910_gkeys/data_mappers/supported_configs.py
similarity index 100%
rename from lib/data_mappers/supported_configs.py
rename to g910_gkeys/data_mappers/supported_configs.py
diff --git a/lib/data_mappers/supported_devices.py b/g910_gkeys/data_mappers/supported_devices.py
similarity index 100%
rename from lib/data_mappers/supported_devices.py
rename to g910_gkeys/data_mappers/supported_devices.py
diff --git a/lib/data_mappers/uinput_all_keys.py b/g910_gkeys/data_mappers/uinput_all_keys.py
similarity index 100%
rename from lib/data_mappers/uinput_all_keys.py
rename to g910_gkeys/data_mappers/uinput_all_keys.py
diff --git a/lib/g910_gkey_mapper.py b/g910_gkeys/g910_gkeys.py
similarity index 75%
rename from lib/g910_gkey_mapper.py
rename to g910_gkeys/g910_gkeys.py
index e815bbe..994afa9 100644
--- a/lib/g910_gkey_mapper.py
+++ b/g910_gkeys/g910_gkeys.py
@@ -1,13 +1,16 @@
+import argparse
 import fcntl
+import importlib.metadata
 import os
 import signal
 import time
 import uinput
-from lib.misc.config import Config
-from lib.usb_device import USBDevice
-from lib.keyboard import Keyboard
-from lib.misc import notify, memory_leds
-from lib.misc.logger import Logger
+from g910_gkeys.misc.helper import Helper
+from g910_gkeys.misc.config import Config
+from g910_gkeys.lib.usb_device import USBDevice
+from g910_gkeys.lib.keyboard import Keyboard
+from g910_gkeys.misc import notify, memory_leds
+from g910_gkeys.misc.logger import Logger
 
 config: Config = Config()
 log = Logger().logger(__name__)
@@ -29,6 +32,11 @@ def config_changed_handler(sig, frame):
     config.update_config()
 
 
+def reload_handler(sig, frame):
+    log.info(f"Reload g910-gkeys.")
+    config.update_config()
+
+
 def change_profile(dev: USBDevice, profile: str):
     log.info(f"Change profile to {profile}.")
     config.profile = profile
@@ -38,6 +46,27 @@ def change_profile(dev: USBDevice, profile: str):
 
 
 def main():
+    global device
+    parser = argparse.ArgumentParser(description=importlib.metadata.metadata("g910-gkeys")["summary"])
+    parser.add_argument("--create-config", help="Creates new config with current keyboard layout",
+                        action='store_true', default=False)
+    parser.add_argument("-s", "--set-config", help="Set the config file to use",
+                        default='', dest="config_file")
+    parser.add_argument("-v", "--version", help="Displays the information about the driver",
+                        action='version', version=f"%(prog)s {Helper.get_version()} by {Helper.get_author()}")
+    args = parser.parse_args()
+    if args.create_config:
+        device = USBDevice()  # init usb device and keyboard interface
+        config.create(device.keyboard)  # create config with keyboard interface
+        device.__exit__()  # clean up usb connection
+    elif args.config_file != "":
+        config.config_path = args.config_file
+        start()
+    else:
+        start()
+
+
+def start():
     global program_running, device, keyboard
     log.info("--------------------------------------------------------------------------------")
     log.info(f"----------------------STARTED g910-keys-pid:{str(os.getpid())}------------------------------")
@@ -47,6 +76,7 @@ def main():
     signal.signal(signal.SIGTERM, signal_handler)
     signal.signal(signal.SIGQUIT, signal_handler)
     signal.signal(signal.SIGIO, config_changed_handler)
+    signal.signal(signal.SIGUSR1, reload_handler)
 
     if program_running:
         # usb keyboard
diff --git a/layout_config_helpers.py b/g910_gkeys/layout_config_helpers.py
similarity index 94%
rename from layout_config_helpers.py
rename to g910_gkeys/layout_config_helpers.py
index 73a08a2..c9390e7 100644
--- a/layout_config_helpers.py
+++ b/g910_gkeys/layout_config_helpers.py
@@ -1,18 +1,20 @@
 """
     This file contains functions that can help you get the right config for your layout.
 """
+import argparse
+import importlib.metadata
 import signal
 import sys
 import tty
 import termios
 import uinput  # used to eval keys
-import lib.data_mappers.char_uinput_mapper as uinput_mapper
-from lib.data_mappers.char_uinput_mapper import keys as locale_key_mapping
-from lib.usb_device import USBDevice
-from lib.keyboard import Keyboard, KeyInputTimeoutException
-from lib.data_mappers.bytearrays import keys as uinput_key_map, commands as uinput_if1
-from lib.misc.helper import Helper
-from lib.misc.config import Config
+import g910_gkeys.data_mappers.char_uinput_mapper as uinput_mapper
+from g910_gkeys.data_mappers.char_uinput_mapper import keys as locale_key_mapping
+from g910_gkeys.lib.usb_device import USBDevice
+from g910_gkeys.lib.keyboard import Keyboard, KeyInputTimeoutException
+from g910_gkeys.data_mappers.bytearrays import keys as uinput_key_map, commands as uinput_if1
+from g910_gkeys.misc.helper import Helper
+from g910_gkeys.misc.config import Config
 
 
 class LayoutHelper:
@@ -286,11 +288,8 @@ def __exit__(self):
             pass  # pass if no uinput device was initialized
 
 
-if __name__ == "__main__":
-    import argparse
-    from lib import PROJECT_INFO
-
-    parser = argparse.ArgumentParser(description=PROJECT_INFO.DESCRIPTION)
+def main():
+    parser = argparse.ArgumentParser(description=f'{importlib.metadata.metadata("g910-gkeys")["summary"]} - Layout config helpers')
     parser.add_argument("--read0", help="Read the raw bytes from interface 0 (default keys)",
                         action='store_true', default=False)
     parser.add_argument("--read1", help="Read the raw bytes from interface 1 (macro- and media-keys)",
@@ -302,7 +301,7 @@ def __exit__(self):
     parser.add_argument("-u", "--uinput", help="Get uinput key from key press",
                         action='store_true', default=False)
     parser.add_argument("-v", "--version", help="Displays version of the driver",
-                        action='version', version='%(prog)s ' + PROJECT_INFO.VERSION)
+                        action='version', version=f"%(prog)s {Helper.get_version()} by {Helper.get_author()}")
     args = parser.parse_args()
 
     command = "help"
@@ -318,3 +317,7 @@ def __exit__(self):
         command = "uinput"
 
     LayoutHelper(command)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/lib/misc/__init__.py b/g910_gkeys/lib/__init__.py
similarity index 100%
rename from lib/misc/__init__.py
rename to g910_gkeys/lib/__init__.py
diff --git a/lib/keyboard.py b/g910_gkeys/lib/keyboard.py
similarity index 94%
rename from lib/keyboard.py
rename to g910_gkeys/lib/keyboard.py
index 34a8f5a..49d4cd4 100644
--- a/lib/keyboard.py
+++ b/g910_gkeys/lib/keyboard.py
@@ -2,11 +2,11 @@
 import time
 import uinput
 import subprocess
-from lib.data_mappers import supported_configs
-from lib.data_mappers.char_uinput_mapper import keys, reverse_keys
-from lib.data_mappers.uinput_all_keys import uinput_all_keys
-from lib.data_mappers.supported_devices import KeyboardInterface
-from lib.misc.logger import Logger
+from g910_gkeys.data_mappers import supported_configs
+from g910_gkeys.data_mappers.char_uinput_mapper import keys, reverse_keys
+from g910_gkeys.data_mappers.uinput_all_keys import uinput_all_keys
+from g910_gkeys.data_mappers.supported_devices import KeyboardInterface
+from g910_gkeys.misc.logger import Logger
 
 output_string = ''
 
diff --git a/lib/usb_device.py b/g910_gkeys/lib/usb_device.py
similarity index 97%
rename from lib/usb_device.py
rename to g910_gkeys/lib/usb_device.py
index f1c3a58..17cb1af 100644
--- a/lib/usb_device.py
+++ b/g910_gkeys/lib/usb_device.py
@@ -1,8 +1,8 @@
 import time
 import usb
 import signal
-from lib.data_mappers.supported_devices import KeyboardInterface, SUPPORTED_DEVICES
-from lib.misc.logger import Logger
+from g910_gkeys.data_mappers.supported_devices import KeyboardInterface, SUPPORTED_DEVICES
+from g910_gkeys.misc.logger import Logger
 
 
 class USBDevice:
diff --git a/tests/__init__.py b/g910_gkeys/misc/__init__.py
similarity index 100%
rename from tests/__init__.py
rename to g910_gkeys/misc/__init__.py
diff --git a/lib/misc/config.py b/g910_gkeys/misc/config.py
similarity index 90%
rename from lib/misc/config.py
rename to g910_gkeys/misc/config.py
index f2bdac5..1b1f1b6 100644
--- a/lib/misc/config.py
+++ b/g910_gkeys/misc/config.py
@@ -2,9 +2,9 @@
 import os
 import signal
 from json.decoder import JSONDecodeError
-from lib.misc.helper import Helper
-from lib.data_mappers import supported_configs, char_uinput_mapper
-from lib.misc.logger import Logger
+from g910_gkeys.misc.helper import Helper
+from g910_gkeys.data_mappers import supported_configs, char_uinput_mapper
+from g910_gkeys.misc.logger import Logger
 
 
 class ConfigException(Exception):
@@ -17,27 +17,14 @@ class Config:
 
     profile: str = None
 
-    config_dir: str
+    config_dir: str = os.getenv("HOME") + "/.config/g910-gkeys"
 
-    config_path: str
+    config_path: str = config_dir + "/config.json"
 
-    logs_path: str
+    logs_path: str = os.getenv("HOME") + "/g910-gkeys.log"
 
     def __init__(self):
         self.profile = supported_configs.default_profile
-        # set config path
-        if Helper.is_installed():
-            self.config_dir = "/etc/g910-gkeys"
-            self.config_path = self.config_dir + "/config.json"
-        else:
-            main_dir = Helper.get_base_path()
-            self.config_dir = os.path.join(main_dir, "config")
-            self.config_path = self.config_dir + "/config.json"
-        # set log path
-        if os.geteuid() != 0:
-            self.logs_path = "g910-gkeys.log"
-        else:
-            self.logs_path = "/var/log/g910-gkeys.log"
 
     @staticmethod
     def validate_hotkey_action(do, hotkey_action, keyboard_mapping):
@@ -95,8 +82,7 @@ def validate_config(self, config_dic: dict):
         if keyboard_mapping not in supported_configs.keyboard_mappings:
             return {"keyboard_mapping": keyboard_mapping+" does not exist!"}, None
 
-        return_config["notify"] = config_dic.get("notify", False)
-        return_config["username"] = config_dic.get("username", "")
+        return_config["notify"] = config_dic.get("notify", "False")
 
         profile_start_range = 1
         return_config["profiles"] = {}
@@ -123,6 +109,10 @@ def validate_config(self, config_dic: dict):
                 except ConfigException as e:
                     errors += [e]
 
+        return_config["logging"] = config_dic.get("logging", "False")
+        return_config["log_path"] = config_dic.get("log_path", os.getenv("HOME") + "/g910-gkeys.log")
+        return_config["log_level"] = config_dic.get("log_level", "INFO")
+
         if len(errors) > 0:
             raise ConfigException(errors)
         else:
diff --git a/lib/misc/helper.py b/g910_gkeys/misc/helper.py
similarity index 52%
rename from lib/misc/helper.py
rename to g910_gkeys/misc/helper.py
index 9f56873..3f737ba 100644
--- a/lib/misc/helper.py
+++ b/g910_gkeys/misc/helper.py
@@ -1,3 +1,5 @@
+import email.policy
+import importlib.metadata
 import locale
 import os
 import sys
@@ -20,3 +22,17 @@ def get_locale():
     def get_base_path():
         main_dir = os.path.abspath(os.getcwd())
         return main_dir
+
+    @staticmethod
+    def get_version():
+        return importlib.metadata.version('g910-gkeys')
+
+    @staticmethod
+    def get_author():
+        em = email.message_from_string(
+            f"To: {importlib.metadata.metadata('g910-gkeys')['author-email']}",
+            policy=email.policy.default
+        )
+
+        for address in em['to'].addresses:
+            return address.display_name
diff --git a/lib/misc/logger.py b/g910_gkeys/misc/logger.py
similarity index 74%
rename from lib/misc/logger.py
rename to g910_gkeys/misc/logger.py
index bae6410..743d101 100644
--- a/lib/misc/logger.py
+++ b/g910_gkeys/misc/logger.py
@@ -16,11 +16,13 @@ class Logger:
     }
 
     def __init__(self, log_level: int = logging.DEBUG):
-        from lib.misc.config import Config
+        from g910_gkeys.misc.config import Config
         config = Config()
-        log_level = config.load().get('log_level', 'INFO')
+        config_dict = config.load()
+        log_level = config_dict.get('log_level', 'INFO')
         self.log_level = self.log_level_map[log_level]
-        self.log_to_file(config.logs_path, self.log_level)
+        if config_dict.get('logging', "False") != "False":
+            self.log_to_file(config_dict.get('log_path', config.logs_path), self.log_level)
 
     def logger(self, name=None):
         log = logging.getLogger(name)
@@ -45,3 +47,7 @@ def log_to_file(self, filename, log_level):
                 os.rename(filename, filename + ".old")
         except:
             pass
+
+    def set_log_level(self, log_level):
+        self.log_level = self.log_level_map[log_level]
+        self.file_handler.setLevel(self.log_level)
diff --git a/lib/misc/memory_leds.py b/g910_gkeys/misc/memory_leds.py
similarity index 89%
rename from lib/misc/memory_leds.py
rename to g910_gkeys/misc/memory_leds.py
index 886dde4..2ef5b27 100644
--- a/lib/misc/memory_leds.py
+++ b/g910_gkeys/misc/memory_leds.py
@@ -1,6 +1,6 @@
 import usb
-from lib.usb_device import USBDevice
-from lib.misc.logger import Logger
+from g910_gkeys.lib.usb_device import USBDevice
+from g910_gkeys.misc.logger import Logger
 
 
 def change_profile(device: USBDevice, profile: str):
diff --git a/g910_gkeys/misc/notify.py b/g910_gkeys/misc/notify.py
new file mode 100644
index 0000000..57e9eb2
--- /dev/null
+++ b/g910_gkeys/misc/notify.py
@@ -0,0 +1,22 @@
+import subprocess
+import os
+from g910_gkeys.misc.config import Config
+from g910_gkeys.misc.logger import Logger
+
+
+class Notification:
+
+    log = None
+
+    config: Config = None
+
+    def __init__(self, config: Config):
+        self.log = Logger().logger(__name__)
+        self.config = config
+
+    def send_notification(self, profile: str):
+        config = self.config.read()
+        if config['notify'] != "False":
+            command = f"notify-send -i keyboard Logitech-G910 \"Switched profile to {profile}\""
+            self.log.debug(f"Sending notification: /bin/bash -c {command}")
+            subprocess.Popen(['/bin/bash', '-c', command], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
diff --git a/installer.sh b/installer.sh
index b853428..43bd82f 100755
--- a/installer.sh
+++ b/installer.sh
@@ -5,13 +5,7 @@
 # options:
 #  -n: DO NOT enable and start systemd service.
 
-# check if we are 'root' user.
-(( EUID != 0 )) && echo Must be root to run this script. Exiting. &&
-    exit 1
-
 # get system unit directory
-DESTINATION=$(pkg-config systemd --variable=systemdsystemunitdir)
-FILES=files.txt
 START_SERVICE=y
 SUPPORTED_KEYBOARDS=(de en fr si)
 KEYBOARD=$(locale | grep LANG= | cut -d= -f2 | cut -d_ -f1)
@@ -32,26 +26,57 @@ done
 
 [[ ! " ${SUPPORTED_KEYBOARDS[*]} " =~ ${KEYBOARD} ]] &&
 	echo "Your system default language is $KEYBOARD, but it's not supported." &&
-	echo "You can try to run: sudo python3 cli_entry_point.py -l create" &&
-	echo "You need to add the created mapping to lib.data_mappers.char_uinput_mapper and" &&
-	echo "add your locale to lib.data_mappers.supported_configs, before installing again." &&
+	echo "You can try to run: python3 cli_layout_config_helpers.py --create" &&
+	echo "You need to add the created mapping to g910-gkeys.lib.data_mappers.char_uinput_mapper and" &&
+	echo "add your locale to g910-gkeys.lib.data_mappers.supported_configs, before installing again." &&
+	echo "The locale also have to be added to this installer script 10:SUPPORTED_KEYBOARDS." &&
 	echo "Please open a feature request on github with your language:" &&
 	echo "https://github.com/JSubelj/g910-gkey-macro-support/issues/new/choose" &&
 	exit 1
 
-python3 setup.py install --record "$FILES"
+# install via pip
+pip install -e ./
+
+# make config dir
+if [[ ! -d "$HOME"/.config/g910-gkeys ]]; then
+  mkdir "$HOME"/.config/g910-gkeys
+fi
+
+# check for existing config file
+if [[ ! -f "$HOME"/.config/g910-gkeys/config.json ]]; then
+  if [[ -f /etc/g910-gkeys/config.json ]]; then
+    # if old config exist move it to new location (will need root privileges)
+    sudo mv /etc/g910-gkeys/config.json "$HOME"/.config/g910-gkeys/config.json
+    sudo chown "$USER":"$USER" "$HOME"/.config/g910-gkeys/config.json
+  else
+    # if not copy default config to config dir
+    cp ./etc/config.json "$HOME"/.config/g910-gkeys/config.json
+  fi
+fi
+
+# copy service unit to user home
+if [[ -d "$HOME"/.config/systemd/user ]]; then
+  cp ./etc/g910-gkeys.service "$HOME"/.config/systemd/user/g910-gkeys.service
+fi
 
-# systemd service file
-echo "$DESTINATION"/g910-gkeys.service >> "$FILES"
-cp etc/g910-gkeys.service "$DESTINATION"/g910-gkeys.service
+# copy udev rules
+if [[ ! -f /etc/udev/rules.d/60-g910-gkeys.rules ]]; then
+ sudo cp ./etc/60-g910-gkeys.rules /etc/udev/rules.d/60-g910-gkeys.rules
+fi
+
+# enable uinput in kernel
+if [[ ! -f /etc/modules-load.d/uinput-g910-gkeys.conf ]]; then
+  sudo cp ./etc/uinput-g910-gkeys.conf /etc/modules-load.d/uinput-g910-gkeys.conf
+fi
 
-systemctl daemon-reload
+# reload daemon
+systemctl --user daemon-reload
 
 # enable and start service if necessary
 if [[ $START_SERVICE = y ]]; then
-    systemctl enable --now g910-gkeys.service
+    systemctl --user enable --now g910-gkeys.service
 else
     echo "g910-gkeys service was not started."
     echo "You can enable/start it with this command: "
-    echo "  systemctl enable --now g910-gkeys.service"
+    echo "  systemctl --user enable --now g910-gkeys.service"
 fi
diff --git a/lib/PROJECT_INFO.py b/lib/PROJECT_INFO.py
deleted file mode 100644
index 2e60529..0000000
--- a/lib/PROJECT_INFO.py
+++ /dev/null
@@ -1,7 +0,0 @@
-NAME = 'g910-gkeys'
-DESCRIPTION = 'Support for Logitech G910 GKeys on GNU/Linux'
-URL = 'https://github.com/JSubelj/g910-gkey-macro-support'
-EMAIL = 'jan.subelj010@gmail.com'
-AUTHOR = 'Jan Šubelj'
-REQUIRES_PYTHON = '>=3.7.0'
-VERSION = '0.3.0'
diff --git a/lib/misc/notify.py b/lib/misc/notify.py
deleted file mode 100644
index dd231d5..0000000
--- a/lib/misc/notify.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import subprocess
-import os
-from lib.misc.config import Config
-from lib.misc.logger import Logger
-
-
-class Notification:
-
-    log = None
-
-    config: Config = None
-
-    def __init__(self, config: Config):
-        self.log = Logger().logger(__name__)
-        self.config = config
-
-    def send_notification(self, profile: str):
-        config = self.config.read()
-        if config['notify'] == "True":
-            inner_command = f"notify-send -i keyboard Logitech-G910 \"Switched profile to {profile}\""
-            command = None
-            if os.geteuid() == 0:
-                if config['username'] != "":
-                    # if run as root service use su <username> wrapper
-                    command = f"su {config['username']} -c '{inner_command}'"
-                else:
-                    self.log.warn("Notifications enabled but no username set in config!")
-            else:
-                command = inner_command  # if run as user we can use notify-send directly
-
-            if command is not None:
-                self.log.debug(f"Sending notification: /bin/bash -c {command}")
-                subprocess.Popen(['/bin/bash', '-c', command], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
diff --git a/pkgbuild/PKGBUILD b/pkgbuild/PKGBUILD
index f86dbd8..e27baf9 100644
--- a/pkgbuild/PKGBUILD
+++ b/pkgbuild/PKGBUILD
@@ -3,7 +3,7 @@
 pkgname=g910-gkeys-git
 _appname=g910-gkeys
 _gitname=g910-gkey-macro-support
-pkgver=0.3.0
+pkgver=0.4.0
 pkgrel=1
 pkgdesc='GKey support for Logitech G910 Keyboard on GNU/Linux'
 url='https://github.com/JSubelj/g910-gkey-macro-support'
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..de8af6b
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,41 @@
+[build-system]
+requires = ["setuptools>=61.0.0"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "g910-gkeys"
+version = "0.4.0"
+authors = [
+    { name="Jan Šubelj", email="jan.subelj010@gmail.com" },
+    { name="Marcel Grolms", email="support@suabo.de" }
+]
+description = "Support for Logitech G910 GKeys on GNU/Linux"
+keywords = ["logitech", "keyboard", "gkey", "G910", "G915", "G815", "G710", "G510"]
+readme = "README.md"
+requires-python = ">=3.7"
+license = {file = "LICENSE"}
+classifiers = [
+    "Development Status :: 4 - Beta",
+    "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.7",
+    "Programming Language :: Python :: 3.8"
+]
+dependencies = [
+    "python-uinput==0.11.2",
+    "pyusb==1.2.1"
+]
+
+[project.urls]
+"Homepage" = "https://github.com/JSubelj/g910-gkey-macro-support"
+"Bug Tracker" = "https://github.com/JSubelj/g910-gkey-macro-support/issues"
+
+[project.scripts]
+g910-gkeys = "g910_gkeys.g910_gkeys:main"
+
+[tool.setuptools.packages.find]
+# All the following settings are optional:
+where = ["."]
+include = ["g910_gkeys*"]
+exclude = ["g910_gkeys.tests*"]
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 73d17c2..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-python-uinput==0.11.2
-pyusb==1.0.2
-setuptools>=60.2.0
\ No newline at end of file
diff --git a/setup.py b/setup.py
index a74132b..cccc564 100644
--- a/setup.py
+++ b/setup.py
@@ -1,76 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
-import io
-import os
-
-from setuptools import find_packages, setup
-import lib.PROJECT_INFO as PROJECT_INFO
-
-# Package meta-data.
-NAME = PROJECT_INFO.NAME
-DESCRIPTION = PROJECT_INFO.DESCRIPTION
-URL = PROJECT_INFO.URL
-EMAIL = PROJECT_INFO.EMAIL
-AUTHOR = PROJECT_INFO.AUTHOR
-REQUIRES_PYTHON = PROJECT_INFO.REQUIRES_PYTHON
-VERSION = PROJECT_INFO.VERSION
-
-# What packages are required for this module to be executed?
-REQUIRED = [
-    "python-uinput==0.11.2", "pyusb==1.0.2"
-]
-
-
-# The rest you shouldn't have to touch too much :)
-# ------------------------------------------------
-# Except, perhaps the License and Trove Classifiers!
-# If you do change the License, remember to change the Trove Classifier for that!
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-# Import the README and use it as the long-description.
-# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
-try:
-    with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
-        long_description = '\n' + f.read()
-except FileNotFoundError:
-    long_description = DESCRIPTION
-
-# Load the package's __version__.py module as a dictionary.
-about = {'__version__': VERSION}
+from setuptools import setup
 
 # Where the magic happens:
-setup(
-    name=NAME,
-    version=about['__version__'],
-    description=DESCRIPTION,
-    long_description=long_description,
-    long_description_content_type='text/markdown',
-    author=AUTHOR,
-    author_email=EMAIL,
-    python_requires=REQUIRES_PYTHON,
-    url=URL,
-    packages=find_packages(),
-    # If your package is a single module, use this instead of 'packages':
-    py_modules=['cli_entry_point'],
-
-    entry_points={
-        'console_scripts': ['g910-gkeys=cli_entry_point:main'],
-    },
-    install_requires=REQUIRED,
-    # extras_require=EXTRAS,
-    include_package_data=True,
-    license='GPL3',
-    classifiers=[
-        # Trove classifiers
-        # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
-        'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.7'
-    ],
-    # $ setup.py publish support.
-    cmdclass={
-    },
-)
+setup()
diff --git a/uninstall.sh b/uninstall.sh
index 92facda..7abfe1f 100755
--- a/uninstall.sh
+++ b/uninstall.sh
@@ -1,34 +1,23 @@
 #!/bin/bash
 #
-# uninstall/removes g910-gkeys.
+# uninstall g910-gkeys.
 #
 # options:
-#  -a               Remove all (configuration)
 #  -d --dry-run     Only print what would be done
 
-# check if we are 'root' user.
-(( EUID != 0 )) && echo Must be root to run this script. Exiting. &&
-    exit 1
-
-FILESLST=files.txt
 PIPCMD=""
-REMOVECONF=n
 DRYRUN=""
-CONFDIR=/etc/g910-gkeys
-OPTIONS=$(getopt -l "all,dry-run" -o "ad" -- "$@")
+OPTIONS=$(getopt -l "dry-run" -o "d" -- "$@")
 eval set -- "$OPTIONS"
 
 usage() {
-    echo "usage: ${0##*/}" [-a][-d]$'\n'
-    echo "  -a --all         Remove all (configuration)"
+    echo "usage: ${0##*/}" [-d]$'\n'
     echo "  -d --dry-run     Only print what would be done"
     echo Exiting.
 }
 
 while true; do
     case "$1" in
-        -a) REMOVECONF=y
-           ;;
         -d|--dry-run) DRYRUN="echo"
            ;;
         --)
@@ -37,33 +26,50 @@ while true; do
     shift
 done
 
+[[ $DRYRUN = "echo" ]] && ${DRYRUN} Running dry...
+
 # determine if we should use pip or pip3, pip3 being preferred
 for p in pip pip3; do
     type "$p" &>/dev/null && PIPCMD="$p"
 done
 
-# stops and disable service
+# stop and disable service
 if [[ $DRYRUN = "echo" ]]; then
-    echo "systemctl disable --now g910-gkeys &>/dev/null"
+  ${DRYRUN} sudo systemctl disable --now g910-gkeys # <= 0.3.0
+  ${DRYRUN} systemctl --user disable --now g910-gkeys # >= 0.4.0
 else
-    systemctl disable --now g910-gkeys &>/dev/null
-fi
-
-# remove all installed files (not configuration files, in /etc/g910-gkeys)
-[[ -f "$FILESLST" ]] &&
-    ${DRYRUN} xargs --arg-file="$FILESLST" rm -rf &&
-    [[ $DRYRUN = "" ]] && echo "Removed installed files"
-
-# remove configuration file[s] if requested
-if [[ "$REMOVECONF" = y ]]; then
-    ${DRYRUN} rm -rf "$CONFDIR"
-    [[ $DRYRUN = "" ]] && echo "Removed configuration files"
+  ${DRYRUN} sudo systemctl disable --now g910-gkeys &>/dev/null # <= 0.3.0
+  ${DRYRUN} systemctl --user disable --now g910-gkeys &>/dev/null # >= 0.4.0
 fi
 
 # remove pip package
 if [[ -n "$PIPCMD" ]]; then
     PIPLST=$($PIPCMD list | grep 'g910-gkeys' | cut -d " " -f 1)
     [[ -n "$PIPLST" ]] &&
-        ${DRYRUN} ${PIPCMD} uninstall "$PIPLST" &&
+        ${DRYRUN} ${PIPCMD} uninstall -q "$PIPLST" &&
         [[ $DRYRUN = "" ]] && echo "Uninstalled $PIPCMD files"
 fi
+
+# remove service unit <= 0.3.0
+if [[ -f /etc/systemd/system/g910-gkeys.service ]]; then
+    ${DRYRUN} sudo rm /etc/systemd/system/g910-gkeys.service &&
+    [[ $DRYRUN = "" ]] && echo "Removed service unit /etc/systemd/system/g910-gkeys.service"
+fi
+
+# remove service unit >= 0.4.0
+if [[ -f "$HOME"/.config/systemd/user/g910-gkeys.service ]]; then
+    ${DRYRUN} rm "$HOME"/.config/systemd/user/g910-gkeys.service &&
+    [[ $DRYRUN = "" ]] && echo "Removed service unit $HOME/.config/systemd/user/g910-gkeys.service"
+fi
+
+# remove udev rules
+if [[ -f /etc/udev/rules.d/60-g910-gkeys.rules ]]; then
+  ${DRYRUN} sudo rm /etc/udev/rules.d/60-g910-gkeys.rules &&
+  [[ $DRYRUN = "" ]] && echo "Removed udev rules /etc/udev/rules.d/60-g910-gkeys.rules"
+fi
+
+# remove uinput config for kernel
+if [[ -f /etc/modules-load.d/uinput-g910-gkeys.conf ]]; then
+  ${DRYRUN} sudo rm /etc/modules-load.d/uinput-g910-gkeys.conf &&
+  [[ $DRYRUN = "" ]] && echo "Removed uinput config /etc/modules-load.d/uinput-g910-gkeys.conf"
+fi


Test patch:
diff --git a/g910_gkeys/tests/__init__.py b/g910_gkeys/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_config.py b/g910_gkeys/tests/test_config.py
similarity index 100%
rename from tests/test_config.py
rename to g910_gkeys/tests/test_config.py
diff --git a/tests/test_uinput.py b/g910_gkeys/tests/test_uinput.py
similarity index 100%
rename from tests/test_uinput.py
rename to g910_gkeys/tests/test_uinput.py
diff --git a/tests/test_usb.py b/g910_gkeys/tests/test_usb.py
similarity index 100%
rename from tests/test_usb.py
rename to g910_gkeys/tests/test_usb.py