Initial POC commit

This commit is contained in:
jetsparrow 2023-10-20 23:48:39 +03:00
commit e6f4f7a0ea
8 changed files with 602 additions and 0 deletions

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
# Autosave files
*~
# build
[Oo]bj/
[Bb]in/
packages/
TestResults/
# globs
Makefile.in
*.DS_Store
*.sln.cache
*.suo
*.cache
*.pidb
*.userprefs
*.usertasks
config.log
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.user
*.tar.gz
tarballs/
test-results/
Thumbs.db
.vs/
# Mac bundle stuff
*.dmg
*.app
# resharper
*_Resharper.*
*.Resharper
# dotCover
*.dotCover
minikbd-ilspy.zip

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34031.279
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jetsparrow.MiniKeyboard", "Jetsparrow.MiniKeyboard\Jetsparrow.MiniKeyboard.csproj", "{44CB124B-35D1-4FF4-8AE5-C03E9A647BD4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{44CB124B-35D1-4FF4-8AE5-C03E9A647BD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44CB124B-35D1-4FF4-8AE5-C03E9A647BD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44CB124B-35D1-4FF4-8AE5-C03E9A647BD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44CB124B-35D1-4FF4-8AE5-C03E9A647BD4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {43FDE226-D5FF-4EEA-A69B-10317D189C8E}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,82 @@
using HidSharp;
using HidSharp.Reports;
namespace Jetsparrow.MiniKeyboard;
public class MiniKeyboardDevice
{
public MiniKeyboardDevice(ProductDescr descr, HidDevice device, HidStream stream)
{
Descr = descr;
Device = device;
Stream = stream;
}
public ProductDescr Descr { get; }
public int ProtocolType => Descr.ProtocolType;
HidDevice Device { get; }
HidStream Stream { get; }
public async Task SendBuffer(ReadOnlyMemory<byte> report)
{
Console.WriteLine($"Sending {Convert.ToHexString(report.Span)}");
var SendBuf = new byte[65];
report.CopyTo(SendBuf);
Stream.Write(SendBuf);
Stream.Flush();
}
public async Task<int> GetKeyboardVersion()
{
byte[] buf = new byte[65];
for (byte i = 0; i < 10; ++i)
{
try
{
buf[0] = i;
await SendBuffer(buf);
return i;
}
catch { }
}
throw new NotImplementedException();
}
}
public partial class DeviceManager
{
public async Task<MiniKeyboardDevice?> Connect()
{
await Task.Yield();
var compat = GetCompatibleDevice();
if (compat is null)
return null;
(var dev, var descr) = compat.Value;
var stream = dev.Open();
return new MiniKeyboardDevice(descr, dev, stream);
}
(HidDevice device, ProductDescr descr)? GetCompatibleDevice()
{
var list = DeviceList.Local;
var compatDeviceList = list.GetAllDevices()
.OfType<HidDevice>()
.ToList();
foreach (var dev in compatDeviceList)
{
var id = (dev.VendorID, dev.ProductID);
if (!ProductRegistry.ProductsById.TryGetValue(id, out var descr))
continue;
if (dev.DevicePath.Contains(descr.SearchPathSegment))
return (dev, descr);
}
return null;
}
}

View File

@ -0,0 +1,297 @@
namespace Jetsparrow.MiniKeyboard;
public enum PhysicalKey : byte
{
None = 0,
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key10,
Key11,
Key12,
Knob1Left,
Knob1Click,
Knob1Right,
Knob2Left,
Knob2Click,
Knob2Right,
Knob3Left,
Knob3Click,
Knob3Right
}
[Flags]
public enum KeyModifier : byte
{
None = 0,
KEY_MOD_LCTRL = 0x01,
KEY_MOD_LSHIFT = 0x02,
KEY_MOD_LALT = 0x04,
KEY_MOD_LMETA = 0x08,
KEY_MOD_LWIN = 0x08,
KEY_MOD_RCTRL = 0x10,
KEY_MOD_RSHIFT = 0x20,
KEY_MOD_RALT = 0x40,
KEY_MOD_RMETA = 0x80,
KEY_MOD_RWIN = 0x80,
}
public enum UsbHidKeys
{
KEY_NONE = 0x00, // No key pressed
KEY_ERR_OVF = 0x01, // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
KEY_ERR_PF = 0x02, // Keyboard POST Fail
KEY_ERR_UNDEF = 0x03, // Keyboard Error Undefined
KEY_A = 0x04, // Keyboard a and A
KEY_B = 0x05, // Keyboard b and B
KEY_C = 0x06, // Keyboard c and C
KEY_D = 0x07, // Keyboard d and D
KEY_E = 0x08, // Keyboard e and E
KEY_F = 0x09, // Keyboard f and F
KEY_G = 0x0a, // Keyboard g and G
KEY_H = 0x0b, // Keyboard h and H
KEY_I = 0x0c, // Keyboard i and I
KEY_J = 0x0d, // Keyboard j and J
KEY_K = 0x0e, // Keyboard k and K
KEY_L = 0x0f, // Keyboard l and L
KEY_M = 0x10, // Keyboard m and M
KEY_N = 0x11, // Keyboard n and N
KEY_O = 0x12, // Keyboard o and O
KEY_P = 0x13, // Keyboard p and P
KEY_Q = 0x14, // Keyboard q and Q
KEY_R = 0x15, // Keyboard r and R
KEY_S = 0x16, // Keyboard s and S
KEY_T = 0x17, // Keyboard t and T
KEY_U = 0x18, // Keyboard u and U
KEY_V = 0x19, // Keyboard v and V
KEY_W = 0x1a, // Keyboard w and W
KEY_X = 0x1b, // Keyboard x and X
KEY_Y = 0x1c, // Keyboard y and Y
KEY_Z = 0x1d, // Keyboard z and Z
KEY_1 = 0x1e, // Keyboard 1 and !
KEY_2 = 0x1f, // Keyboard 2 and @
KEY_3 = 0x20, // Keyboard 3 and #
KEY_4 = 0x21, // Keyboard 4 and $
KEY_5 = 0x22, // Keyboard 5 and %
KEY_6 = 0x23, // Keyboard 6 and ^
KEY_7 = 0x24, // Keyboard 7 and &
KEY_8 = 0x25, // Keyboard 8 and *
KEY_9 = 0x26, // Keyboard 9 and (
KEY_0 = 0x27, // Keyboard 0 and )
KEY_ENTER = 0x28, // Keyboard Return (ENTER)
KEY_ESC = 0x29, // Keyboard ESCAPE
KEY_BACKSPACE = 0x2a, // Keyboard DELETE (Backspace)
KEY_TAB = 0x2b, // Keyboard Tab
KEY_SPACE = 0x2c, // Keyboard Spacebar
KEY_MINUS = 0x2d, // Keyboard - and _
KEY_EQUAL = 0x2e, // Keyboard = and +
KEY_LEFTBRACE = 0x2f, // Keyboard [ and {
KEY_RIGHTBRACE = 0x30, // Keyboard ] and }
KEY_BACKSLASH = 0x31, // Keyboard \ and |
KEY_HASHTILDE = 0x32, // Keyboard Non-US # and ~
KEY_SEMICOLON = 0x33, // Keyboard ; and :
KEY_APOSTROPHE = 0x34, // Keyboard ' and "
KEY_GRAVE = 0x35, // Keyboard ` and ~
KEY_COMMA = 0x36, // Keyboard , and <
KEY_DOT = 0x37, // Keyboard . and >
KEY_SLASH = 0x38, // Keyboard / and ?
KEY_CAPSLOCK = 0x39, // Keyboard Caps Lock
KEY_F1 = 0x3a, // Keyboard F1
KEY_F2 = 0x3b, // Keyboard F2
KEY_F3 = 0x3c, // Keyboard F3
KEY_F4 = 0x3d, // Keyboard F4
KEY_F5 = 0x3e, // Keyboard F5
KEY_F6 = 0x3f, // Keyboard F6
KEY_F7 = 0x40, // Keyboard F7
KEY_F8 = 0x41, // Keyboard F8
KEY_F9 = 0x42, // Keyboard F9
KEY_F10 = 0x43, // Keyboard F10
KEY_F11 = 0x44, // Keyboard F11
KEY_F12 = 0x45, // Keyboard F12
KEY_SYSRQ = 0x46, // Keyboard Print Screen
KEY_SCROLLLOCK = 0x47, // Keyboard Scroll Lock
KEY_PAUSE = 0x48, // Keyboard Pause
KEY_INSERT = 0x49, // Keyboard Insert
KEY_HOME = 0x4a, // Keyboard Home
KEY_PAGEUP = 0x4b, // Keyboard Page Up
KEY_DELETE = 0x4c, // Keyboard Delete Forward
KEY_END = 0x4d, // Keyboard End
KEY_PAGEDOWN = 0x4e, // Keyboard Page Down
KEY_RIGHT = 0x4f, // Keyboard Right Arrow
KEY_LEFT = 0x50, // Keyboard Left Arrow
KEY_DOWN = 0x51, // Keyboard Down Arrow
KEY_UP = 0x52, // Keyboard Up Arrow
KEY_NUMLOCK = 0x53, // Keyboard Num Lock and Clear
KEY_KPSLASH = 0x54, // Keypad /
KEY_KPASTERISK = 0x55, // Keypad *
KEY_KPMINUS = 0x56, // Keypad -
KEY_KPPLUS = 0x57, // Keypad +
KEY_KPENTER = 0x58, // Keypad ENTER
KEY_KP1 = 0x59, // Keypad 1 and End
KEY_KP2 = 0x5a, // Keypad 2 and Down Arrow
KEY_KP3 = 0x5b, // Keypad 3 and PageDn
KEY_KP4 = 0x5c, // Keypad 4 and Left Arrow
KEY_KP5 = 0x5d, // Keypad 5
KEY_KP6 = 0x5e, // Keypad 6 and Right Arrow
KEY_KP7 = 0x5f, // Keypad 7 and Home
KEY_KP8 = 0x60, // Keypad 8 and Up Arrow
KEY_KP9 = 0x61, // Keypad 9 and Page Up
KEY_KP0 = 0x62, // Keypad 0 and Insert
KEY_KPDOT = 0x63, // Keypad . and Delete
KEY_102ND = 0x64, // Keyboard Non-US \ and |
KEY_COMPOSE = 0x65, // Keyboard Application
KEY_POWER = 0x66, // Keyboard Power
KEY_KPEQUAL = 0x67, // Keypad =
KEY_F13 = 0x68, // Keyboard F13
KEY_F14 = 0x69, // Keyboard F14
KEY_F15 = 0x6a, // Keyboard F15
KEY_F16 = 0x6b, // Keyboard F16
KEY_F17 = 0x6c, // Keyboard F17
KEY_F18 = 0x6d, // Keyboard F18
KEY_F19 = 0x6e, // Keyboard F19
KEY_F20 = 0x6f, // Keyboard F20
KEY_F21 = 0x70, // Keyboard F21
KEY_F22 = 0x71, // Keyboard F22
KEY_F23 = 0x72, // Keyboard F23
KEY_F24 = 0x73, // Keyboard F24
KEY_OPEN = 0x74, // Keyboard Execute
KEY_HELP = 0x75, // Keyboard Help
KEY_PROPS = 0x76, // Keyboard Menu
KEY_FRONT = 0x77, // Keyboard Select
KEY_STOP = 0x78, // Keyboard Stop
KEY_AGAIN = 0x79, // Keyboard Again
KEY_UNDO = 0x7a, // Keyboard Undo
KEY_CUT = 0x7b, // Keyboard Cut
KEY_COPY = 0x7c, // Keyboard Copy
KEY_PASTE = 0x7d, // Keyboard Paste
KEY_FIND = 0x7e, // Keyboard Find
KEY_MUTE = 0x7f, // Keyboard Mute
KEY_VOLUMEUP = 0x80, // Keyboard Volume Up
KEY_VOLUMEDOWN = 0x81, // Keyboard Volume Down
// = 0x82 Keyboard Locking Caps Lock
// = 0x83 Keyboard Locking Num Lock
// = 0x84 Keyboard Locking Scroll Lock
KEY_KPCOMMA = 0x85, // Keypad Comma
// = 0x86 Keypad Equal Sign
KEY_RO = 0x87, // Keyboard International1
KEY_KATAKANAHIRAGANA = 0x88, // Keyboard International2
KEY_YEN = 0x89, // Keyboard International3
KEY_HENKAN = 0x8a, // Keyboard International4
KEY_MUHENKAN = 0x8b, // Keyboard International5
KEY_KPJPCOMMA = 0x8c, // Keyboard International6
// = 0x8d Keyboard International7
// = 0x8e Keyboard International8
// = 0x8f Keyboard International9
KEY_HANGEUL = 0x90, // Keyboard LANG1
KEY_HANJA = 0x91, // Keyboard LANG2
KEY_KATAKANA = 0x92, // Keyboard LANG3
KEY_HIRAGANA = 0x93, // Keyboard LANG4
KEY_ZENKAKUHANKAKU = 0x94, // Keyboard LANG5
// = 0x95 Keyboard LANG6
// = 0x96 Keyboard LANG7
// = 0x97 Keyboard LANG8
// = 0x98 Keyboard LANG9
// = 0x99 Keyboard Alternate Erase
// = 0x9a Keyboard SysReq/Attention
// = 0x9b Keyboard Cancel
// = 0x9c Keyboard Clear
// = 0x9d Keyboard Prior
// = 0x9e Keyboard Return
// = 0x9f Keyboard Separator
// = 0xa0 Keyboard Out
// = 0xa1 Keyboard Oper
// = 0xa2 Keyboard Clear/Again
// = 0xa3 Keyboard CrSel/Props
// = 0xa4 Keyboard ExSel
// = 0xb0 Keypad 00
// = 0xb1 Keypad 000
// = 0xb2 Thousands Separator
// = 0xb3 Decimal Separator
// = 0xb4 Currency Unit
// = 0xb5 Currency Sub-unit
KEY_KPLEFTPAREN = 0xb6, // Keypad (
KEY_KPRIGHTPAREN = 0xb7, // Keypad )
// = 0xb8 Keypad {
// = 0xb9 Keypad }
// = 0xba Keypad Tab
// = 0xbb Keypad Backspace
// = 0xbc Keypad A
// = 0xbd Keypad B
// = 0xbe Keypad C
// = 0xbf Keypad D
// = 0xc0 Keypad E
// = 0xc1 Keypad F
// = 0xc2 Keypad XOR
// = 0xc3 Keypad ^
// = 0xc4 Keypad %
// = 0xc5 Keypad <
// = 0xc6 Keypad >
// = 0xc7 Keypad &
// = 0xc8 Keypad &&
// = 0xc9 Keypad |
// = 0xca Keypad ||
// = 0xcb Keypad :
// = 0xcc Keypad #
// = 0xcd Keypad Space
// = 0xce Keypad @
// = 0xcf Keypad !
// = 0xd0 Keypad Memory Store
// = 0xd1 Keypad Memory Recall
// = 0xd2 Keypad Memory Clear
// = 0xd3 Keypad Memory Add
// = 0xd4 Keypad Memory Subtract
// = 0xd5 Keypad Memory Multiply
// = 0xd6 Keypad Memory Divide
// = 0xd7 Keypad +/-
// = 0xd8 Keypad Clear
// = 0xd9 Keypad Clear Entry
// = 0xda Keypad Binary
// = 0xdb Keypad Octal
// = 0xdc Keypad Decimal
// = 0xdd Keypad Hexadecimal
KEY_LEFTCTRL = 0xe0, // Keyboard Left Control
KEY_LEFTSHIFT = 0xe1, // Keyboard Left Shift
KEY_LEFTALT = 0xe2, // Keyboard Left Alt
KEY_LEFTMETA = 0xe3, // Keyboard Left GUI
KEY_RIGHTCTRL = 0xe4, // Keyboard Right Control
KEY_RIGHTSHIFT = 0xe5, // Keyboard Right Shift
KEY_RIGHTALT = 0xe6, // Keyboard Right Alt
KEY_RIGHTMETA = 0xe7, // Keyboard Right GUI
KEY_MEDIA_PLAYPAUSE = 0xe8,
KEY_MEDIA_STOPCD = 0xe9,
KEY_MEDIA_PREVIOUSSONG = 0xea,
KEY_MEDIA_NEXTSONG = 0xeb,
KEY_MEDIA_EJECTCD = 0xec,
KEY_MEDIA_VOLUMEUP = 0xed,
KEY_MEDIA_VOLUMEDOWN = 0xee,
KEY_MEDIA_MUTE = 0xef,
KEY_MEDIA_WWW = 0xf0,
KEY_MEDIA_BACK = 0xf1,
KEY_MEDIA_FORWARD = 0xf2,
KEY_MEDIA_STOP = 0xf3,
KEY_MEDIA_FIND = 0xf4,
KEY_MEDIA_SCROLLUP = 0xf5,
KEY_MEDIA_SCROLLDOWN = 0xf6,
KEY_MEDIA_EDIT = 0xf7,
KEY_MEDIA_SLEEP = 0xf8,
KEY_MEDIA_COFFEE = 0xf9,
KEY_MEDIA_REFRESH = 0xfa,
KEY_MEDIA_CALC = 0xfb,
}

View File

@ -0,0 +1,4 @@
global using System;
global using System.Linq;
global using System.Collections.Generic;
global using System.Threading.Tasks;

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HidSharpCore" Version="1.2.1.1" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,62 @@
namespace Jetsparrow.MiniKeyboard;
public class ProductDescr
{
public int VendorId { get; set; }
public int ProductId { get; set; }
public int ProtocolType { get; set; }
public string SearchPathSegment { get; set; }
}
public static class ProductRegistry
{
public static IReadOnlyDictionary<(int vendorId, int productId), ProductDescr> ProductsById { get; }
public static IReadOnlyList<ProductDescr> Products => m_Products;
static ProductRegistry()
{
ProductsById = Products.ToDictionary(p => (p.VendorId, p.ProductId));
}
const int ThisVendorId = 0x1189; // TODO RENAME
static readonly List<ProductDescr> m_Products = new ()
{
new() {
VendorId = ThisVendorId,
ProductId = 0x8890,
ProtocolType = 0,
SearchPathSegment = "mi_01"
},
new() {
VendorId = ThisVendorId,
ProductId = 34864,
ProtocolType = 1,
SearchPathSegment = "mi_00"
},
new() {
VendorId = ThisVendorId,
ProductId = 34865,
ProtocolType = 1,
SearchPathSegment = "mi_00"
},
new() {
VendorId = ThisVendorId,
ProductId = 34866,
ProtocolType = 1,
SearchPathSegment = "mi_00"
},
new() {
VendorId = ThisVendorId,
ProductId = 34867,
ProtocolType = 1,
SearchPathSegment = "mi_00"
},
new() {
VendorId = ThisVendorId,
ProductId = 34832,
ProtocolType = 1,
SearchPathSegment = "mi_00"
},
};
}

View File

@ -0,0 +1,75 @@
// See https://aka.ms/new-console-template for more information
using HidSharp.Utility;
using Jetsparrow.MiniKeyboard;
HidSharpDiagnostics.EnableTracing = true;
HidSharpDiagnostics.PerformStrictChecks = true;
Console.WriteLine("Hello, World!");
var man = new DeviceManager();
var dev = await man.Connect();
var keyboardVersion = await dev.GetKeyboardVersion();
/*
ReportID
KeyType_Num
KeyGroupCharNum
KeyGroupCharNum
Key_Fun_Num
KEY_Char_Num
KEY_Char_Num
...
*/
//await dev.SendBuffer(Convert.FromHexString("03 A1 02 00 000000000000".Replace(" ", "")));
// 03 01 1__________1 05 00 00 00
// VERSION KEY layer1 key+mods STRLEN I MODS KEY
// strings are sent starting with null at pos zero
Console.WriteLine($"KeyboardVersion {keyboardVersion}");
await SetKey(PhysicalKey.Key1, 0, Convert.FromHexString("0918060E2C"));
await SetKey(PhysicalKey.Key2, 0, Convert.FromHexString("0918060E2C"));
await SetKey(PhysicalKey.Key3, 0, Convert.FromHexString("0918060E2C"));
await SetKey(PhysicalKey.Knob1Left, 0, Convert.FromHexString("0918060E2C"));
await SetKey(PhysicalKey.Knob1Right, 0, Convert.FromHexString("0918060E2C"));
await SetKey(PhysicalKey.Knob1Click, 0, Convert.FromHexString("0918060E2C"));
//await dev.SendBuffer(Convert.FromHexString("03 AA AA 00 000000000000".Replace(" ", "")));
//await dev.SendBuffer(Convert.FromHexString("03 02 00 01 01 000700000000".Replace(" ", "")));
//await dev.SendBuffer(Convert.FromHexString("03 03 00 01 01 000800000000".Replace(" ", "")));
async Task SetKey(PhysicalKey keyNum, KeyModifier mods, byte[] codes)
{
var buf = new byte[7];
buf[0] = (byte)keyboardVersion;
buf[1] = (byte)keyNum;
buf[2] = 0x11;
buf[3] = (byte)codes.Length;
buf[5] = (byte)mods;
await dev.SendBuffer(buf);
for (int i = 1; i <= codes.Length; ++i)
{
buf[4] = (byte)i;
buf[6] = (byte)codes[i-1];
await dev.SendBuffer(buf);
}
}