Keebie icon indicating copy to clipboard operation
Keebie copied to clipboard

some comments trying to make keebie run

Open ZaidaZadkiel opened this issue 3 years ago • 13 comments

is issue: no

Issue description

Im trying to use a NEC point-of-sale keyboard OS: Linux Mint 20.1 x86_64 Kernel: 5.11.0-27-generic

Tried just installing python3-evdev didnt work, had to use pip install evdev

Then right after installing the permission for the /dev/input was not set properly, i read elsewhere it could fix with log-out or reboot, so i tried rebooting and it read proper

Next the NEC keyboard has no leds in hardware, and keebie uses a hardcoded index 17 in line L#311

            leds = self.device.capabilities()[17] # Get a list of LEDs the device has

added a line and increased tab space on the rest of this scope

            if(17 in self.device.capabilities().keys()):
                leds = self.device.capabilities()[17] # Get a list of LEDs the device has
                ...

next running keebie --install breaks with error because it attempts to copy files that already exists, added on L#1011

def firstUses(): # Setup to be run when a user first runs keebie
    if os.path.exists(dataDir):
        print("files already installed in ", dataDir)
        return
    shutil.copytree(installDataDir + "data/", dataDir) # Copy template configuration files to user
    print(f"configuration files copied from {installDataDir}/data/ to {dataDir}") # And inform the user

next, because of the reboot the evdev input id number changed from what it autodetected (input30) and running keebie --detect returns /dev/input//event2

Then edited the files by hand in /home/zaida/.config/keebie/ Suggestion that i have no idea how to make: use /dev/input/by-id/* instead of input/event*

then running as root sudo chown zaida /dev/input/event2

then running keebie works properly. This last part is probably fixed with editing the udev rules but i havent rebooted and idek lel

ZaidaZadkiel avatar Aug 19 '21 14:08 ZaidaZadkiel

Alright there's quite a bit here, I'ma run through this bit by bit.

Tried just installing python3-evdev didnt work, had to use pip install evdev

Interesting, I wonder if we can find other systems where this is needed.

Then right after installing the permission for the /dev/input was not set properly, i read elsewhere it could fix with log-out or reboot, so i tried rebooting and it read proper

I'm not entirely certain what you mean by "installing the permission for the /dev/input", I assume you mean having Keebie set up the Udev rule is which case a reboot should not be necessary.

Next the NEC keyboard has no leds in hardware, and keebie uses a hardcoded index 17 in line L#311

            leds = self.device.capabilities()[17] # Get a list of LEDs the device has

added a line and increased tab space on the rest of this scope

            if(17 in self.device.capabilities().keys()):
                leds = self.device.capabilities()[17] # Get a list of LEDs the device has
                ...

If I'm honest the LEDs feature as a whole needs to be rehauled or removed, this is a good patch to slap on though.

next running keebie --install breaks with error because it attempts to copy files that already exists, added on L#1011

def firstUses(): # Setup to be run when a user first runs keebie
    if os.path.exists(dataDir):
        print("files already installed in ", dataDir)
        return
    shutil.copytree(installDataDir + "data/", dataDir) # Copy template configuration files to user
    print(f"configuration files copied from {installDataDir}/data/ to {dataDir}") # And inform the user

The --install option isn't really meant to be used much (first time setup gets run automatically if needed), I only ever tested it by removing the whole folder. This is definitely something that should get a proper fix instead of a side-stepping.

next, because of the reboot the evdev input id number changed from what it autodetected (input30) and running keebie --detect returns /dev/input//event2

Interesting, I've never had this happen with any of my devices.

Then edited the files by hand in /home/zaida/.config/keebie/ Suggestion that i have no idea how to make: use /dev/input/by-id/* instead of input/event*

That's definitely the way to go (this was actually the instruction back when paths had to be entered manually), checking for matching symlinks in by-id and by-path and preferring those would be a good way to do this, not sure of what functions to use for this but I'm sure there's something.

then running as root sudo chown zaida /dev/input/event2 then running keebie works properly. This last part is probably fixed with editing the udev rules but i havent rebooted and idek lel

You should instead have edited the Udev rule in /etc/udev/rules.d/85-keebie-event30.rules.

Michael-E-B avatar Aug 19 '21 15:08 Michael-E-B

With regards to --install I'm adding dirs_exist_ok=True, this should fix it fully.

Michael-E-B avatar Aug 19 '21 16:08 Michael-E-B

One issue with using links in /dev/input/by-id and by-path is that the Udev rules Keebie generates rely the KERNEL property which is the name of the event file, so if the event file name changes the Udev rule will break. I'm looking for other good properties to use but some amount of new logic may be needed to select them.

Michael-E-B avatar Aug 19 '21 17:08 Michael-E-B

Heads up: Starting tomorrow (20th) I will be out of contact until Monday.

Michael-E-B avatar Aug 20 '21 00:08 Michael-E-B

Then right after installing the permission for the /dev/input was not set properly, i read elsewhere it could fix with log-out or reboot, so i tried rebooting and it read proper

I'm not entirely certain what you mean by "installing the permission for the /dev/input", I assume you mean having Keebie set up the Udev rule is which case a reboot should not be necessary.

ah sorry, i missed a comma. Right after installing i tried to run keebie, but it wouldnt open the input file due to the udev file not being run. I didnt try figuring how to fix the perms just then, rebooted instead. So right after installing keebie, the permission for the input file wasnt set.

I still havent rebooted so i havent tried if the udev rule is working, sorry

Hope you have a good weekend, thanks for the program :)

ZaidaZadkiel avatar Aug 20 '21 09:08 ZaidaZadkiel

Actually I don't think that needs a comma, I'm just bad at reading comprehension (you did forget to capitalize your "I"s though).

Hope you have a good weekend

Wilco (or try).

Michael-E-B avatar Aug 20 '21 16:08 Michael-E-B

I've installed Keebie on a old x64 gaming laptop running Ubuntu 20.10 and have noticed some(but not all) of the issues present here, particularly the permissions failing on first run and the device id changing between boots. The permissions failing I can ignore, because I did see it work on reboot when I tested the laptop's primary keyboard(which didn't change id), but I need to solve the device id issue to experience joy. I already have a working model of the causation:

  1. At boot time, USB devices are added in order to /dev/input as part of the init sequence.
  2. If any timing difference or minor change in configuration at boot makes init run out of sequence then device order will be different.
  3. Thus you will get a "works for me" iff your init is stable, which of course no user has any idea about because that's the kind of thing deep in the guts of the OS.

(And it's a common software issue. Gamepad, audio and storage device mappings also have this ambiguity. A lot of applications will hardcode a default to "the first one" and never test what happens if you have two.)

The correct thing to do is to treat the mapping as a heuristic: we can record everything we know about the device that was originally polled, and then when we restore the settings we look for the closest match. In my gamedev practice I've implemented this kind of thing a lot to do input config; it's not super difficult to write a constraint solver that evaluates multiple solutions and comes up with the best according to the heuristic - it's just boilerplate algorithmic code once you know the principles.

But in my initial review of how to do things with udev(which I don't have any real experience with), it looks like this is something that udev rules are also meant to address, so the right move should be to dive deeper into udev and do some learning instead of reinventing wheels. I'm seeing some material about mapping a physical device to a symlink representing the desired logical mapping, which would be a pretty concise way of grabbing the right device from the script every time. Then the flow would look something like:

  1. Run "keebie -a", it polls as normal, grabs a more complete data sample from whichever source ("udevadm info" seems to work for me), parses it into a nice data structure, and then:
  2. It prompts for what parts of that info the user wants to have in the udev rule, with some easy default to help things along.
  3. It prompts for what the device is called, as well as what the initial layer is called. This also goes into the udev rule.
  4. It records what it did in "/devices/devicename.json" - the device name, the intended symlink, the original data sample, what parts of the sample are being used, and the layer to map it to.
  5. It reads all the configs, and compiles out a single file consolidating all of the rules, to keep /etc/rules.d clean. (This could be called from the command line with a "--recompile" flag for users that edit the device config manually.)
  6. Then when Keebie boots the live config, it looks up each device and uses the appropriate symlink.

If I get it together to work on that, a patch revising device config may be forthcoming. Fingers crossed. Otherwise, at least this note will remain to give some clues for the next adventurer.

triplefox avatar Mar 11 '22 22:03 triplefox

Good notes on the boot sequence stuff, lines up with the few times I've booted without my macro device and then hotplugged it.

I was at one point trying to build a (rather janky) way of using the device's PID and VID (or something like that, I've forgotten) but it was messy and didn't work well with PS/2 devices like mine so I lost interest in it; I don't think I'll be able to find any of it back again unfortunately.

Handing this of to Udev sounds like a good idea, but Udev just doesn't really click with me so I don't know.

Michael-E-B avatar Mar 11 '22 23:03 Michael-E-B

I got myself to work on udev a little bit. It's fiddly but I made a discovery: one keyboard does not equal one event generator! I (manually) wrote this udev rule:

ACTION=="add", KERNEL=="event[0-9]*", SUBSYSTEM=="input", ATTRS{id/product}=="0282", SYMLINK+="macropad", OWNER="triplefox"

then after rebooting(or using udevadm to reload rules and replugging the keyboard to get the trigger), ran this test python script:

import evdev

device = evdev.InputDevice('/dev/macropad')

print(device)
print(device.capabilities(verbose=True))
for event in device.read_loop():
        print(evdev.categorize(event))

but it only picked up the events for media keys. However, we can add %k to the symlink to remap each event source:

ACTION=="add", KERNEL=="event[0-9]*", SUBSYSTEM=="input", ATTRS{id/product}=="0282", SYMLINK+="macropad%k", OWNER="triplefox"

which produces /dev/macropadevent10, /dev/macropadevent11, /dev/macropadevent12, /dev/macropadevent13. And then feeding /dev/macropadevent10 into my script made it pick up the regular keys.

Then the next challenge would be to do some multiplexing to present this again as one "device"...which I would probably just do from python with some additional polling and string matching. It's messy but there's a path forward.

triplefox avatar Mar 12 '22 00:03 triplefox

I have come across examples of one device sending to multiple event files.

Multi event Udev stuff looks neat, have fun with that. I'm sorry to say I almost certainly won't be helping.

Michael-E-B avatar Mar 12 '22 01:03 Michael-E-B

I have been making progress on this issue in the month-and-a-half since I last commented here. However, there is a problem. It's not a functionality problem - the device support works great now and lets you specify if you want to detect the model of keyboard, the USB plug it's attached to, or both - it's that my changes have gradually turned into a rewrite of each part of Keebie, still reusing the general structure but reevaluating fundamental assumptions along the way and making more changes as necessary. So, frontend, backend, config formats, architecture strategy - almost everything has been touched in some way.

The benefit is that everything's a little bit more organized, a little bit more documented, and a little bit more reliable, and there's some new functionality: it can input specific key sequences as well as launching commands, so it can be used to trigger existing shortcuts in apps or fill forms, and the functionality for triggering a macro is more robust and can support both chords and sequences. It's a new program, and I have a backlog of things to flesh out, clean up and fix to bring everything up to speed, particularly a redesign of layer configuration to actually support the new features. And some of the old features may need more maintenance to work again. So it's "working" but not "done", "done" will probably be a few more weekends of effort at the rate I've been going lately.

I don't want to dump a huge pull request unasked, so if you have any particular thoughts on this or must-have features for it to still be "Keebie", I'm listening. Or if this doesn't sound like where you'd like to take it, I'm happy to publish it as a fork instead.

triplefox avatar Apr 27 '22 10:04 triplefox

@triplefox where is your fork? i would like to try/test ....

lblabr avatar Jul 31 '22 07:07 lblabr

I have completed my fork! It is a rewrite named "Macrobie" with no code remaining from the original, and is designed around extending Autokey(a much more sophisticated hotkey program). Keebie is credited. https://github.com/triplefox/macrobie

triplefox avatar Oct 15 '22 09:10 triplefox