XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.NativeKernel;

public unsafe struct UsbHidField
{
    public uint Bit, Size, Count, Page, Minimum, Maximum, Report, Flags;
}
public unsafe struct UsbHidLayout
{
    public UsbHidField* Fields;
    public uint Count, Capacity, Kind, ReportIds;
}
public unsafe struct UsbHidState
{
    public ulong A, B, C, D;
    public byte Modifiers;
    public Ps2DecodeState Decoder;
}

// HID 1.11 short-item parser. Bounded input, fields and bit offsets; vendor,
// absolute-pointer and oversized reports do not become fabricated input.
// Shared directly with the host descriptor tests, without any hardware I/O.
public static unsafe class UsbHid
{
    public static bool Parse(byte* bytes, uint length, UsbHidLayout* layout)
    {
        if (bytes == null || length == 0 || length > 4096 || layout == null || layout->Fields == null) return false;
        layout->Count = layout->Kind = layout->ReportIds = 0;
        uint page = 0, size = 0, count = 0, report = 0, minimum = 0, maximum = 0, usageCount = 0;
        uint* usages = stackalloc uint[256];
        uint* bits = stackalloc uint[256];
        uint* globals = stackalloc uint[32];
        for (uint i = 0; i < 256; i++) bits[i] = 0;
        uint depth = 0;
        for (uint p = 0; p < length;)
        {
            byte prefix = bytes[p++];
            if (prefix == 0xfe) return false; // long/vendor items are outside the supported contract
            uint n = (uint)(prefix & 3); if (n == 3) n = 4;
            if (n > length - p) return false;
            uint value = 0; for (uint i = 0; i < n; i++) value |= (uint)bytes[p++] << (int)(8 * i);
            uint type = (uint)(prefix >> 2) & 3, tag = (uint)prefix >> 4;
            if (type == 1)
            {
                if (tag == 0) page = value;
                else if (tag == 7) { if (value > 32) return false; size = value; }
                else if (tag == 8) { if (value == 0 || value > 255) return false; report = value; layout->ReportIds = 1; }
                else if (tag == 9) { if (value > 256) return false; count = value; }
                else if (tag == 10)
                {
                    if (depth >= 8) return false;
                    globals[depth * 4] = page; globals[depth * 4 + 1] = size;
                    globals[depth * 4 + 2] = count; globals[depth++ * 4 + 3] = report;
                }
                else if (tag == 11)
                {
                    if (depth == 0) return false; depth--;
                    page = globals[depth * 4]; size = globals[depth * 4 + 1];
                    count = globals[depth * 4 + 2]; report = globals[depth * 4 + 3];
                }
            }
            else if (type == 2)
            {
                if (tag == 0) { if (usageCount == 256) return false; usages[usageCount++] = value; }
                else if (tag == 1) minimum = value;
                else if (tag == 2) maximum = value;
            }
            else if (type == 0)
            {
                if (tag == 8)
                {
                    if (size == 0 || count == 0 || bits[report] > 32768 || size * count > 32768 - bits[report]) return false;
                    uint start = bits[report]; bits[report] += size * count;
                    if ((value & 1) == 0)
                    {
                        bool variable = (value & 2) != 0;
                        if (page == 7 && !variable)
                        {
                            if (!Add(layout, start, size, count, page, minimum, maximum, report, value)) return false;
                            layout->Kind |= 1;
                        }
                        else if (page == 7 || page == 9 || page == 1)
                        {
                            for (uint i = 0; i < count; i++)
                            {
                                uint usage = usageCount != 0 ? usages[i < usageCount ? i : usageCount - 1] : minimum + i;
                                uint actualPage = usage > 65535 ? usage >> 16 : page;
                                usage &= 65535;
                                if (actualPage == 7 || actualPage == 9 || actualPage == 1 && usage is 0x30 or 0x31 or 0x38)
                                {
                                    if (!Add(layout, start + i * size, size, 1, actualPage, usage, usage, report, value)) return false;
                                    if (actualPage == 7) layout->Kind |= 1;
                                    else if (actualPage == 9 || (value & 4) != 0) layout->Kind |= 2;
                                }
                            }
                        }
                    }
                }
                minimum = maximum = usageCount = 0;
            }
        }
        return depth == 0 && layout->Count != 0 && layout->Kind != 0;
    }
    static bool Add(UsbHidLayout* layout, uint bit, uint size, uint count, uint page, uint min, uint max, uint id, uint flags)
    {
        if (layout->Count >= layout->Capacity) return false;
        layout->Fields[layout->Count++] = new UsbHidField { Bit = bit, Size = size, Count = count,
            Page = page, Minimum = min, Maximum = max, Report = id, Flags = flags };
        return true;
    }
    public static void BootKeyboard(UsbHidLayout* layout)
    {
        layout->Count = 0; layout->Kind = 1; layout->ReportIds = 0;
        for (uint i = 0; i < 8; i++) Add(layout, i, 1, 1, 7, 224 + i, 224 + i, 0, 2);
        Add(layout, 16, 8, 6, 7, 0, 255, 0, 0);
    }
    public static uint Bits(byte* data, uint bit, uint size)
    {
        uint value = 0;
        for (uint i = 0; i < size; i++) if ((data[(bit + i) / 8] & (1 << (int)((bit + i) & 7))) != 0) value |= 1u << (int)i;
        return value;
    }
    static int Signed(uint value, uint size) => size == 32 ? unchecked((int)value) : (int)(value << (int)(32 - size)) >> (int)(32 - size);
    static bool Has(ulong* set, uint key) => key < 256 && (set[key / 64] & (1UL << (int)(key & 63))) != 0;
    public static uint Decode(UsbHidLayout* layout, UsbHidState* state, byte* data, uint bytes, NativeInputReport* output, uint capacity)
    {
        if (layout == null || state == null || data == null || bytes == 0 || bytes > 4096 || output == null || capacity < 64) return 0;
        uint id = 0;
        if (layout->ReportIds != 0) { id = *data++; bytes--; }
        ulong* keys = stackalloc ulong[4]; for (uint i = 0; i < 4; i++) keys[i] = 0;
        bool keyboard = false, pointer = false, rollover = false;
        uint mods = 0, buttons = 0; int x = 0, y = 0, wheel = 0;
        for (uint i = 0; i < layout->Count; i++)
        {
            UsbHidField* f = &layout->Fields[i];
            if (f->Report != id) continue;
            if (f->Bit + f->Size * f->Count > bytes * 8) return 0; // truncated input changes no held state
            if (f->Page == 7) keyboard = true;
            for (uint j = 0; j < f->Count; j++)
            {
                uint v = Bits(data, f->Bit + j * f->Size, f->Size);
                if (f->Page == 7)
                {
                    uint usage = (f->Flags & 2) != 0 ? (v != 0 ? f->Minimum : 0) : v;
                    if (usage is >= 224 and <= 231) mods |= 1u << (int)(usage - 224);
                    else if (usage is >= 1 and <= 3) rollover = true;
                    else if (usage is >= 4 and < 224) keys[usage / 64] |= 1UL << (int)(usage & 63);
                }
                else if (f->Page == 9 && f->Minimum is >= 1 and <= 5)
                { pointer = true; if (v != 0) buttons |= 1u << (int)(f->Minimum - 1); }
                else if (f->Page == 1 && (f->Flags & 4) != 0)
                {
                    int signed = Signed(v, f->Size); pointer = true;
                    if (f->Minimum == 0x30) x = signed; else if (f->Minimum == 0x31) y = signed; else if (f->Minimum == 0x38) wheel = signed;
                }
            }
        }
        uint made = 0;
        if (keyboard && !rollover)
        {
            // Modifier transitions precede ordinary keys, using the common
            // native set-1 ABI so Win/Alt+Tab work in both input backends.
            for (uint i = 0; i < 8; i++)
                if (((mods ^ state->Modifiers) & (1u << (int)i)) != 0)
                    Emit(state, Scan(224 + i), (mods & (1u << (int)i)) == 0, output, ref made);
            ulong* prior = &state->A;
            for (uint key = 4; key < 224; key++)
                if (Has(prior, key) && !Has(keys, key)) Emit(state, Scan(key), true, output, ref made);
            for (uint key = 4; key < 224; key++)
                if (!Has(prior, key) && Has(keys, key)) Emit(state, Scan(key), false, output, ref made);
            for (uint i = 0; i < 4; i++) prior[i] = keys[i];
            state->Modifiers = (byte)mods;
        }
        if (pointer && made < 64) output[made++] = new NativeInputReport { Kind = Ps2Decoder.Pointer,
            DeltaX = x, DeltaY = y, Buttons = buttons, Wheel = wheel, Modifiers = state->Decoder.Modifiers };
        return made;
    }
    static void Emit(UsbHidState* state, uint scan, bool release, NativeInputReport* output, ref uint count)
    {
        if (scan == 0 || count >= 63) return;
        if ((scan & 0x100) != 0) Ps2Decoder.DecodeKeyboard(ref state->Decoder, 0xe0, &output[count]);
        byte value = (byte)((scan & 127) | (release ? 128u : 0u));
        if (Ps2Decoder.DecodeKeyboard(ref state->Decoder, value, &output[count])) count++;
    }
    public static uint Scan(uint usage) => usage switch
    {
        4=>0x1e,5=>0x30,6=>0x2e,7=>0x20,8=>0x12,9=>0x21,10=>0x22,11=>0x23,12=>0x17,13=>0x24,14=>0x25,15=>0x26,
        16=>0x32,17=>0x31,18=>0x18,19=>0x19,20=>0x10,21=>0x13,22=>0x1f,23=>0x14,24=>0x16,25=>0x2f,26=>0x11,27=>0x2d,28=>0x15,29=>0x2c,
        >=30 and <=38=>usage-28,39=>0x0b,40=>0x1c,41=>1,42=>0xe,43=>0xf,44=>0x39,45=>0xc,46=>0xd,47=>0x1a,48=>0x1b,49=>0x2b,
        50=>0x2b,51=>0x27,52=>0x28,53=>0x29,54=>0x33,55=>0x34,56=>0x35,57=>0x3a,>=58 and <=67=>usage+1,68=>0x57,69=>0x58,
        70=>0x137,71=>0x46,73=>0x152,74=>0x147,75=>0x149,76=>0x153,77=>0x14f,78=>0x151,79=>0x14d,80=>0x14b,81=>0x150,82=>0x148,
        83=>0x45,84=>0x135,85=>0x37,86=>0x4a,87=>0x4e,88=>0x11c,89=>0x4f,90=>0x50,91=>0x51,92=>0x4b,93=>0x4c,94=>0x4d,95=>0x47,96=>0x48,97=>0x49,98=>0x52,99=>0x53,
        224=>0x1d,225=>0x2a,226=>0x38,227=>0x15b,228=>0x11d,229=>0x36,230=>0x138,231=>0x15c,_=>0
    };
}