Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to add Madlion Nano 68 Pro? #10

Open
nisayera opened this issue Mar 10, 2025 · 52 comments
Open

Possible to add Madlion Nano 68 Pro? #10

nisayera opened this issue Mar 10, 2025 · 52 comments

Comments

@nisayera
Copy link

If needed i could supply any info that is needed. Thanks :)

@Sainan
Copy link
Member

Sainan commented Mar 10, 2025

Certainly possible (albeit very bad polling-based support as their firmware has no better interface), it'd just need to have some basic descriptions including the layout. It might help you to try modifying AnalogSense.js and then I could port it to C++: https://github.com/AnalogSense/JavaScript-SDK/blob/senpai/AnalogSense.js#L715

@nisayera
Copy link
Author

Certainly possible (albeit very bad polling-based support as their firmware has no better interface), it'd just need to have some basic descriptions including the layout. It might help you to try modifying AnalogSense.js and then I could port it to C++: https://github.com/AnalogSense/JavaScript-SDK/blob/senpai/AnalogSense.js#L715

Could you give me a brief explanation on how to do that? Im a hardstuck noob when it comes to doing stuff like that

@Sainan
Copy link
Member

Sainan commented Mar 10, 2025

Well, you can download the JavaScript-SDK repository and open the demo.html in your browser to test it, then just modify the AnalogSense.js to adjust the layout.

I'm not entirely sure about the productId but you can remove that from the filter and then use console.log(this.dev.productId) to read what you selected.

@nisayera
Copy link
Author

The device does not even show up on trying to connect on this demo site. What exactly do i need to do? Im so sorry D:

@Sainan
Copy link
Member

Sainan commented Mar 10, 2025

Yeah, you'd have to adjust AnalogSense.js like so:

image

Then also likely some modification to the layout below will be needed as well.

@nisayera
Copy link
Author

I added that to the AnalogSense.js now. Device still does not show up when i try to connect.

Image

@Sainan
Copy link
Member

Sainan commented Mar 10, 2025

You did not remove productId from the filters

@nisayera
Copy link
Author

Image I hope this is right now.. I feel stupid

@Sainan
Copy link
Member

Sainan commented Mar 10, 2025

Well, that's interesting. I guess you can try also removing vendorId?

@nisayera
Copy link
Author

Still nothing

@Sainan
Copy link
Member

Sainan commented Mar 10, 2025

You did press Ctrl+S and reload the browser, yeah? Otherwise I'm not sure what's wrong with your keyboard firmware if it's not even got the interface I'd expect from Madlions.

@nisayera
Copy link
Author

Its the same Site as the Mad products. And yeah i saved and reloaded the page.

Image

@nisayera
Copy link
Author

nisayera commented Mar 13, 2025

Noticed u did not text back. Will there be any fix for this?
https://nondebug.github.io/webhid-explorer/ <-- This is an univeral HID reader

i got this info from my keyboard:

productName: Nano 68 Pro
vendorId: 0x373B (14139) Unknown vendor
productId: 0x106B (4203)
opened: true
collections[0]
Usage: 0001:0000 (Generic Desktop usage 0x0000)
Input reports: 0x00
Output reports: 0x00
Input report 0x00
64 values * 8 bits (bits 0 to 511)
Data,Var,Abs
Usages: 0001:0000 (Generic Desktop usage 0x0000) to 0001:0008 (Generic Desktop > Multi-axis Controller)
Logical bounds: 0 to 255
Output report 0x00
64 values * 8 bits (bits 0 to 511)
Data,Var,Abs
Usages: 0001:0001 (Generic Desktop > Pointer) to 0001:0008 (Generic Desktop > Multi-axis Controller)
Logical bounds: 0 to 255

The device splits into 3 modes i guess:

Image

productName: Nano 68 Pro
vendorId: 0x373B (14139) Unknown vendor
productId: 0x106B (4203)
opened: true
collections[0]
Usage: 0001:0006 (Generic Desktop > Keyboard)

productName: Nano 68 Pro
vendorId: 0x373B (14139) Unknown vendor
productId: 0x106B (4203)
opened: true
collections[0]
Usage: 000C:0001 (Consumer > Consumer Control)
Input reports: 0x03
collections[1]
Usage: 0001:0080 (Generic Desktop > System Control)
collections[2]
Usage: 0001:000C (Generic Desktop > Wireless Radio Controls)
Input reports: 0x05
collections[3]
Usage: 0001:0006 (Generic Desktop > Keyboard)
collections[4]
Usage: 0001:0002 (Generic Desktop > Mouse)
Input report 0x03
16 bits (bits 0 to 15)
Data,Ary,Abs
Usages: 000C:0001 (Consumer > Consumer Control) to 000C:02A0 (Consumer > AC Soft Key Left)
Logical bounds: 672 to 0
Input report 0x05
1 bit (bit 0)
Data,Var,Rel
Usage: 0001:000C (Generic Desktop > Wireless Radio Controls)
Logical bounds: 0 to 0
7 bits (bits 1 to 7)
Cnst,Ary,Abs
Logical bounds: 0 to 0

@Sainan
Copy link
Member

Sainan commented Mar 13, 2025

None of these seem like the expected management interface.

@nisayera
Copy link
Author

Yeah. When i remove the usage and usagepage i can connect to it. Seems like the usage is not the one u thought it was.

Image

@Sainan
Copy link
Member

Sainan commented Mar 13, 2025

Does it actually detect your key presses when you 'connect to it'?

@nisayera
Copy link
Author

Detect it where? They keyboard is still usable as usual

@Sainan
Copy link
Member

Sainan commented Mar 13, 2025

On the demo page.

@nisayera
Copy link
Author

No the site is blank.

@Sainan
Copy link
Member

Sainan commented Mar 13, 2025

Yeah, I thought so. I'm probably not gonna bother buying a Nano 68 Pro because Madlions have a horribly useless firmware interface to begin with.

@nisayera
Copy link
Author

Yeah, do you have any idea on how i could do this myself? I guess i need to figure the usage and usagepage?

@Sainan
Copy link
Member

Sainan commented Mar 13, 2025

I guess reverse-engineer their management website if you say it does indeed work.

@nisayera
Copy link
Author

Image

This is the connection of the original website

@nisayera
Copy link
Author

With the usage 0x0 and usagepage 0x1 i can connect on your site. It wont show anything still...

@nisayera
Copy link
Author

Ive tried multiple things now. Cant seem to get an this.dev.oninputreport out of this crap. The keyboard wont put out anything in the usage modes 0x0 and 0x6. The other ones cant be used to connect.
Also wrote my own code with some AI help.

const analogsense = {
    providers: [],
    findProviderForDevice: function(dev) {
        for (const provider of analogsense.providers) {
            const filters = [];
            provider.populateFilters(filters);
            for (const filter of filters) {
                if (filter.vendorId && dev.vendorId !== filter.vendorId) continue;
                if (filter.productId && dev.productId !== filter.productId) continue;
                return provider;
            }
        }
    },
    getDevices: async function() {
        const devices = await navigator.hid.getDevices();
        return devices.map(dev => new (analogsense.findProviderForDevice(dev))(dev));
    },
    requestDevice: async function() {
        const filters = [];
        for (const provider of analogsense.providers) {
            provider.populateFilters(filters);
        }
        const devices = await navigator.hid.requestDevice({ filters });
        return new (analogsense.findProviderForDevice(devices[0]))(devices[0]);
    }
};

class AsProvider {
    constructor(dev) {
        this.dev = dev;
    }
    async getProductName() {
        return this.dev.productName;
    }
    forget() {
        this.dev.forget();
    }
}

class AsProviderMadlions extends AsProvider {
    static populateFilters(filters) {
        filters.push({ vendorId: 0x373B, usagePage: 0x1, usage: 0x0, productId: 0x106B });
    }

    async startListening(handler) {
        console.log("Listening started for", this.dev.productId);
        this.offset = 0;
        this.buffer = {};

        if (!this.dev.opened) {
            try {
                await this.dev.open();
                console.log("Device opened successfully");
            } catch (error) {
                console.error("Failed to open device:", error);
                return;
            }
        }

        setInterval(() => {
            console.log("Sending request for key report");
            try {
                //console.log("Checking Error");
                this.dev.sendReport(0, new Uint8Array([0x02, 0x96, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04]));
            } catch (error) {
                console.error("Failed to send report:", error);
            }

            //console.log("Trying now...");
            this.dev.oninputreport = function(event) {
                console.log("🔹 Received event:", event.data);
                console.log("🔹 Report ID:", event.reportId);
                
                const active_keys = [];
                for (let i = 0; i < event.data.byteLength; i++) {
                    console.log(`Byte ${i}:`, event.data.getUint8(i));
                }
            };
            //console.log("No key pressed.");

        }, 500);

        this.dev.oninputreport = function(event) {
            console.log("Raw event data:", event.data);
            console.log("Report ID:", event.reportId);
            for (let i = 0; i < 4; ++i) {
                if (this.offset + i < this.layout.length) {
                    const key = this.layout[this.offset + i];
                    const travel = event.data.getUint16(7 + (i * 5) + 3);
                    if (travel == 0) {
                        delete this.buffer[key];
                    } else {
                        this.buffer[key] = travel / 350;
                    }
                }
            }
            handler(this._bufferToActiveKeys());
            this.offset = (this.offset + 4) % this.layout.length;
        };
    }

    _bufferToActiveKeys() {
        const active_keys = [];
        for (const [scancode, value] of Object.entries(this.buffer)) {
            active_keys.push({ scancode, value });
        }
        console.log("Active keys detected:", active_keys);
        return active_keys;
    }
}

analogsense.providers.push(AsProviderMadlions);

@Actiongomini
Copy link

Ok i have absolutely why or how this works, but i was able to get it to do this when turning on axis alignment mode on the official website, i assume this is what allows it to start interfacing analogue inputs but i might be wrong. Normally on the website this mode allows you to see travel distances of each key, I hope this helps idk, maybe try your code with this enabled, as i only added filters to get this to trigger

Image

Image

Image

@Actiongomini
Copy link

Image

also it gives you object undefined whenever a switch moves so i assume that this means it isnt interfacing with the correct switches

@nisayera
Copy link
Author

Why didnt i thought of that. Yeah thats good! Can u share the code that u changed in the AnalogeSense.js? I think i just need to figure out how to get the Calibration running on other sites.

@nisayera
Copy link
Author

I love you. My own code works with the calibration mode on!

Image I can read the exact depth the key is pressed!

@Actiongomini
Copy link

wait fr

@Actiongomini
Copy link

please let me know how the hell you've done that cus all i did was enable the extra filter and turn on axial alignment, essentially ive not done anything but let it actually recognise the keyboard. I assume this is what they changed between the new boards and the madlion 60//68

@nisayera
Copy link
Author

Yes it looks like Byte17 reports the exact depth of the key. I will need to figure more stuff out but this is a breakthrough!
Just need to get @Sainan here to add this and addapt to his code.

@Sainan
Copy link
Member

Sainan commented Mar 17, 2025

And you'll also need to figure out a way to programatically enable the 'axial alignment mode' :^)

@Actiongomini
Copy link

ok cool, idk what the image was or anything cus im about as good at coding as a rock but nicee, good to know i helped ig

@Actiongomini
Copy link

also let me know if your able to implement it and how cus ima see if i can at least try for the mad68 pro (r) aswell. might have bought both

@nisayera
Copy link
Author

And you'll also need to figure out a way to programatically enable the 'axial alignment mode' :^)

Yeah that will be my next step. Should not be too hard.

@Actiongomini
Copy link

damn welp guess bro is cooking ( very excited )

@Actiongomini
Copy link

also @Sainan what does the website actually look like when it works (i dont have any supported boards so idk what it should look like)

@Sainan
Copy link
Member

Sainan commented Mar 17, 2025

image

@Actiongomini
Copy link

ohr, makes a lot more sense than what i was seeing before, thanks

@Actiongomini
Copy link

ok so i got ai to try to write something, it sort of works (it updates when you click, connects etc) but idk if its accurate or correct cus theres way too many keys, its using the code that u put here earlier so idk. How would i at least try to filter it a bit so im not being overwhelmed by values

Image

`

<script src="analogsense.js"></script> <title>AnalogSense HID Tester</title> <style> body { font-family: Arial, sans-serif; padding: 20px; } button { padding: 10px; margin: 10px 0; cursor: pointer; } #device-list { margin-top: 20px; } #key-logs { background: #f4f4f4; padding: 10px; min-height: 150px; border-radius: 5px; } </style>
<h1>AnalogSense HID Device Tester</h1>
<button id="request-device">Request Device</button>
<button id="list-devices">List Connected Devices</button>

<h2>Connected Devices:</h2>
<ul id="device-list"></ul>

<h2>Key Inputs:</h2>
<div id="key-logs">Waiting for input...</div>

<script>
    async function listDevices() {
        const devices = await analogsense.getDevices();
        const deviceList = document.getElementById("device-list");
        deviceList.innerHTML = ""; // Clear previous entries

        if (devices.length === 0) {
            deviceList.innerHTML = "<li>No devices found</li>";
            return;
        }

        devices.forEach(device => {
            const li = document.createElement("li");
            li.textContent = device.dev.productName || "Unknown Device";
            deviceList.appendChild(li);
        });
    }

    async function requestDevice() {
        try {
            const device = await analogsense.requestDevice();
            const li = document.createElement("li");
            li.textContent = device.dev.productName || "Unknown Device";
            document.getElementById("device-list").appendChild(li);
            
            device.startListening(updateKeyLogs);
        } catch (error) {
            alert("No device selected or an error occurred.");
            console.error(error);
        }
    }

    function updateKeyLogs(activeKeys) {
        const logContainer = document.getElementById("key-logs");
        logContainer.innerHTML = activeKeys.length > 0 
            ? activeKeys.map(k => `Key: ${k.scancode}, Value: ${k.value}`).join("<br>")
            : "No keys pressed";
    }

    document.getElementById("list-devices").addEventListener("click", listDevices);
    document.getElementById("request-device").addEventListener("click", requestDevice);
</script>
`

@nisayera
Copy link
Author

Does not look accurate because u have a weird output. Ur Output has the same number everytime. I dont have time today to look into this more but maybe tomorrow. I will figure something out :)

@Actiongomini
Copy link

yup oki sounds about right thanks

@nisayera
Copy link
Author

nisayera commented Mar 22, 2025

This is a working code for the nano68 pro. The only thing that is missing, is the activation of the Calibration mode.

const keys = [
    { "name": "A", "wooting": 0x04 },
    { "name": "B", "wooting": 0x05 },
    { "name": "C", "wooting": 0x06 },
    { "name": "D", "wooting": 0x07 },
    { "name": "E", "wooting": 0x08 },
    { "name": "F", "wooting": 0x09 },
    { "name": "G", "wooting": 0x0A },
    { "name": "H", "wooting": 0x0B },
    { "name": "I", "wooting": 0x0C },
    { "name": "J", "wooting": 0x0D },
    { "name": "K", "wooting": 0x0E },
    { "name": "L", "wooting": 0x0F },
    { "name": "M", "wooting": 0x10 },
    { "name": "N", "wooting": 0x11 },
    { "name": "O", "wooting": 0x12 },
    { "name": "P", "wooting": 0x13 },
    { "name": "Q", "wooting": 0x14 },
    { "name": "R", "wooting": 0x15 },
    { "name": "S", "wooting": 0x16 },
    { "name": "T", "wooting": 0x17 },
    { "name": "U", "wooting": 0x18 },
    { "name": "V", "wooting": 0x19 },
    { "name": "W", "wooting": 0x1A },
    { "name": "X", "wooting": 0x1B },
    { "name": "Y", "wooting": 0x1C },
    { "name": "Z", "wooting": 0x1D }
];

const wooting_to_name = {};
keys.forEach(key => wooting_to_name[key.wooting] = key.name);

class AsProvider {
    constructor(dev) {
        this.dev = dev;
    }

    getProductName() {
        return this.dev.productName;
    }

    async startListening(handler) {
        console.log("📡 Versuche, das Gerät zu öffnen:", this.dev.productId);
    
        if (!this.dev.opened) {
            await this.dev.open().catch(err => {
                console.error("❌ Fehler beim Öffnen des Geräts:", err);
                return;
            });
        }
    
        if (!this.dev.opened) {
            console.error("❌ Gerät konnte nicht geöffnet werden!");
            return;
        }
    
        console.log("✅ Gerät erfolgreich geöffnet:", this.dev.productId);

        // Aktuellen und vorherigen Wert speichern
        let previousValue = 0;

        this.dev.oninputreport = function(event) {
            const scancode = event.data.getUint8(3);  // Scancode der Taste
            const rawValue = event.data.getUint8(5);  // Rohwert aus Byte 5
            const normalizedValue = rawValue / 255;  // Normalisieren (0.0 - 1.0)
        
            console.log(`🎹 Taste: ${scancode}, Raw: ${rawValue}, Normalisiert: ${normalizedValue}`);
        
            if (scancode !== 0) {
                handler([{ scancode, value: normalizedValue }]);
            }
        };

    
        setInterval(() => {
            console.log("📩 Sending request for key report");
            this.dev.sendReport(0, new Uint8Array([0x02, 0x96, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04]));
        }, 100);
    }
    
}

window.analogsense = {
    getDevices: async function() {
        const devices = await navigator.hid.getDevices();
        return devices.map(dev => new AsProvider(dev));
    },
    
    requestDevice: async function() {
        const devices = await navigator.hid.requestDevice({ filters: [] });
        return devices.length > 0 ? new AsProvider(devices[0]) : null;
    }
};

@Actiongomini

@nisayera
Copy link
Author

@Actiongomini ive got some news!!

Image

AnalogSense.JS

const keys = [
    { "name": "A", "wooting": 0x04 },
    { "name": "B", "wooting": 0x05 },
    { "name": "C", "wooting": 0x06 },
    { "name": "D", "wooting": 0x07 },
    { "name": "E", "wooting": 0x08 },
    { "name": "F", "wooting": 0x09 },
    { "name": "G", "wooting": 0x0A },
    { "name": "H", "wooting": 0x0B },
    { "name": "I", "wooting": 0x0C },
    { "name": "J", "wooting": 0x0D },
    { "name": "K", "wooting": 0x0E },
    { "name": "L", "wooting": 0x0F },
    { "name": "M", "wooting": 0x10 },
    { "name": "N", "wooting": 0x11 },
    { "name": "O", "wooting": 0x12 },
    { "name": "P", "wooting": 0x13 },
    { "name": "Q", "wooting": 0x14 },
    { "name": "R", "wooting": 0x15 },
    { "name": "S", "wooting": 0x16 },
    { "name": "T", "wooting": 0x17 },
    { "name": "U", "wooting": 0x18 },
    { "name": "V", "wooting": 0x19 },
    { "name": "W", "wooting": 0x1A },
    { "name": "X", "wooting": 0x1B },
    { "name": "Y", "wooting": 0x1C },
    { "name": "Z", "wooting": 0x1D }
];

const wooting_to_name = {};
keys.forEach(key => wooting_to_name[key.wooting] = key.name);

class AsProvider {
    constructor(dev) {
        this.dev = dev;
    }

    getProductName() {
        return this.dev.productName;
    }

    async startListening(handler) {
        console.log("📡 Versuche, das Gerät zu öffnen:", this.dev.productId);

        if (!this.dev.opened) {
            await this.dev.open().catch(err => {
                console.error("❌ Fehler beim Öffnen des Geräts:", err);
                return;
            });
        }

        if (!this.dev.opened) {
            console.error("❌ Gerät konnte nicht geöffnet werden!");
            return;
        }

        console.log("✅ Gerät erfolgreich geöffnet:", this.dev.productId);

        // Aktuellen und vorherigen Wert speichern
        let previousValue = 0;

        this.dev.oninputreport = function(event) {
            const scancode = event.data.getUint8(3);  // Scancode der Taste
            const rawValue = event.data.getUint8(5);  // Rohwert aus Byte 5 (Tiefe)
            const cycleCount = event.data.getUint8(4);  // Zyklus aus Byte 4
            const totalValue = (cycleCount * 255) + rawValue;  // Kombinieren von Byte 4 und Byte 5
            const normalizedValue = totalValue / (255 * 6.2);  // Normalisieren (0.0 - 1.0) für 10 Zyklen

            console.log(`🎹 Taste: ${scancode}, Raw: ${rawValue}, Zyklus: ${cycleCount}, Gesamtwert: ${totalValue}, Normalisiert: ${normalizedValue}`);

            if (scancode !== 0) {
                handler([{ scancode, value: normalizedValue, totalValue }]);
            }
        };

        setInterval(() => {
            console.log("📩 Sending request for key report");
            this.dev.sendReport(0, new Uint8Array([0x02, 0x96, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x04]));
        }, 100);
    }
}



window.analogsense = {
    getDevices: async function() {
        const devices = await navigator.hid.getDevices();
        return devices.map(dev => new AsProvider(dev));
    },
    
    requestDevice: async function() {
        const devices = await navigator.hid.requestDevice({ filters: [] });
        return devices.length > 0 ? new AsProvider(devices[0]) : null;
    }
};

HTML

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AnalogSense.js Demo</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        /* Dark Mode */
        body {
            background-color: #121212;
            color: #e0e0e0;
        }

        .container {
            background-color: #1c1c1c;
            padding: 20px;
            border-radius: 10px;
        }

        .btn {
            background-color: #4CAF50;
            color: white;
            border: none;
        }

        .btn:hover {
            background-color: #45a049;
        }

        .slider-container {
            display: flex;
            flex-direction: column;
            width: 100%;
            margin-bottom: 1rem;
        }

        .slider-label {
            display: flex;
            justify-content: space-between;
            align-items: center;
            color: #e0e0e0;
        }

        .key {
            font-weight: bold;
            color: #4CAF50;
        }

        .slider {
            width: 100%;
            height: 20px;
            border-radius: 5px;
            background-color: #333;
            border: 2px solid #444;
            box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.7);
        }

        .slider-fill {
            height: 100%;
            background-color: #4CAF50;
            border-radius: 5px;
            transition: width 0.2s ease-in-out;
        }

        /* Calibration Mode Switch */
        .switch {
            position: relative;
            display: inline-block;
            width: 60px;
            height: 34px;
        }

        .switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }

        .slider-mode {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: .4s;
            border-radius: 34px;
        }

        .slider-mode:before {
            position: absolute;
            content: "";
            height: 26px;
            width: 26px;
            border-radius: 50%;
            left: 4px;
            bottom: 4px;
            background-color: white;
            transition: .4s;
        }

        input:checked + .slider-mode {
            background-color: #4CAF50;
        }

        input:checked + .slider-mode:before {
            transform: translateX(26px);
        }

        .switch-label {
            font-size: 18px;
            margin-left: 10px;
            vertical-align: middle;
        }
    </style>
</head>
<body>
    <div class="container pt-2">
        <!-- Calibration Mode Switch -->
        <div class="d-flex align-items-center mb-3">
            <label class="switch">
                <input type="checkbox" id="calibrationModeToggle">
                <span class="slider-mode"></span>
            </label>
            <label for="calibrationModeToggle" class="switch-label">Calibration Mode</label>
        </div>

        <div id="nodev">
            <h2>Kein Gerät verbunden</h2>
            <button class="btn btn-primary" onclick="doConnect();">Verbinden</button>
        </div>
        <div id="nohid" style="display:none">
            <h2>WebHID nicht unterstützt</h2>
            <p>Nutze Chrome, Edge oder einen anderen Chromium-basierten Browser.</p>
        </div>
        <div id="demo" style="display:none">
            <h2 id="devname"></h2>
            <button class="btn btn-secondary" onclick="doDisconnect();">Trennen</button>
            <div id="active-keys" class="mt-3"></div>
        </div>
    </div>
    
    <script src="AnalogSense.js"></script>
    <script>
        let dev = null;  // Sicherstellen, dass dev nicht vorab verbunden ist

        async function doConnect() {
            const device = await analogsense.requestDevice();
            if (device) {
                dev = device;
                initDemo(dev);
            }
        }

        function initDemo(dev) {
            document.getElementById("nodev").style.display = "none";
            document.getElementById("demo").style.display = "block";
            document.getElementById("devname").textContent = `Verbunden mit: ${dev.getProductName()}`;

            dev.startListening(function(active_keys) {
                document.getElementById("active-keys").innerHTML = "";
                for (const key of active_keys) {
                    const div = document.createElement("div");
                    div.className = "slider-container";

                    const label = document.createElement("div");
                    label.className = "slider-label";
                    label.innerHTML = `<span class="key">${wooting_to_name[key.scancode] || "Unbekannt"}</span><span>${(key.value * 255).toFixed(0)}</span>`;
                    div.appendChild(label);

                    // Der Slider für den Tastendruck
                    const sliderContainer = document.createElement("div");
                    sliderContainer.className = "slider";
                    const sliderFill = document.createElement("div");
                    sliderFill.className = "slider-fill";
                    sliderFill.style.width = `${key.value * 100}%`; // Setze die Breite des Füllbalkens
                    sliderContainer.appendChild(sliderFill);
                    div.appendChild(sliderContainer);

                    document.getElementById("active-keys").appendChild(div);
                }
            });
        }

        function doDisconnect() {
            if (dev) {
                dev = null;
                document.getElementById("demo").style.display = "none";
                document.getElementById("nodev").style.display = "block";
                document.getElementById("active-keys").innerHTML = "";
            }
        }

        async function checkPairedDevices() {
            const devices = await analogsense.getDevices();
            if (devices.length != 0) {
                // Keine automatische Verbindung mehr
            }
        }

        if ("hid" in navigator) {
            checkPairedDevices();
        } else {
            document.getElementById("nodev").style.display = "none";
            document.getElementById("nohid").style.display = "block";
        }
    </script>
</body>
</html>

@nisayera
Copy link
Author

Calibration mode ist still missing but i will need to get that later. its hard do reverse the original website. But this is working with the management website open and enabled Axial Alignment mode. Just have both sites open at the same time.

Image

@Actiongomini
Copy link

WAIT SICK nice bro got it, i dont believe u need the other site open but you do need to enable it as an option

again might be wrong but i'll check in a sec thx @nisayera

@Actiongomini
Copy link

Image

i've replicated as close as i can to your setup with the html and js but i dont know why it doesnt seem to be working as of right now.

@Actiongomini
Copy link

Image
oki idk why but it started working once i unplugged and replugged it back in, also had to reenable the axial alignment but it works now.

VERY COOL so now we just need to figure out what we gonna use this for...

@nisayera
Copy link
Author

Nice, yeah we will need @Sainan to implement this in the thing. Ai helped me out so much, glad that exists

@nisayera
Copy link
Author

Also figured out the Axial Alignment code. but i was not able to execute it .

This is the enable command.

00000000  55 06 00 C9 38 00 00 00 50 00 AA BB 01 00 00 0A 
00000010  02 00 02 00 00 00 FF 00 80 00 00 00 00 00 00 00 
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

@nisayera
Copy link
Author

Does not look like that im able to get the Axial Alignment to work. If anyone could help out this is the protocoll:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html><head><title>USBlyzer  Report</title>
<style type=text/css>
body {
	padding: 0;
	background: #fff; 
	color: #000;
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 70%;
	}
p {
	margin-top: .6em;
	margin-bottom: .6em;
	}
font.cap {
	font-weight: bold; font-size: 120%;
	}
table {
	width: 100%;
	background: #fff;
	margin-top: .3em;
	margin-bottom: .3em;
	border: 1px solid #999;
	border-collapse: collapse;
	table-layout:auto;
	}
th {
	padding: 1px 2px;
	background: #eee;
	color: #666666;
	font-size: 70%;
	white-space: nowrap;
	text-align: left;
	vertical-align: top;
	border: 1px solid #999;
	}
td {
	padding: 1px 2px;
	background: #fff;
	font-size: 70%;
	white-space: nowrap;
	vertical-align: top;
	border: 1px solid #999;
	}
td.rawdata {
	padding: 2px;
	background: #efefef;
	font-size: 70%;
	white-space: nowrap;
	vertical-align: top;
	border: 1px solid #999;
	}
td pre {
	padding-left: 1em;
	margin: 0;
	}
</style>
</head>

<body>

<font class="cap">USBlyzer  Report</font>

<p><b>Capture List</b> 

<table>
<tr><th>Type</th>
<th>Seq</th>
<th>Time</th>
<th>Elapsed</th>
<th>Duration</th>
<th>Request</th>
<th>Request Details</th>
<th>Raw Data</th>
<th>I/O</th>
<th>C:I:E</th>
<th>Device Object</th>
<th>Device Name</th>
<th>Driver Name</th>
<th>IRP</th>
<th>Status</th>
</tr>
<tr><td>START</td><td>0001</td><td>17:03:10.125</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>URB</td><td>0002</td><td>17:03:11.943</td><td>1.819070 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 C9 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C570EA9A0h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 C9 38 00 00 00 50 00 AA BB 01 00 00 0A  U...8...P.......
00000010  02 00 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  ................
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0003</td><td>17:03:11.943</td><td>1.819073 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 C9 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C570EA9A0h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 C9 38 00 00 00 50 00 AA BB 01 00 00 0A  U...8...P.......
00000010  02 00 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  ................
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0004-0003</td><td>17:03:11.944</td><td>1.819251 s</td><td>178 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C570EA9A0h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0005-0002</td><td>17:03:11.944</td><td>1.819252 s</td><td>181 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C570EA9A0h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0006</td><td>17:03:11.966</td><td>1.841242 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C558CF560h</td><td></td></tr>
<tr><td>URB</td><td>0007</td><td>17:03:11.966</td><td>1.841244 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C558CF560h</td><td></td></tr>
<tr><td>URB</td><td>0008</td><td>17:03:17.743</td><td>7.618440 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 25 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C570EA9A0h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 25 38 00 00 00 50 00 AA BB 01 00 00 02  U..%8...P.......
00000010  02 64 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  .d..............
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0009</td><td>17:03:17.743</td><td>7.618442 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 25 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C570EA9A0h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 25 38 00 00 00 50 00 AA BB 01 00 00 02  U..%8...P.......
00000010  02 64 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  .d..............
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0010-0009</td><td>17:03:17.743</td><td>7.618607 s</td><td>164 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C570EA9A0h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0011-0008</td><td>17:03:17.743</td><td>7.618607 s</td><td>168 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C570EA9A0h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0012</td><td>17:03:17.763</td><td>7.638113 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C51BE0560h</td><td></td></tr>
<tr><td>URB</td><td>0013</td><td>17:03:17.763</td><td>7.638115 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C51BE0560h</td><td></td></tr>
<tr><td>START</td><td>0014</td><td>17:18:16.265</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>URB</td><td>0015</td><td>17:18:48.504</td><td>938.379035 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 C9 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C53BF0270h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 C9 38 00 00 00 50 00 AA BB 01 00 00 0A  U...8...P.......
00000010  02 00 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  ................
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0016</td><td>17:18:48.504</td><td>938.379038 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 C9 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C53BF0270h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 C9 38 00 00 00 50 00 AA BB 01 00 00 0A  U...8...P.......
00000010  02 00 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  ................
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0017-0016</td><td>17:18:48.504</td><td>938.379317 s</td><td>279 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C53BF0270h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0018-0015</td><td>17:18:48.504</td><td>938.379319 s</td><td>284 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C53BF0270h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0019-0007</td><td>17:18:48.529</td><td>938.404179 s</td><td>936.562935 s</td><td>Bulk or Interrupt Transfer</td><td>Input Report len:64</td><td>AA 06 00 C9 38 00 00 00...</td><td>in</td><td>01:01:82</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C558CF560h</td><td>Success (Success)</td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  AA 06 00 C9 38 00 00 00 50 00 AA BB 01 00 00 0A  ....8...P.......
00000010  02 00 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  ................
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0020-0006</td><td>17:18:48.529</td><td>938.404180 s</td><td>936.562938 s</td><td>Bulk or Interrupt Transfer</td><td>Input Report len:64</td><td>AA 06 00 C9 38 00 00 00...</td><td>in</td><td>01:01:82</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C558CF560h</td><td>Success (Success)</td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  AA 06 00 C9 38 00 00 00 50 00 AA BB 01 00 00 0A  ....8...P.......
00000010  02 00 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  ................
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0021</td><td>17:18:48.529</td><td>938.404194 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C558CF560h</td><td></td></tr>
<tr><td>URB</td><td>0022</td><td>17:18:48.529</td><td>938.404196 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C558CF560h</td><td></td></tr>
<tr><td>URB</td><td>0023</td><td>17:18:51.629</td><td>941.504391 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 25 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C53BF0270h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 25 38 00 00 00 50 00 AA BB 01 00 00 02  U..%8...P.......
00000010  02 64 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  .d..............
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0024</td><td>17:18:51.629</td><td>941.504393 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>Output Report len:64</td><td>55 06 00 25 38 00 00 00...</td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C53BF0270h</td><td></td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  55 06 00 25 38 00 00 00 50 00 AA BB 01 00 00 02  U..%8...P.......
00000010  02 64 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  .d..............
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0025-0024</td><td>17:18:51.629</td><td>941.504557 s</td><td>164 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C53BF0270h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0026-0023</td><td>17:18:51.629</td><td>941.504558 s</td><td>167 us</td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>out</td><td>01:01:04</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C53BF0270h</td><td>Success (Success)</td></tr>
<tr><td>URB</td><td>0027-0013</td><td>17:18:51.651</td><td>941.526177 s</td><td>933.888062 s</td><td>Bulk or Interrupt Transfer</td><td>Input Report len:64</td><td>AA 06 00 25 38 00 00 00...</td><td>in</td><td>01:01:82</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C51BE0560h</td><td>Success (Success)</td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  AA 06 00 25 38 00 00 00 50 00 AA BB 01 00 00 02  ...%8...P.......
00000010  02 64 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  .d..............
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0028-0012</td><td>17:18:51.651</td><td>941.526178 s</td><td>933.888065 s</td><td>Bulk or Interrupt Transfer</td><td>Input Report len:64</td><td>AA 06 00 25 38 00 00 00...</td><td>in</td><td>01:01:82</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C51BE0560h</td><td>Success (Success)</td></tr>
<tr><td colspan='15' class='rawdata'><pre>
00000000  AA 06 00 25 38 00 00 00 50 00 AA BB 01 00 00 02  ...%8...P.......
00000010  02 64 02 00 00 00 FF 00 80 00 00 00 00 00 00 00  .d..............
00000020  02 64 02 00 01 FF 00 E6 00 00 00 00 00 00 00 00  .d..............
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre></td></tr>
<tr><td>URB</td><td>0029</td><td>17:18:51.651</td><td>941.526188 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C562BBE10h</td><td></td><td>ACPI</td><td>FFFFBB8C51BE0560h</td><td></td></tr>
<tr><td>URB</td><td>0030</td><td>17:18:51.651</td><td>941.526189 s</td><td></td><td>Bulk or Interrupt Transfer</td><td>64 bytes buffer</td><td></td><td>in</td><td>01:01:82</td><td>FFFFBB8C53A3DDE0h</td><td>USBPDO-10</td><td>USBHUB3</td><td>FFFFBB8C51BE0560h</td><td></td></tr>
</table>

<br><br><p align=center>This report was generated by <a href="http://www.usblyzer.com/">USBlyzer</a>

</body>

</html>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants