~marnold128/magic-keyboard

b9122b70fe01af5d02f34069b7ab53d61a982d0e — Matt Arnold 2 months ago 8024a13
Mouse emulation now works, as do key combinations sort of flaky for both
6 files changed, 120 insertions(+), 6 deletions(-)

M .gitignore
A debug_layout.py
M mkd.py
M mkd/evdev.py
M qdl.py
M sample_event_script.py
M .gitignore => .gitignore +3 -2
@@ 1,4 1,5 @@
 Byte-compiled / optimized / DLL files
mkd.conf
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class


@@ 161,4 162,4 @@ cython_debug/
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

*.swp
\ No newline at end of file
*.swp

A debug_layout.py => debug_layout.py +66 -0
@@ 0,0 1,66 @@
import evdev
from evdev import ecodes
from math import ceil, floor


def mk_evread(e: evdev.KeyEvent, ctx: ContextDict):
    active_config = ctx.active_config
    evqueue = ctx.evqueue
    send_notice = ctx.send_notice
    ceil = ctx.ceil
    floor = ctx.floor
    if ctx.get("current_velocity") == None:
        ctx["current_velocity"] = 5
    ov = ctx.active_config.get("mouse_invel")
    if ov == None:
        ov = 5
    mouse_keys = [ecodes.KEY_I, ecodes.KEY_J, ecodes.KEY_K, ecodes.KEY_L]
    if e.scancode == ecodes.KEY_UP:
        ctx.evqueue.put((ecodes.EV_KEY, ecodes.KEY_W, e.keystate))
    if e.scancode == ecodes.KEY_DOWN:
        ctx.evqueue.put((ecodes.EV_KEY, ecodes.KEY_S, e.keystate))
    if e.scancode == ecodes.KEY_LEFT:
        ctx.evqueue.put((ecodes.EV_KEY, ecodes.KEY_A, e.keystate))
    if e.scancode == ecodes.KEY_RIGHT:
        ctx.evqueue.put((ecodes.EV_KEY, ecodes.KEY_D, e.keystate))

    if (e.scancode == ecodes.KEY_I) and (
        e.keystate == e.key_down or e.keystate == e.key_hold
    ):
        ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_Y, floor(-ctx.current_velocity)))
        print("Should Be Moving up")
        if ecodes.KEY_J in ctx.active_keys:
            ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_X, floor(-ctx.current_velocity)))
            ctx.evqueue.put((ecodes.EV_SYN, ecodes.SYN_REPORT, 0))
        if ecodes.KEY_L in ctx.active_keys:
            ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_X, ceil(ctx.current_velocity)))
            ctx.evqueue.put((ecodes.EV_SYN, ecodes.SYN_REPORT, 0))
        ctx.current_velocity = ctx.current_velocity + 0.125
    if (e.scancode == ecodes.KEY_K) and (
        e.keystate == e.key_down or e.keystate == e.key_hold
    ):

        ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_Y, ceil(ctx.current_velocity)))
        ctx.current_velocity = ctx.current_velocity + 0.125
        print("going down")
        if ecodes.KEY_J in ctx.active_keys:
            ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_X, floor(-ctx.current_velocity)))
            ctx.evqueue.put((ecodes.EV_SYN, ecodes.SYN_REPORT, 0))
        if ecodes.KEY_L in ctx.active_keys:
            ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_X, ceil(ctx.current_velocity)))
            ctx.evqueue.put((ecodes.EV_SYN, ecodes.SYN_REPORT, 0))
    if (e.scancode == ecodes.KEY_J) and (
        e.keystate == e.key_down or e.keystate == e.key_hold
    ):
        ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_X, floor(-ctx.current_velocity)))
        ctx.current_velocity = ctx.current_velocity + 0.125
        print("going left")
    if (e.scancode == ecodes.KEY_L) and (
        e.keystate == e.key_down or e.keystate == e.key_hold
    ):
        ctx.evqueue.put((ecodes.EV_REL, ecodes.REL_X, ceil(ctx.current_velocity)))
        ctx.current_velocity = ctx.current_velocity + 0.125
        print("going right")
    if e.scancode in mouse_keys and (e.keystate == e.key_up):
        ctx.current_velocity = ov
    return ctx

M mkd.py => mkd.py +21 -3
@@ 29,6 29,7 @@ import queue
import tomllib
import syslog
import signal
from math import ceil, floor
from time import sleep
import socket
import threading


@@ 51,6 52,7 @@ from mkd.evdev import (
    STOP_VALUE,
    leds_loop,
    default_evread,
    Emulated_Device,
)
from mkd.misc import ContextDict, LostDeviceError



@@ 71,7 73,10 @@ def main():
    if os.getuid() == 0 or os.geteuid == 0:
        print("Do not run me as root, add urself to input")
        exit(0x0F)
    cfig = get_config("~/.mkd.conf")
    if os.path.exists(os.path.abspath("./mkd.conf")):
        cfig = get_config(os.path.abspath("./mkd.conf"))
    else:
        cfig = get_config("~/.mkd.conf")
    if cfig == None:
        print("Config Syntax Error")
        exit(2)


@@ 163,6 168,9 @@ def daemon_main(cfig):
        script_context["evqueue"] = evqueue
        script_context["active_config"] = active_config
        script_context["send_notice"] = send_notice
        script_context["ceil"] = ceil
        script_context["floor"] = floor
        script_context["active_keys"] = None
        if halt_in_progress.is_set():
            break
        if not lisnr.is_alive() and not halt_in_progress.is_set():


@@ 191,6 199,7 @@ def daemon_main(cfig):
        # he knows they want to wake
        # he knows zombies are not good
        # so a zombie let's not make
        script_context.active_keys = current_device.active_keys()
        try:
            event = current_device.read_one()
        except OSError:


@@ 200,7 209,10 @@ def daemon_main(cfig):

        if event is not None:
            if event.type == ecodes.EV_KEY:
                dispatch_event(evdev.util.categorize(event), script_context)
                rt = dispatch_event(evdev.util.categorize(event), script_context)
                if rt != None:
                    script_context = rt

        else:
            # this is just a visual indicator that the main thread is awake
            # could also be useful in anti cheat circumvention


@@ 267,7 279,13 @@ def uinput_thread(evqueue):
        raise HaltRequested("Halt")
    Notify.init("mkd Vinput")

    ui = UInput()
    ui = UInput(
        events=Emulated_Device.events,
        name=Emulated_Device.name,
        product=Emulated_Device.product,
        vendor=Emulated_Device.vendor,
        version=Emulated_Device.version,
    )
    send_notice("input synth ready")
    while not stop_flag.is_set():
        if halt_in_progress.is_set():

M mkd/evdev.py => mkd/evdev.py +27 -1
@@ 2,6 2,7 @@
Where all the evdev related functions go
"""

from math import ceil, floor
from time import sleep
import evdev
from evdev import ecodes, InputDevice


@@ 23,9 24,34 @@ STOCK_LEDS = [
]
from .misc import ContextDict

__devname = "sorcery-usb-keyboard"
__vendor = 0x0C
__product = 0x71
__version = 0x01

def default_evread(e: evdev.KeyEvent, ctx: ContextDict):

__target_events = {
    ecodes.EV_KEY: ecodes.keys.keys(),
    ecodes.EV_REL: [
        ecodes.REL_X,
        ecodes.REL_Y,
        ecodes.REL_WHEEL,
        ecodes.REL_WHEEL_HI_RES,
        ecodes.REL_HWHEEL,
        ecodes.REL_HWHEEL_HI_RES,
    ],
}

Emulated_Device = ContextDict()

Emulated_Device["name"] = __devname
Emulated_Device["vendor"] = __vendor
Emulated_Device["product"] = __product
Emulated_Device["version"] = __version
Emulated_Device["events"] = __target_events


def default_evread(e: evdev.KeyEvent, ctx: ContextDict):
    if e.scancode == ecodes.KEY_UP:
        ctx.evqueue.put((ecodes.EV_KEY, ecodes.KEY_W, e.keystate))
    if e.scancode == ecodes.KEY_DOWN:

M qdl.py => qdl.py +1 -0
@@ 1,5 1,6 @@
#!/usr/bin/env python3
import evdev

devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
for d in devices:
    print(d)

M sample_event_script.py => sample_event_script.py +2 -0
@@ 1,11 1,13 @@
import evdev
from evdev import ecodes


class ContextDict(dict):
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__


def mk_evread(e: evdev.KeyEvent, ctx: ContextDict):
    active_config = ctx.active_config
    evqueue = ctx.evqueue