summaryrefslogtreecommitdiff
path: root/wrapper/input.cpp
blob: e34af4af2f1f2c757bbda1c107db6fcabe151dbc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "input.h"

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;

[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Unicode)]
public ref struct RawInputDevice {
    System::IntPtr handle;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = MAX_NAME_LEN)]
    System::String^ name;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = MAX_DEV_ID_LEN)]
    System::String^ id;
};

static int CompareByID(RawInputDevice^ x, RawInputDevice^ y)
{
    return String::Compare(x->id, y->id);
}

public ref struct MultiHandleDevice {
    System::String^ name;
    System::String^ id;
    List<System::IntPtr>^ handles;

    // Each element in the list returned has a distinct id
    // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-ids
    static List<MultiHandleDevice^>^ GetList()
    {
        return ListMaker::MakeList();
    }

    ref class ListMaker {
        List<RawInputDevice^>^ devices = gcnew List<RawInputDevice^>();

        delegate void NativeDevHandler(rawinput_device&);

        void Add(rawinput_device& dev)
        {
            devices->Add(Marshal::PtrToStructure<RawInputDevice^>(IntPtr(&dev)));
        }

        ListMaker() {}
    public:
        static List<MultiHandleDevice^>^ MakeList()
        {
            auto maker = gcnew ListMaker();
            NativeDevHandler^ del = gcnew NativeDevHandler(maker, &Add);
            GCHandle gch = GCHandle::Alloc(del);
            auto fp = static_cast<void (*)(rawinput_device&)>(
                Marshal::GetFunctionPointerForDelegate(del).ToPointer());
            rawinput_foreach(fp);
            gch.Free();

            auto ret = gcnew List<MultiHandleDevice^>();
            auto count = maker->devices->Count;
            auto first = 0;
            auto last = 0;

            if (count > 0) {
                maker->devices->Sort(gcnew Comparison<RawInputDevice^>(&CompareByID));
                while (++last != count) {
                    if (!String::Equals(maker->devices[first]->id, maker->devices[last]->id)) {
                        auto range = maker->devices->GetRange(first, last - first);
                        ret->Add(gcnew MultiHandleDevice(range));
                        first = last;
                    }
                }
                auto range = maker->devices->GetRange(first, last - first);
                ret->Add(gcnew MultiHandleDevice(range));
            }

            return ret;
        }
    };

private:
    MultiHandleDevice(IEnumerable<RawInputDevice^>^ seq)
    {
        auto it = seq->GetEnumerator();
        if (it->MoveNext()) {
            name = it->Current->name;
            id = it->Current->id;
            handles = gcnew List<IntPtr>();
            do handles->Add(it->Current->handle); while (it->MoveNext());
        }
    }
};