diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f2d1ab6..905de6fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,11 +6,43 @@ on: pull_request: branches: [master, 'chromatics-4.0.x', 'chromatics-4.*'] +# Minimum-privilege GITHUB_TOKEN: the workflow only checks out the repo and +# runs build/test/manifest-validation locally on the runner — it never calls +# the GitHub API to write commits, comments, releases, packages, etc. So +# contents: read is the only permission needed. Explicit block also silences +# the GitHub Advanced Security warning about unrestricted token scope. +permissions: + contents: read + +# Deduplicate push + pull_request runs on the same branch. A commit pushed to +# a PR branch fires both a `push` event and a `pull_request:synchronize` +# event; with the same concurrency group key (resolved from +# pull_request.head.ref on PR events and ref_name on push events), the +# newer run cancels the older one, so we get a single CI completion per +# commit instead of two parallel ones. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref_name }} + cancel-in-progress: true + jobs: build-and-test: - # GDI + WASAPI loopback means the project targets - # net10.0-windows7.0 and can only build on a Windows runner. - runs-on: windows-latest + # GDI + WASAPI loopback + Windows.Devices.Lights.LampArray plus the + # sparse-package PackageManager APIs mean the project targets + # net10.0-windows10.0.19041.0 and can only build on a Windows runner. + # + # Matrix on both currently-supported GitHub-hosted Windows runners so + # platform-specific regressions surface early: + # - windows-2022 = Server 2022, build 20348 (~Win11 21H2 equivalent) + # - windows-2025 = Server 2025, build 26100 (~Win11 24H2 equivalent) + # windows-2019 (build 17763) was retired by GitHub Actions in mid-2025, so + # SupportedOSPlatformVersion=10.0.17763.0 cannot be exercised in CI today; + # OS-guarded codepaths (e.g. SparsePackageRegistrar skipping on <19041) are + # validated locally / via user-reported issues. + strategy: + fail-fast: false + matrix: + runner: [windows-2022, windows-2025] + runs-on: ${{ matrix.runner }} steps: - name: Checkout @@ -21,11 +53,58 @@ jobs: with: dotnet-version: '10.0.x' + # nuget.org occasionally returns 502 Bad Gateway mid-restore (saw + # one such failure on commit bb0c9ed, second run on the same SHA + # succeeded immediately). Retry up to 3 times before failing the + # build to absorb transient feed flakiness without needing a + # manual re-run. - name: Restore - run: dotnet restore Chromatics.sln + uses: nick-fields/retry@v3 + with: + timeout_minutes: 10 + max_attempts: 3 + retry_wait_seconds: 30 + shell: pwsh + command: dotnet restore Chromatics.sln - name: Build (Release, no restore) run: dotnet build Chromatics.sln --configuration Release --no-restore --nologo - name: Test (Release, no build) run: dotnet test Chromatics.Tests/Chromatics.Tests.csproj --configuration Release --no-build --nologo --verbosity normal + + # Validate the Dynamic Lighting sparse-package manifest by packing it + # with makeappx (no signing, /nv = no schema validation skipping). The + # real publish.py pipeline does this against a freshly-bumped version + # number; here we substitute 0.0.0.0 just to satisfy the 4-part + # version requirement. Catches schema regressions (typo'd capability + # names, namespace drift, missing assets) before they reach a user, + # because registration failures at runtime are silent — the AppX + # subsystem reports them via DeploymentResult.ErrorText into the log, + # not via a dialog or exception. SDK 10 ships on both runners. + - name: Validate sparse-package manifest (makeappx) + shell: pwsh + run: | + $sdk = Get-ChildItem 'C:\Program Files (x86)\Windows Kits\10\bin' -Directory ` + | Where-Object { $_.Name -match '^10\.' } ` + | Sort-Object Name -Descending ` + | Select-Object -First 1 + if (-not $sdk) { throw "Windows 10 SDK not found on runner" } + $makeappx = Join-Path $sdk.FullName 'x64\makeappx.exe' + if (-not (Test-Path $makeappx)) { throw "makeappx.exe not found at $makeappx" } + Write-Host "Using makeappx at $makeappx" + + $src = 'Chromatics/Resources/SparsePackage' + $work = Join-Path $env:RUNNER_TEMP 'sparse-validate' + if (Test-Path $work) { Remove-Item $work -Recurse -Force } + Copy-Item $src $work -Recurse + + # Substitute the {{VERSION}} placeholder so the manifest parses. + $manifest = Join-Path $work 'AppxManifest.xml' + (Get-Content $manifest -Raw) -replace '\{\{VERSION\}\}', '0.0.0.0' ` + | Set-Content $manifest -NoNewline + + $out = Join-Path $env:RUNNER_TEMP 'Chromatics.test.appx' + & $makeappx pack /d $work /p $out /o /nv + if ($LASTEXITCODE -ne 0) { throw "makeappx pack failed with exit code $LASTEXITCODE" } + Write-Host "Sparse package validated: $out" diff --git a/CHANGELOG.md b/CHANGELOG.md index c85beb23..ef3056c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All notable changes to Chromatics are documented here. +## 4.2.13 + +- **New:** Windows Dynamic Lighting (Beta). Controls compatible devices during gameplay, not only while Chromatics has focus. The in-game part needs Windows 11 22H2 or newer; on older builds only the foreground side works. After enabling the provider in Chromatics, open Settings → Personalization → Dynamic Lighting → Background light control in Windows and drag Chromatics to the top. Chromatics only appears in that Windows list while its Dynamic Lighting provider is on; turning it off or uninstalling Chromatics removes the entry. +- **New:** Yeelight device support (Beta). +- **New:** Alienware LightFX device support (Beta). +- **New:** Copy layers between devices. A small copy icon next to the device brightness button on the Mappings tab opens a dialog that duplicates every layer from one device onto another. +- Hue, LIFX and Yeelight tiles added to the first-run wizard, each with their own discovery flow. +- PlayStation, Hue & LIFX devices are no longer classed as Beta. +- Minor fixes to Logitech implementation. +- Some keyboards and headsets used to show up in Chromatics without any usable LEDs. They now get a default key grid filled in automatically, so layers can paint them just like any other device. +- Bumped the project's minimum Windows target to Windows 10 1809 (build 17763). +- Chromatics installer is now officially signed for extra security. + +## 4.1.44 + +- **New:** QMK Raw HID keyboard support (Beta). Covers custom keyboards from NovelKeys, KBDFans, Drop, GMMK, Glorious, and any other brand running QMK firmware with Raw HID enabled. Enable it from Settings → Device Providers or pick it on the first-run device selector. Chromatics auto-detects compatible boards over USB and adopts them with no firmware flashing or extra software required. The provider drives per-key lighting through the OpenRGB-QMK plugin when the firmware has it installed; otherwise it controls the firmware's built-in RGB matrix base colour and effect mode via VIA. A pre-built key layout database covering 2650 QMK boards ships with Chromatics, so the Highlight and Keybind layers map to the correct physical keys without manual setup. +- Updated dependency libraries to latest version + ## 4.1.38 - Added Auto-discovery for Hue bridges. diff --git a/Chromatics.DecoratorHarnessUI/Chromatics.DecoratorHarnessUI.csproj b/Chromatics.DecoratorHarnessUI/Chromatics.DecoratorHarnessUI.csproj index 61239982..b4b98d3c 100644 --- a/Chromatics.DecoratorHarnessUI/Chromatics.DecoratorHarnessUI.csproj +++ b/Chromatics.DecoratorHarnessUI/Chromatics.DecoratorHarnessUI.csproj @@ -2,7 +2,7 @@ WinExe - net10.0-windows7.0 + net10.0-windows10.0.19041.0 enable enable True @@ -16,11 +16,28 @@ - - - - + + + + + + + + <_NativeSdkDlls Include="$(MSBuildThisFileDirectory)..\Chromatics\bin\$(Configuration)\$(TargetFramework)\x64\*.dll" /> + <_NativeSdkDllsX86 Include="$(MSBuildThisFileDirectory)..\Chromatics\bin\$(Configuration)\$(TargetFramework)\x86\*.dll" /> + + + + + diff --git a/Chromatics.DecoratorHarnessUI/MainViewModel.cs b/Chromatics.DecoratorHarnessUI/MainViewModel.cs index 3cb740a0..b5bec288 100644 --- a/Chromatics.DecoratorHarnessUI/MainViewModel.cs +++ b/Chromatics.DecoratorHarnessUI/MainViewModel.cs @@ -101,6 +101,32 @@ private async Task LoadProvider() { var provider = SelectedProvider.Factory(); + // Native-DLL providers (Logitech, Corsair, etc.) resolve their + // PossibleX64NativePaths entries against the current working + // directory, which is the workspace root when the harness + // launches from VS or `dotnet run` — not the harness's own bin + // folder where the DLLs actually sit. Pre-pend an absolute path + // computed from the harness assembly location so the SDK loader + // finds the wrapper without the user juggling cwd. Mirrors what + // the main app does for Corsair in RGBController.Setup. + string asmDir = System.IO.Path.GetDirectoryName( + System.Reflection.Assembly.GetExecutingAssembly().Location) ?? ""; + if (!string.IsNullOrEmpty(asmDir)) + { + if (provider is LogitechDeviceProvider) + { + LogitechDeviceProvider.PossibleX64NativePaths.Insert( + 0, System.IO.Path.Combine(asmDir, "x64", "LogitechLedEnginesWrapper.dll")); + LogitechDeviceProvider.PossibleX86NativePaths.Insert( + 0, System.IO.Path.Combine(asmDir, "x86", "LogitechLedEnginesWrapper.dll")); + } + else if (provider is CorsairDeviceProvider) + { + CorsairDeviceProvider.PossibleX64NativePaths.Insert( + 0, System.IO.Path.Combine(asmDir, "x64", "CUESDK.dll")); + } + } + // LIFX is the only provider in the harness that needs an // adoption gate — the LAN protocol has no concept of "all // devices on the segment", so the user has to pick which @@ -137,20 +163,60 @@ private async Task LoadProvider() } } - provider.Initialize(throwExceptions: false); - _surface.Load(provider); - _loadedProvider = provider; - - Devices.Clear(); - foreach (var d in _surface.Devices) - Devices.Add(new DeviceItem(d.DeviceInfo.DeviceName, d.DeviceInfo.DeviceType.ToString(), d)); - - StartSurfaceTick(); - ProviderLoaded = true; - ProviderStatus = $"{Devices.Count} device(s) loaded"; - // Now that the surface has devices, evaluate the WASD highlight - // hook so the toggle works even before the user starts an effect. - RefreshWasdOverlay(); + // Capture provider-side exceptions before we try to Initialize so + // the harness surfaces them in the status panel rather than + // silently coming up with zero devices. RGB.NET reports SDK + // failures (missing native DLL, vendor service not running, + // exclusive-mode conflict) through this event and would + // otherwise drop them on the floor when throwExceptions:false. + var providerErrors = new System.Text.StringBuilder(); + void OnProviderException(object? s, ExceptionEventArgs e) + => providerErrors.AppendLine(e.Exception?.Message ?? e.Exception?.GetType().Name ?? "(null)"); + provider.Exception += OnProviderException; + + try + { + provider.Initialize(throwExceptions: false); + _surface.Load(provider); + _loadedProvider = provider; + + // Same Logitech-layout fixup the main app applies in + // RGBController.DevicesChanged.Added — rebinds Led.Location + // for Logitech keyboards/mice so position-aware decorators + // (conical gradients in particular) render correctly. RGB.NET's + // LogitechPerKeyRGBDevice ships every LED at Y=0 by default. + string asmDirForLayout = System.IO.Path.GetDirectoryName( + System.Reflection.Assembly.GetExecutingAssembly().Location) ?? ""; + foreach (var d in _surface.Devices) + Chromatics.Helpers.LogitechLayoutFixup.Apply(d, asmDirForLayout); + + Devices.Clear(); + foreach (var d in _surface.Devices) + Devices.Add(new DeviceItem(d.DeviceInfo.DeviceName, d.DeviceInfo.DeviceType.ToString(), d)); + + StartSurfaceTick(); + ProviderLoaded = true; + + if (Devices.Count > 0) + { + ProviderStatus = $"{Devices.Count} device(s) loaded"; + } + else if (providerErrors.Length > 0) + { + ProviderStatus = $"0 devices. SDK said: {providerErrors.ToString().Trim()}"; + } + else + { + ProviderStatus = "0 devices. SDK initialized but enumerated nothing — vendor service may not be running, or no supported hardware connected."; + } + // Now that the surface has devices, evaluate the WASD highlight + // hook so the toggle works even before the user starts an effect. + RefreshWasdOverlay(); + } + finally + { + provider.Exception -= OnProviderException; + } } catch (Exception ex) { @@ -170,18 +236,18 @@ private async Task LoadProvider() "Chromatics.DecoratorHarnessUI", "lifx-adopted.json"); - private static List LoadHarnessLifxAdoptions() + private static List LoadHarnessLifxAdoptions() { try { if (!System.IO.File.Exists(LifxAdoptionsPath)) return new(); var json = System.IO.File.ReadAllText(LifxAdoptionsPath); - return System.Text.Json.JsonSerializer.Deserialize>(json) ?? new(); + return System.Text.Json.JsonSerializer.Deserialize>(json) ?? new(); } catch { return new(); } } - private static void SaveHarnessLifxAdoptions(IEnumerable adoptions) + private static void SaveHarnessLifxAdoptions(IEnumerable adoptions) { try { @@ -2247,5 +2313,13 @@ public void Dispose() _surfaceTimer?.Stop(); _surfaceTimer?.Dispose(); try { _surface.Dispose(); } catch { } + + // Provider disposal stops the per-provider UpdateTrigger threads. + // Each provider's trigger is a Task.Factory.StartNew(... LongRunning ...) + // which spawns a foreground thread, and surface.Dispose only kills + // triggers explicitly registered via RegisterUpdateTrigger — not the + // providers' internal ones. Without this, the harness window closes + // but the process hangs around forever. + try { _loadedProvider?.Dispose(); } catch { } } } diff --git a/Chromatics.Tests/Chromatics.Tests.csproj b/Chromatics.Tests/Chromatics.Tests.csproj index 9e438fe2..880446a3 100644 --- a/Chromatics.Tests/Chromatics.Tests.csproj +++ b/Chromatics.Tests/Chromatics.Tests.csproj @@ -1,7 +1,7 @@ - net10.0-windows7.0 + net10.0-windows10.0.19041.0 enable enable diff --git a/Chromatics/Chromatics.csproj b/Chromatics/Chromatics.csproj index 4a3179a4..014ac89f 100644 --- a/Chromatics/Chromatics.csproj +++ b/Chromatics/Chromatics.csproj @@ -2,9 +2,15 @@ WinExe - net10.0-windows7.0 + + net10.0-windows10.0.19041.0 + 10.0.17763.0 Chromatics.Program - 4.1.38.0 + 4.2.13.0 Danielle Thompson app.manifest logicallysynced 2026 @@ -32,6 +38,10 @@ + + + + @@ -48,12 +58,12 @@ - - - - + + + + - + @@ -66,7 +76,7 @@ - + @@ -82,7 +92,6 @@ - diff --git a/Chromatics/Core/AppSettings.cs b/Chromatics/Core/AppSettings.cs index 13bfb987..d343bbc1 100644 --- a/Chromatics/Core/AppSettings.cs +++ b/Chromatics/Core/AppSettings.cs @@ -13,7 +13,9 @@ public static class AppSettings { private static SettingsModel _settings = new SettingsModel(); - public static readonly string currentSettingsVersion = "2"; + // v3: adds deviceDynamicLightingEnabled, dynamicLightingHintShown, + // and dynamicLightingBypassConflictCheck (v4.2.6+). + public static readonly string currentSettingsVersion = "3"; public static readonly string currentEffectsVersion = "2"; public static readonly string currentPalettesVersion = "1"; public static readonly string currentMappingLayerVersion = "2"; diff --git a/Chromatics/Core/RGBController.cs b/Chromatics/Core/RGBController.cs index 8ffe6d18..4e53acc1 100644 --- a/Chromatics/Core/RGBController.cs +++ b/Chromatics/Core/RGBController.cs @@ -3,6 +3,10 @@ using Chromatics.Extensions.RGB.NET.Devices.Hue; using Chromatics.Extensions.RGB.NET.Devices.LIFX; using Chromatics.Extensions.RGB.NET.Devices.PlayStation; +using Chromatics.Extensions.RGB.NET.Devices.Alienware; +using Chromatics.Extensions.RGB.NET.Devices.DynamicLighting; +using Chromatics.Extensions.RGB.NET.Devices.QmkRawHid; +using Chromatics.Extensions.RGB.NET.Devices.Yeelight; using Chromatics.Helpers; using Chromatics.Layers; using Chromatics.Models; @@ -17,7 +21,6 @@ using RGB.NET.Devices.Razer; using RGB.NET.Devices.SteelSeries; using RGB.NET.Devices.Wooting; -using RGB.NET.Layout; using RGB.NET.Presets.Decorators; using RGB.NET.Presets.Textures; using RGB.NET.Presets.Textures.Gradients; @@ -231,7 +234,7 @@ public static void Setup() var devicesResp = api.Device.GetAllAsync().GetAwaiter().GetResult(); var modelByDevice = devicesResp.Data.ToDictionary(d => d.Id, d => d.ProductData?.ModelId ?? ""); - var migrated = lights.Data.Select(l => new Models.HueAdoptedDevice + var migrated = lights.Data.Select(l => new Chromatics.Extensions.RGB.NET.Devices.Hue.HueAdoptedDevice { LightId = l.Id, Label = l.Metadata?.Name ?? l.Id.ToString(), @@ -304,8 +307,231 @@ public static void Setup() Logger.WriteConsole(Enums.LoggerTypes.Error, $"[LifxDeviceProvider] LoadDeviceProvider Error: {ex.Message}"); } } - - + + if (appSettings.deviceYeelightEnabled) + { + try + { + // Auto-adopt on first enable. Mirrors the QMK + // provider's pattern: when the persisted adopted-set + // is empty (initial launch after the user enabled + // the Yeelight toggle), run one SSDP sweep and adopt + // every bulb that responds. Subsequent launches + // reuse the persisted list and re-resolve only the + // IPs that may have changed. Users disable specific + // bulbs they don't want Chromatics to drive from the + // Mapping tab. + // + // (A proper Hue/LIFX-style adoption picker dialog + // is tracked as a v4.2.x follow-up — it's + // significantly more UI work and shipping + // auto-adopt first keeps the beta path testable.) + var adopted = appSettings.deviceYeelightAdoptedDevices ?? new List(); + if (adopted.Count == 0) + { + try + { + var discovered = Chromatics.Extensions.RGB.NET.Devices.Yeelight.Protocol.YeelightDiscovery + .DiscoverAsync(TimeSpan.FromMilliseconds(2500)) + .GetAwaiter().GetResult(); + foreach (var d in discovered) + { + if (string.IsNullOrEmpty(d.Id) || d.Endpoint == null) continue; + adopted.Add(new YeelightAdoptedDevice + { + Id = d.Id, + Label = d.DisplayLabel, + LastIp = d.Endpoint.Address.ToString(), + LastPort = d.Endpoint.Port, + Model = d.Model, + FirmwareVersion = d.FirmwareVersion, + Support = d.Support is List list ? list : new List(d.Support ?? Array.Empty()), + }); + } + if (adopted.Count > 0) + { + appSettings.deviceYeelightAdoptedDevices = adopted; + AppSettings.SaveSettings(appSettings); + Logger.WriteConsole(Enums.LoggerTypes.Devices, $"[Yeelight] Adopted {adopted.Count} bulb(s) discovered on the LAN. Open the Mapping tab to disable any you don't want Chromatics to control."); + } + else + { + Logger.WriteConsole(Enums.LoggerTypes.Devices, "[Yeelight] Discovery found no Yeelight bulbs on the LAN. Make sure each bulb has LAN Control enabled in the Yeelight / Mi Home app (Settings -> LAN Control).", forwardToSentry: false); + } + } + catch (Exception discEx) + { + Logger.WriteConsole(Enums.LoggerTypes.Error, $"[Yeelight] Initial discovery sweep failed: {discEx.Message}"); + } + } + + YeelightRGBDeviceProvider.Instance.ClientDefinitions.Clear(); + foreach (var d in adopted) + { + System.Net.IPEndPoint ep = null; + if (!string.IsNullOrEmpty(d.LastIp) && + System.Net.IPAddress.TryParse(d.LastIp, out var ip)) + { + ep = new System.Net.IPEndPoint(ip, d.LastPort > 0 ? d.LastPort : 55443); + } + YeelightRGBDeviceProvider.Instance.ClientDefinitions.Add( + new YeelightClientDefinition(d.Id, d.Label, ep, d.Model, d.FirmwareVersion, d.Support)); + } + + LoadDeviceProvider(YeelightRGBDeviceProvider.Instance); + } + catch (Exception ex) + { + Logger.WriteConsole(Enums.LoggerTypes.Error, $"[YeelightDeviceProvider] LoadDeviceProvider Error: {ex.Message}"); + } + } + + if (appSettings.deviceQmkRawHidEnabled) + { + try + { + // QMK Raw HID provider — auto-adopts every QMK-compatible + // keyboard discovered on the USB bus when the user has + // an empty persisted adopted-set (first launch after + // enabling). The adopted-set is the union of (a) the + // boards the user has explicitly seen in the Mapping + // tab and not removed via per-device disable, and (b) + // any new boards that appear on subsequent launches + // — the keymap fetch + handshake is cheap so refreshing + // is fine. Persistence stays in + // deviceQmkRawHidAdoptedDevices for the next launch's + // hot-plug filter. + Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance.AdoptedDevices.Clear(); + var adopted = appSettings.deviceQmkRawHidAdoptedDevices ?? new List(); + if (adopted.Count == 0) + { + // Discover once and adopt everything that responds. + // Subsequent launches will reuse the persisted list + // unless the user explicitly clears it. + var discovered = Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol.QmkRawHidDiscovery.Discover(); + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var c in discovered) + { + string mfg = ""; + string prod = ""; + try { mfg = c.Hid.GetManufacturer() ?? ""; } catch { } + try { prod = c.Hid.GetProductName() ?? ""; } catch { } + var key = $"{c.Hid.VendorID:X4}:{c.Hid.ProductID:X4}:{mfg}:{prod}"; + if (!seen.Add(key)) continue; + adopted.Add(new QmkRawHidAdoptedDevice + { + VendorId = c.Hid.VendorID, + ProductId = c.Hid.ProductID, + Manufacturer = mfg, + Product = prod, + LedCount = c.LedCount, + Protocol = c.Protocol.ToString(), + ViaKeymapKey = string.Empty, + }); + } + appSettings.deviceQmkRawHidAdoptedDevices = adopted; + if (adopted.Count > 0) AppSettings.SaveSettings(appSettings); + } + + foreach (var d in adopted) + { + Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance.AdoptedDevices.Add( + new Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidAdoptedDeviceFilter( + d.VendorId, d.ProductId, d.Manufacturer, d.Product)); + } + + LoadDeviceProvider(Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance); + } + catch (Exception ex) + { + Logger.WriteConsole(Enums.LoggerTypes.Error, $"[QmkRawHidDeviceProvider] LoadDeviceProvider Error: {ex.Message}"); + } + } + + if (appSettings.deviceAlienwareEnabled) + { + try + { + // Auto-adopt on first enable. Mirrors the QMK / Yeelight + // pattern: when the persisted adopted-set is empty, + // sweep the HID bus once and adopt every Alienware + // device that responds. Subsequent launches reuse the + // persisted list and re-bind by VID/PID/DevicePath. + var adopted = appSettings.deviceAlienwareAdoptedDevices ?? new List(); + if (adopted.Count == 0) + { + try + { + var discovered = Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol.AlienwareDiscovery.Discover(); + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var c in discovered) + { + string key = $"{c.Hid.VendorID:X4}:{c.Hid.ProductID:X4}:{c.Hid.DevicePath}"; + if (!seen.Add(key)) continue; + adopted.Add(new AlienwareAdoptedDevice + { + VendorId = c.Hid.VendorID, + ProductId = c.Hid.ProductID, + Manufacturer = c.Manufacturer, + Product = c.Product, + DevicePath = c.Hid.DevicePath, + ApiVersion = c.ApiVersion.ToString(), + LightCount = c.LightCount, + ReportLength = c.ReportLength, + }); + } + if (adopted.Count > 0) + { + appSettings.deviceAlienwareAdoptedDevices = adopted; + AppSettings.SaveSettings(appSettings); + Logger.WriteConsole(Enums.LoggerTypes.Devices, $"[Alienware] Adopted {adopted.Count} AlienFX device(s) discovered on the HID bus."); + } + else + { + Logger.WriteConsole(Enums.LoggerTypes.Devices, "[Alienware] No AlienFX devices detected. Make sure your machine is an Alienware / Dell G-series with AlienFX hardware, and that the Alienware Command Center isn't holding the HID interface exclusively.", forwardToSentry: false); + } + } + catch (Exception discEx) + { + Logger.WriteConsole(Enums.LoggerTypes.Error, $"[Alienware] Initial discovery sweep failed: {discEx.Message}"); + } + } + + Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareRGBDeviceProvider.Instance.ClientDefinitions.Clear(); + foreach (var d in adopted) + { + if (!Enum.TryParse(d.ApiVersion, out var api)) + api = Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol.AlienwareApiVersion.Unknown; + Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareRGBDeviceProvider.Instance.ClientDefinitions.Add( + new Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareClientDefinition( + d.VendorId, d.ProductId, d.Manufacturer, d.Product, + api, d.LightCount, d.ReportLength, d.DevicePath)); + } + + LoadDeviceProvider(Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareRGBDeviceProvider.Instance); + } + catch (Exception ex) + { + Logger.WriteConsole(Enums.LoggerTypes.Error, $"[AlienwareDeviceProvider] LoadDeviceProvider Error: {ex.Message}"); + } + } + + if (appSettings.deviceDynamicLightingEnabled) + { + try + { + // Windows Dynamic Lighting (LampArray). DeviceWatcher + // inside the provider handles initial enumeration and + // hot-plug, so there's no per-device adoption list to + // hydrate before LoadDeviceProvider. + LoadDeviceProvider(DynamicLightingRGBDeviceProvider.Instance); + } + catch (Exception ex) + { + Logger.WriteConsole(Enums.LoggerTypes.Error, $"[DynamicLightingDeviceProvider] LoadDeviceProvider Error: {ex.Message}"); + } + } + if (appSettings.rgbRefreshRate <= 0) appSettings.rgbRefreshRate = 0.05; _timerUpdateTrigger = new TimerUpdateTrigger(); @@ -378,6 +604,16 @@ public static void RemoveDevice(IRGBDevice device) catch { /* best-effort */ } }); } + else if (device is Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidDevice qmkDev) + { + // QMK boards have no captured pre-Chromatics state to + // restore — the firmware's built-in RGB matrix mode + // resumes by itself as soon as Update() stops sending + // frames. Gate the queue so any buffered frames in + // flight don't slip through, then let the firmware + // take over. + qmkDev.SetPerDeviceDisabled(true); + } surface.Detach(device); @@ -429,6 +665,11 @@ public static void AddDevice(IRGBDevice device) { hueDev.SetPerDeviceDisabled(false); } + else if (device is Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidDevice qmkDev) + { + qmkDev.ResetCache(); + qmkDev.SetPerDeviceDisabled(false); + } // Tagged effects (startup rainbow, title-screen starfield) // build their per-device ListLedGroup at the moment the tag @@ -584,35 +825,29 @@ private static void DevicesChanged(object sender, DevicesChangedEventArgs e) { //Device Added - //Handle cases where a device is loaded with 0 LEDs - if (device.Count() <= 0 && device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard) - { - var path = $"{enviroment}/Layouts/Default/Keyboard/Artemis XL keyboard-ISO.xml"; - - if (File.Exists(path)) - { - var layout = DeviceLayout.Load(path); - LayoutExtension.ApplyTo(layout, device, true); - - #if DEBUG - Debug.WriteLine($"Loaded layout for {device.DeviceInfo.Manufacturer} {device.DeviceInfo.DeviceType}. New Leds: {device.Count()}"); - #endif - } - } - else if (device.Count() <= 0 && device.DeviceInfo.DeviceType == RGBDeviceType.Headset) - { - var path = $"{enviroment}/Layouts/Default/Keyboard/Artemis 4 LEDs headset.xml"; - - if (File.Exists(path)) - { - var layout = DeviceLayout.Load(path); - LayoutExtension.ApplyTo(layout, device, true); - - #if DEBUG - Debug.WriteLine($"Loaded layout for {device.DeviceInfo.Manufacturer} {device.DeviceInfo.DeviceType}. New Leds: {device.Count()}"); - #endif - } - } + // Some providers hand us a device with zero LEDs (SDK silent + // on the geometry, or a model we have no layout for). Without + // at least one Led the device is invisible to every layer, + // so synthesise a sensible default grid from KeyLocalization + // — keyboards get the full QWERTY ANSI 104, headsets get a + // 2x2 left-ear / right-ear quartet. + Helpers.DefaultLayoutInference.Apply(device); + + // Logitech per-key keyboards arrive from RGB.NET with every + // LED at Y=0 (LogitechPerKeyRGBDevice.InitializeLayout lays + // them out in a single horizontal row at pos*19,0). That + // breaks any decorator that reads Led.Location for spatial + // computation — most visibly conical gradients, which use + // atan2(dy, dx) and degenerate to a left-half / right-half + // fade when every dy is 0. Per-key matrix-grid effects + // (CircularPulse via DeviceGridHelper) are unaffected + // because they use the QWERTY row/col grid, not Location. + // + // Apply the matching shipped layout XML over the top so + // Location matches the physical keycap. Mice / headsets + // get the same treatment for consistency. Falls through + // silently when the model has no shipped layout. + Helpers.LogitechLayoutFixup.Apply(device, enviroment); lock (_devicesLock) { @@ -822,6 +1057,18 @@ public static bool LoadDeviceProvider(IRGBDeviceProvider provider) surface.Load(provider); loadedDeviceProviders.Add(provider); + // Warn the user when a freshly-loaded provider gives us + // devices whose hardware/SDK can't accept per-LED writes + // (zone-only or single-colour fallback). Effects that + // depend on per-LED spatial position — radial pulses, + // ripples, audio-visualizer columns — degrade visually + // on those devices, and the user can't tell whether + // it's a Chromatics bug or hardware limit without this + // hint. Logitech is the only provider with a known set + // of zone/per-device fallback classes; the helper is + // pattern-matchable and easy to extend. + WarnLimitedDevices(provider); + // surface.Load attaches every device in provider.Devices // unconditionally (the comment in DevicesChanged about // "startup attachment is owned by SurfaceExtensions.Load" @@ -852,6 +1099,8 @@ public static bool LoadDeviceProvider(IRGBDeviceProvider provider) lifxDev.SetPerDeviceDisabled(true); else if (device is Extensions.RGB.NET.Devices.Hue.HueDevice hueDev) hueDev.SetPerDeviceDisabled(true); + else if (device is Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidDevice qmkDev) + qmkDev.SetPerDeviceDisabled(true); if (_activeDevices.ContainsKey(device)) _activeDevices[device] = false; else @@ -877,7 +1126,41 @@ public static bool LoadDeviceProvider(IRGBDeviceProvider provider) Logger.WriteConsole(Enums.LoggerTypes.Error, $"[{provider.Devices.FirstOrDefault().DeviceInfo.DeviceName}] LoadDeviceProvider Error: {ex.Message}"); return false; } - + + } + + // Surface a one-time console warning per provider load when devices + // can't accept per-LED writes — zone-based or single-colour SDK + // fallbacks. Effects that depend on per-LED spatial position + // (CircularPulse, BPMRipple, AudioVisualizer) degrade visibly on + // those devices, and the user otherwise has no way to tell whether + // it's a hardware limit or a Chromatics bug. Pattern-match on the + // device's runtime class — RGB.NET names them RGBDevice + // (LogitechZoneRGBDevice, LogitechPerDeviceRGBDevice, etc.). + // Extend the type-name list as new providers ship limited-mode + // device classes. + private static readonly Dictionary _limitedDeviceTypeWarnings = new(StringComparer.Ordinal) + { + ["LogitechZoneRGBDevice"] = "is using zone-based lighting (the SDK limits this model to a small number of zones); radial effects (CircularPulse, BPMRipple, AudioVisualizer) will look like horizontal stripes rather than circles", + ["LogitechPerDeviceRGBDevice"] = "is using single-colour lighting (the SDK exposes one zone for the whole device); radial and per-key effects will paint a single uniform colour", + }; + + private static void WarnLimitedDevices(IRGBDeviceProvider provider) + { + if (provider == null) return; + try + { + foreach (var device in provider.Devices) + { + string typeName = device.GetType().Name; + if (!_limitedDeviceTypeWarnings.TryGetValue(typeName, out var description)) continue; + + Logger.WriteConsole(Enums.LoggerTypes.Devices, + $"[Devices] '{device.DeviceInfo.DeviceName}' {description}.", + forwardToSentry: false); + } + } + catch { /* diagnostic — never fatal */ } } public static void UnloadDeviceProvider(IRGBDeviceProvider provider, bool removeFromList = true) @@ -1236,7 +1519,7 @@ public static void RegisterTaggedEffect(string tag, Guid deviceGuid, ListLedGrou // Tear down ONLY the groups registered under `tag` — used when the // user disables Startup Animation / Title Screen via the Effects - // tab and we need to stop the rainbow / starfield mid-cycle without + // tab and we need to stop the effects mid-cycle without // killing other running effects on the surface. // // LEDs are painted BLACK and one surface render is forced before diff --git a/Chromatics/Core/SparsePackageRegistrar.cs b/Chromatics/Core/SparsePackageRegistrar.cs new file mode 100644 index 00000000..15c7a31d --- /dev/null +++ b/Chromatics/Core/SparsePackageRegistrar.cs @@ -0,0 +1,189 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Threading.Tasks; +using Windows.Management.Deployment; + +namespace Chromatics.Core +{ + // Registers Chromatics' sparse signed AppX package on startup so the Win32 + // install gains package identity. The AmbientLightingServer that fronts + // Windows Dynamic Lighting only accepts background lighting controllers + // from packaged processes declaring the com.microsoft.windows.lighting + // AppExtension — without this registration Chromatics can only paint DL + // devices while it has foreground focus, which is useless during gameplay. + // + // Idempotent, per-user, no admin needed. Silently no-ops on: + // - Windows builds older than 22621 (TargetDeviceFamily MinVersion in the manifest) + // - Builds without a bundled Chromatics.appx (dev/debug runs, unsigned local builds) + // - Registration errors — logged and swallowed so foreground DL still works + // 19041 = Win10 2004 — required for AddPackageOptions.ExternalLocationUri, + // the sparse-package mechanism we use. Callers must guard with + // OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041) or carry the same + // [SupportedOSPlatform] attribute or the CA1416 analyzer will flag them. + [SupportedOSPlatform("windows10.0.19041.0")] + public static class SparsePackageRegistrar + { + // Must match Identity.Name + Publisher in Resources/SparsePackage/AppxManifest.xml. + // Windows looks the registered package up by these two fields below. + private const string PackageName = "com.logicallysynced.Chromatics"; + private const string PackagePublisher = "CN=Danielle Thompson"; + private const string AppxFileName = "Chromatics.appx"; + + // Synchronous wrapper safe to call from STAThread Main. Wraps the async + // call in Task.Run to dispatch to the thread pool and avoid the + // sync-over-async deadlock that bites WinRT calls on the STA. + public static void EnsureRegistered() + { + try + { + Task.Run(EnsureRegisteredAsync).GetAwaiter().GetResult(); + } + catch (Exception ex) + { + Logger.WriteVerbose($"[SparsePackage] EnsureRegistered failed at top level: {ex.GetType().Name} — {ex.Message}"); + Debug.WriteLine(ex); + } + } + + public static async Task EnsureRegisteredAsync() + { + try + { + var exeDir = Path.GetDirectoryName(Environment.ProcessPath); + if (string.IsNullOrEmpty(exeDir)) + { + Logger.WriteVerbose("[SparsePackage] Skipped: Environment.ProcessPath is empty"); + return; + } + + var appxPath = Path.Combine(exeDir, AppxFileName); + if (!File.Exists(appxPath)) + { + Logger.WriteVerbose($"[SparsePackage] Skipped: {AppxFileName} not bundled with this install (debug/unsigned build)"); + return; + } + + var currentAppVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version + ?? new Version(0, 0, 0, 0); + + PackageManager pm; + try + { + pm = new PackageManager(); + } + catch (PlatformNotSupportedException ex) + { + Logger.WriteVerbose($"[SparsePackage] Skipped: PackageManager unsupported on this OS — {ex.Message}"); + return; + } + + // Already registered at the same version? No-op. + // FindPackagesForUser("") = current user. Filtering by name + publisher + // sidesteps having to compute the publisher hash for the family name. + var existing = pm.FindPackagesForUser(string.Empty, PackageName, PackagePublisher); + foreach (var pkg in existing) + { + var v = pkg.Id.Version; + var installed = new Version(v.Major, v.Minor, v.Build, v.Revision); + if (installed == currentAppVersion) + { + Logger.WriteVerbose($"[SparsePackage] Already registered at {installed}; no action needed"); + return; + } + } + + Logger.WriteVerbose($"[SparsePackage] Registering {currentAppVersion} from {appxPath} (external location {exeDir})"); + + var options = new AddPackageOptions + { + // file:/// URI of the directory containing Chromatics.exe — Windows + // resolves the unpackaged binaries referenced by the manifest from here. + ExternalLocationUri = new Uri(exeDir), + // Allows registering 4.2.14 over a previously-installed 4.2.13 without + // the caller having to compare versions first. + ForceUpdateFromAnyVersion = true, + }; + + var op = pm.AddPackageByUriAsync(new Uri(appxPath), options); + var result = await op.AsTask().ConfigureAwait(false); + if (result.ExtendedErrorCode != null) + { + Logger.WriteVerbose( + $"[SparsePackage] Registration failed: {result.ErrorText} " + + $"(HRESULT 0x{result.ExtendedErrorCode.HResult:X8})"); + return; + } + Logger.WriteVerbose("[SparsePackage] Registered successfully"); + } + catch (COMException ex) + { + Logger.WriteVerbose($"[SparsePackage] Registration failed: COM HRESULT 0x{ex.HResult:X8} — {ex.Message}"); + } + catch (Exception ex) + { + Logger.WriteVerbose($"[SparsePackage] Registration failed: {ex.GetType().Name} — {ex.Message}"); + Debug.WriteLine(ex); + } + } + + // Called from Velopack's OnBeforeUninstallFastCallback — must run sync + // and exit fast (no UI, no network) because Velopack kills the process + // shortly after the callback returns. Removes the sparse package entry + // so Chromatics stops appearing in Settings → Personalization → + // Dynamic Lighting → Background light control after uninstall. + public static void Deregister() + { + try + { + Task.Run(DeregisterAsync).GetAwaiter().GetResult(); + } + catch (Exception ex) + { + Logger.WriteVerbose($"[SparsePackage] Deregister failed at top level: {ex.GetType().Name} — {ex.Message}"); + Debug.WriteLine(ex); + } + } + + public static async Task DeregisterAsync() + { + try + { + PackageManager pm; + try + { + pm = new PackageManager(); + } + catch (PlatformNotSupportedException) + { + return; + } + + var existing = pm.FindPackagesForUser(string.Empty, PackageName, PackagePublisher); + foreach (var pkg in existing) + { + Logger.WriteVerbose($"[SparsePackage] Removing {pkg.Id.FullName} for current user"); + var op = pm.RemovePackageAsync(pkg.Id.FullName, RemovalOptions.None); + var result = await op.AsTask().ConfigureAwait(false); + if (result.ExtendedErrorCode != null) + { + Logger.WriteVerbose( + $"[SparsePackage] Remove failed: {result.ErrorText} " + + $"(HRESULT 0x{result.ExtendedErrorCode.HResult:X8})"); + } + } + } + catch (COMException ex) + { + Logger.WriteVerbose($"[SparsePackage] Deregister failed: COM HRESULT 0x{ex.HResult:X8} — {ex.Message}"); + } + catch (Exception ex) + { + Logger.WriteVerbose($"[SparsePackage] Deregister failed: {ex.GetType().Name} — {ex.Message}"); + Debug.WriteLine(ex); + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareAdoptedDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareAdoptedDevice.cs new file mode 100644 index 00000000..7f73cdef --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareAdoptedDevice.cs @@ -0,0 +1,22 @@ +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + // Persisted (settings.json) record of a user-adopted Alienware device. + // Identity is the VID/PID/DevicePath tuple. ApiVersion captures which + // wire format the discovery probe decided on so we don't have to re- + // probe the HID interface every launch. + public class AlienwareAdoptedDevice + { + public int VendorId { get; set; } + public int ProductId { get; set; } + public string Manufacturer { get; set; } + public string Product { get; set; } + public string DevicePath { get; set; } + + // String representation of AlienwareApiVersion. Stored as string + // rather than int so a future enum addition can't silently + // collide with the persisted value. + public string ApiVersion { get; set; } + public int LightCount { get; set; } + public int ReportLength { get; set; } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareClientDefinition.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareClientDefinition.cs new file mode 100644 index 00000000..92ed85e5 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareClientDefinition.cs @@ -0,0 +1,59 @@ +using Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + // Runtime descriptor for one adopted Alienware AlienFX device. + // Captures everything the UpdateQueue and Device need from + // discovery time so they don't have to re-probe per frame. + public sealed class AlienwareClientDefinition + { + public AlienwareClientDefinition( + int vendorId, + int productId, + string manufacturer, + string product, + AlienwareApiVersion apiVersion, + int lightCount, + int reportLength, + string devicePath) + { + VendorId = vendorId; + ProductId = productId; + Manufacturer = manufacturer ?? string.Empty; + Product = product ?? string.Empty; + ApiVersion = apiVersion; + LightCount = lightCount; + ReportLength = reportLength; + DevicePath = devicePath ?? string.Empty; + } + + public int VendorId { get; } + public int ProductId { get; } + public string Manufacturer { get; } + public string Product { get; } + + // Which AlienFX HID dialect this device speaks. Decided by the + // discovery probe from VID + report-length geometry; the + // UpdateQueue dispatches to the corresponding protocol builder. + public AlienwareApiVersion ApiVersion { get; } + + // For per-key (V5/V8) devices: number of addressable lights the + // firmware exposes. We map each one to LedId.Custom1+i. + // For zone (V4) devices: number of named zones. + public int LightCount { get; } + + // HID report length the device negotiated. V5 uses the device's + // FeatureReportByteLength (typically 65); V8 uses + // OutputReportByteLength (typically 65); V4 uses its own. + // Buffers are sized to this value. + public int ReportLength { get; } + + // Stable identity for matching against persisted SettingsModel + // entries. AlienFX devices generally only have one of each + // model per machine but we include the device path for + // disambiguation when there are duplicates. + public string DevicePath { get; } + + public string Identity => $"{VendorId:X4}:{ProductId:X4}:{Manufacturer}:{Product}"; + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDefaultKeymap.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDefaultKeymap.cs new file mode 100644 index 00000000..9fe8b0b9 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDefaultKeymap.cs @@ -0,0 +1,95 @@ +using Chromatics.Localization; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + // Best-effort (row, col) → LedId mapping for per-key Alienware + // keyboards (V5 notebook, V8 external like AW510K / AW920K). + // + // The honest situation: Alienware doesn't ship a public per-board + // light-index → physical-key table, and T-Troll's open source builds + // these from user-supplied registry mappings rather than hardcoding + // them. Without hardware to empirically capture the mapping, we + // fall back to a standard ANSI 104 enumeration ordered top-to-bottom, + // left-to-right — which matches how most matrix keyboards + // enumerate firmware-side. + // + // For the user this means: + // - Highlight / Keybind layers will likely paint roughly the right + // keys on AW510K / AW920K-class boards out of the box. + // - Where firmware enumeration order differs from this assumption, + // keys will paint the wrong physical positions until the user + // remaps them via the Mapping tab. + // - Lights past the first 104 (status bars, side LEDs, logos) + // surface as LedId.Custom105..N for manual placement. + // + // When community testing confirms a specific board's enumeration + // pattern, we can replace this default with a per-PID table. + internal static class AlienwareDefaultKeymap + { + public sealed class KeymapEntry + { + public LedId LedId { get; init; } + public Point Location { get; init; } + public Size Size { get; init; } + } + + // Default ANSI 104 QWERTY layout pulled from Chromatics' shared + // KeyLocalization grid (the same data that powers the Logitech + // and other per-key keyboard providers). Iterated in row-major + // order so light index 0 = top-left key (Escape). + public static IReadOnlyList BuildAnsi104(int totalLights, float cellSize = 30f) + { + var grid = KeyLocalization.QWERTY_Grid; + // Sort by row then column so the enumeration matches the + // matrix-scan order the firmware most commonly uses. + var ordered = grid + .OrderBy(kvp => kvp.Value[0]) + .ThenBy(kvp => kvp.Value[1]) + .ToList(); + + var result = new List(Math.Max(totalLights, ordered.Count)); + int produced = 0; + + for (int i = 0; i < Math.Min(totalLights, ordered.Count); i++) + { + var (ledId, rc) = (ordered[i].Key, ordered[i].Value); + int row = rc[0]; + int col = rc[1]; + result.Add(new KeymapEntry + { + LedId = ledId, + Location = new Point(col * cellSize, row * cellSize), + Size = new Size(cellSize, cellSize), + }); + produced++; + } + + // Lights past the standard ANSI grid (chassis logos, status + // bars, side strips) get Custom* slots arranged in a small + // tail row below the keyboard so they're visually distinct + // and easy to find in the Mapping tab. + int tailRow = (grid.Values.Max(p => p[0]) + 2); + int tailCol = 0; + int customIndex = 0; + for (int i = produced; i < totalLights; i++) + { + var entry = new KeymapEntry + { + LedId = (LedId)((int)LedId.Custom1 + customIndex), + Location = new Point(tailCol * cellSize, tailRow * cellSize), + Size = new Size(cellSize, cellSize), + }; + result.Add(entry); + customIndex++; + tailCol++; + if (tailCol >= 24) { tailCol = 0; tailRow++; } + } + + return result; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDevice.cs new file mode 100644 index 00000000..64d3cb26 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDevice.cs @@ -0,0 +1,75 @@ +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol; +using RGB.NET.Core; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + public class AlienwareDevice : AbstractRGBDevice + { + private readonly AlienwareUpdateQueue _updateQueue; + private readonly AlienwareClientDefinition _def; + + public AlienwareDevice(AlienwareDeviceInfo info, AlienwareUpdateQueue updateQueue, AlienwareClientDefinition def) + : base(info, updateQueue) + { + _updateQueue = updateQueue; + _def = def; + InitializeLayout(); + } + + public AlienwareClientDefinition Definition => _def; + + public void BeginShutdown() => _updateQueue.BeginShutdown(); + public void SetPerDeviceDisabled(bool disabled) => _updateQueue.SetPerDeviceDisabled(disabled); + public void ResetCache() => _updateQueue.ResetCache(); + + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _updateQueue.SetPerDeviceBrightness(correction); + + // Layout decision is per dialect: + // + // Per-key keyboards (V5 notebook, V8 external) — apply the + // default ANSI 104 QWERTY keymap so Highlight / Keybind layers + // light approximately the right keys out of the box. Lights + // past the first 104 surface as Custom* in a tail row below + // the keyboard. Where the firmware's enumeration order doesn't + // match standard matrix-scan order the user can remap via + // the Mapping tab. See AlienwareDefaultKeymap for the + // reasoning + tradeoff. + // + // Zone-based chassis (V4) — each light is an opaque per-board + // zone (Front, Rear, Left, Right, Logo, etc.) with no + // universal layout. Surface as Custom1..N in a synthetic + // grid; user positions them in the Mapping tab. + private void InitializeLayout() + { + int count = System.Math.Max(1, _def.LightCount); + + if (_def.ApiVersion == AlienwareApiVersion.PerKeyV5 + || _def.ApiVersion == AlienwareApiVersion.PerKeyV8) + { + var keymap = AlienwareDefaultKeymap.BuildAnsi104(count); + foreach (var entry in keymap) + { + var led = AddLed(entry.LedId, entry.Location, entry.Size); + if (led != null) led.Shape = Shape.Rectangle; + } + return; + } + + // Zone-based fallback: synthetic wider-than-tall grid. + const float cell = 30f; + int cols = System.Math.Max(1, (int)System.Math.Ceiling(System.Math.Sqrt(count * 4.0 / 3.0))); + for (int i = 0; i < count; i++) + { + int col = i % cols; + int row = i / cols; + var led = AddLed( + (LedId)((int)LedId.Custom1 + i), + new Point(col * cell, row * cell), + new Size(cell, cell)); + if (led != null) led.Shape = Shape.Rectangle; + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDeviceInfo.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDeviceInfo.cs new file mode 100644 index 00000000..99ae5fd1 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareDeviceInfo.cs @@ -0,0 +1,32 @@ +using Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol; +using RGB.NET.Core; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + public class AlienwareDeviceInfo : IRGBDeviceInfo + { + public AlienwareDeviceInfo(AlienwareClientDefinition def) + { + Manufacturer = string.IsNullOrEmpty(def.Manufacturer) ? "Alienware" : def.Manufacturer; + Model = string.IsNullOrEmpty(def.Product) ? $"AlienFX {def.ApiVersion}" : def.Product; + DeviceName = string.IsNullOrEmpty(def.Product) ? $"Alienware AlienFX ({def.ApiVersion})" : def.Product; + + // Per-key keyboards (V5 notebook, V8 external) → Keyboard. + // Zone-based chassis (V4) → Mainboard since the LEDs live on + // the case rather than a peripheral. + DeviceType = def.ApiVersion switch + { + AlienwareApiVersion.PerKeyV5 => RGBDeviceType.Keyboard, + AlienwareApiVersion.PerKeyV8 => RGBDeviceType.Keyboard, + AlienwareApiVersion.ZoneV4 => RGBDeviceType.Mainboard, + _ => RGBDeviceType.Unknown, + }; + } + + public RGBDeviceType DeviceType { get; } + public string DeviceName { get; } + public string Manufacturer { get; } + public string Model { get; } + public object LayoutMetadata { get; set; } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareRGBDeviceProvider.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareRGBDeviceProvider.cs new file mode 100644 index 00000000..59d772bc --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareRGBDeviceProvider.cs @@ -0,0 +1,212 @@ +using Chromatics.Core; +using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol; +using HidSharp; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + // Custom RGB.NET device provider for Alienware AlienFX hardware. + // Pure managed implementation via HidSharp — no LightFX_SDK.dll, no + // Dell AWCC dependency, no precompiled bridge. Three HID dialects + // are dispatched from one provider: + // + // - V4: 5-zone chassis (Aurora R7-R14 desktops, m15 zone laptops, + // m17R1, Dell G7/G5). VID 0x187C. + // - V5: per-key notebook keyboards (Area51m-R2, x17R2, m15R3+, + // m17R3). VID 0x0D62. + // - V8: per-key external keyboards (AW510K, AW920K, AW768, AW410K). + // VID 0x04F2. + // + // Auto-adopt on first enable mirrors the QMK pattern. The Mapping + // tab handles per-device disable for users who don't want every + // discovered Alienware device controlled. + public class AlienwareRGBDeviceProvider : AbstractRGBDeviceProvider + { + #region Singleton + + private static AlienwareRGBDeviceProvider _instance; + public static AlienwareRGBDeviceProvider Instance => _instance ?? new AlienwareRGBDeviceProvider(); + + public AlienwareRGBDeviceProvider() + { + if (_instance != null) Throw(new Exception($"There can be only one instance of type {nameof(AlienwareRGBDeviceProvider)}")); + _instance = this; + } + + #endregion + + // Adopted devices the user opted to control. Hydrated by the + // Settings layer / RGBController.Setup before LoadDeviceProvider + // runs. Empty list short-circuits LoadDevices. + public List ClientDefinitions { get; } = new(); + + // Track open HID streams so Dispose can shut them down cleanly. + private readonly Dictionary _openStreams = new(); + + // 30Hz cap. AlienFX hardware accepts sustained 30Hz reliably across + // V4/V5/V8 in T-Troll's testing; faster than this risks the + // firmware's internal queue dropping commands silently. + private const double UpdateFrequencySeconds = 1.0 / 30.0; + + protected override void InitializeSDK() + { + // No SDK init — pure managed HID. + } + + protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) + => new AlienwareUpdateTrigger(UpdateFrequencySeconds); + + protected override IEnumerable LoadDevices() + { + var devices = new List(); + if (ClientDefinitions.Count == 0) return devices; + + foreach (var def in ClientDefinitions) + { + try + { + HidDevice hid = ResolveHidDevice(def); + if (hid == null) + { + Logger.WriteConsole(LoggerTypes.Devices, + $"[Alienware] {def.Product}: not present on this PC right now — skipping. Will retry on next enable.", + forwardToSentry: false); + continue; + } + + if (!hid.TryOpen(out HidStream stream)) + { + // Most common reason a TryOpen fails on AlienFX + // hardware: Alienware Command Center is running and + // holds the HID interface exclusively. Detect that + // and give the user a specific, actionable hint + // rather than the generic "another app may be + // holding it" message. + var awccProcess = DetectAwccConflict(); + if (awccProcess != null) + { + Logger.WriteConsole(LoggerTypes.Error, + $"[Alienware] Could not open {def.Product} ({def.VendorId:X4}:{def.ProductId:X4}). Alienware Command Center ({awccProcess}) is currently running and holds the AlienFX HID interface exclusively. Quit AWCC from the system tray (right-click the AWCC icon → Exit), then re-enable the Alienware provider in Settings.", + forwardToSentry: false); + } + else + { + Logger.WriteConsole(LoggerTypes.Error, + $"[Alienware] Could not open {def.Product} ({def.VendorId:X4}:{def.ProductId:X4}). Another app may be holding the AlienFX HID interface exclusively. Common culprits: Alienware Command Center (AWCC), AlienFX Tools (T-Troll), and the older AlienFX Editor. Close any of these and try again.", + forwardToSentry: false); + } + continue; + } + + var trigger = (AlienwareUpdateTrigger)GetUpdateTrigger(); + var queue = new AlienwareUpdateQueue(trigger, def, stream); + var info = new AlienwareDeviceInfo(def); + var dev = new AlienwareDevice(info, queue, def); + + Logger.WriteConsole(LoggerTypes.Devices, + $"[Alienware] Adopted {def.Product} ({def.ApiVersion}, {def.LightCount} addressable lights).", + forwardToSentry: false); + + _openStreams[dev] = stream; + devices.Add(dev); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, + $"[Alienware] failed to set up {def.Product}: {ex.Message}"); + } + } + + return devices; + } + + // Returns the friendly process name of a running Alienware Command + // Center component if one is detected, or null if none are running. + // AWCC ships as a multi-process suite — the main UI is `AWCC.exe`, + // the background lighting service is `AlienFXService.exe` / + // `LightingService.exe` depending on AWCC version, and the + // legacy editor is `AlienFXEditor.exe`. Any of these holding the + // HID interface is enough to lock us out. + private static readonly string[] _awccProcessNames = + { + "AWCC", + "AlienFXService", + "LightingService", + "AlienFXEditor", + "AlienFusionUpdate", + "AlienwareCommandCenter", + }; + + private static string DetectAwccConflict() + { + try + { + foreach (var name in _awccProcessNames) + { + var procs = System.Diagnostics.Process.GetProcessesByName(name); + if (procs.Length == 0) continue; + foreach (var p in procs) try { p.Dispose(); } catch { /* ignore */ } + return $"{name}.exe"; + } + } + catch { /* process enumeration is best-effort */ } + return null; + } + + // Find the HidDevice on the bus that matches a client definition. + // Match by VID+PID first; tie-break on DevicePath when the user has + // multiple of the same model (rare for AlienFX hardware but + // possible — e.g. two AW510Ks). + private static HidDevice ResolveHidDevice(AlienwareClientDefinition def) + { + try + { + HidDevice fallback = null; + foreach (var hid in DeviceList.Local.GetHidDevices()) + { + int vid = 0; int pid = 0; + try { vid = hid.VendorID; pid = hid.ProductID; } catch { continue; } + if (vid != def.VendorId || pid != def.ProductId) continue; + + if (!string.IsNullOrEmpty(def.DevicePath) + && string.Equals(hid.DevicePath, def.DevicePath, StringComparison.OrdinalIgnoreCase)) + return hid; + + fallback ??= hid; + } + return fallback; + } + catch { return null; } + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + try + { + foreach (var dev in Devices.OfType()) + { + try { dev.BeginShutdown(); } catch { /* ignore */ } + } + foreach (var s in _openStreams.Values) + { + try { s.Dispose(); } catch { /* ignore */ } + } + _openStreams.Clear(); + ClientDefinitions.Clear(); + } + catch { /* swallow during teardown */ } + } + + base.Dispose(disposing); + + if (ReferenceEquals(_instance, this)) + _instance = null; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareUpdateQueue.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareUpdateQueue.cs new file mode 100644 index 00000000..dc7f6e85 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareUpdateQueue.cs @@ -0,0 +1,340 @@ +using Chromatics.Core; +using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol; +using HidSharp; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Threading; +using Color = RGB.NET.Core.Color; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + public class AlienwareUpdateQueue : UpdateQueue + { + #region Properties & Fields + + private readonly AlienwareClientDefinition _def; + private readonly HidStream _stream; + private readonly Lock _lock = new(); + private volatile bool _shuttingDown; + private volatile bool _perDeviceDisable; + + private PerDeviceBrightnessCorrection _perDeviceBrightness; + + // LedId → flat hardware light index. Built from the LightCount once + // at construction so the per-frame Resolve doesn't allocate. + private readonly Dictionary _ledIndexByLedId; + + // Per-light RGB cache. Sparse decorator updates only re-send the + // lights whose values actually changed; per-frame the queue diffs + // against this and skips the HID writes entirely when nothing's + // dirty. 3 bytes per light (R, G, B). + private readonly byte[] _ledBytes; + + // V8 announce/data sequencing uses an incrementing batch counter + // per frame. + private byte _v8BatchCounter; + + #endregion + + #region Constructors + + public AlienwareUpdateQueue(IDeviceUpdateTrigger trigger, AlienwareClientDefinition def, HidStream stream) + : base(trigger) + { + _def = def; + _stream = stream; + + int count = Math.Max(1, _def.LightCount); + _ledIndexByLedId = new Dictionary(count); + + // Build the LedId → light-index map using the same ordering + // AlienwareDevice.InitializeLayout uses, so each LedId paint + // routes to the matching firmware light. Per-key boards + // get the ANSI 104 mapping; zone boards get sequential + // Custom1..N. + if (_def.ApiVersion == Protocol.AlienwareApiVersion.PerKeyV5 + || _def.ApiVersion == Protocol.AlienwareApiVersion.PerKeyV8) + { + var keymap = AlienwareDefaultKeymap.BuildAnsi104(count); + for (int i = 0; i < keymap.Count; i++) + _ledIndexByLedId[keymap[i].LedId] = i; + } + else + { + for (int i = 0; i < count; i++) + _ledIndexByLedId[(LedId)((int)LedId.Custom1 + i)] = i; + } + + _ledBytes = new byte[count * 3]; + } + + #endregion + + #region Lifecycle + + public void BeginShutdown() => _shuttingDown = true; + public void SetPerDeviceDisabled(bool disabled) => _perDeviceDisable = disabled; + + public void ResetCache() + { + lock (_lock) + { + Array.Clear(_ledBytes, 0, _ledBytes.Length); + _v8BatchCounter = 0; + } + } + + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _perDeviceBrightness = correction; + + #endregion + + #region Update + + protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet) + { + lock (_lock) + { + if (_shuttingDown || _perDeviceDisable) return true; + if (dataSet.IsEmpty) return true; + + try + { + int globalPct = GlobalBrightnessCorrection.Instance.BrightnessPercent; + int perDevicePct = _perDeviceBrightness?.BrightnessPercent ?? 100; + double brightnessScale = (globalPct / 100.0) * (perDevicePct / 100.0); + + // Patch dirty lights into the per-light cache. Track + // the dirty index list so we only resend lights whose + // value changed. + var dirty = new List(dataSet.Length); + foreach (var (key, color) in dataSet) + { + int idx = ResolveLightIndex(key); + if (idx < 0 || idx >= _def.LightCount) continue; + + ToRgb255(color, brightnessScale, out byte r, out byte g, out byte b); + int off = idx * 3; + if (_ledBytes[off] == r && _ledBytes[off + 1] == g && _ledBytes[off + 2] == b) continue; + + _ledBytes[off] = r; + _ledBytes[off + 1] = g; + _ledBytes[off + 2] = b; + dirty.Add(idx); + } + + if (dirty.Count == 0) return true; + + switch (_def.ApiVersion) + { + case AlienwareApiVersion.PerKeyV5: + SendV5Frame(dirty); + break; + case AlienwareApiVersion.PerKeyV8: + SendV8Frame(dirty); + break; + case AlienwareApiVersion.ZoneV4: + SendV4Frame(dirty); + break; + default: + // Unknown version — silent no-op so we don't + // pelt the device with garbage. + return true; + } + + return true; + } + catch (Exception ex) + { + AlienwareRGBDeviceProvider.Instance?.Throw(ex); + return false; + } + } + } + + private int ResolveLightIndex(object key) + { + if (key is LedId id && _ledIndexByLedId.TryGetValue(id, out int idx)) return idx; + if (key is Led led && _ledIndexByLedId.TryGetValue(led.Id, out int idx2)) return idx2; + return -1; + } + + #endregion + + #region V5 path (per-key notebook keyboards, VID 0x0d62) + + private void SendV5Frame(List dirty) + { + int reportLen = _def.ReportLength > 0 ? _def.ReportLength : AlienwarePerKeyV5Protocol.ReportLength; + byte[] buffer = new byte[reportLen]; + + // Pack dirty lights into colour-set reports of up to 15 lights + // each. Each report = one HidStream.SetFeature call. + int packedThisReport = 0; + var batch = new (byte, byte, byte, byte)[AlienwarePerKeyV5Protocol.MaxLightsPerReport]; + + for (int i = 0; i < dirty.Count; i++) + { + int idx = dirty[i]; + int off = idx * 3; + batch[packedThisReport++] = ((byte)idx, _ledBytes[off], _ledBytes[off + 1], _ledBytes[off + 2]); + + bool isLast = i == dirty.Count - 1; + if (packedThisReport == AlienwarePerKeyV5Protocol.MaxLightsPerReport || isLast) + { + AlienwarePerKeyV5Protocol.BuildColorSet(buffer, new ReadOnlySpan<(byte, byte, byte, byte)>(batch, 0, packedThisReport)); + SendFeatureReport(buffer); + packedThisReport = 0; + } + } + + // Loop marker (required between SetColor sequence and Update). + AlienwarePerKeyV5Protocol.BuildLoop(buffer); + SendFeatureReport(buffer); + + // Commit. + AlienwarePerKeyV5Protocol.BuildUpdate(buffer); + SendFeatureReport(buffer); + } + + #endregion + + #region V8 path (per-key external keyboards, VID 0x04f2) + + private void SendV8Frame(List dirty) + { + int reportLen = _def.ReportLength > 0 ? _def.ReportLength : AlienwarePerKeyV8Protocol.ReportLength; + byte[] buffer = new byte[reportLen]; + + // Step 1: announce the batch size via feature report. Tells + // the firmware how many lights to expect in the data packets + // that follow. + AlienwarePerKeyV8Protocol.BuildAnnounceBatch(buffer, (byte)dirty.Count); + SendFeatureReport(buffer); + + // Step 2: stream up to 4 lights per write report. + _v8BatchCounter = 1; + var batch = new (byte, byte, byte, byte)[AlienwarePerKeyV8Protocol.MaxLightsPerPacket]; + int packedThisPacket = 0; + + for (int i = 0; i < dirty.Count; i++) + { + int idx = dirty[i]; + int off = idx * 3; + batch[packedThisPacket++] = ((byte)idx, _ledBytes[off], _ledBytes[off + 1], _ledBytes[off + 2]); + + bool isLast = i == dirty.Count - 1; + if (packedThisPacket == AlienwarePerKeyV8Protocol.MaxLightsPerPacket || isLast) + { + AlienwarePerKeyV8Protocol.BuildDataPacket(buffer, _v8BatchCounter, new ReadOnlySpan<(byte, byte, byte, byte)>(batch, 0, packedThisPacket)); + WriteOutputReport(buffer); + _v8BatchCounter++; + packedThisPacket = 0; + } + } + } + + #endregion + + #region V4 path (zone-based chassis, VID 0x187C) + + private void SendV4Frame(List dirty) + { + int reportLen = AlienwareZoneV4Protocol.ReportLength; + byte[] buffer = new byte[reportLen]; + + // Reset (Remove + Start) opens a new colour sequence on the + // device. Required before the first SetColor of every frame — + // skipping it leaves the device on the previous frame's + // sequence and the new SetColors get appended rather than + // overriding. + AlienwareZoneV4Protocol.BuildReset_Remove(buffer); + WriteOutputReport(buffer); + AlienwareZoneV4Protocol.BuildReset_Start(buffer); + WriteOutputReport(buffer); + + // Group dirty lights by colour so lights sharing a colour go + // out in one HID write rather than N. Common case for static + // overlays / single-colour layers. + var byColor = new Dictionary>(); + foreach (int idx in dirty) + { + int off = idx * 3; + byte r = _ledBytes[off], g = _ledBytes[off + 1], b = _ledBytes[off + 2]; + uint packed = (uint)((r << 16) | (g << 8) | b); + if (!byColor.TryGetValue(packed, out var list)) + byColor[packed] = list = new List(dirty.Count); + list.Add((byte)idx); + } + + // Each SetColor command packs at most 26 light ids + // (ReportLength=34 minus 8-byte header). Split colour groups + // larger than that across multiple writes. + const int maxIdsPerWrite = 34 - 8; + foreach (var kvp in byColor) + { + byte r = (byte)((kvp.Key >> 16) & 0xFF); + byte g = (byte)((kvp.Key >> 8) & 0xFF); + byte b = (byte)(kvp.Key & 0xFF); + var ids = kvp.Value; + for (int start = 0; start < ids.Count; start += maxIdsPerWrite) + { + int chunk = Math.Min(maxIdsPerWrite, ids.Count - start); + AlienwareZoneV4Protocol.BuildSetColor( + buffer, r, g, b, + new ReadOnlySpan(ids.GetRange(start, chunk).ToArray())); + WriteOutputReport(buffer); + } + } + + // Commit (firmware applies the freshly-set sequence). + AlienwareZoneV4Protocol.BuildCommit(buffer); + WriteOutputReport(buffer); + } + + #endregion + + #region HID I/O + + private void SendFeatureReport(byte[] buffer) + { + try { _stream.SetFeature(buffer); } + catch (System.IO.IOException ex) { OnIoError(ex); } + catch (ObjectDisposedException) { _shuttingDown = true; } + } + + private void WriteOutputReport(byte[] buffer) + { + try { _stream.Write(buffer); } + catch (System.IO.IOException ex) { OnIoError(ex); } + catch (ObjectDisposedException) { _shuttingDown = true; } + } + + private void OnIoError(System.IO.IOException ex) + { + // PnP unplug between Write call and current frame. Mark + // shutting down so the rest of this batch becomes no-ops; + // the provider's hot-plug reconcile (or next session) will + // dispose us. + Logger.WriteConsole(LoggerTypes.Devices, $"[Alienware] {_def.Product}: HID write failed ({ex.Message}); pausing queue."); + _shuttingDown = true; + } + + #endregion + + #region Helpers + + private static void ToRgb255(Color rgb, double brightnessScale, out byte r, out byte g, out byte b) + { + double scale = Math.Clamp(brightnessScale, 0.0, 1.0); + r = (byte)Math.Round(Math.Clamp(rgb.R, 0.0, 1.0) * 255 * scale); + g = (byte)Math.Round(Math.Clamp(rgb.G, 0.0, 1.0) * 255 * scale); + b = (byte)Math.Round(Math.Clamp(rgb.B, 0.0, 1.0) * 255 * scale); + } + + #endregion + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareUpdateTrigger.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareUpdateTrigger.cs new file mode 100644 index 00000000..b735a99e --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/AlienwareUpdateTrigger.cs @@ -0,0 +1,46 @@ +using RGB.NET.Core; +using System; +using System.Diagnostics; +using System.Threading; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware +{ + // 30Hz trigger with 50ms idle wake. Same shape as the QMK and + // Yeelight triggers — the idle refresh keeps per-device brightness + // slider changes propagating when devices are sitting on a static + // base layer (HasDataEvent only signals when a colour changed). + public class AlienwareUpdateTrigger : DeviceUpdateTrigger + { + private const int WaitOneTimeoutMs = 50; + + public AlienwareUpdateTrigger() { } + + public AlienwareUpdateTrigger(double updateRateHardLimit) + : base(updateRateHardLimit) { } + + protected override void UpdateLoop() + { + OnStartup(); + + while (!UpdateToken.IsCancellationRequested) + { + if (HasDataEvent.WaitOne(WaitOneTimeoutMs)) + { + long preUpdateTicks = Stopwatch.GetTimestamp(); + OnUpdate(); + + if (UpdateFrequency > 0) + { + double elapsedMs = (Stopwatch.GetTimestamp() - preUpdateTicks) / (double)TimeSpan.TicksPerMillisecond; + int sleep = (int)(UpdateFrequency * 1000.0 - elapsedMs); + if (sleep > 0) Thread.Sleep(sleep); + } + } + else + { + OnUpdate(new CustomUpdateData(("refresh", true))); + } + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareApiVersion.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareApiVersion.cs new file mode 100644 index 00000000..b440b19a --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareApiVersion.cs @@ -0,0 +1,34 @@ +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol +{ + // Which AlienFX HID dialect the device speaks. Decided at discovery + // time from the device's USB vendor id and HID report geometry — see + // AlienwareDiscovery for the detection rules. + // + // ZoneV4 — 5-zone chassis (Aurora R7-R14 desktops, m15R1-R6 + // zone laptops, m17R1, Dell G7/G5). Routed through + // T-Troll's LightFX_SDK.dll because the V4 wire + // format isn't fully documented in their open + // source. Aurora-RGB targets this same path. + // VID 0x187C, ~34-byte output reports. + // + // PerKeyV5 — Per-key notebook keyboards (Area51m-R2, x17R2, + // m15R3 / R4 / R5, m15R6, x15R2, m17R3). Pure + // managed HidSharp via HID feature reports. + // VID 0x0d62, FeatureReportByteLength typically 65. + // + // PerKeyV8 — Per-key external keyboards (AW510K, AW920K, + // AW768, AW410K). Pure managed HidSharp via HID + // write reports. VID 0x04f2, OutputReportByteLength + // typically 65. + // + // Mice (V7), monitors (V6), and the headset family aren't covered in + // this initial release — they share the same protocol families but + // need additional capability tables we don't have yet. + public enum AlienwareApiVersion + { + Unknown = 0, + ZoneV4 = 4, + PerKeyV5 = 5, + PerKeyV8 = 8, + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareDiscovery.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareDiscovery.cs new file mode 100644 index 00000000..2060ef1c --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareDiscovery.cs @@ -0,0 +1,123 @@ +using HidSharp; +using System.Collections.Generic; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol +{ + // HidSharp-based discovery for AlienFX devices. Walks the local HID + // device list, filters by Alienware-relevant USB vendor ids, then + // probes each candidate's HID descriptor to decide which AlienFX + // dialect (V4 zone, V5 per-key notebook, V8 per-key external) it + // speaks. Detection signals are taken from T-Troll's reference SDK + // (alienfx-tools, MIT licensed) which has the only public + // documentation of the geometry-based version probe. + // + // The result is a flat candidate list — adopt all, then let the + // user disable specific devices from the Mapping tab if they only + // want a subset. Mirrors the QmkRawHidDiscovery pattern. + internal static class AlienwareDiscovery + { + // USB vendor ids relevant to AlienFX devices. Filtering up-front + // keeps the per-device probe loop cheap on machines with hundreds + // of HID nodes (VR headsets, tablets, fitness trackers all + // enumerate as HID devices on Windows). + public const int VidAlienware = 0x187C; // V4 zone (Aurora R7-R14, m15R1-R6 zone, m17R1, Dell G7/G5) + public const int VidDarfon = 0x0D62; // V5 per-key notebook (Area51m-R2, x17R2, m15R3+, m17R3) + public const int VidChicony = 0x04F2; // V8 per-key external (AW510K, AW920K, AW768, AW410K) + + public sealed class Candidate + { + public HidDevice Hid { get; init; } + public AlienwareApiVersion ApiVersion { get; init; } + public int ReportLength { get; init; } + public string Manufacturer { get; init; } + public string Product { get; init; } + + // V8 / V5 firmware reports the addressable light count + // dynamically through later interactions. For initial discovery + // we estimate a sensible default per dialect; the device's + // first paint frame can grow this if the firmware exposes more. + public int LightCount { get; init; } + } + + public static IReadOnlyList Discover() + { + var results = new List(); + + IEnumerable hidDevices; + try { hidDevices = DeviceList.Local.GetHidDevices(); } + catch { return results; } + + foreach (var hid in hidDevices) + { + int vid; + try { vid = hid.VendorID; } catch { continue; } + + AlienwareApiVersion version; + int reportLen; + int lightCount; + + if (vid == VidAlienware) + { + // V4 — Alienware-branded zone chassis. Detected purely + // by VID at this layer; the actual report-length probe + // happens in the V4 protocol handler when we open the + // device. Default report length 34 bytes per T-Troll + // (the documented V4 output-report size). Light count + // varies per chassis (Aurora R7 has ~4, R14 has ~8); we + // expose 16 as a generous upper bound and trim + // unbound LEDs at the Device layer. + version = AlienwareApiVersion.ZoneV4; + reportLen = 34; + lightCount = 16; + } + else if (vid == VidDarfon) + { + // V5 — notebook per-key keyboards. T-Troll's detection + // gates on Usage==0xcc AND OutputReportByteLength==0. + // We can't query HID usage through HidSharp without + // opening the device; defer the strict check to the + // probe step in the provider's Load. Default light + // count 100 (typical full-size notebook keyboard); the + // firmware tolerates writes to invalid indices. + version = AlienwareApiVersion.PerKeyV5; + reportLen = AlienwarePerKeyV5Protocol.ReportLength; + lightCount = 100; + } + else if (vid == VidChicony) + { + // V8 — external per-key keyboards (AW510K, AW920K, + // AW768, AW410K). T-Troll's detection gates on + // OutputReportByteLength==65. We trust the VID match + // here — Chicony makes other peripherals but they + // don't enumerate as HID with this VID + 65-byte + // output report combo. Default light count 105 covers + // the full ANSI 104 + the chassis logo. + version = AlienwareApiVersion.PerKeyV8; + reportLen = AlienwarePerKeyV8Protocol.ReportLength; + lightCount = 105; + } + else + { + continue; + } + + string mfg = ""; + string prod = ""; + try { mfg = hid.GetManufacturer() ?? ""; } catch { /* ignore */ } + try { prod = hid.GetProductName() ?? ""; } catch { /* ignore */ } + + results.Add(new Candidate + { + Hid = hid, + ApiVersion = version, + ReportLength = reportLen, + Manufacturer = mfg, + Product = prod, + LightCount = lightCount, + }); + } + + return results; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwarePerKeyV5Protocol.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwarePerKeyV5Protocol.cs new file mode 100644 index 00000000..1312ba3a --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwarePerKeyV5Protocol.cs @@ -0,0 +1,101 @@ +using System; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol +{ + // V5 wire format for per-key Alienware notebook keyboards (Darfon, + // VID 0x0d62). Covers the Area51m-R2, x17R2, m15R3 / R4 / R5, m15R6, + // x15R2, m17R3 and any other notebook with the standard AlienFX V5 + // HID interface (Usage 0xcc, FeatureReportByteLength populated). + // + // Reverse-engineered by T-Troll (alienfx-tools, MIT licensed). Re- + // implemented in managed code via HidSharp's HidStream.SetFeature. + // + // Frame protocol (must run in order each paint frame): + // + // 1. One or more colour-block reports — each carries up to 15 + // lights packed as 4-byte (id+1, R, G, B) tuples. + // 2. Loop report — marks the end of the colour-block sequence. + // 3. Update report — commits the frame; firmware applies the + // colours after this lands. + // + // V5 uses HID feature reports (HidD_SetFeature on the native side), + // not write reports. HidSharp exposes this via HidStream.SetFeature. + internal static class AlienwarePerKeyV5Protocol + { + // Default report length the SDK uses for V5. Some boards report + // a larger FeatureReportByteLength via HidP_GetCaps; callers can + // size the buffer to the device's reported value but 65 is the + // documented baseline and matches every confirmed-working board. + public const int ReportLength = 65; + public const byte ReportId = 0xCC; + + // Maximum lights packed into one colour-set report. Each light is + // 4 bytes (id+1, R, G, B); the report header eats 4 bytes; the + // remaining 61 bytes hold (61 / 4) = 15 lights with 1 trailing byte + // padding. + public const int MaxLightsPerReport = 15; + public const int LightBlockSize = 4; + public const int ColorReportHeaderSize = 4; + + // Build the colour-set report carrying up to 15 lights. Sent via + // HidStream.SetFeature. Trailing buffer bytes stay zero. + public static void BuildColorSet( + Span buffer, + ReadOnlySpan<(byte hardwareId, byte r, byte g, byte b)> lights) + { + EnsureLength(buffer); + if (lights.Length > MaxLightsPerReport) + throw new ArgumentException($"V5 colour-set report holds at most {MaxLightsPerReport} lights (got {lights.Length}).", nameof(lights)); + + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x8C; // COMMV5_colorSet[0] + buffer[2] = 0x02; // COMMV5_colorSet[1] + buffer[3] = 0x00; + + int offset = ColorReportHeaderSize; + for (int i = 0; i < lights.Length; i++) + { + var l = lights[i]; + // Light index is stored 1-based in the V5 wire format. + // The HID firmware treats id 0 as "no light" and skips it, + // so we shift everything up by one. + buffer[offset + 0] = (byte)(l.hardwareId + 1); + buffer[offset + 1] = l.r; + buffer[offset + 2] = l.g; + buffer[offset + 3] = l.b; + offset += LightBlockSize; + } + } + + // Loop report — marks the end of a sequence of colour-set reports. + // Required between the last SetColor and the Update; without it + // the firmware silently drops the frame. + public static void BuildLoop(Span buffer) + { + EnsureLength(buffer); + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x8C; // COMMV5_loop[0] + buffer[2] = 0x13; // COMMV5_loop[1] + } + + // Update report — commits the frame. Sent once after the Loop + // marker; firmware applies the freshly-set colours when it lands. + public static void BuildUpdate(Span buffer) + { + EnsureLength(buffer); + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x8B; // COMMV5_update[0] + buffer[2] = 0x01; + buffer[3] = 0xFF; + } + + private static void EnsureLength(Span buffer) + { + if (buffer.Length < ReportLength) + throw new ArgumentException($"V5 buffer must be at least {ReportLength} bytes (got {buffer.Length})."); + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwarePerKeyV8Protocol.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwarePerKeyV8Protocol.cs new file mode 100644 index 00000000..6bae1171 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwarePerKeyV8Protocol.cs @@ -0,0 +1,105 @@ +using System; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol +{ + // V8 wire format for per-key external Alienware keyboards (Chicony, + // VID 0x04f2). Covers the AW510K, AW920K, AW768, AW410K and any + // other Chicony-made AlienFX keyboard with OutputReportByteLength==65. + // + // Reverse-engineered by T-Troll (alienfx-tools, MIT licensed). We + // re-implement in managed code via HidSharp rather than P/Invoking + // a native bridge, so there's no precompiled DLL to ship. + // + // Frame protocol (must run in order each paint frame): + // + // 1. Announce — feature report tells the device how many lights + // will follow in this batch. + // 2. Data packets — write reports carrying up to four lights + // (15 bytes each) per 65-byte report. Send as many as needed + // to cover all dirty lights. + // + // Each frame's worth of data packets must follow one announce. + // No explicit Loop / Commit / ExecuteColors call is required for V8 — + // the firmware applies colours as soon as the data packets land. + internal static class AlienwarePerKeyV8Protocol + { + public const int ReportLength = 65; + public const byte ReportId = 0x01; + + // Maximum lights per data packet. 65-byte report minus 5-byte + // header leaves 60 bytes for light blocks; each light block is + // 15 bytes. (65 - 5) / 15 = 4. + public const int MaxLightsPerPacket = 4; + public const int LightBlockSize = 15; + public const int DataHeaderSize = 5; + + // Static-colour opcode. T-Troll's `v8OpCodes` table also defines + // pulse (0x82), morph (0x83), breathing (0x87), spectrum (0x88), + // rainbow (0x84) — we only ship Color for the RGB.NET path. + private const byte OpCodeColor = 0x81; + + // Build a 65-byte feature-report buffer that announces a colour + // batch of `lightCount` lights. Sent via HidStream.SetFeature + // BEFORE the first data packet of a frame. The firmware uses this + // to size its incoming-buffer expectation. + public static void BuildAnnounceBatch(Span buffer, byte lightCount) + { + EnsureLength(buffer); + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x0e; // COMMV8_readyToColor[0] + buffer[2] = lightCount; + buffer[3] = 0x00; + buffer[4] = 0x01; + } + + // Build a 65-byte write-report buffer carrying up to four lights. + // `batchCounter` increments per packet within a frame (1, 2, 3...). + // `lights` is the list of (index, R, G, B) tuples for this packet — + // up to MaxLightsPerPacket entries; trailing slots stay zero. + public static void BuildDataPacket( + Span buffer, + byte batchCounter, + ReadOnlySpan<(byte index, byte r, byte g, byte b)> lights) + { + EnsureLength(buffer); + if (lights.Length > MaxLightsPerPacket) + throw new ArgumentException($"V8 data packet holds at most {MaxLightsPerPacket} lights (got {lights.Length}).", nameof(lights)); + + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x0e; // COMMV8_readyToColor[0] + buffer[2] = 0x01; + buffer[3] = 0x00; + buffer[4] = batchCounter; + + int offset = DataHeaderSize; + for (int i = 0; i < lights.Length; i++) + { + var l = lights[i]; + buffer[offset + 0] = l.index; + buffer[offset + 1] = OpCodeColor; + buffer[offset + 2] = 0; // tempo (irrelevant for static) + buffer[offset + 3] = 0xa5; + buffer[offset + 4] = 0; // time (irrelevant for static) + buffer[offset + 5] = 0x0a; + buffer[offset + 6] = l.r; // primary RGB + buffer[offset + 7] = l.g; + buffer[offset + 8] = l.b; + buffer[offset + 9] = l.r; // secondary RGB (same as primary for static) + buffer[offset + 10] = l.g; + buffer[offset + 11] = l.b; + buffer[offset + 12] = 0x02; + buffer[offset + 13] = 0; + buffer[offset + 14] = 0; + offset += LightBlockSize; + } + } + + private static void EnsureLength(Span buffer) + { + if (buffer.Length < ReportLength) + throw new ArgumentException($"V8 buffer must be at least {ReportLength} bytes (got {buffer.Length})."); + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareZoneV4Protocol.cs b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareZoneV4Protocol.cs new file mode 100644 index 00000000..5a519b53 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Alienware/Protocol/AlienwareZoneV4Protocol.cs @@ -0,0 +1,149 @@ +using System; + +namespace Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol +{ + // V4 wire format for AlienFX zone-based chassis (Aurora R7-R14 + // desktops, m15R1-R6 zone laptops, m17R1, Dell G7/G5/G5SE). + // VID 0x187C, output reports of 34 bytes via HidStream.Write + // (HidD_SetOutputReport on the native side). + // + // Reverse-engineered by T-Troll (alienfx-tools, MIT licensed). + // V4 light IDs are opaque per-device integers — different chassis + // expose different counts and physical-zone mappings. We expose + // them as flat Custom1..N LEDs and let users position them via + // the Mapping tab. + // + // Frame protocol (must run in order each paint frame): + // + // 1. Remove existing sequence + Start new sequence (these are + // collectively the "Reset" pair). + // 2. SetColor for each light or batch of lights painting the + // same colour. + // 3. Commit (control type "finish and play"). + // + // Status polling between commands is required by T-Troll's + // reference flow but in practice the firmware tolerates + // back-to-back writes for static colours; we skip the polling + // dance and rely on HID interrupt-OUT pacing. + internal static class AlienwareZoneV4Protocol + { + public const int ReportLength = 34; + public const byte ReportId = 0x00; + + // V4 device-status bytes returned in buffer[2] of an input report. + public const byte StatusReady = 0x21; + public const byte StatusBusy = 0x22; + public const byte StatusWaitColor = 0x23; + public const byte StatusWaitUpdate = 0x24; + public const byte StatusWasOn = 0x26; + + // Control-command sub-types (byte 4 of COMMV4_control). + public const byte ControlStartNew = 0x01; + public const byte ControlFinishSave = 0x02; + public const byte ControlFinishPlay = 0x03; // commit / "execute colors" + public const byte ControlRemove = 0x04; + public const byte ControlPlay = 0x05; + public const byte ControlSetDefault = 0x06; + public const byte ControlSetStartup = 0x07; + + // Build a control command (Remove / Start / Commit etc.). + // COMMV4_control template: {0x03, 0x21, 0x00, controlType, 0x00, 0xFF} + // at offsets 1..6, with byte[0] = 0 (report ID). + public static void BuildControl(Span buffer, byte controlType) + { + EnsureLength(buffer); + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x03; + buffer[2] = 0x21; + buffer[3] = 0x00; + buffer[4] = controlType; + buffer[5] = 0x00; + buffer[6] = 0xFF; + } + + // Convenience: the two-step Reset pair the device expects before + // the first SetColor of a frame. Caller sends Remove first, then + // Start. + public static void BuildReset_Remove(Span buffer) => BuildControl(buffer, ControlRemove); + public static void BuildReset_Start (Span buffer) => BuildControl(buffer, ControlStartNew); + + // Commit the frame (firmware applies the freshly-set colours). + public static void BuildCommit(Span buffer) => BuildControl(buffer, ControlFinishPlay); + + // Set one or more lights to the same RGB colour. Batches lights + // that share a colour into a single HID write. T-Troll's + // COMMV4_setOneColor template: {0x03, 0x27} at offsets 1..2, + // then payload at offset 3+: {R, G, B, 0x00, count, id0, id1, + // ...}. + // + // `lightIds` is the opaque per-device integer light id list. + // The protocol packs them as one byte each starting at offset 8. + public static void BuildSetColor(Span buffer, byte r, byte g, byte b, ReadOnlySpan lightIds) + { + EnsureLength(buffer); + if (lightIds.Length == 0) + throw new ArgumentException("V4 SetColor requires at least one light id.", nameof(lightIds)); + // 8 bytes header (incl. count) + N bytes for ids; protocol caps + // at the buffer's remaining capacity. + int maxIds = ReportLength - 8; + if (lightIds.Length > maxIds) + throw new ArgumentException($"V4 SetColor packs at most {maxIds} light ids per command (got {lightIds.Length}).", nameof(lightIds)); + + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x03; + buffer[2] = 0x27; + buffer[3] = r; + buffer[4] = g; + buffer[5] = b; + buffer[6] = 0x00; + buffer[7] = (byte)lightIds.Length; + for (int i = 0; i < lightIds.Length; i++) + buffer[8 + i] = lightIds[i]; + } + + // Brightness command. Operates per-frame, separate from RGB. + // Wire format: {0x03, 0x26} at offsets 1..2; payload at offset 3+: + // {(0x64 - brightnessPercent), 0x00, count, id0, id1, ...}. + // NOTE: brightness is INVERTED — 0 = full bright, 100 = off. + public static void BuildBrightness(Span buffer, int brightnessPercent, ReadOnlySpan lightIds) + { + EnsureLength(buffer); + int maxIds = ReportLength - 6; + if (lightIds.Length > maxIds) + throw new ArgumentException($"V4 SetBrightness packs at most {maxIds} light ids per command (got {lightIds.Length}).", nameof(lightIds)); + + int pct = Math.Clamp(brightnessPercent, 0, 100); + byte invertedPct = (byte)(0x64 - pct); + + buffer.Clear(); + buffer[0] = ReportId; + buffer[1] = 0x03; + buffer[2] = 0x26; + buffer[3] = invertedPct; + buffer[4] = 0x00; + buffer[5] = (byte)lightIds.Length; + for (int i = 0; i < lightIds.Length; i++) + buffer[6 + i] = lightIds[i]; + } + + // Status query — caller reads the device's input report and + // inspects buffer[2] for one of the Status* constants. + public static void BuildStatusQuery(Span buffer) + { + // V4 status is read via HidD_GetInputReport with no preceding + // write — caller just reads. We expose this stub for symmetry + // with the other protocol files; it isn't actually sent. + EnsureLength(buffer); + buffer.Clear(); + buffer[0] = ReportId; + } + + private static void EnsureLength(Span buffer) + { + if (buffer.Length < ReportLength) + throw new ArgumentException($"V4 buffer must be at least {ReportLength} bytes (got {buffer.Length})."); + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingClientDefinition.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingClientDefinition.cs new file mode 100644 index 00000000..5104c4c9 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingClientDefinition.cs @@ -0,0 +1,40 @@ +using Windows.Devices.Lights; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + // Runtime descriptor for one Windows Dynamic Lighting (LampArray) + // device. Captures the WinRT LampArray instance the DeviceWatcher + // resolved from the device id, plus the OS-supplied identification + // bits used for the Mapping tab label. + // + // The LampArray itself owns the live connection to the device and + // is what the UpdateQueue calls SetColor / SetColorsForIndices on. + // We hold a reference here so the provider's lifecycle can dispose + // it when the device is removed. + public sealed class DynamicLightingClientDefinition + { + public DynamicLightingClientDefinition( + string deviceId, + string displayName, + LampArray lampArray) + { + DeviceId = deviceId ?? string.Empty; + DisplayName = displayName ?? "Dynamic Lighting Device"; + LampArray = lampArray; + } + + // OS device identifier (HID-style \\?\HID#... path). Stable across + // reconnects of the same physical device; lets us match incoming + // DeviceWatcher.Added events to existing entries during refresh. + public string DeviceId { get; } + + // OEM-supplied display name from DeviceInformation.Name. Falls + // back to a generic label when the OS doesn't give us one. + public string DisplayName { get; } + + // The live WinRT object that fronts the device. The UpdateQueue + // calls SetColor / SetColorsForIndices / SetSingleColor on this. + // Disposed by the provider when the device is removed. + public LampArray LampArray { get; } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingDevice.cs new file mode 100644 index 00000000..8687fddf --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingDevice.cs @@ -0,0 +1,145 @@ +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using RGB.NET.Core; +using System.Collections.Generic; +using Windows.Devices.Lights; +using WinColor = Windows.UI.Color; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + public class DynamicLightingDevice : AbstractRGBDevice + { + private readonly DynamicLightingUpdateQueue _updateQueue; + private readonly DynamicLightingClientDefinition _def; + + // LedId → LampArray lamp index. Built once at construction so the + // per-frame Update doesn't have to rebuild the map. The UpdateQueue + // reads this to translate Chromatics LedId paint events into + // LampArray.SetSingleColor / SetColorsForIndices calls. + private readonly Dictionary _ledIndexByLedId = new(); + + public DynamicLightingDevice(DynamicLightingDeviceInfo info, DynamicLightingUpdateQueue updateQueue, DynamicLightingClientDefinition def) + : base(info, updateQueue) + { + _updateQueue = updateQueue; + _def = def; + InitializeLayout(); + _updateQueue.SetLedIndexMap(_ledIndexByLedId); + } + + public DynamicLightingClientDefinition Definition => _def; + + public void BeginShutdown() => _updateQueue.BeginShutdown(); + public void SetPerDeviceDisabled(bool disabled) => _updateQueue.SetPerDeviceDisabled(disabled); + public void ResetCache() => _updateQueue.ResetCache(); + + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _updateQueue.SetPerDeviceBrightness(correction); + + // Layout pulls per-lamp metadata from the WinRT LampArray: + // + // - For keyboard-kind devices, LampInfo.GetPurposes() identifies + // control lamps (the actual keys); we map each by its + // VirtualKey association via LampArray.GetIndicesForKey() so + // the Highlight / Keybind layers light the right physical + // keys without manual setup. + // + // - For non-keyboard devices (mice, chassis, headsets, etc.), + // we expose each lamp as Custom1..N and use LampInfo.Position + // for the RGB.NET Point so spatial decorators (radial pulses) + // can compute distances correctly. + // + // LampArray.MinUpdateInterval is the OEM's claimed cap on update + // rate; we don't enforce it client-side because the trigger's + // 30Hz cadence is already inside the documented envelope for + // every shipping LampArray device family. + private void InitializeLayout() + { + var lampArray = _def.LampArray; + if (lampArray == null) return; + + int lampCount = lampArray.LampCount; + if (lampCount <= 0) return; + + // Bounding box is in millimetres. RGB.NET uses arbitrary + // units, but ratios are what matter for decorators — so + // multiply by a fixed scale that keeps positions in the + // same numerical range as our other providers (Custom1..N + // grids use a 30-unit cell). 10 units per mm produces a + // ~430-unit-wide keyboard, which sits comfortably alongside + // the QMK and Alienware layouts at default cell sizes. + const float MmToUnits = 10f; + + // Try VirtualKey-based semantic mapping first for keyboards. + // GetIndicesForKey returns the lamp indices the OS associates + // with that virtual key; for the standard ANSI 104 we walk + // each LedId.Keyboard_* and look it up. + bool isKeyboard = lampArray.LampArrayKind == LampArrayKind.Keyboard; + var assigned = new HashSet(); + + if (isKeyboard) + { + foreach (var (ledId, vk) in DynamicLightingKeyMap.LedIdToVirtualKey) + { + int[] indices; + try { indices = lampArray.GetIndicesForKey(vk); } + catch { indices = System.Array.Empty(); } + + if (indices == null || indices.Length == 0) continue; + int lampIndex = indices[0]; + if (lampIndex < 0 || lampIndex >= lampCount) continue; + if (assigned.Contains(lampIndex)) continue; + + AddLedFromLampInfo(lampArray, lampIndex, ledId, MmToUnits); + _ledIndexByLedId[ledId] = lampIndex; + assigned.Add(lampIndex); + } + } + + // Anything not claimed by the semantic mapping (non-keyboard + // devices, plus keyboard lamps that aren't standard ANSI keys + // — function row extras, status LEDs, logos) gets Custom1..N + // in lamp-index order. This guarantees every lamp the OS + // exposes is addressable from Chromatics. + int customCounter = 0; + for (int i = 0; i < lampCount; i++) + { + if (assigned.Contains(i)) continue; + var ledId = (LedId)((int)LedId.Custom1 + customCounter); + AddLedFromLampInfo(lampArray, i, ledId, MmToUnits); + _ledIndexByLedId[ledId] = i; + customCounter++; + } + } + + private void AddLedFromLampInfo(LampArray lampArray, int lampIndex, LedId ledId, float mmToUnits) + { + LampInfo info; + try { info = lampArray.GetLampInfo(lampIndex); } + catch { info = null; } + + // Lamp positions are Vector3 in millimetres relative to the + // device bounding box origin. We project to 2D by dropping Z + // (depth) since RGB.NET decorators operate in 2D space; for + // every shipping LampArray device the keys are coplanar so + // dropping Z loses no information. + Point location; + Size size = new Size(20, 20); + if (info != null) + { + location = new Point(info.Position.X * mmToUnits, info.Position.Y * mmToUnits); + } + else + { + // Fallback: arrange in a wider-than-tall grid like the + // synthetic layouts in DeviceGridHelper. + int cols = System.Math.Max(1, (int)System.Math.Ceiling(System.Math.Sqrt(lampArray.LampCount * 4.0 / 3.0))); + int row = lampIndex / cols; + int col = lampIndex % cols; + location = new Point(col * 30f, row * 30f); + } + + var led = AddLed(ledId, location, size); + if (led != null) led.Shape = Shape.Rectangle; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingDeviceInfo.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingDeviceInfo.cs new file mode 100644 index 00000000..8e42d655 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingDeviceInfo.cs @@ -0,0 +1,66 @@ +using RGB.NET.Core; +using Windows.Devices.Lights; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + public class DynamicLightingDeviceInfo : IRGBDeviceInfo + { + public DynamicLightingDeviceInfo(DynamicLightingClientDefinition def) + { + // Windows hands us bare model names through DeviceInformation.Name + // ("G512" rather than "Logitech G512"), and two devices from the + // same vendor can collide in the Mappings tab combo without the + // prefix. Re-prefix by looking up the OEM name from the LampArray + // HardwareVendorId and tag with "(Dynamic Lighting)" so the + // device is also distinguishable from the same physical board's + // entry under its vendor SDK provider. + string baseName = def.DisplayName ?? string.Empty; + string vendorPrefix = def.LampArray != null + ? DynamicLightingVendorOverlap.TryGetVendorDisplayName(def.LampArray.HardwareVendorId) + : null; + + bool alreadyPrefixed = !string.IsNullOrEmpty(vendorPrefix) + && baseName.StartsWith(vendorPrefix, System.StringComparison.OrdinalIgnoreCase); + + string prefixed = (vendorPrefix == null || alreadyPrefixed) + ? baseName + : $"{vendorPrefix} {baseName}".Trim(); + + DeviceName = string.IsNullOrWhiteSpace(prefixed) + ? "Dynamic Lighting device" + : $"{prefixed} (Dynamic Lighting)"; + + Manufacturer = vendorPrefix ?? "Windows Dynamic Lighting"; + Model = def.LampArray?.LampArrayKind.ToString() ?? "LampArray"; + DeviceType = MapDeviceType(def.LampArray?.LampArrayKind ?? LampArrayKind.Undefined); + } + + public RGBDeviceType DeviceType { get; } + public string DeviceName { get; } + public string Manufacturer { get; } + public string Model { get; } + public object LayoutMetadata { get; set; } + + // LampArrayKind → RGBDeviceType. The LampArrayKind enum carries + // OEM intent ("this device is a keyboard / mouse / chassis / ..."); + // we map it onto the closest RGBDeviceType so the Mapping tab + // groups Dynamic Lighting devices with the right vendor counterparts. + private static RGBDeviceType MapDeviceType(LampArrayKind kind) + { + return kind switch + { + LampArrayKind.Keyboard => RGBDeviceType.Keyboard, + LampArrayKind.Mouse => RGBDeviceType.Mouse, + LampArrayKind.GameController => RGBDeviceType.GameController, + LampArrayKind.Chassis => RGBDeviceType.Mainboard, + LampArrayKind.Wearable => RGBDeviceType.LedController, + LampArrayKind.Furniture => RGBDeviceType.LedController, + LampArrayKind.Art => RGBDeviceType.LedController, + LampArrayKind.Peripheral => RGBDeviceType.LedController, + LampArrayKind.Scene => RGBDeviceType.LedController, + LampArrayKind.Notification => RGBDeviceType.LedController, + _ => RGBDeviceType.Unknown, + }; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingKeyMap.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingKeyMap.cs new file mode 100644 index 00000000..b25f914e --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingKeyMap.cs @@ -0,0 +1,146 @@ +using RGB.NET.Core; +using System.Collections.Generic; +using Windows.System; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + // Static map from RGB.NET LedId.Keyboard_* values to the Windows + // VirtualKey codes that LampArray.GetIndicesForKey() resolves + // against. Lets the device's InitializeLayout produce semantic + // LedId mappings for keyboards without any per-OEM lookup table. + // + // The OS owns the mapping from VirtualKey → physical-lamp-index + // (it's part of the LampArray firmware response to + // LampAttributesRequestReport). We just have to declare which + // VirtualKey corresponds to each LedId in our own keyboard + // vocabulary and let the OS resolve the rest. + internal static class DynamicLightingKeyMap + { + // Ordered list of (LedId, VirtualKey) pairs covering the standard + // ANSI 104 layout plus media keys. Iterated by InitializeLayout + // in the order presented; first-match wins for any duplicate + // VirtualKey resolution. + public static readonly IReadOnlyList<(LedId LedId, VirtualKey VirtualKey)> LedIdToVirtualKey = new (LedId, VirtualKey)[] + { + // Function row + (LedId.Keyboard_Escape, VirtualKey.Escape), + (LedId.Keyboard_F1, VirtualKey.F1), + (LedId.Keyboard_F2, VirtualKey.F2), + (LedId.Keyboard_F3, VirtualKey.F3), + (LedId.Keyboard_F4, VirtualKey.F4), + (LedId.Keyboard_F5, VirtualKey.F5), + (LedId.Keyboard_F6, VirtualKey.F6), + (LedId.Keyboard_F7, VirtualKey.F7), + (LedId.Keyboard_F8, VirtualKey.F8), + (LedId.Keyboard_F9, VirtualKey.F9), + (LedId.Keyboard_F10, VirtualKey.F10), + (LedId.Keyboard_F11, VirtualKey.F11), + (LedId.Keyboard_F12, VirtualKey.F12), + (LedId.Keyboard_PrintScreen, VirtualKey.Print), + (LedId.Keyboard_ScrollLock, VirtualKey.Scroll), + (LedId.Keyboard_PauseBreak, VirtualKey.Pause), + + // Number row + (LedId.Keyboard_GraveAccentAndTilde, (VirtualKey)0xC0), // VK_OEM_3 + (LedId.Keyboard_1, VirtualKey.Number1), + (LedId.Keyboard_2, VirtualKey.Number2), + (LedId.Keyboard_3, VirtualKey.Number3), + (LedId.Keyboard_4, VirtualKey.Number4), + (LedId.Keyboard_5, VirtualKey.Number5), + (LedId.Keyboard_6, VirtualKey.Number6), + (LedId.Keyboard_7, VirtualKey.Number7), + (LedId.Keyboard_8, VirtualKey.Number8), + (LedId.Keyboard_9, VirtualKey.Number9), + (LedId.Keyboard_0, VirtualKey.Number0), + (LedId.Keyboard_MinusAndUnderscore, (VirtualKey)0xBD), // VK_OEM_MINUS + (LedId.Keyboard_EqualsAndPlus, (VirtualKey)0xBB), // VK_OEM_PLUS + (LedId.Keyboard_Backspace, VirtualKey.Back), + + // Top alpha row + (LedId.Keyboard_Tab, VirtualKey.Tab), + (LedId.Keyboard_Q, VirtualKey.Q), + (LedId.Keyboard_W, VirtualKey.W), + (LedId.Keyboard_E, VirtualKey.E), + (LedId.Keyboard_R, VirtualKey.R), + (LedId.Keyboard_T, VirtualKey.T), + (LedId.Keyboard_Y, VirtualKey.Y), + (LedId.Keyboard_U, VirtualKey.U), + (LedId.Keyboard_I, VirtualKey.I), + (LedId.Keyboard_O, VirtualKey.O), + (LedId.Keyboard_P, VirtualKey.P), + (LedId.Keyboard_BracketLeft, (VirtualKey)0xDB), // VK_OEM_4 + (LedId.Keyboard_BracketRight, (VirtualKey)0xDD), // VK_OEM_6 + (LedId.Keyboard_Backslash, (VirtualKey)0xDC), // VK_OEM_5 + + // Home alpha row + (LedId.Keyboard_CapsLock, VirtualKey.CapitalLock), + (LedId.Keyboard_A, VirtualKey.A), + (LedId.Keyboard_S, VirtualKey.S), + (LedId.Keyboard_D, VirtualKey.D), + (LedId.Keyboard_F, VirtualKey.F), + (LedId.Keyboard_G, VirtualKey.G), + (LedId.Keyboard_H, VirtualKey.H), + (LedId.Keyboard_J, VirtualKey.J), + (LedId.Keyboard_K, VirtualKey.K), + (LedId.Keyboard_L, VirtualKey.L), + (LedId.Keyboard_SemicolonAndColon, (VirtualKey)0xBA), // VK_OEM_1 + (LedId.Keyboard_ApostropheAndDoubleQuote, (VirtualKey)0xDE), // VK_OEM_7 + (LedId.Keyboard_Enter, VirtualKey.Enter), + + // Bottom alpha row + (LedId.Keyboard_LeftShift, VirtualKey.LeftShift), + (LedId.Keyboard_Z, VirtualKey.Z), + (LedId.Keyboard_X, VirtualKey.X), + (LedId.Keyboard_C, VirtualKey.C), + (LedId.Keyboard_V, VirtualKey.V), + (LedId.Keyboard_B, VirtualKey.B), + (LedId.Keyboard_N, VirtualKey.N), + (LedId.Keyboard_M, VirtualKey.M), + (LedId.Keyboard_CommaAndLessThan, (VirtualKey)0xBC), // VK_OEM_COMMA + (LedId.Keyboard_PeriodAndBiggerThan, (VirtualKey)0xBE), // VK_OEM_PERIOD + (LedId.Keyboard_SlashAndQuestionMark, (VirtualKey)0xBF), // VK_OEM_2 + (LedId.Keyboard_RightShift, VirtualKey.RightShift), + + // Bottom row modifiers + (LedId.Keyboard_LeftCtrl, VirtualKey.LeftControl), + (LedId.Keyboard_LeftGui, VirtualKey.LeftWindows), + (LedId.Keyboard_LeftAlt, VirtualKey.LeftMenu), + (LedId.Keyboard_Space, VirtualKey.Space), + (LedId.Keyboard_RightAlt, VirtualKey.RightMenu), + (LedId.Keyboard_RightGui, VirtualKey.RightWindows), + (LedId.Keyboard_Application, VirtualKey.Application), + (LedId.Keyboard_RightCtrl, VirtualKey.RightControl), + + // Nav cluster + (LedId.Keyboard_Insert, VirtualKey.Insert), + (LedId.Keyboard_Home, VirtualKey.Home), + (LedId.Keyboard_PageUp, VirtualKey.PageUp), + (LedId.Keyboard_Delete, VirtualKey.Delete), + (LedId.Keyboard_End, VirtualKey.End), + (LedId.Keyboard_PageDown, VirtualKey.PageDown), + (LedId.Keyboard_ArrowUp, VirtualKey.Up), + (LedId.Keyboard_ArrowLeft, VirtualKey.Left), + (LedId.Keyboard_ArrowDown, VirtualKey.Down), + (LedId.Keyboard_ArrowRight, VirtualKey.Right), + + // Numpad + (LedId.Keyboard_NumLock, VirtualKey.NumberKeyLock), + (LedId.Keyboard_NumSlash, VirtualKey.Divide), + (LedId.Keyboard_NumAsterisk, VirtualKey.Multiply), + (LedId.Keyboard_NumMinus, VirtualKey.Subtract), + (LedId.Keyboard_NumPlus, VirtualKey.Add), + (LedId.Keyboard_NumEnter, VirtualKey.Enter), + (LedId.Keyboard_Num0, VirtualKey.NumberPad0), + (LedId.Keyboard_Num1, VirtualKey.NumberPad1), + (LedId.Keyboard_Num2, VirtualKey.NumberPad2), + (LedId.Keyboard_Num3, VirtualKey.NumberPad3), + (LedId.Keyboard_Num4, VirtualKey.NumberPad4), + (LedId.Keyboard_Num5, VirtualKey.NumberPad5), + (LedId.Keyboard_Num6, VirtualKey.NumberPad6), + (LedId.Keyboard_Num7, VirtualKey.NumberPad7), + (LedId.Keyboard_Num8, VirtualKey.NumberPad8), + (LedId.Keyboard_Num9, VirtualKey.NumberPad9), + (LedId.Keyboard_NumPeriodAndDelete, VirtualKey.Decimal), + }; + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingRGBDeviceProvider.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingRGBDeviceProvider.cs new file mode 100644 index 00000000..2d109286 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingRGBDeviceProvider.cs @@ -0,0 +1,253 @@ +using Chromatics.Core; +using Chromatics.Enums; +using RGB.NET.Core; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Windows.Devices.Enumeration; +using Windows.Devices.Lights; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + // Custom RGB.NET device provider for Windows Dynamic Lighting. + // + // Talks to the Windows.Devices.Lights.LampArray WinRT API. Devices + // that expose the standard HID Lighting and Illumination usage page + // (0x59, HUTRR84) are picked up by Windows automatically; any + // device Windows exposes via LampArray.GetDeviceSelector() is a + // candidate for adoption here. + // + // Discovery uses Windows' DeviceWatcher so hot-plug works without + // any per-frame polling on our side. The watcher fires Added / + // Removed events on a thread-pool worker; we resolve each Added + // event into a LampArray instance via FromIdAsync and surface + // them to RGB.NET through AddDevice / RemoveDevice. + public class DynamicLightingRGBDeviceProvider : AbstractRGBDeviceProvider + { + #region Singleton + + private static DynamicLightingRGBDeviceProvider _instance; + public static DynamicLightingRGBDeviceProvider Instance => _instance ?? new DynamicLightingRGBDeviceProvider(); + + public DynamicLightingRGBDeviceProvider() + { + if (_instance != null) Throw(new Exception($"There can be only one instance of type {nameof(DynamicLightingRGBDeviceProvider)}")); + _instance = this; + } + + #endregion + + // 30Hz update cap. LampArray devices report MinUpdateInterval + // ranging from 4ms to 33ms across the shipping device set; + // 30Hz sits comfortably inside that envelope and matches the + // cadence the QMK / Yeelight / Alienware providers use. + private const double UpdateFrequencySeconds = 1.0 / 30.0; + + private DeviceWatcher _watcher; + private readonly ConcurrentDictionary _devicesById = new(StringComparer.OrdinalIgnoreCase); + + // Count of devices currently adopted by this provider. Polled by + // SettingsViewModel's toggle handler after LoadDeviceProvider so + // it can flip the toggle back off (and surface a dialog) when + // Windows enumerated zero compatible devices. + public int AdoptedDeviceCount => _devicesById.Count; + + protected override void InitializeSDK() + { + // No SDK init required; LampArray is part of the Windows + // platform. We just need to start the device watcher + // (which happens in LoadDevices below). + } + + protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) + => new DynamicLightingUpdateTrigger(UpdateFrequencySeconds); + + protected override IEnumerable LoadDevices() + { + // Synchronously enumerate the initial device set. The + // DeviceWatcher gives us hot-plug for the rest of the + // session lifetime. + var initialDevices = LoadInitialDevicesAsync().GetAwaiter().GetResult(); + StartWatcher(); + return initialDevices; + } + + private async Task> LoadInitialDevicesAsync() + { + var devices = new List(); + DeviceInformationCollection found; + try + { + string selector = LampArray.GetDeviceSelector(); + found = await DeviceInformation.FindAllAsync(selector).AsTask().ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, $"[DynamicLighting] Initial enumeration failed: {ex.Message}"); + return devices; + } + + foreach (var info in found) + { + var dev = await TryAdoptAsync(info).ConfigureAwait(false); + if (dev != null) devices.Add(dev); + } + + if (devices.Count == 0) + { + Logger.WriteConsole(LoggerTypes.Devices, + "[DynamicLighting] No Dynamic Lighting devices detected. Compatible hardware (Razer, Logitech G LIGHTSYNC, ASUS ROG, HyperX, MSI, SteelSeries, HP/Omen) shows up here when its firmware enables the Dynamic Lighting HID profile and Settings -> Personalization -> Dynamic Lighting is turned on in Windows.", + forwardToSentry: false); + } + return devices; + } + + // Build the RGB.NET device wrapper for one OS-supplied + // DeviceInformation. Returns null on any failure (LampArray + // construction failed, device disappeared between enumeration + // and adoption, etc.) so the caller can keep going. + private async Task TryAdoptAsync(DeviceInformation info) + { + try + { + var lampArray = await LampArray.FromIdAsync(info.Id).AsTask().ConfigureAwait(false); + if (lampArray == null || lampArray.LampCount <= 0) return null; + + // Conflict check: when the user has opted into the + // conservative conflict-handling behaviour (Settings -> + // Advanced -> "Block Dynamic Lighting on devices already + // covered by a vendor provider"), skip adoption of any + // device whose OEM has a Chromatics vendor provider + // currently enabled. The vendor SDK retains exclusive + // control of the device. + // + // Default is the bypass path (adopt every device Windows + // exposes regardless of overlap), since most users + // running Dynamic Lighting want it to work on every + // supported device. The opt-in conservative path is + // for users who see flickering from both providers + // writing to the same hardware. + try + { + var settings = AppSettings.GetSettings(); + if (!settings.dynamicLightingBypassConflictCheck) + { + string overlapVendor = DynamicLightingVendorOverlap.TryGetEnabledVendorOwner( + lampArray.HardwareVendorId, settings); + if (overlapVendor != null) + { + Logger.WriteConsole(LoggerTypes.Devices, + $"[DynamicLighting] Skipped '{info.Name}' (VID 0x{lampArray.HardwareVendorId:X4}); the {overlapVendor} provider is enabled and owns this device. Settings -> Advanced controls this behaviour.", + forwardToSentry: false); + return null; + } + } + } + catch { /* conflict check is best-effort; never block adoption on a check failure */ } + + var def = new DynamicLightingClientDefinition(info.Id, info.Name, lampArray); + var trigger = (DynamicLightingUpdateTrigger)GetUpdateTrigger(); + var queue = new DynamicLightingUpdateQueue(trigger, def); + var rgbInfo = new DynamicLightingDeviceInfo(def); + var dev = new DynamicLightingDevice(rgbInfo, queue, def); + _devicesById[info.Id] = dev; + + Logger.WriteConsole(LoggerTypes.Devices, + $"[DynamicLighting] Adopted '{info.Name}' ({lampArray.LampArrayKind}, {lampArray.LampCount} lamps).", + forwardToSentry: false); + return dev; + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, + $"[DynamicLighting] Failed to adopt '{info?.Name ?? info?.Id ?? "unknown"}': {ex.Message}", + forwardToSentry: false); + return null; + } + } + + // ── DeviceWatcher hot-plug ──────────────────────────────────── + + private void StartWatcher() + { + if (_watcher != null) return; + try + { + _watcher = DeviceInformation.CreateWatcher(LampArray.GetDeviceSelector()); + _watcher.Added += OnDeviceAdded; + _watcher.Removed += OnDeviceRemoved; + _watcher.Start(); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, $"[DynamicLighting] DeviceWatcher start failed: {ex.Message}"); + } + } + + private async void OnDeviceAdded(DeviceWatcher sender, DeviceInformation info) + { + if (info == null || string.IsNullOrEmpty(info.Id)) return; + if (_devicesById.ContainsKey(info.Id)) return; // already adopted at startup + + var dev = await TryAdoptAsync(info).ConfigureAwait(false); + if (dev != null) + { + try { AddDevice(dev); } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, $"[DynamicLighting] AddDevice failed for '{info.Name}': {ex.Message}"); + } + } + } + + private void OnDeviceRemoved(DeviceWatcher sender, DeviceInformationUpdate update) + { + if (update == null || string.IsNullOrEmpty(update.Id)) return; + if (!_devicesById.TryRemove(update.Id, out var dev)) return; + try + { + dev.BeginShutdown(); + RemoveDevice(dev); + Logger.WriteConsole(LoggerTypes.Devices, $"[DynamicLighting] Removed '{dev.DeviceInfo.DeviceName}'.", forwardToSentry: false); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, $"[DynamicLighting] RemoveDevice failed: {ex.Message}"); + } + } + + // ── Dispose ─────────────────────────────────────────────────── + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_watcher != null) + { + try { _watcher.Stop(); } catch { /* ignore */ } + try + { + _watcher.Added -= OnDeviceAdded; + _watcher.Removed -= OnDeviceRemoved; + } + catch { /* ignore */ } + _watcher = null; + } + + foreach (var dev in _devicesById.Values) + { + try { dev.BeginShutdown(); } catch { /* ignore */ } + } + _devicesById.Clear(); + } + + base.Dispose(disposing); + + if (ReferenceEquals(_instance, this)) + _instance = null; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingUpdateQueue.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingUpdateQueue.cs new file mode 100644 index 00000000..fb5e2060 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingUpdateQueue.cs @@ -0,0 +1,190 @@ +using Chromatics.Core; +using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Threading; +using Windows.Devices.Lights; +using Color = RGB.NET.Core.Color; +using WinColor = Windows.UI.Color; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + public class DynamicLightingUpdateQueue : UpdateQueue + { + #region Properties & Fields + + private readonly DynamicLightingClientDefinition _def; + private readonly Lock _lock = new(); + private volatile bool _shuttingDown; + // Per-device disable gate — parity with LIFX/Hue/QMK/Yeelight. + private volatile bool _perDeviceDisable; + + private PerDeviceBrightnessCorrection _perDeviceBrightness; + + // LedId → lamp index, set by DynamicLightingDevice after layout + // construction. Not built here because the device is the only + // place that knows about VirtualKey-based semantic mapping. + private Dictionary _ledIndexByLedId = new(); + + // Per-lamp colour cache. Skips redundant SetSingleColor calls + // when nothing changed for a lamp this frame. + private byte[] _lampBytes; + private int _lampCount; + + // Reusable buffers for SetColorsForIndices to avoid per-frame + // allocations on the trigger thread. + private int[] _dirtyIndicesBuffer; + private WinColor[] _dirtyColorsBuffer; + + #endregion + + #region Constructors + + public DynamicLightingUpdateQueue(IDeviceUpdateTrigger trigger, DynamicLightingClientDefinition def) + : base(trigger) + { + _def = def; + _lampCount = def.LampArray?.LampCount ?? 0; + _lampBytes = new byte[Math.Max(_lampCount, 1) * 3]; + _dirtyIndicesBuffer = new int[Math.Max(_lampCount, 1)]; + _dirtyColorsBuffer = new WinColor[Math.Max(_lampCount, 1)]; + } + + #endregion + + #region Lifecycle + + public void BeginShutdown() => _shuttingDown = true; + public void SetPerDeviceDisabled(bool disabled) => _perDeviceDisable = disabled; + + public void ResetCache() + { + lock (_lock) + { + Array.Clear(_lampBytes, 0, _lampBytes.Length); + } + } + + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _perDeviceBrightness = correction; + + // Called by DynamicLightingDevice once layout has been built. + // We don't construct the map here because the device is the only + // layer that knows about VirtualKey-based semantic mapping vs + // Custom1..N fallback. + public void SetLedIndexMap(Dictionary map) + { + lock (_lock) + { + _ledIndexByLedId = map ?? new Dictionary(); + } + } + + #endregion + + #region Update + + protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet) + { + lock (_lock) + { + if (_shuttingDown || _perDeviceDisable) return true; + if (dataSet.IsEmpty) return true; + + var lampArray = _def.LampArray; + if (lampArray == null) return true; + + // Skip the entire frame when the OS has yielded our + // device to a higher-priority owner (a foreground app + // with the lighting AppExtension, or system overrides). + // Without the IsEnabled gate every paint frame would + // throw an unhandled COMException since the WinRT + // surface refuses writes when our app isn't the + // currently-allowed lighting client. + // + // IsConnected reports whether the underlying USB / BT + // device is physically present; IsEnabled reports + // whether Windows is currently letting us write to + // it (foreground / background priority gate). + if (!lampArray.IsConnected || !lampArray.IsEnabled) return true; + + try + { + int globalPct = GlobalBrightnessCorrection.Instance.BrightnessPercent; + int perDevicePct = _perDeviceBrightness?.BrightnessPercent ?? 100; + double brightnessScale = (globalPct / 100.0) * (perDevicePct / 100.0); + + int dirtyCount = 0; + foreach (var (key, color) in dataSet) + { + if (!TryResolveLampIndex(key, out int idx)) continue; + if (idx < 0 || idx >= _lampCount) continue; + + ToRgb255(color, brightnessScale, out byte r, out byte g, out byte b); + int off = idx * 3; + if (_lampBytes[off] == r && _lampBytes[off + 1] == g && _lampBytes[off + 2] == b) continue; + + _lampBytes[off] = r; + _lampBytes[off + 1] = g; + _lampBytes[off + 2] = b; + + _dirtyIndicesBuffer[dirtyCount] = idx; + // WinRT Color.FromArgb takes (a, r, g, b) — alpha 255 since + // LampArray ignores alpha but the API still requires it. + _dirtyColorsBuffer[dirtyCount] = WinColor.FromArgb(255, r, g, b); + dirtyCount++; + } + + if (dirtyCount == 0) return true; + + // SetColorsForIndices applies all changed lamps in one + // WinRT call. Cheaper than N SetSingleColor calls + // (one IPC trip vs N), and the WinRT layer batches + // the underlying HID multi-update reports for us. + var indicesSlice = new int[dirtyCount]; + var colorsSlice = new WinColor[dirtyCount]; + Array.Copy(_dirtyIndicesBuffer, indicesSlice, dirtyCount); + Array.Copy(_dirtyColorsBuffer, colorsSlice, dirtyCount); + lampArray.SetColorsForIndices(colorsSlice, indicesSlice); + return true; + } + catch (Exception ex) + { + // COMException with E_ACCESSDENIED happens when the + // OS revokes our write permission mid-frame (another + // app took foreground priority). It's expected under + // the foreground/background priority model and not + // worth alerting the user about each frame; we just + // wait for AvailabilityChanged on the device side. + if (ex is System.Runtime.InteropServices.COMException) return true; + DynamicLightingRGBDeviceProvider.Instance?.Throw(ex); + return false; + } + } + } + + private bool TryResolveLampIndex(object key, out int idx) + { + if (key is LedId id && _ledIndexByLedId.TryGetValue(id, out idx)) return true; + if (key is Led led && _ledIndexByLedId.TryGetValue(led.Id, out idx)) return true; + idx = -1; + return false; + } + + #endregion + + #region Helpers + + private static void ToRgb255(Color rgb, double brightnessScale, out byte r, out byte g, out byte b) + { + double scale = Math.Clamp(brightnessScale, 0.0, 1.0); + r = (byte)Math.Round(Math.Clamp(rgb.R, 0.0, 1.0) * 255 * scale); + g = (byte)Math.Round(Math.Clamp(rgb.G, 0.0, 1.0) * 255 * scale); + b = (byte)Math.Round(Math.Clamp(rgb.B, 0.0, 1.0) * 255 * scale); + } + + #endregion + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingUpdateTrigger.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingUpdateTrigger.cs new file mode 100644 index 00000000..465e5453 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingUpdateTrigger.cs @@ -0,0 +1,51 @@ +using RGB.NET.Core; +using System; +using System.Diagnostics; +using System.Threading; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + // 30Hz trigger with 50ms idle wake. Matches the QMK / Yeelight / + // Alienware triggers — the idle refresh keeps per-device brightness + // slider changes propagating when devices are sitting on a static + // base layer. + // + // Dynamic Lighting devices report their min update interval via + // LampArray.MinUpdateInterval. Most current devices report somewhere + // between 4ms and 33ms; we pick 33ms (30Hz) as a conservative cap + // that comfortably covers the documented range. + public class DynamicLightingUpdateTrigger : DeviceUpdateTrigger + { + private const int WaitOneTimeoutMs = 50; + + public DynamicLightingUpdateTrigger() { } + + public DynamicLightingUpdateTrigger(double updateRateHardLimit) + : base(updateRateHardLimit) { } + + protected override void UpdateLoop() + { + OnStartup(); + + while (!UpdateToken.IsCancellationRequested) + { + if (HasDataEvent.WaitOne(WaitOneTimeoutMs)) + { + long preUpdateTicks = Stopwatch.GetTimestamp(); + OnUpdate(); + + if (UpdateFrequency > 0) + { + double elapsedMs = (Stopwatch.GetTimestamp() - preUpdateTicks) / (double)TimeSpan.TicksPerMillisecond; + int sleep = (int)(UpdateFrequency * 1000.0 - elapsedMs); + if (sleep > 0) Thread.Sleep(sleep); + } + } + else + { + OnUpdate(new CustomUpdateData(("refresh", true))); + } + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingVendorOverlap.cs b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingVendorOverlap.cs new file mode 100644 index 00000000..af65a120 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/DynamicLighting/DynamicLightingVendorOverlap.cs @@ -0,0 +1,135 @@ +using Chromatics.Models; +using System; +using System.Collections.Generic; + +namespace Chromatics.Extensions.RGB.NET.Devices.DynamicLighting +{ + // Maps USB vendor ids to the Chromatics vendor-provider name that + // would otherwise own the same physical device. Used by both the + // DynamicLightingRGBDeviceProvider's auto-dedup logic (skip a + // LampArray device if its OEM has a Chromatics vendor provider + // already enabled) and the conflict-popup logic in + // SettingsViewModel. + // + // Default behaviour when both providers cover a device: the + // existing vendor SDK wins. This is the safer default because: + // + // 1. The vendor SDK predates Dynamic Lighting and tends to be + // better tested per-device. + // 2. The vendor SDK doesn't have the foreground/background + // priority gate Dynamic Lighting has, so it works during + // gameplay regardless of which package identity Chromatics + // ships with. + // + // Users who want Dynamic Lighting to win on a specific device can + // override per-device in the Mapping tab (separate UI commit; + // this layer just handles the default). + internal static class DynamicLightingVendorOverlap + { + // Vendor IDs of OEMs whose hardware appears in BOTH a Chromatics + // vendor provider AND Windows Dynamic Lighting. The list is + // narrow because Dynamic Lighting only ships with a subset of + // OEMs that signed onto the HID Lighting and Illumination + // standard. CoolerMaster, Wooting, Novation, Corsair, OpenRGB + // are NOT in this list — none of them ship Dynamic Lighting + // firmware. + private static readonly Dictionary _byVendorId = new() + { + // Razer + [0x1532] = new("Razer", s => s.deviceRazerEnabled), + // Logitech G LIGHTSYNC + general Logitech + [0x046D] = new("Logitech", s => s.deviceLogitechEnabled), + // ASUS ROG + [0x0B05] = new("ASUS", s => s.deviceAsusEnabled), + // MSI Mystic Light + [0x1462] = new("MSI", s => s.deviceMsiEnabled), + // SteelSeries Apex + [0x1038] = new("SteelSeries", s => s.deviceSteelseriesEnabled), + }; + + // Friendly display-name table for ALL Dynamic Lighting OEMs we + // know about, used to prefix the OS-supplied device name in + // DynamicLightingDeviceInfo (Windows often hands us a bare + // model name like "G512" instead of "Logitech G512"). Includes + // vendors that don't overlap with a Chromatics vendor provider + // (HyperX, HP/Omen) so their devices still get a vendor + // prefix. + private static readonly Dictionary _vendorDisplayNames = new() + { + [0x1532] = "Razer", + [0x046D] = "Logitech", + [0x0B05] = "ASUS", + [0x1462] = "MSI", + [0x1038] = "SteelSeries", + [0x0951] = "HyperX", + [0x03F0] = "HP", + [0x187C] = "Alienware", + [0x1B1C] = "Corsair", + [0x2516] = "Cooler Master", + [0x04D9] = "Holtek", + [0x05AC] = "Apple", + }; + + // Returns a friendly vendor display name for the supplied USB + // vendor id (Razer, Logitech, ASUS, etc.). Returns null when + // the vendor isn't in our table — caller falls back to the + // bare device name string. + public static string TryGetVendorDisplayName(uint hardwareVendorId) + => _vendorDisplayNames.TryGetValue(hardwareVendorId, out var name) ? name : null; + + // Returns the vendor display name when the supplied USB vendor id + // belongs to an OEM whose Chromatics provider is currently enabled. + // Returns null when there's no overlap (either an unknown OEM, or + // the OEM's Chromatics provider isn't currently enabled). + public static string TryGetEnabledVendorOwner(uint hardwareVendorId, SettingsModel settings) + { + if (settings == null) return null; + if (!_byVendorId.TryGetValue(hardwareVendorId, out var entry)) return null; + return entry.IsEnabled(settings) ? entry.DisplayName : null; + } + + // List the display names of every Chromatics vendor provider + // currently enabled whose hardware overlaps with Dynamic Lighting. + // Used by the SettingsViewModel toggle to show a one-time + // conflict popup when the user enables Dynamic Lighting. + public static IReadOnlyList GetEnabledOverlappingVendorNames(SettingsModel settings) + { + if (settings == null) return Array.Empty(); + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + var result = new List(); + foreach (var (_, entry) in _byVendorId) + { + if (!entry.IsEnabled(settings)) continue; + if (seen.Add(entry.DisplayName)) result.Add(entry.DisplayName); + } + return result; + } + + // True when the supplied vendor display name (case-insensitive) + // matches one of the Dynamic-Lighting-overlapping OEMs. Used to + // gate the conflict popup on the vendor toggles in + // SettingsViewModel — only Razer / Logitech / ASUS / MSI / + // SteelSeries trigger the popup; CoolerMaster, Wooting, etc. + // don't because they don't overlap with Dynamic Lighting. + public static bool IsOverlappingVendorName(string vendorName) + { + if (string.IsNullOrEmpty(vendorName)) return false; + foreach (var (_, entry) in _byVendorId) + if (string.Equals(entry.DisplayName, vendorName, StringComparison.OrdinalIgnoreCase)) + return true; + return false; + } + + private sealed class OverlapEntry + { + public string DisplayName { get; } + public Func IsEnabled { get; } + + public OverlapEntry(string displayName, Func isEnabled) + { + DisplayName = displayName; + IsEnabled = isEnabled; + } + } + } +} diff --git a/Chromatics/Models/HueAdoptedDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/Hue/HueAdoptedDevice.cs similarity index 94% rename from Chromatics/Models/HueAdoptedDevice.cs rename to Chromatics/Extensions/RGB.NET/Devices/Hue/HueAdoptedDevice.cs index 2cda2e59..6df98a7a 100644 --- a/Chromatics/Models/HueAdoptedDevice.cs +++ b/Chromatics/Extensions/RGB.NET/Devices/Hue/HueAdoptedDevice.cs @@ -1,6 +1,6 @@ using System; -namespace Chromatics.Models +namespace Chromatics.Extensions.RGB.NET.Devices.Hue { // Persisted (settings.json) record of a user-adopted Hue bulb. LightId is // the canonical identity (CLIP v2 Guid for the light resource). Label / diff --git a/Chromatics/Extensions/RGB.NET/Devices/Hue/HueDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/Hue/HueDevice.cs index eae15080..dfd7ba1f 100644 --- a/Chromatics/Extensions/RGB.NET/Devices/Hue/HueDevice.cs +++ b/Chromatics/Extensions/RGB.NET/Devices/Hue/HueDevice.cs @@ -51,7 +51,23 @@ private void InitializeLayout() Led led = model switch { // ── Light strips: long thin rectangle, gets LedStripe1 ────────── + // + // Single-colour strips (LST*, LCL*): the whole strip is one + // colour at a time — Hue's CLIP REST API only addresses the + // overall light colour. One LedStripe1 LED is the right model. + // + // Gradient strips (LCX*, the Hue Play Gradient Lightstrip + // family): the hardware supports per-zone (5 zones for the + // TV strip), but per-zone addressing is only exposed through + // Hue's Entertainment streaming API (DTLS UDP), not the CLIP + // REST API Chromatics currently uses. So for now LCX strips + // also show as a single LedStripe1 LED that paints the + // entire strip a uniform colour. Adding Entertainment + // streaming would unlock true per-zone — tracked as a + // future enhancement. "LST001" or "LST002" or "LCL001" + or "LCX001" or "LCX002" or "LCX003" + or "LCX004" or "LCX005" or "LCX006" => AddLed(LedId.LedStripe1, new Point(0, 0), new Size(2000, 14)), // ── BR30 reflectors: large round ──────────────────────────────── @@ -122,7 +138,9 @@ _ when model.StartsWith("LLC", StringComparison.OrdinalIgnoreCase) }; // Light strips render as elongated rectangles; everything else is a circle. - bool isStrip = model is "LST001" or "LST002" or "LCL001"; + bool isStrip = model is "LST001" or "LST002" or "LCL001" + or "LCX001" or "LCX002" or "LCX003" + or "LCX004" or "LCX005" or "LCX006"; if (led != null && !isStrip) led.Shape = Shape.Circle; } diff --git a/Chromatics/Extensions/RGB.NET/Devices/Hue/HueRGBDeviceProvider.cs b/Chromatics/Extensions/RGB.NET/Devices/Hue/HueRGBDeviceProvider.cs index b684bc82..6ee7798f 100644 --- a/Chromatics/Extensions/RGB.NET/Devices/Hue/HueRGBDeviceProvider.cs +++ b/Chromatics/Extensions/RGB.NET/Devices/Hue/HueRGBDeviceProvider.cs @@ -120,7 +120,7 @@ private async Task> LoadDevicesAsync() // runs, so an empty list at this layer means we're // running through the legacy code path and should keep // the original "adopt everything" behaviour). - var adopted = appSettings.deviceHueAdoptedDevices ?? new System.Collections.Generic.List(); + var adopted = appSettings.deviceHueAdoptedDevices ?? new System.Collections.Generic.List(); var adoptedIds = new System.Collections.Generic.HashSet(adopted.Select(a => a.LightId)); bool adoptEverything = adoptedIds.Count == 0; diff --git a/Chromatics/Models/LifxAdoptedDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/LIFX/LifxAdoptedDevice.cs similarity index 90% rename from Chromatics/Models/LifxAdoptedDevice.cs rename to Chromatics/Extensions/RGB.NET/Devices/LIFX/LifxAdoptedDevice.cs index 233fc8e0..d226148f 100644 --- a/Chromatics/Models/LifxAdoptedDevice.cs +++ b/Chromatics/Extensions/RGB.NET/Devices/LIFX/LifxAdoptedDevice.cs @@ -1,4 +1,4 @@ -namespace Chromatics.Models +namespace Chromatics.Extensions.RGB.NET.Devices.LIFX { // Persisted (settings.json) record of a user-adopted LIFX bulb. Identity // is the MAC; LastIp / Label / ProductId / ZoneCount are hints we re- diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/OpenRgbQmkProtocol.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/OpenRgbQmkProtocol.cs new file mode 100644 index 00000000..adddc266 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/OpenRgbQmkProtocol.cs @@ -0,0 +1,170 @@ +using System; +using System.Buffers.Binary; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol +{ + // OpenRGB QMK plugin command set (master branch reference, see + // https://gitlab.com/CalcProgrammer1/OpenRGB → Controllers/QMKOpenRGBController). + // This sits ON TOP of the same Raw HID transport that VIA uses; + // VIA's commands occupy id 0x01-0x09, OpenRGB-QMK's start at 0x20 + // so the two can coexist on one HID interface. Firmware support + // requires the qmk_openrgb fork or patch — we detect at handshake + // and gracefully fall back to ViaProtocol if absent. + // + // Wire format: every request is `cmd_byte | request_payload[31]`. + // Replies echo cmd_byte in byte 0; mismatched echoes mean the + // firmware doesn't speak this command. + internal static class OpenRgbQmkProtocol + { + public const byte Cmd_GetProtocolVersion = 0x20; + public const byte Cmd_GetQmkVersion = 0x21; + public const byte Cmd_GetDeviceInfo = 0x22; + public const byte Cmd_GetLedInfo = 0x23; + public const byte Cmd_GetEnabledModes = 0x24; + public const byte Cmd_GetLedMatrixSize = 0x25; + public const byte Cmd_SetLedRange = 0x27; + public const byte Cmd_SetSingleLed = 0x28; + public const byte Cmd_SetMode = 0x29; + public const byte Cmd_Save = 0x2A; + + // Each Cmd_SetLedRange packet carries (start_idx u16 | count u8 | + // RGB triplets). Header overhead = 1 byte cmd + 2 bytes start + + // 1 byte count = 4 bytes, leaving 28 bytes / 3 = 9 LEDs per packet. + // Caller chunks the strip and paces packets to stay within the + // firmware's RX queue (typical RX queue is 4-8 deep at full speed, + // hence the 1ms inter-packet pacing we use in the queue). + public const int MaxLedsPerSetRange = 9; + + // ── Frame builders ──────────────────────────────────────────── + + public static void BuildGetProtocolVersion(Span payload) + { + payload.Clear(); + payload[0] = Cmd_GetProtocolVersion; + } + + public static void BuildGetDeviceInfo(Span payload) + { + payload.Clear(); + payload[0] = Cmd_GetDeviceInfo; + } + + // Cmd_GetLedInfo takes (start_idx u16) and returns matrix + // (column, row) + flags for up to N LEDs starting at start_idx. + // The firmware decides N based on remaining payload room + // (typically 9 LEDs * 3 bytes per record = 27 + 1 byte echo). + public static void BuildGetLedInfo(Span payload, ushort startIndex) + { + payload.Clear(); + payload[0] = Cmd_GetLedInfo; + BinaryPrimitives.WriteUInt16LittleEndian(payload.Slice(1, 2), startIndex); + } + + public static void BuildGetLedMatrixSize(Span payload) + { + payload.Clear(); + payload[0] = Cmd_GetLedMatrixSize; + } + + // Bulk set: pack RGB triplets starting at byte 4. Caller must + // ensure rgbBytes.Length == count * 3 and count <= MaxLedsPerSetRange. + public static void BuildSetLedRange(Span payload, ushort startIndex, byte count, ReadOnlySpan rgbBytes) + { + if (count > MaxLedsPerSetRange) throw new ArgumentOutOfRangeException(nameof(count)); + if (rgbBytes.Length != count * 3) throw new ArgumentException("rgbBytes length must equal count*3", nameof(rgbBytes)); + payload.Clear(); + payload[0] = Cmd_SetLedRange; + BinaryPrimitives.WriteUInt16LittleEndian(payload.Slice(1, 2), startIndex); + payload[3] = count; + rgbBytes.CopyTo(payload.Slice(4, count * 3)); + } + + public static void BuildSetSingleLed(Span payload, ushort index, byte r, byte g, byte b) + { + payload.Clear(); + payload[0] = Cmd_SetSingleLed; + BinaryPrimitives.WriteUInt16LittleEndian(payload.Slice(1, 2), index); + payload[3] = r; + payload[4] = g; + payload[5] = b; + } + + // Switch the firmware to direct host-driven mode (mode 0 in the + // OpenRGB-QMK convention) or back to a built-in effect index. + // Direct mode suspends the firmware's own RGB matrix animations + // so our Set commands aren't fighting them every tick. + public static void BuildSetMode(Span payload, byte modeIndex) + { + payload.Clear(); + payload[0] = Cmd_SetMode; + payload[1] = modeIndex; + } + + // ── Reply parsers ───────────────────────────────────────────── + + public static ushort TryParseProtocolVersion(ReadOnlySpan reply) + { + if (reply.Length < 3) return 0; + if (reply[0] != Cmd_GetProtocolVersion) return 0; + return BinaryPrimitives.ReadUInt16LittleEndian(reply.Slice(1, 2)); + } + + // GetDeviceInfo reply layout: + // byte 0 = Cmd_GetDeviceInfo (echo) + // bytes 1-2 = total LED count (uint16 LE) + // bytes 3-4 = vendor id (uint16 LE) + // bytes 5-6 = product id (uint16 LE) + // byte 7 = device type (informational) + // bytes 8+ = null-terminated device name + public static bool TryParseDeviceInfo(ReadOnlySpan reply, out ushort ledCount, out ushort vendorId, out ushort productId, out string deviceName) + { + ledCount = 0; vendorId = 0; productId = 0; deviceName = string.Empty; + if (reply.Length < 8) return false; + if (reply[0] != Cmd_GetDeviceInfo) return false; + ledCount = BinaryPrimitives.ReadUInt16LittleEndian(reply.Slice(1, 2)); + vendorId = BinaryPrimitives.ReadUInt16LittleEndian(reply.Slice(3, 2)); + productId = BinaryPrimitives.ReadUInt16LittleEndian(reply.Slice(5, 2)); + + int nameEnd = 8; + while (nameEnd < reply.Length && reply[nameEnd] != 0) nameEnd++; + if (nameEnd > 8) + deviceName = System.Text.Encoding.UTF8.GetString(reply.Slice(8, nameEnd - 8)); + return true; + } + + // GetLedInfo reply layout (variable LED records, 3 bytes each): + // byte 0 = Cmd_GetLedInfo (echo) + // byte 1 = record count for this packet + // then records: column (u8) | row (u8) | flags (u8) + // Caller iterates start_index for additional batches. + public static bool TryParseLedInfoBatch(ReadOnlySpan reply, out int recordCount, out ReadOnlySpan records) + { + recordCount = 0; records = default; + if (reply.Length < 2) return false; + if (reply[0] != Cmd_GetLedInfo) return false; + recordCount = reply[1]; + int recordBytes = recordCount * 3; + if (reply.Length < 2 + recordBytes) return false; + records = reply.Slice(2, recordBytes); + return true; + } + + public static bool TryParseLedMatrixSize(ReadOnlySpan reply, out byte columns, out byte rows) + { + columns = 0; rows = 0; + if (reply.Length < 3) return false; + if (reply[0] != Cmd_GetLedMatrixSize) return false; + columns = reply[1]; + rows = reply[2]; + return true; + } + + public readonly struct LedRecord + { + public readonly byte Column; + public readonly byte Row; + public readonly byte Flags; + public LedRecord(byte column, byte row, byte flags) { Column = column; Row = row; Flags = flags; } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/QmkRawHidConstants.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/QmkRawHidConstants.cs new file mode 100644 index 00000000..a5f7fb66 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/QmkRawHidConstants.cs @@ -0,0 +1,30 @@ +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol +{ + // QMK Raw HID transport constants. Reference: + // https://docs.qmk.fm/#/feature_rawhid (firmware side) and + // OpenRGB's QMKOpenRGBController + VIA's protocol/constants + // for the host side. + internal static class QmkRawHidConstants + { + // Vendor-defined HID usage page + usage that every QMK keyboard + // exposes on its Raw HID interface. Discovery filters HidSharp's + // enumeration on these two values rather than VID/PID so we work + // across NovelKeys, KBDFans, Drop, GMMK, Glorious, etc. without + // a hardcoded allow-list. + public const ushort RawHidUsagePage = 0xFF60; + public const ushort RawHidUsage = 0x61; + + // QMK Raw HID transfers are 32-byte payloads. Windows HidSharp + // expects an extra leading report-id byte, so the output buffer + // is 33 bytes total (report id 0 + 32 data bytes). Reply reports + // are the same shape minus the leading id on the HidSharp read + // side (HidStream strips the id from inputs). + public const int ReportPayloadBytes = 32; + public const int OutputReportBytes = ReportPayloadBytes + 1; + + // Default request/response wait. Most QMK Raw HID round-trips + // complete in ~5-20ms over USB Full Speed; 250ms is generous + // and matches OpenRGB's default for the same protocol. + public const int ResponseTimeoutMs = 250; + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/QmkRawHidDiscovery.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/QmkRawHidDiscovery.cs new file mode 100644 index 00000000..c0b3d1f2 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/QmkRawHidDiscovery.cs @@ -0,0 +1,240 @@ +using Chromatics.Core; +using Chromatics.Enums; +using HidSharp; +using HidSharp.Reports; +using System; +using System.Collections.Generic; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol +{ + // Enumerates the host's HID devices, picks out the ones exposing the + // QMK Raw HID interface (usage page 0xFF60, usage 0x61), and + // classifies each by which protocol(s) the firmware actually + // implements via the handshake probe. + internal static class QmkRawHidDiscovery + { + public enum ProtocolSupport + { + None, // Discovered but neither VIA nor OpenRGB-QMK responded — skip. + ViaOnly, // Tier 1: drive base hue/sat/val via VIA's RGB matrix sub-commands. + OpenRgbQmk, // Tier 2: per-key control via OpenRGB-QMK direct mode. + } + + public readonly struct Candidate + { + public readonly HidDevice Hid; + public readonly ProtocolSupport Protocol; + public readonly int LedCount; // Populated when Protocol == OpenRgbQmk. + public readonly byte MatrixColumns; // Optional hint from OpenRGB-QMK GetLedMatrixSize. + public readonly byte MatrixRows; + public readonly string FirmwareDeviceName; + + public Candidate(HidDevice hid, ProtocolSupport protocol, int ledCount, byte columns, byte rows, string firmwareDeviceName) + { + Hid = hid; Protocol = protocol; LedCount = ledCount; + MatrixColumns = columns; MatrixRows = rows; + FirmwareDeviceName = firmwareDeviceName ?? string.Empty; + } + } + + // Walks HidSharp's enumeration, filters to interfaces whose + // report descriptor advertises the QMK Raw HID usage, and runs + // the handshake on each. Output is ordered by VID:PID for + // stable adoption-dialog presentation across launches. + public static IReadOnlyList Discover() + { + var results = new List(); + HidDevice[] all; + try { all = DeviceList.Local.GetHidDevices() as HidDevice[] ?? new List(DeviceList.Local.GetHidDevices()).ToArray(); } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] HID enumeration failed: {ex.Message}", + forwardToSentry: false); + return results; + } + + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] Enumerated {all.Length} HID device(s) on the USB bus; scanning for the Raw HID interface (usage page 0x{QmkRawHidConstants.RawHidUsagePage:X4}, usage 0x{QmkRawHidConstants.RawHidUsage:X2})..."); + + int rawHidCandidates = 0; + int openFailures = 0; + int handshakeMisses = 0; + + foreach (HidDevice hid in all) + { + if (!ExposesRawHidUsage(hid)) continue; + rawHidCandidates++; + + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] Candidate: VID=0x{hid.VendorID:X4} PID=0x{hid.ProductID:X4} ({SafeProductName(hid)} / {SafeManufacturer(hid)})"); + + if (!TryHandshake(hid, out var protocol, out int ledCount, out byte cols, out byte rows, out string fwName, out string failureReason)) + { + openFailures++; + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] handshake skipped — {failureReason}", + forwardToSentry: false); + continue; + } + + if (protocol == ProtocolSupport.None) + { + handshakeMisses++; + Logger.WriteConsole(LoggerTypes.Devices, + "[QMK] neither VIA nor OpenRGB-QMK responded; firmware probably doesn't have Raw HID enabled."); + continue; + } + + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] handshake OK — protocol: {protocol}, LEDs: {ledCount}, matrix: {cols}x{rows}"); + results.Add(new Candidate(hid, protocol, ledCount, cols, rows, fwName)); + } + + results.Sort((a, b) => + { + int v = a.Hid.VendorID.CompareTo(b.Hid.VendorID); + if (v != 0) return v; + return a.Hid.ProductID.CompareTo(b.Hid.ProductID); + }); + + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] Discovery done: {all.Length} HID devices total, {rawHidCandidates} with Raw HID interface, " + + $"{openFailures} could not be opened, {handshakeMisses} did not respond to handshake, {results.Count} usable."); + + return results; + } + + private static string SafeManufacturer(HidDevice hid) + { try { return hid.GetManufacturer() ?? ""; } catch { return "?"; } } + private static string SafeProductName(HidDevice hid) + { try { return hid.GetProductName() ?? ""; } catch { return "?"; } } + + // Returns true if any of the HidDevice's top-level collections + // declares usage page 0xFF60, usage 0x61. Multi-interface USB + // devices expose each interface as a separate HidDevice, so + // this check naturally selects only the Raw HID interface and + // leaves the keyboard/consumer interfaces alone. + private static bool ExposesRawHidUsage(HidDevice hid) + { + ReportDescriptor desc; + try { desc = hid.GetReportDescriptor(); } + catch { return false; } + + foreach (var item in desc.DeviceItems) + { + foreach (uint usage in item.Usages.GetAllValues()) + { + ushort page = (ushort)(usage >> 16); + ushort usageLo = (ushort)(usage & 0xFFFF); + if (page == QmkRawHidConstants.RawHidUsagePage && usageLo == QmkRawHidConstants.RawHidUsage) + return true; + } + } + return false; + } + + // Open the candidate's HID stream and try VIA first, then + // OpenRGB-QMK. OpenRGB wins when both respond — it's the + // strictly more capable protocol. Stream is disposed before + // we return; the provider will reopen it for the device's + // permanent UpdateQueue. + private static bool TryHandshake(HidDevice hid, out ProtocolSupport protocol, out int ledCount, out byte cols, out byte rows, out string firmwareDeviceName, out string failureReason) + { + protocol = ProtocolSupport.None; + ledCount = 0; cols = 0; rows = 0; firmwareDeviceName = string.Empty; + failureReason = string.Empty; + + HidStream stream; + try + { + if (!hid.TryOpen(out stream)) + { + failureReason = "could not open the Raw HID interface (likely held exclusively by another app — close VIA / Vial / OpenRGB and try again)"; + return false; + } + } + catch (Exception ex) + { + failureReason = $"open threw: {ex.Message}"; + return false; + } + + try + { + stream.ReadTimeout = QmkRawHidConstants.ResponseTimeoutMs; + stream.WriteTimeout = QmkRawHidConstants.ResponseTimeoutMs; + + Span outBuf = stackalloc byte[QmkRawHidConstants.OutputReportBytes]; + Span payload = outBuf.Slice(1, QmkRawHidConstants.ReportPayloadBytes); + byte[] inBuf = new byte[QmkRawHidConstants.ReportPayloadBytes + 1]; + + bool viaOk = false; + ViaProtocol.BuildGetProtocolVersion(payload); + if (SendAndReceive(stream, outBuf, inBuf)) + { + if (ViaProtocol.TryParseProtocolVersion(StripReportId(inBuf)) > 0) + viaOk = true; + } + + bool openRgbOk = false; + OpenRgbQmkProtocol.BuildGetProtocolVersion(payload); + if (SendAndReceive(stream, outBuf, inBuf)) + { + if (OpenRgbQmkProtocol.TryParseProtocolVersion(StripReportId(inBuf)) > 0) + openRgbOk = true; + } + + if (openRgbOk) + { + OpenRgbQmkProtocol.BuildGetDeviceInfo(payload); + if (SendAndReceive(stream, outBuf, inBuf) && + OpenRgbQmkProtocol.TryParseDeviceInfo(StripReportId(inBuf), + out ushort count, out _, out _, out string name)) + { + ledCount = count; + firmwareDeviceName = name; + } + + OpenRgbQmkProtocol.BuildGetLedMatrixSize(payload); + if (SendAndReceive(stream, outBuf, inBuf)) + { + OpenRgbQmkProtocol.TryParseLedMatrixSize(StripReportId(inBuf), out cols, out rows); + } + + protocol = ProtocolSupport.OpenRgbQmk; + return true; + } + + if (viaOk) + { + protocol = ProtocolSupport.ViaOnly; + return true; + } + + return true; + } + finally + { + try { stream.Dispose(); } catch { /* ignore */ } + } + } + + private static bool SendAndReceive(HidStream stream, ReadOnlySpan outBuf, byte[] inBuf) + { + try + { + stream.Write(outBuf.ToArray()); + int n = stream.Read(inBuf, 0, inBuf.Length); + return n > 0; + } + catch { return false; } + } + + // Strips the leading report-id byte HidSharp prepends to inputs + // on Windows; QMK Raw HID always uses report id 0 so the strip + // is unconditional. + private static ReadOnlySpan StripReportId(byte[] inBuf) => + new ReadOnlySpan(inBuf, 1, inBuf.Length - 1); + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/ViaProtocol.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/ViaProtocol.cs new file mode 100644 index 00000000..bab254f5 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/ViaProtocol.cs @@ -0,0 +1,100 @@ +using System; +using System.Buffers.Binary; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol +{ + // VIA protocol command IDs and frame builders. Reference: + // https://www.caniusevia.com/docs/specification — the live spec + // for VIA's keyboard configuration protocol. VIA-compatible firmware + // is the lowest-common-denominator: most stock QMK boards ship with + // it enabled, and it exposes RGB matrix mode + base hue/sat/val + // controls even when the firmware doesn't have OpenRGB's per-key + // plugin built in. + internal static class ViaProtocol + { + // Top-level command IDs (byte 0 of the request payload). + public const byte Id_GetProtocolVersion = 0x01; + public const byte Id_GetKeyboardValue = 0x02; + public const byte Id_SetKeyboardValue = 0x03; + public const byte Id_LightingSetValue = 0x07; + public const byte Id_LightingGetValue = 0x08; + public const byte Id_LightingSave = 0x09; + + // Lighting sub-commands (byte 1 of request when command = 0x07/0x08). + // The "QMK RGB Matrix" naming reflects firmware-side terminology; + // VIA-compatible firmware exposes these on RGB matrix builds. + public const byte SubId_QmkRgbMatrixBrightness = 0x81; + public const byte SubId_QmkRgbMatrixEffect = 0x82; + public const byte SubId_QmkRgbMatrixEffectSpeed = 0x83; + public const byte SubId_QmkRgbMatrixColor = 0x84; + + // RGB Matrix effect indices. Only SolidColor is hard-required for + // Tier 1; the rest are useful as escape hatches for game-driven + // mode switches (e.g. Vegas → CycleAll, idle → SolidReactiveCross). + public const byte Effect_SolidColor = 1; + public const byte Effect_AlphaMods = 2; + public const byte Effect_GradientUpDown = 3; + public const byte Effect_Breathing = 6; + public const byte Effect_CycleAll = 9; + public const byte Effect_RainbowMovingChevron = 11; + public const byte Effect_DualBeacon = 16; + public const byte Effect_RainbowBeacon = 17; + public const byte Effect_RainbowPinwheels = 18; + public const byte Effect_SolidSplash = 30; + + // ── Frame builders ──────────────────────────────────────────── + // All builders write into a caller-supplied 32-byte payload span + // (no allocation). Caller is responsible for the leading report-id + // byte the HidSharp output buffer needs. + + public static void BuildGetProtocolVersion(Span payload) + { + payload.Clear(); + payload[0] = Id_GetProtocolVersion; + } + + public static void BuildSetRgbMatrixEffect(Span payload, byte effectIndex) + { + payload.Clear(); + payload[0] = Id_LightingSetValue; + payload[1] = SubId_QmkRgbMatrixEffect; + payload[2] = effectIndex; + } + + public static void BuildSetRgbMatrixBrightness(Span payload, byte brightness0to255) + { + payload.Clear(); + payload[0] = Id_LightingSetValue; + payload[1] = SubId_QmkRgbMatrixBrightness; + payload[2] = brightness0to255; + } + + // Hue + saturation in a single packet — VIA's + // QMK_RGB_MATRIX_COLOR sub-command takes 2 bytes after the + // sub-id. Both values are 0-255. + public static void BuildSetRgbMatrixColor(Span payload, byte hue0to255, byte sat0to255) + { + payload.Clear(); + payload[0] = Id_LightingSetValue; + payload[1] = SubId_QmkRgbMatrixColor; + payload[2] = hue0to255; + payload[3] = sat0to255; + } + + public static void BuildLightingSave(Span payload) + { + payload.Clear(); + payload[0] = Id_LightingSave; + } + + // Reply parser for GetProtocolVersion. Returns 0 if the reply + // doesn't echo the command id (firmware doesn't speak VIA, or + // request collided with another consumer on the same HID interface). + public static ushort TryParseProtocolVersion(ReadOnlySpan reply) + { + if (reply.Length < 3) return 0; + if (reply[0] != Id_GetProtocolVersion) return 0; + return BinaryPrimitives.ReadUInt16BigEndian(reply.Slice(1, 2)); + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkKeycodeMap.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkKeycodeMap.cs new file mode 100644 index 00000000..f47eaf4c --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkKeycodeMap.cs @@ -0,0 +1,224 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using RGB.NET.Core; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + // QMK label / keycode string → RGB.NET LedId. QMK boards label their keys + // inconsistently across the keyboards/ tree — some entries use the QMK + // keycode short form ("ESC", "BSPC"), some the full prefix ("KC_ESC"), + // and many use human-readable legends ("Esc", "Backspace", "Page Up"). + // This map covers all three styles for the canonical ANSI 104 plus + // numpad and ISO-only keys; lookup is case-insensitive and the "KC_" + // prefix is stripped if present so all conventions resolve. + // + // Unknown labels return LedId.Invalid so the layout merger falls back + // to LedId.Custom1+i for that LED. + internal static class QmkKeycodeMap + { + public static LedId ToLedId(string label) + { + if (string.IsNullOrEmpty(label)) return LedId.Invalid; + string key = label.Trim(); + if (key.StartsWith("KC_")) key = key.Substring(3); + return _map.TryGetValue(key, out var id) ? id : LedId.Invalid; + } + + // Stored as a FrozenDictionary because lookups happen during layout + // construction (once per device + LED count) and the table never + // changes at runtime. Case-insensitive — covers "Esc"/"ESC"/"esc". + private static readonly FrozenDictionary _map = + new Dictionary(System.StringComparer.OrdinalIgnoreCase) + { + // ── Letters ────────────────────────────────────────── + ["A"] = LedId.Keyboard_A, ["B"] = LedId.Keyboard_B, ["C"] = LedId.Keyboard_C, + ["D"] = LedId.Keyboard_D, ["E"] = LedId.Keyboard_E, ["F"] = LedId.Keyboard_F, + ["G"] = LedId.Keyboard_G, ["H"] = LedId.Keyboard_H, ["I"] = LedId.Keyboard_I, + ["J"] = LedId.Keyboard_J, ["K"] = LedId.Keyboard_K, ["L"] = LedId.Keyboard_L, + ["M"] = LedId.Keyboard_M, ["N"] = LedId.Keyboard_N, ["O"] = LedId.Keyboard_O, + ["P"] = LedId.Keyboard_P, ["Q"] = LedId.Keyboard_Q, ["R"] = LedId.Keyboard_R, + ["S"] = LedId.Keyboard_S, ["T"] = LedId.Keyboard_T, ["U"] = LedId.Keyboard_U, + ["V"] = LedId.Keyboard_V, ["W"] = LedId.Keyboard_W, ["X"] = LedId.Keyboard_X, + ["Y"] = LedId.Keyboard_Y, ["Z"] = LedId.Keyboard_Z, + + // ── Top-row digits ─────────────────────────────────── + ["1"] = LedId.Keyboard_1, ["2"] = LedId.Keyboard_2, ["3"] = LedId.Keyboard_3, + ["4"] = LedId.Keyboard_4, ["5"] = LedId.Keyboard_5, ["6"] = LedId.Keyboard_6, + ["7"] = LedId.Keyboard_7, ["8"] = LedId.Keyboard_8, ["9"] = LedId.Keyboard_9, + ["0"] = LedId.Keyboard_0, + + // ── Function row ───────────────────────────────────── + ["F1"] = LedId.Keyboard_F1, ["F2"] = LedId.Keyboard_F2, ["F3"] = LedId.Keyboard_F3, + ["F4"] = LedId.Keyboard_F4, ["F5"] = LedId.Keyboard_F5, ["F6"] = LedId.Keyboard_F6, + ["F7"] = LedId.Keyboard_F7, ["F8"] = LedId.Keyboard_F8, ["F9"] = LedId.Keyboard_F9, + ["F10"] = LedId.Keyboard_F10, ["F11"] = LedId.Keyboard_F11, ["F12"] = LedId.Keyboard_F12, + // F13+ exists on the QMK side (full-size + macropad layouts) but + // RGB.NET's LedId enum tops out at F12; entries above that drop + // to LedId.Custom_* via the merge step's fallback. + + // ── Punctuation: QMK keycode forms ─────────────────── + ["MINS"] = LedId.Keyboard_MinusAndUnderscore, + ["EQL"] = LedId.Keyboard_EqualsAndPlus, + ["LBRC"] = LedId.Keyboard_BracketLeft, + ["RBRC"] = LedId.Keyboard_BracketRight, + ["BSLS"] = LedId.Keyboard_Backslash, + ["SCLN"] = LedId.Keyboard_SemicolonAndColon, + ["QUOT"] = LedId.Keyboard_ApostropheAndDoubleQuote, + ["COMM"] = LedId.Keyboard_CommaAndLessThan, + ["DOT"] = LedId.Keyboard_PeriodAndBiggerThan, + ["SLSH"] = LedId.Keyboard_SlashAndQuestionMark, + ["GRV"] = LedId.Keyboard_GraveAccentAndTilde, + + // ── Punctuation: human-legend forms ────────────────── + ["-"] = LedId.Keyboard_MinusAndUnderscore, + ["="] = LedId.Keyboard_EqualsAndPlus, + ["["] = LedId.Keyboard_BracketLeft, + ["]"] = LedId.Keyboard_BracketRight, + ["\\"] = LedId.Keyboard_Backslash, + [";"] = LedId.Keyboard_SemicolonAndColon, + ["'"] = LedId.Keyboard_ApostropheAndDoubleQuote, + [","] = LedId.Keyboard_CommaAndLessThan, + ["."] = LedId.Keyboard_PeriodAndBiggerThan, + ["/"] = LedId.Keyboard_SlashAndQuestionMark, + ["`"] = LedId.Keyboard_GraveAccentAndTilde, + + // ── Modifiers + edit: short + long forms ───────────── + ["ESC"] = LedId.Keyboard_Escape, + ["Escape"] = LedId.Keyboard_Escape, + ["TAB"] = LedId.Keyboard_Tab, + ["Tab"] = LedId.Keyboard_Tab, + ["CAPS"] = LedId.Keyboard_CapsLock, + ["Caps"] = LedId.Keyboard_CapsLock, + ["Caps Lock"] = LedId.Keyboard_CapsLock, + ["CapsLock"] = LedId.Keyboard_CapsLock, + ["LSFT"] = LedId.Keyboard_LeftShift, + ["LShift"] = LedId.Keyboard_LeftShift, + ["Left Shift"] = LedId.Keyboard_LeftShift, + ["Shift"] = LedId.Keyboard_LeftShift, // ambiguous label; first occurrence wins, second falls back to Custom_* + ["RSFT"] = LedId.Keyboard_RightShift, + ["RShift"] = LedId.Keyboard_RightShift, + ["Right Shift"] = LedId.Keyboard_RightShift, + ["LCTL"] = LedId.Keyboard_LeftCtrl, + ["LCtrl"] = LedId.Keyboard_LeftCtrl, + ["Left Ctrl"] = LedId.Keyboard_LeftCtrl, + ["Ctrl"] = LedId.Keyboard_LeftCtrl, + ["Control"] = LedId.Keyboard_LeftCtrl, + ["RCTL"] = LedId.Keyboard_RightCtrl, + ["RCtrl"] = LedId.Keyboard_RightCtrl, + ["Right Ctrl"] = LedId.Keyboard_RightCtrl, + ["LALT"] = LedId.Keyboard_LeftAlt, + ["LAlt"] = LedId.Keyboard_LeftAlt, + ["Left Alt"] = LedId.Keyboard_LeftAlt, + ["Alt"] = LedId.Keyboard_LeftAlt, + ["RALT"] = LedId.Keyboard_RightAlt, + ["RAlt"] = LedId.Keyboard_RightAlt, + ["Right Alt"] = LedId.Keyboard_RightAlt, + ["AltGr"] = LedId.Keyboard_RightAlt, + ["LGUI"] = LedId.Keyboard_LeftGui, + ["LGui"] = LedId.Keyboard_LeftGui, + ["Left GUI"] = LedId.Keyboard_LeftGui, + ["Left Win"] = LedId.Keyboard_LeftGui, + ["Win"] = LedId.Keyboard_LeftGui, + ["Windows"] = LedId.Keyboard_LeftGui, + ["Cmd"] = LedId.Keyboard_LeftGui, + ["RGUI"] = LedId.Keyboard_RightGui, + ["RGui"] = LedId.Keyboard_RightGui, + ["Right GUI"] = LedId.Keyboard_RightGui, + ["Right Win"] = LedId.Keyboard_RightGui, + ["ENT"] = LedId.Keyboard_Enter, + ["ENTER"] = LedId.Keyboard_Enter, + ["Enter"] = LedId.Keyboard_Enter, + ["Return"] = LedId.Keyboard_Enter, + ["BSPC"] = LedId.Keyboard_Backspace, + ["Backspace"] = LedId.Keyboard_Backspace, + ["BkSp"] = LedId.Keyboard_Backspace, + ["SPC"] = LedId.Keyboard_Space, + ["Space"] = LedId.Keyboard_Space, + ["APP"] = LedId.Keyboard_Application, + ["Menu"] = LedId.Keyboard_Application, + ["App"] = LedId.Keyboard_Application, + + // ── Navigation cluster ─────────────────────────────── + ["INS"] = LedId.Keyboard_Insert, + ["Ins"] = LedId.Keyboard_Insert, + ["Insert"] = LedId.Keyboard_Insert, + ["DEL"] = LedId.Keyboard_Delete, + ["Del"] = LedId.Keyboard_Delete, + ["Delete"] = LedId.Keyboard_Delete, + ["HOME"] = LedId.Keyboard_Home, + ["Home"] = LedId.Keyboard_Home, + ["END"] = LedId.Keyboard_End, + ["End"] = LedId.Keyboard_End, + ["PGUP"] = LedId.Keyboard_PageUp, + ["PgUp"] = LedId.Keyboard_PageUp, + ["Page Up"] = LedId.Keyboard_PageUp, + ["PageUp"] = LedId.Keyboard_PageUp, + ["PGDN"] = LedId.Keyboard_PageDown, + ["PgDn"] = LedId.Keyboard_PageDown, + ["Page Down"] = LedId.Keyboard_PageDown, + ["PageDown"] = LedId.Keyboard_PageDown, + ["UP"] = LedId.Keyboard_ArrowUp, + ["Up"] = LedId.Keyboard_ArrowUp, + ["↑"] = LedId.Keyboard_ArrowUp, + ["DOWN"] = LedId.Keyboard_ArrowDown, + ["Down"] = LedId.Keyboard_ArrowDown, + ["↓"] = LedId.Keyboard_ArrowDown, + ["LEFT"] = LedId.Keyboard_ArrowLeft, + ["Left"] = LedId.Keyboard_ArrowLeft, + ["←"] = LedId.Keyboard_ArrowLeft, + ["RGHT"] = LedId.Keyboard_ArrowRight, + ["Right"] = LedId.Keyboard_ArrowRight, + ["→"] = LedId.Keyboard_ArrowRight, + + // ── System / locks ─────────────────────────────────── + ["PSCR"] = LedId.Keyboard_PrintScreen, + ["PrtSc"] = LedId.Keyboard_PrintScreen, + ["PrintScreen"] = LedId.Keyboard_PrintScreen, + ["Print Screen"] = LedId.Keyboard_PrintScreen, + ["SCRL"] = LedId.Keyboard_ScrollLock, + ["ScrLk"] = LedId.Keyboard_ScrollLock, + ["Scroll Lock"] = LedId.Keyboard_ScrollLock, + ["ScrollLock"] = LedId.Keyboard_ScrollLock, + ["PAUS"] = LedId.Keyboard_PauseBreak, + ["Pause"] = LedId.Keyboard_PauseBreak, + ["Break"] = LedId.Keyboard_PauseBreak, + ["Pause/Break"] = LedId.Keyboard_PauseBreak, + ["NLCK"] = LedId.Keyboard_NumLock, + ["NumLk"] = LedId.Keyboard_NumLock, + ["Num Lock"] = LedId.Keyboard_NumLock, + ["NumLock"] = LedId.Keyboard_NumLock, + + // ── Numpad: QMK keycode forms (P0..P9, PDOT etc.) ──── + ["P0"] = LedId.Keyboard_Num0, ["P1"] = LedId.Keyboard_Num1, + ["P2"] = LedId.Keyboard_Num2, ["P3"] = LedId.Keyboard_Num3, + ["P4"] = LedId.Keyboard_Num4, ["P5"] = LedId.Keyboard_Num5, + ["P6"] = LedId.Keyboard_Num6, ["P7"] = LedId.Keyboard_Num7, + ["P8"] = LedId.Keyboard_Num8, ["P9"] = LedId.Keyboard_Num9, + ["PDOT"] = LedId.Keyboard_NumPeriodAndDelete, + ["PSLS"] = LedId.Keyboard_NumSlash, + ["PAST"] = LedId.Keyboard_NumAsterisk, + ["PMNS"] = LedId.Keyboard_NumMinus, + ["PPLS"] = LedId.Keyboard_NumPlus, + ["PENT"] = LedId.Keyboard_NumEnter, + + // ── Numpad: human-legend forms (KP_0..KP_9, KP_Plus, etc.) ── + ["KP_0"] = LedId.Keyboard_Num0, ["KP_1"] = LedId.Keyboard_Num1, + ["KP_2"] = LedId.Keyboard_Num2, ["KP_3"] = LedId.Keyboard_Num3, + ["KP_4"] = LedId.Keyboard_Num4, ["KP_5"] = LedId.Keyboard_Num5, + ["KP_6"] = LedId.Keyboard_Num6, ["KP_7"] = LedId.Keyboard_Num7, + ["KP_8"] = LedId.Keyboard_Num8, ["KP_9"] = LedId.Keyboard_Num9, + ["KP_."] = LedId.Keyboard_NumPeriodAndDelete, + ["KP_/"] = LedId.Keyboard_NumSlash, + ["KP_*"] = LedId.Keyboard_NumAsterisk, + ["KP_-"] = LedId.Keyboard_NumMinus, + ["KP_+"] = LedId.Keyboard_NumPlus, + ["KP_Enter"] = LedId.Keyboard_NumEnter, + + // ── ISO-only keys: map to closest ANSI siblings ────── + // NUHS = ISO non-US hash (between Enter and ' on ISO layouts). + ["NUHS"] = LedId.Keyboard_Backslash, + // NUBS = ISO non-US backslash (next to Left Shift on ISO). + ["NUBS"] = LedId.Keyboard_NonUsBackslash, + }.ToFrozenDictionary(System.StringComparer.OrdinalIgnoreCase); + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkKeymapFetcher.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkKeymapFetcher.cs new file mode 100644 index 00000000..66c9957c --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkKeymapFetcher.cs @@ -0,0 +1,206 @@ +using Chromatics.Core; +using Chromatics.Enums; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + // Lookup of QMK per-board keymap data — matrix-position-to-keycap-label + // mapping for ~500 QMK boards (the subset whose keyboard.json includes + // "label" fields). Sourced from snakkarike/qmk_firmware and pre-processed + // into Chromatics/Resources/qmk_keymap_data.json by + // build_qmk_keymap_index.py at the workspace root. + // + // The file ships as an embedded resource inside the Chromatics assembly, + // so this lookup is purely in-memory: no network fetch, no disk cache, + // no failure mode for offline users. Bundled size is ~450 KB compact + // JSON for 2650 boards (boards without labels get an empty entry so the + // runtime still knows the board is recognised; the layout merge then + // falls back to LedId.Custom_* for every LED on that board). + // + // The bundled data refreshes when build_qmk_keymap_index.py is re-run + // and the resulting JSON is committed. Re-run periodically to pick up + // newly-upstreamed boards. + internal static class QmkKeymapFetcher + { + private const string ResourceName = "Chromatics.Resources.qmk_keymap_data.json"; + + // Loaded once, never mutated. Key = "VID:PID" hex uppercase + // (e.g. "8968:4E4C"); value = the parsed Labels dict. + private static Dictionary _byVidPid; + private static readonly object _initLock = new(); + + public sealed class QmkKeymap + { + // Keycap label at each keyswitch matrix coordinate. Boards + // present in the bundle but with no labels in their source JSON + // get an empty dictionary — discovery still recognises them but + // the layout merge step falls back to LedId.Custom_* for every + // LED. + public IReadOnlyDictionary<(byte col, byte row), string> Labels { get; set; } + } + + // Returns the cached entry for (vendorId, productId), or null if the + // board isn't in the bundle. Synchronous — the data is already in + // memory once the embedded resource has been parsed. Kept async-shaped + // so callers don't have to be rewritten when the implementation + // changed (and so a future fallback to remote fetch can re-add the + // await without another API churn). + public static Task TryGetKeymapAsync(int vendorId, int productId) + { + try + { + if (!TryEnsureLoaded()) return Task.FromResult(null); + string key = $"{vendorId:X4}:{productId:X4}"; + return Task.FromResult(_byVidPid.TryGetValue(key, out var km) ? km : null); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] keymap lookup failed for {vendorId:X4}:{productId:X4} ({ex.Message}); falling back to Custom1..N.", + forwardToSentry: false); + return Task.FromResult(null); + } + } + + // ── Bundle load ────────────────────────────────────────────── + + private static bool TryEnsureLoaded() + { + if (_byVidPid != null) return true; + lock (_initLock) + { + if (_byVidPid != null) return true; + _byVidPid = LoadBundle(); + return _byVidPid != null; + } + } + + private static Dictionary LoadBundle() + { + try + { + var asm = typeof(QmkKeymapFetcher).Assembly; + using var stream = asm.GetManifestResourceStream(ResourceName); + if (stream == null) + { + Logger.WriteConsole(LoggerTypes.Devices, + $"[QMK] embedded keymap bundle '{ResourceName}' missing; per-key semantic mapping will use Custom1..N for every board.", + forwardToSentry: false); + return new Dictionary(); + } + using var doc = JsonDocument.Parse(stream); + return ParseBundle(doc.RootElement); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, + $"[QMK] failed to load embedded keymap bundle: {ex.Message}", + forwardToSentry: false); + return new Dictionary(); + } + } + + // Bundle schema (see build_qmk_keymap_index.py): + // { + // "_source": ..., "_generated_utc": ..., "_count": N, + // "boards": { + // "VID:PID": [[col, row, "label"], ...], + // ... + // } + // } + private static Dictionary ParseBundle(JsonElement root) + { + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + if (!root.TryGetProperty("boards", out var boards) || boards.ValueKind != JsonValueKind.Object) + return result; + + foreach (var board in boards.EnumerateObject()) + { + var labels = new Dictionary<(byte col, byte row), string>(); + if (board.Value.ValueKind == JsonValueKind.Array) + { + foreach (var rec in board.Value.EnumerateArray()) + { + if (rec.ValueKind != JsonValueKind.Array || rec.GetArrayLength() < 3) continue; + int col = rec[0].GetInt32(); + int row = rec[1].GetInt32(); + if (rec[2].ValueKind != JsonValueKind.String) continue; + string label = rec[2].GetString(); + if (col < 0 || col > byte.MaxValue || row < 0 || row > byte.MaxValue) continue; + if (string.IsNullOrWhiteSpace(label)) continue; + // First-write-wins on collision within a board (shouldn't + // happen — the build script already de-dupes). + var key = ((byte)col, (byte)row); + if (!labels.ContainsKey(key)) + labels[key] = label; + } + } + result[board.Name] = new QmkKeymap { Labels = labels }; + } + return result; + } + + // ── Layout merge: firmware LED records + bundled labels → LedId list ── + + // Combines the firmware's GetLedInfo records (per-LED matrix col/row) + // with the bundle's labels (per matrix coord → "Esc" / "F1" / etc.) + // to assign a semantic LedId.Keyboard_* to each LED. LEDs whose + // (col, row) doesn't appear in the bundle (underglow, board variants, + // or boards whose source JSON omits labels entirely) fall back to + // LedId.Custom1+firmwareIndex. + // + // Physical placement is derived from matrix coords × a fixed cell + // size — good enough for the Mapping tab preview; users adjust via + // drag-position UX from there. + public static IReadOnlyList BuildLayout( + QmkKeymap keymap, + IReadOnlyList<(int firmwareIndex, byte col, byte row)> ledRecords) + { + const float cellW = 60f; + const float cellH = 60f; + var entries = new List(ledRecords.Count); + + for (int i = 0; i < ledRecords.Count; i++) + { + var rec = ledRecords[i]; + LedId ledId = LedId.Invalid; + + if (keymap?.Labels != null + && keymap.Labels.TryGetValue((rec.col, rec.row), out string label)) + { + ledId = QmkKeycodeMap.ToLedId(label); + } + + if (ledId == LedId.Invalid) + ledId = (LedId)((int)LedId.Custom1 + i); + + var location = new Point(rec.col * cellW, rec.row * cellH); + var size = new Size(cellW, cellH); + entries.Add(new QmkLedLayoutEntry(rec.firmwareIndex, rec.col, rec.row, ledId, location, size)); + } + + // De-dupe LedIds: two LEDs claiming the same semantic id (left vs + // right Shift both labelled "Shift") keep the first and demote + // the rest to Custom_* so RGB.NET's uniqueness invariant holds. + var seen = new HashSet(); + for (int i = 0; i < entries.Count; i++) + { + if (entries[i].PreferredLedId == LedId.Invalid) continue; + if ((int)entries[i].PreferredLedId >= (int)LedId.Custom1) { seen.Add(entries[i].PreferredLedId); continue; } + if (seen.Add(entries[i].PreferredLedId)) continue; + entries[i] = new QmkLedLayoutEntry( + entries[i].FirmwareIndex, entries[i].MatrixCol, entries[i].MatrixRow, + (LedId)((int)LedId.Custom1 + i), + entries[i].Location, entries[i].Size); + } + + return entries; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidAdoptedDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidAdoptedDevice.cs new file mode 100644 index 00000000..def436c5 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidAdoptedDevice.cs @@ -0,0 +1,27 @@ +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + // Persisted (settings.json) record of a user-adopted QMK keyboard. + // + // Identity is the triple (VendorId, ProductId, Manufacturer + Product), + // not the OS HID DevicePath — DevicePath changes when the user moves the + // keyboard between USB ports, but VID/PID + the firmware-reported product + // string are stable across plugs. We re-resolve a concrete HidDevice on + // each provider start via QmkRawHidDiscovery, then match candidates to + // adopted entries on this triple. + // + // Layout (the VIA keymap source URL) is captured at adoption time so a + // subsequent run knows which keymap JSON to fetch + cache without + // re-running detection. Empty string means "no semantic layout known — + // present LEDs as Custom1..N and let the user position them via the + // Mapping tab." + public class QmkRawHidAdoptedDevice + { + public int VendorId { get; set; } + public int ProductId { get; set; } + public string Manufacturer { get; set; } + public string Product { get; set; } + public int LedCount { get; set; } + public string Protocol { get; set; } // "ViaOnly" | "OpenRgbQmk" + public string ViaKeymapKey { get; set; } // via-keyboards repo key (e.g. "novelkeys/nk65"), empty if unmapped + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidClientDefinition.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidClientDefinition.cs new file mode 100644 index 00000000..c6fc8357 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidClientDefinition.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using RGBNetCore = global::RGB.NET.Core; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + // Runtime descriptor for an adopted QMK keyboard. Captures the + // identifying metadata from the firmware handshake plus the + // resolved LED layout (per-key semantic LedIds when a VIA keymap + // was fetchable, Custom1..N otherwise) so the device and update + // queue don't have to re-probe on every Load. + public sealed class QmkRawHidClientDefinition + { + public QmkRawHidClientDefinition( + int vendorId, int productId, + string manufacturer, string product, + string firmwareDeviceName, + int ledCount, + QmkRawHidProtocolMode protocol, + byte matrixColumns, byte matrixRows, + string viaKeymapKey, + IReadOnlyList layout) + { + VendorId = vendorId; + ProductId = productId; + Manufacturer = manufacturer ?? string.Empty; + Product = product ?? string.Empty; + FirmwareDeviceName = firmwareDeviceName ?? string.Empty; + LedCount = ledCount; + Protocol = protocol; + MatrixColumns = matrixColumns; + MatrixRows = matrixRows; + ViaKeymapKey = viaKeymapKey ?? string.Empty; + Layout = layout ?? System.Array.Empty(); + } + + public int VendorId { get; } + public int ProductId { get; } + public string Manufacturer { get; } + public string Product { get; } + public string FirmwareDeviceName { get; } + public int LedCount { get; } + public QmkRawHidProtocolMode Protocol { get; } + public byte MatrixColumns { get; } + public byte MatrixRows { get; } + public string ViaKeymapKey { get; } + + // One entry per RGB LED reported by the firmware, ordered by LED + // index. For OpenRgbQmk mode this is populated from + // Cmd_GetLedInfo + the optional VIA keymap merge. For ViaOnly + // mode the list contains a single entry (LedId.Custom1) used + // for the single representative-colour LED. + public IReadOnlyList Layout { get; } + + // Stable identity for matching against persisted SettingsModel + // entries. Manufacturer/Product strings vary in case across firmware + // builds (e.g. "NovelKeys" vs "Novelkeys"); compare case-insensitive. + public string Identity => $"{VendorId:X4}:{ProductId:X4}:{Manufacturer}:{Product}"; + } + + // One physical LED's placement on the host-side keyboard layout. + // MatrixCol/MatrixRow are the firmware's LED-matrix coordinates; + // PreferredLedId is the semantic RGB.NET id when we matched against a + // VIA keymap (e.g. LedId.Keyboard_A), or LedId.Custom1 + index when + // we fell back to Custom1..N. PreferredLedId is consumed by + // QmkRawHidDevice.InitializeLayout. + public readonly struct QmkLedLayoutEntry + { + public readonly int FirmwareIndex; + public readonly byte MatrixCol; + public readonly byte MatrixRow; + public readonly RGBNetCore.LedId PreferredLedId; + public readonly RGBNetCore.Point Location; + public readonly RGBNetCore.Size Size; + + public QmkLedLayoutEntry(int firmwareIndex, byte matrixCol, byte matrixRow, RGBNetCore.LedId preferredLedId, RGBNetCore.Point location, RGBNetCore.Size size) + { + FirmwareIndex = firmwareIndex; + MatrixCol = matrixCol; + MatrixRow = matrixRow; + PreferredLedId = preferredLedId; + Location = location; + Size = size; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidDevice.cs new file mode 100644 index 00000000..75d0a891 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidDevice.cs @@ -0,0 +1,63 @@ +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using RGB.NET.Core; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + public class QmkRawHidDevice : AbstractRGBDevice + { + private readonly QmkRawHidUpdateQueue _updateQueue; + private readonly QmkRawHidClientDefinition _def; + + public QmkRawHidDevice(QmkRawHidDeviceInfo info, QmkRawHidUpdateQueue updateQueue, QmkRawHidClientDefinition def) + : base(info, updateQueue) + { + _updateQueue = updateQueue; + _def = def; + InitializeLayout(); + } + + public QmkRawHidClientDefinition Definition => _def; + + // Per-device lifecycle parity with LifxDevice / HueDevice — the + // queue gate flag is the primary mechanism for stopping paint + // frames on per-device disable in the Mapping tab. + public void SetPerDeviceDisabled(bool disabled) => _updateQueue.SetPerDeviceDisabled(disabled); + public void ResetCache() => _updateQueue.ResetCache(); + public void BeginShutdown() => _updateQueue.BeginShutdown(); + + // Per-device brightness — Hue uses xy chromaticity so it needs a + // separate channel; QMK's RGB matrix is plain RGB so the global + // brightness correction is sufficient. Method kept for parity in + // case future firmware exposes a bridge-style brightness query. + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _updateQueue.SetPerDeviceBrightness(correction); + + // Layout: VIA-only devices show up as a single representative LED + // (LedId.Custom1) since VIA can't drive per-key from the host. + // OpenRGB-QMK devices iterate the Layout entries the provider built + // — these carry either LedId.Keyboard_* semantic IDs (when a VIA + // keymap was fetchable from the via-keyboards repo) or LedId.Custom1+i + // synthetic ids as a fallback. RGB.NET treats both identically; the + // semantic IDs are just what lets Chromatics' Highlight / Keybinds + // layers light the right physical keys out of the box. + private void InitializeLayout() + { + if (_def.Protocol == QmkRawHidProtocolMode.ViaOnly || _def.Layout.Count == 0) + { + var single = AddLed(LedId.Custom1, new Point(0, 0), new Size(60, 60)); + if (single != null) single.Shape = Shape.Rectangle; + return; + } + + // OpenRGB-QMK: one LED per firmware index, ordered by FirmwareIndex + // so the UpdateQueue's bulk-set path can pack rgbBytes in the + // canonical strip order without a re-sort per frame. + for (int i = 0; i < _def.Layout.Count; i++) + { + var entry = _def.Layout[i]; + var led = AddLed(entry.PreferredLedId, entry.Location, entry.Size); + if (led != null) led.Shape = Shape.Rectangle; + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidDeviceInfo.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidDeviceInfo.cs new file mode 100644 index 00000000..a641f149 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidDeviceInfo.cs @@ -0,0 +1,23 @@ +using RGB.NET.Core; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + public class QmkRawHidDeviceInfo : IRGBDeviceInfo + { + public QmkRawHidDeviceInfo(QmkRawHidClientDefinition def) + { + DeviceName = string.IsNullOrEmpty(def.Product) + ? (string.IsNullOrEmpty(def.FirmwareDeviceName) ? "QMK Keyboard" : def.FirmwareDeviceName) + : def.Product; + Manufacturer = string.IsNullOrEmpty(def.Manufacturer) ? "QMK" : def.Manufacturer; + Model = string.IsNullOrEmpty(def.FirmwareDeviceName) ? def.Product : def.FirmwareDeviceName; + DeviceType = RGBDeviceType.Keyboard; + } + + public RGBDeviceType DeviceType { get; } + public string DeviceName { get; } + public string Manufacturer { get; } + public string Model { get; } + public object LayoutMetadata { get; set; } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidProtocolMode.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidProtocolMode.cs new file mode 100644 index 00000000..1636f5ff --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidProtocolMode.cs @@ -0,0 +1,11 @@ +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + // Which protocol the UpdateQueue should target on a given device. Set + // once at handshake (see QmkRawHidDiscovery) and stable for the + // lifetime of the device — we don't downgrade mid-session. + public enum QmkRawHidProtocolMode + { + ViaOnly, + OpenRgbQmk, + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidRGBDeviceProvider.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidRGBDeviceProvider.cs new file mode 100644 index 00000000..e1a674b5 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidRGBDeviceProvider.cs @@ -0,0 +1,457 @@ +using Chromatics.Core; +using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol; +using HidSharp; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + // Custom RGB.NET device provider for QMK Raw HID keyboards — covers + // NovelKeys, KBDFans, Drop, GMMK, Glorious and anything else running + // QMK firmware with Raw HID enabled. Talks to two protocols on the + // same HID interface: + // - VIA (universal, exposes only RGB matrix mode + base hue/sat/val) + // - OpenRGB-QMK plugin (per-key control via direct mode) + // + // Protocol is decided per device at handshake. VIA-only keyboards + // become a single-LED device that drives the firmware's RGB matrix + // base colour; OpenRGB-QMK keyboards become a full per-key keyboard + // with semantic LedId.Keyboard_* IDs when a VIA keymap is fetchable + // from www.caniusevia.com (Custom1..N fallback otherwise). + // + // Hot-plug parity with PlayStationControllerRGBDeviceProvider — + // DeviceList.Local.Changed reconciles the open set on USB connect / + // disconnect events. Adoption picker UX parity with LIFX/Hue — + // ClientDefinitions is hydrated from SettingsModel before LoadDevices + // runs; an empty list short-circuits the load so users explicitly opt + // in to which boards Chromatics drives. + public class QmkRawHidRGBDeviceProvider : AbstractRGBDeviceProvider + { + #region Singleton + + private static QmkRawHidRGBDeviceProvider _instance; + public static QmkRawHidRGBDeviceProvider Instance => _instance ?? new QmkRawHidRGBDeviceProvider(); + + public QmkRawHidRGBDeviceProvider() + { + if (_instance != null) Throw(new Exception($"There can be only one instance of type {nameof(QmkRawHidRGBDeviceProvider)}")); + _instance = this; + } + + #endregion + + #region Configuration & state + + // 30Hz update rate — same cadence as the PlayStation provider. QMK + // boards accept sustained 30Hz over Raw HID without flooding the + // USB EP RX queue; faster than this risks dropped packets on + // multi-zone bulk updates. + private const double UpdateFrequencySeconds = 1.0 / 30.0; + + // Same debounce as PlayStation. Windows fires several PnP events + // for one logical USB connect; we wait long enough for the device + // tree to settle before re-enumerating, otherwise TryOpen wins a + // partially-enumerated handle and the first write fails. + private const int HotplugDebounceMs = 1500; + + public List AdoptedDevices { get; } = new(); + + private readonly Dictionary _openStreams = new(); + private readonly Dictionary _devicePaths = new(); + private bool _hotplugSubscribed; + private int _hotplugScheduleSeq; + + #endregion + + protected override void InitializeSDK() + { + if (!_hotplugSubscribed) + { + DeviceList.Local.Changed += OnHidDeviceListChanged; + _hotplugSubscribed = true; + } + } + + protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) + => new QmkRawHidUpdateTrigger(UpdateFrequencySeconds); + + protected override IEnumerable LoadDevices() + { + return LoadDevicesAsync().GetAwaiter().GetResult(); + } + + // Async device load — runs the handshake on every candidate, fetches + // VIA keymaps in parallel for adopted boards (network calls run + // concurrently rather than serial), then materialises one + // QmkRawHidDevice per adopted+responsive board. + private async Task> LoadDevicesAsync() + { + var devices = new List(); + if (AdoptedDevices.Count == 0) return devices; + + var candidates = QmkRawHidDiscovery.Discover(); + if (candidates.Count == 0) + { + Logger.WriteConsole(LoggerTypes.Devices, + "[QMK] No QMK Raw HID keyboards detected on the USB bus. " + + "Make sure your keyboard's firmware has Raw HID enabled (it's the default for most VIA-compatible builds) " + + "and that no other app (VIA, Vial, OpenRGB) is holding the Raw HID interface exclusively.", + forwardToSentry: false); + return devices; + } + + // Reduce candidate list to adopted entries up-front — no point + // running keymap fetches for boards the user didn't pick. + var adoptedCandidates = new List(candidates.Count); + foreach (var c in candidates) + { + if (!IsAdopted(c)) continue; + adoptedCandidates.Add(c); + } + if (adoptedCandidates.Count == 0) return devices; + + // Fetch keymaps in parallel for the OpenRGB-QMK ones. VIA-only + // boards don't use keymaps (single LED), so skip those. + var keymapTasks = new Dictionary<(int vid, int pid), Task>(); + foreach (var c in adoptedCandidates) + { + if (c.Protocol != QmkRawHidDiscovery.ProtocolSupport.OpenRgbQmk) continue; + var key = (c.Hid.VendorID, c.Hid.ProductID); + if (keymapTasks.ContainsKey(key)) continue; + keymapTasks[key] = QmkKeymapFetcher.TryGetKeymapAsync(c.Hid.VendorID, c.Hid.ProductID); + } + if (keymapTasks.Count > 0) + await Task.WhenAll(keymapTasks.Values).ConfigureAwait(false); + + foreach (var c in adoptedCandidates) + { + try + { + if (!c.Hid.TryOpen(out HidStream stream)) + { + Logger.WriteConsole(LoggerTypes.Error, + $"[QMK] Could not open {SafeProductName(c.Hid)} ({c.Hid.VendorID:X4}:{c.Hid.ProductID:X4}). " + + "Another app may be holding the Raw HID interface exclusively (VIA, Vial, OpenRGB).", + forwardToSentry: false); + continue; + } + stream.ReadTimeout = QmkRawHidConstants.ResponseTimeoutMs; + stream.WriteTimeout = QmkRawHidConstants.ResponseTimeoutMs; + + QmkKeymapFetcher.QmkKeymap keymap = null; + if (c.Protocol == QmkRawHidDiscovery.ProtocolSupport.OpenRgbQmk + && keymapTasks.TryGetValue((c.Hid.VendorID, c.Hid.ProductID), out var kmTask)) + { + keymap = kmTask.Result; + } + + var layout = BuildLayoutForCandidate(stream, c, keymap); + + var def = new QmkRawHidClientDefinition( + vendorId: c.Hid.VendorID, + productId: c.Hid.ProductID, + manufacturer: SafeManufacturer(c.Hid), + product: SafeProductName(c.Hid), + firmwareDeviceName: c.FirmwareDeviceName, + ledCount: layout.Count == 0 ? 1 : layout.Count, + protocol: c.Protocol == QmkRawHidDiscovery.ProtocolSupport.OpenRgbQmk + ? QmkRawHidProtocolMode.OpenRgbQmk + : QmkRawHidProtocolMode.ViaOnly, + matrixColumns: c.MatrixColumns, + matrixRows: c.MatrixRows, + viaKeymapKey: string.Empty, + layout: layout); + + var trigger = (QmkRawHidUpdateTrigger)GetUpdateTrigger(); + var queue = new QmkRawHidUpdateQueue(trigger, def, stream); + var info = new QmkRawHidDeviceInfo(def); + var dev = new QmkRawHidDevice(info, queue, def); + + _openStreams[dev] = stream; + _devicePaths[dev] = c.Hid.DevicePath; + devices.Add(dev); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, + $"[QMK] Failed to set up {SafeProductName(c.Hid)}: {ex.Message}", + forwardToSentry: false); + } + } + + return devices; + } + + // For VIA-only: a single Custom1 LED. + // For OpenRGB-QMK: enumerate the firmware's LED records (paged via + // Cmd_GetLedInfo), then merge against the optional VIA keymap to + // produce the semantic LedId list. + private static IReadOnlyList BuildLayoutForCandidate( + HidStream stream, + QmkRawHidDiscovery.Candidate candidate, + QmkKeymapFetcher.QmkKeymap keymap) + { + if (candidate.Protocol == QmkRawHidDiscovery.ProtocolSupport.ViaOnly) + { + return new[] + { + new QmkLedLayoutEntry(0, 0, 0, LedId.Custom1, new Point(0, 0), new Size(60, 60)), + }; + } + + var records = FetchAllLedRecords(stream, candidate.LedCount); + if (records.Count == 0) + { + // OpenRGB-QMK responded to GetDeviceInfo but failed to return + // LED records — degrade to a synthetic grid sized by LedCount + // so the device still appears for the user to position + // manually in the Mapping tab. + return SyntheticGrid(candidate.LedCount, candidate.MatrixColumns); + } + + return QmkKeymapFetcher.BuildLayout(keymap, records); + } + + private static List<(int firmwareIndex, byte col, byte row)> FetchAllLedRecords(HidStream stream, int totalLeds) + { + var records = new List<(int, byte, byte)>(totalLeds); + byte[] outBuf = new byte[QmkRawHidConstants.OutputReportBytes]; + byte[] inBuf = new byte[QmkRawHidConstants.ReportPayloadBytes + 1]; + + int next = 0; + int safetyBudget = (totalLeds / 8) + 32; // upper bound on batch iterations + while (next < totalLeds && safetyBudget-- > 0) + { + OpenRgbQmkProtocol.BuildGetLedInfo( + new Span(outBuf, 1, QmkRawHidConstants.ReportPayloadBytes), + (ushort)next); + try + { + stream.Write(outBuf); + int n = stream.Read(inBuf, 0, inBuf.Length); + if (n <= 0) break; + } + catch { break; } + + if (!OpenRgbQmkProtocol.TryParseLedInfoBatch( + new ReadOnlySpan(inBuf, 1, inBuf.Length - 1), + out int batchCount, out var batch)) + { + break; + } + if (batchCount == 0) break; + + for (int i = 0; i < batchCount && next < totalLeds; i++, next++) + { + byte col = batch[i * 3]; + byte row = batch[i * 3 + 1]; + // batch[i*3+2] is the flags byte; not used here. + records.Add((next, col, row)); + } + } + return records; + } + + private static IReadOnlyList SyntheticGrid(int ledCount, byte hintColumns) + { + int cols = hintColumns > 0 ? hintColumns : Math.Max(1, (int)Math.Ceiling(Math.Sqrt(ledCount * 4.0 / 3.0))); + const float cell = 60f; + var list = new List(ledCount); + for (int i = 0; i < ledCount; i++) + { + int col = i % cols; + int row = i / cols; + list.Add(new QmkLedLayoutEntry( + firmwareIndex: i, + matrixCol: (byte)col, + matrixRow: (byte)row, + preferredLedId: (LedId)((int)LedId.Custom1 + i), + location: new Point(col * cell, row * cell), + size: new Size(cell, cell))); + } + return list; + } + + // ── Adopted-device matching ─────────────────────────────────── + + private bool IsAdopted(QmkRawHidDiscovery.Candidate candidate) + { + foreach (var ad in AdoptedDevices) + { + if (ad.Matches(candidate.Hid)) return true; + } + return false; + } + + // ── Hot-plug ────────────────────────────────────────────────── + + private void OnHidDeviceListChanged(object sender, DeviceListChangedEventArgs e) + { + int seq = System.Threading.Interlocked.Increment(ref _hotplugScheduleSeq); + Task.Run(async () => + { + await Task.Delay(HotplugDebounceMs).ConfigureAwait(false); + if (seq != _hotplugScheduleSeq) return; // newer event superseded us + try { Reconcile(); } catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, $"[QMK] hot-plug reconcile failed: {ex.Message}", forwardToSentry: false); + } + }); + } + + // Re-enumerate USB and compare to our open set: remove disappeared + // devices, add freshly-connected adopted ones. Same shape as the + // PlayStation provider's reconcile. + private void Reconcile() + { + var currentPaths = new HashSet(StringComparer.OrdinalIgnoreCase); + try + { + foreach (var hid in DeviceList.Local.GetHidDevices()) + { + try { currentPaths.Add(hid.DevicePath); } catch { /* ignore */ } + } + } + catch { return; } + + // Drop devices whose path is no longer present. + var toRemove = new List(); + foreach (var kvp in _devicePaths) + { + if (!currentPaths.Contains(kvp.Value)) + toRemove.Add(kvp.Key); + } + foreach (var dev in toRemove) + { + RemoveDevice(dev); + if (_openStreams.TryGetValue(dev, out var s)) + { + try { s.Dispose(); } catch { /* ignore */ } + _openStreams.Remove(dev); + } + _devicePaths.Remove(dev); + } + + // Add newly-connected adopted devices. + var existingPaths = new HashSet(_devicePaths.Values, StringComparer.OrdinalIgnoreCase); + var freshCandidates = QmkRawHidDiscovery.Discover(); + foreach (var c in freshCandidates) + { + if (!IsAdopted(c)) continue; + if (existingPaths.Contains(c.Hid.DevicePath)) continue; + + try + { + if (!c.Hid.TryOpen(out HidStream stream)) continue; + stream.ReadTimeout = QmkRawHidConstants.ResponseTimeoutMs; + stream.WriteTimeout = QmkRawHidConstants.ResponseTimeoutMs; + + var keymap = c.Protocol == QmkRawHidDiscovery.ProtocolSupport.OpenRgbQmk + ? QmkKeymapFetcher.TryGetKeymapAsync(c.Hid.VendorID, c.Hid.ProductID).GetAwaiter().GetResult() + : null; + + var layout = BuildLayoutForCandidate(stream, c, keymap); + + var def = new QmkRawHidClientDefinition( + c.Hid.VendorID, c.Hid.ProductID, + SafeManufacturer(c.Hid), SafeProductName(c.Hid), + c.FirmwareDeviceName, layout.Count == 0 ? 1 : layout.Count, + c.Protocol == QmkRawHidDiscovery.ProtocolSupport.OpenRgbQmk + ? QmkRawHidProtocolMode.OpenRgbQmk : QmkRawHidProtocolMode.ViaOnly, + c.MatrixColumns, c.MatrixRows, string.Empty, layout); + + var trigger = (QmkRawHidUpdateTrigger)GetUpdateTrigger(); + var queue = new QmkRawHidUpdateQueue(trigger, def, stream); + var info = new QmkRawHidDeviceInfo(def); + var dev = new QmkRawHidDevice(info, queue, def); + + _openStreams[dev] = stream; + _devicePaths[dev] = c.Hid.DevicePath; + AddDevice(dev); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, $"[QMK] hot-plug add failed for {SafeProductName(c.Hid)}: {ex.Message}", forwardToSentry: false); + } + } + } + + // ── Dispose ─────────────────────────────────────────────────── + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_hotplugSubscribed) + { + try { DeviceList.Local.Changed -= OnHidDeviceListChanged; } catch { /* ignore */ } + _hotplugSubscribed = false; + } + + foreach (var dev in Devices.OfType()) + { + try { dev.BeginShutdown(); } catch { /* ignore */ } + } + foreach (var s in _openStreams.Values) + { + try { s.Dispose(); } catch { /* ignore */ } + } + _openStreams.Clear(); + _devicePaths.Clear(); + } + + base.Dispose(disposing); + + if (ReferenceEquals(_instance, this)) + _instance = null; + } + + // ── HidSharp string accessors (Manufacturer/Product can throw on disconnected handles) ── + + private static string SafeManufacturer(HidDevice hid) + { + try { return hid.GetManufacturer() ?? string.Empty; } + catch { return string.Empty; } + } + private static string SafeProductName(HidDevice hid) + { + try { return hid.GetProductName() ?? string.Empty; } + catch { return string.Empty; } + } + } + + // Identity filter used by the adopted-set check. Built from the + // SettingsModel's persisted QmkRawHidAdoptedDevice records so the + // provider doesn't have to depend on the Models layer for runtime + // matching. + public sealed class QmkRawHidAdoptedDeviceFilter + { + public int VendorId { get; } + public int ProductId { get; } + public string Manufacturer { get; } + public string Product { get; } + + public QmkRawHidAdoptedDeviceFilter(int vendorId, int productId, string manufacturer, string product) + { + VendorId = vendorId; + ProductId = productId; + Manufacturer = manufacturer ?? string.Empty; + Product = product ?? string.Empty; + } + + public bool Matches(HidDevice hid) + { + if (hid.VendorID != VendorId) return false; + if (hid.ProductID != ProductId) return false; + string mfg, prod; + try { mfg = hid.GetManufacturer() ?? string.Empty; } catch { mfg = string.Empty; } + try { prod = hid.GetProductName() ?? string.Empty; } catch { prod = string.Empty; } + return string.Equals(mfg, Manufacturer, StringComparison.OrdinalIgnoreCase) + && string.Equals(prod, Product, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidUpdateQueue.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidUpdateQueue.cs new file mode 100644 index 00000000..1fe5ff5a --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidUpdateQueue.cs @@ -0,0 +1,285 @@ +using Chromatics.Core; +using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol; +using HidSharp; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Threading; +using Color = RGB.NET.Core.Color; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + public class QmkRawHidUpdateQueue : UpdateQueue + { + #region Properties & Fields + + private readonly QmkRawHidClientDefinition _def; + private readonly HidStream _stream; + private readonly Lock _lock = new(); + private volatile bool _shuttingDown; + // Per-device disable gate — parity with LifxUpdateQueue. Toggled + // from RGBController.RemoveDevice / AddDevice so paint frames are + // dropped while the user has the keyboard disabled in the Mapping + // tab. Cleared on re-enable. + private volatile bool _perDeviceDisable; + + private PerDeviceBrightnessCorrection _perDeviceBrightness; + + // LedId → firmware LED index. Built once at construction from the + // client definition's Layout so per-frame lookups avoid linear scans. + private readonly Dictionary _ledIndexByLedId; + + // Persistent RGB byte cache for the entire strip — same idea as + // LifxUpdateQueue._strip. Lets sparse decorator updates (a few LEDs + // changed) only resend their chunks rather than the whole strip. + // 3 bytes per LED (R, G, B). Null until the first frame. + private byte[] _ledBytes; + + // Single-LED VIA path coalescing: last sent hue/sat/brightness/effect + // tuple. Set to 0xFFFF when empty so the first frame always sends. + private ushort _lastViaHsbHash = 0xFFFF; + + // True once we've put the OpenRGB-QMK firmware into direct mode + // (mode 0). On enter direct mode the firmware suspends built-in + // RGB matrix effects so our Set commands aren't fighting them. + private bool _openRgbDirectModeArmed; + + #endregion + + #region Constructors + + public QmkRawHidUpdateQueue(IDeviceUpdateTrigger trigger, QmkRawHidClientDefinition def, HidStream stream) + : base(trigger) + { + _def = def; + _stream = stream; + _ledIndexByLedId = new Dictionary(def.Layout.Count); + for (int i = 0; i < def.Layout.Count; i++) + _ledIndexByLedId[def.Layout[i].PreferredLedId] = def.Layout[i].FirmwareIndex; + } + + #endregion + + #region Methods + + public void BeginShutdown() => _shuttingDown = true; + + public void SetPerDeviceDisabled(bool disabled) => _perDeviceDisable = disabled; + + public void ResetCache() + { + lock (_lock) + { + _ledBytes = null; + _lastViaHsbHash = 0xFFFF; + _openRgbDirectModeArmed = false; + } + } + + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _perDeviceBrightness = correction; + + protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet) + { + lock (_lock) + { + if (_shuttingDown || _perDeviceDisable) return true; + if (dataSet.IsEmpty) return true; + + try + { + int globalPct = GlobalBrightnessCorrection.Instance.BrightnessPercent; + int perDevicePct = _perDeviceBrightness?.BrightnessPercent ?? 100; + double brightnessScale = (globalPct / 100.0) * (perDevicePct / 100.0); + + if (_def.Protocol == QmkRawHidProtocolMode.OpenRgbQmk) + SendOpenRgbQmkFrame(dataSet, brightnessScale); + else + SendViaFrame(dataSet, brightnessScale); + + return true; + } + catch (Exception ex) + { + QmkRawHidRGBDeviceProvider.Instance?.Throw(ex); + return false; + } + } + } + + // ── VIA path (Tier 1: single representative colour) ────────── + + private void SendViaFrame(ReadOnlySpan<(object key, Color color)> dataSet, double brightnessScale) + { + Color picked = PickRepresentativeColor(dataSet); + ToHsv255(picked, brightnessScale, out byte hue, out byte sat, out byte val); + + // Pack hue/sat/val + effect index into a single 16-bit hash to + // cheaply detect "nothing changed since last frame" and skip + // the three USB writes the VIA path would otherwise burn. + // 7-bit hue, 5-bit sat, 4-bit val is enough resolution for + // change detection without ever sending a no-op. + ushort hash = (ushort)(((hue >> 1) & 0x7F) << 9 + | ((sat >> 3) & 0x1F) << 4 + | ((val >> 4) & 0x0F)); + if (hash == _lastViaHsbHash) return; + _lastViaHsbHash = hash; + + Span outBuf = stackalloc byte[QmkRawHidConstants.OutputReportBytes]; + Span payload = outBuf.Slice(1, QmkRawHidConstants.ReportPayloadBytes); + + ViaProtocol.BuildSetRgbMatrixEffect(payload, ViaProtocol.Effect_SolidColor); + WritePayload(outBuf); + + ViaProtocol.BuildSetRgbMatrixColor(payload, hue, sat); + WritePayload(outBuf); + + ViaProtocol.BuildSetRgbMatrixBrightness(payload, val); + WritePayload(outBuf); + } + + // ── OpenRGB-QMK path (Tier 2: per-key) ─────────────────────── + + private void SendOpenRgbQmkFrame(ReadOnlySpan<(object key, Color color)> dataSet, double brightnessScale) + { + int total = _def.LedCount; + if (total <= 0) return; + + if (_ledBytes == null) _ledBytes = new byte[total * 3]; + + // Arm direct mode once per session. The firmware persists the + // mode setting in RAM, so we don't have to re-arm every frame — + // but DO re-arm after a ResetCache (which clears _openRgbDirectModeArmed + // alongside _ledBytes, so the next Update arms again). + if (!_openRgbDirectModeArmed) + { + Span armBuf = stackalloc byte[QmkRawHidConstants.OutputReportBytes]; + OpenRgbQmkProtocol.BuildSetMode(armBuf.Slice(1, QmkRawHidConstants.ReportPayloadBytes), modeIndex: 0); + WritePayload(armBuf); + _openRgbDirectModeArmed = true; + } + + // Patch dirty LEDs into _ledBytes and remember which chunks + // (LED indices grouped by MaxLedsPerSetRange) need re-sending. + int chunkSize = OpenRgbQmkProtocol.MaxLedsPerSetRange; + int chunkCount = (total + chunkSize - 1) / chunkSize; + Span dirty = chunkCount <= 256 ? stackalloc bool[chunkCount] : new bool[chunkCount]; + + foreach (var (key, color) in dataSet) + { + int idx = TryResolveLedIndex(key); + if (idx < 0 || idx >= total) continue; + + ToRgb255(color, brightnessScale, out byte r, out byte g, out byte b); + int off = idx * 3; + if (_ledBytes[off] == r && _ledBytes[off + 1] == g && _ledBytes[off + 2] == b) continue; + + _ledBytes[off] = r; + _ledBytes[off + 1] = g; + _ledBytes[off + 2] = b; + dirty[idx / chunkSize] = true; + } + + // Send each dirty chunk. Inter-packet pacing keeps us within the + // firmware's RX queue depth on full-speed USB — 1ms is well above + // QMK's worst-case raw_hid_receive turnaround. + Span outBuf = stackalloc byte[QmkRawHidConstants.OutputReportBytes]; + bool first = true; + for (int c = 0; c < chunkCount; c++) + { + if (!dirty[c]) continue; + if (!first) Thread.Sleep(1); + first = false; + + ushort start = (ushort)(c * chunkSize); + int count = Math.Min(chunkSize, total - start); + OpenRgbQmkProtocol.BuildSetLedRange( + outBuf.Slice(1, QmkRawHidConstants.ReportPayloadBytes), + start, (byte)count, + new ReadOnlySpan(_ledBytes, start * 3, count * 3)); + WritePayload(outBuf); + } + } + + private int TryResolveLedIndex(object key) + { + if (key is LedId id && _ledIndexByLedId.TryGetValue(id, out int idx)) return idx; + return -1; + } + + // ── HID write ──────────────────────────────────────────────── + + private void WritePayload(ReadOnlySpan outBuf) + { + if (_stream == null) return; + try { _stream.Write(outBuf.ToArray()); } + catch (System.IO.IOException ex) + { + // PnP unplug between Write call and current frame. Mark + // shutting down so the rest of this batch becomes no-ops; + // the provider's hot-plug reconcile will dispose us shortly. + Logger.WriteConsole(LoggerTypes.Devices, $"[QMK] {_def.Product}: write failed ({ex.Message}); pausing queue."); + _shuttingDown = true; + } + catch (ObjectDisposedException) + { + _shuttingDown = true; + } + } + + // ── Colour helpers ─────────────────────────────────────────── + + private static Color PickRepresentativeColor(ReadOnlySpan<(object key, Color color)> dataSet) + { + if (dataSet.Length == 1) return dataSet[0].color; + int maxIdx = 0; + double maxL = -1; + for (int i = 0; i < dataSet.Length; i++) + { + double l = dataSet[i].color.R + dataSet[i].color.G + dataSet[i].color.B; + if (l > maxL) { maxL = l; maxIdx = i; } + } + return dataSet[maxIdx].color; + } + + private static void ToHsv255(Color rgb, double brightnessScale, out byte hue, out byte sat, out byte val) + { + double r = Math.Clamp(rgb.R, 0.0, 1.0); + double g = Math.Clamp(rgb.G, 0.0, 1.0); + double bb = Math.Clamp(rgb.B, 0.0, 1.0); + + double max = Math.Max(r, Math.Max(g, bb)); + double min = Math.Min(r, Math.Min(g, bb)); + double delta = max - min; + + double h = 0; + if (delta > 0) + { + if (max == r) h = ((g - bb) / delta) % 6; + else if (max == g) h = ((bb - r) / delta) + 2; + else h = ((r - g) / delta) + 4; + h *= 60; + if (h < 0) h += 360; + } + + double s = max == 0 ? 0 : delta / max; + double v = max * Math.Clamp(brightnessScale, 0.0, 1.0); + + hue = (byte)Math.Round((h / 360.0) * 255); + sat = (byte)Math.Round(s * 255); + val = (byte)Math.Round(v * 255); + } + + private static void ToRgb255(Color rgb, double brightnessScale, out byte r, out byte g, out byte b) + { + double scale = Math.Clamp(brightnessScale, 0.0, 1.0); + r = (byte)Math.Round(Math.Clamp(rgb.R, 0.0, 1.0) * 255 * scale); + g = (byte)Math.Round(Math.Clamp(rgb.G, 0.0, 1.0) * 255 * scale); + b = (byte)Math.Round(Math.Clamp(rgb.B, 0.0, 1.0) * 255 * scale); + } + + #endregion + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidUpdateTrigger.cs b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidUpdateTrigger.cs new file mode 100644 index 00000000..db02e150 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkRawHidUpdateTrigger.cs @@ -0,0 +1,48 @@ +using RGB.NET.Core; +using System; +using System.Diagnostics; +using System.Threading; + +namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid +{ + // 30Hz trigger with idle wake every 50ms so per-device brightness + // slider changes propagate to a board sitting on a static layer. + // Matches the LifxDeviceUpdateTrigger shape — refresh tick fires + // CustomUpdateData("refresh") so the queue's OnUpdate can no-op + // gracefully on empty datasets without missing slider-driven + // re-sends if we later add brightness/effect mode change support. + public class QmkRawHidUpdateTrigger : DeviceUpdateTrigger + { + private const int WaitOneTimeoutMs = 50; + + public QmkRawHidUpdateTrigger() { } + + public QmkRawHidUpdateTrigger(double updateRateHardLimit) + : base(updateRateHardLimit) { } + + protected override void UpdateLoop() + { + OnStartup(); + + while (!UpdateToken.IsCancellationRequested) + { + if (HasDataEvent.WaitOne(WaitOneTimeoutMs)) + { + long preUpdateTicks = Stopwatch.GetTimestamp(); + OnUpdate(); + + if (UpdateFrequency > 0) + { + double elapsedMs = (Stopwatch.GetTimestamp() - preUpdateTicks) / (double)TimeSpan.TicksPerMillisecond; + int sleep = (int)(UpdateFrequency * 1000.0 - elapsedMs); + if (sleep > 0) Thread.Sleep(sleep); + } + } + else + { + OnUpdate(new CustomUpdateData(("refresh", true))); + } + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/Protocol/YeelightConnection.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/Protocol/YeelightConnection.cs new file mode 100644 index 00000000..b7082df8 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/Protocol/YeelightConnection.cs @@ -0,0 +1,256 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight.Protocol +{ + // Single TCP connection to one Yeelight bulb on its LAN control port + // (55443). Wraps a TcpClient and exposes the small subset of JSON-over- + // TCP commands Chromatics actually paints with: set_rgb, set_bright, + // set_power, set_ct_abx. + // + // Music Mode caveat (load-bearing for paint rate): + // + // Yeelight's LAN protocol caps outbound commands at 60 per minute + // per bulb in the normal direction. That's well below any usable + // paint rate. Music Mode flips the direction — we tell the bulb our + // IP + a listening TCP port via `set_music`, the bulb opens a TCP + // connection BACK to us, and that reverse channel has no rate cap. + // Once Music Mode is on we can send 60+Hz updates without the bulb + // silently dropping frames. + // + // Set up by YeelightConnection.EnterMusicModeAsync. If Music Mode + // fails (firewall blocks the reverse TCP, NAT in the way for a + // user on a corporate LAN, etc.) we fall back to the outbound + // connection and let the LIFX-equivalent throttle in + // YeelightUpdateQueue keep us under the rate cap. + // + // JSON wire format example (one line, newline-terminated): + // + // {"id":1,"method":"set_rgb","params":[16711680,"smooth",30]}\r\n + public sealed class YeelightConnection : IDisposable + { + // Yeelight's LAN protocol terminator. Every command is one JSON + // object followed by CR+LF. The bulb parses one line at a time. + private static readonly byte[] LineTerminator = new byte[] { 0x0D, 0x0A }; + + // We use Smooth transitions with a tiny duration (30ms). Sudden + // jumps in colour look harsh on Yeelight Color 1S / Color 1 because + // the firmware step-functions otherwise; 30ms smooth blends frames + // into a continuous gradient without adding perceptible lag at + // 30Hz paint cadence. Smooth durations below 30ms are silently + // rounded up to 30 by the firmware. + private const int SmoothDurationMs = 30; + + private readonly IPEndPoint _endpoint; + private TcpClient _client; + private NetworkStream _stream; + private TcpClient _musicClient; + private NetworkStream _musicStream; + private int _nextId; + + public YeelightConnection(IPEndPoint endpoint) + { + _endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); + } + + public IPEndPoint Endpoint => _endpoint; + public bool IsConnected => _client?.Connected == true; + public bool IsMusicMode => _musicClient?.Connected == true; + + // Establish the outbound control channel. Idempotent — if we're + // already connected, no-op. Caller should not assume Music Mode is + // on; use EnterMusicModeAsync separately and let it fall back. + public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken = default) + { + if (IsConnected) return; + _client?.Dispose(); + _client = new TcpClient { NoDelay = true }; + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(timeout); + try + { + await _client.ConnectAsync(_endpoint.Address, _endpoint.Port, cts.Token).ConfigureAwait(false); + _stream = _client.GetStream(); + } + catch + { + _client?.Dispose(); + _client = null; + _stream = null; + throw; + } + } + + // Hand the bulb our IP + a local listening TCP port; the bulb will + // open a TCP connection back to us. Returns true if Music Mode is + // active afterwards. Falls back gracefully on any failure — the + // outbound channel remains usable. + // + // We accept the reverse connection synchronously up to `acceptTimeout`, + // then store the resulting socket. From that point on, command sends + // go down the reverse channel; the outbound channel stays open as + // a control / fallback path. + public async Task EnterMusicModeAsync(IPAddress localAddress, TimeSpan acceptTimeout, CancellationToken cancellationToken = default) + { + if (!IsConnected) return false; + if (localAddress == null) throw new ArgumentNullException(nameof(localAddress)); + + // Bind a TCP listener on a free port. We loopback this to the + // bulb so it knows where to reach us. + var listener = new TcpListener(IPAddress.Any, 0); + try + { + listener.Start(); + int listenPort = ((IPEndPoint)listener.LocalEndpoint).Port; + + // Fire `set_music` on the outbound channel. Params: + // action: 1 (turn music mode on) + // host: our IP as the bulb sees us + // port: our listening port + int id = NextId(); + string payload = $"{{\"id\":{id},\"method\":\"set_music\",\"params\":[1,\"{localAddress}\",{listenPort}]}}"; + await SendRawAsync(_stream, payload, cancellationToken).ConfigureAwait(false); + + // Wait for the bulb to dial back. Yeelight bulbs typically + // connect in <500ms when on the same subnet. + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(acceptTimeout); + + Task acceptTask = listener.AcceptTcpClientAsync(); + Task winner = await Task.WhenAny(acceptTask, Task.Delay(acceptTimeout, cts.Token)).ConfigureAwait(false); + + if (winner == acceptTask && acceptTask.IsCompletedSuccessfully) + { + _musicClient = acceptTask.Result; + _musicClient.NoDelay = true; + _musicStream = _musicClient.GetStream(); + return true; + } + + // Reverse connect didn't happen in time. Tell the bulb to + // turn Music Mode back off so we don't sit in a half-state. + try + { + int offId = NextId(); + string off = $"{{\"id\":{offId},\"method\":\"set_music\",\"params\":[0]}}"; + await SendRawAsync(_stream, off, cancellationToken).ConfigureAwait(false); + } + catch { /* best-effort cleanup */ } + return false; + } + catch + { + return false; + } + finally + { + try { listener.Stop(); } catch { /* ignore */ } + } + } + + // Send one packed 24-bit RGB value. Encoded as `(R<<16) | (G<<8) | B`, + // matching the protocol's `set_rgb` integer parameter. + public Task SetRgbAsync(byte r, byte g, byte b, CancellationToken cancellationToken = default) + { + int packed = (r << 16) | (g << 8) | b; + // Yeelight rejects rgb=0 (it's the "uninitialised" sentinel in + // their state machine). Map it to (0,0,1) which is visually + // indistinguishable from off but accepted by firmware. + if (packed == 0) packed = 1; + int id = NextId(); + string payload = $"{{\"id\":{id},\"method\":\"set_rgb\",\"params\":[{packed},\"smooth\",{SmoothDurationMs}]}}"; + return SendCommandAsync(payload, cancellationToken); + } + + public Task SetBrightnessAsync(int percent, CancellationToken cancellationToken = default) + { + percent = Math.Clamp(percent, 1, 100); + int id = NextId(); + string payload = $"{{\"id\":{id},\"method\":\"set_bright\",\"params\":[{percent},\"smooth\",{SmoothDurationMs}]}}"; + return SendCommandAsync(payload, cancellationToken); + } + + public Task SetPowerAsync(bool on, CancellationToken cancellationToken = default) + { + int id = NextId(); + string state = on ? "on" : "off"; + string payload = $"{{\"id\":{id},\"method\":\"set_power\",\"params\":[\"{state}\",\"smooth\",{SmoothDurationMs}]}}"; + return SendCommandAsync(payload, cancellationToken); + } + + // Background-light variants for dual-element bulbs (Bedside Lamp 2, + // some ceiling lights). The bulb routes `bg_set_*` commands to the + // secondary light element while `set_*` keeps driving the main one, + // so calling both in the same frame addresses them independently. + // Bulbs that don't have a background element silently ignore these. + public Task SetBackgroundRgbAsync(byte r, byte g, byte b, CancellationToken cancellationToken = default) + { + int packed = (r << 16) | (g << 8) | b; + if (packed == 0) packed = 1; + int id = NextId(); + string payload = $"{{\"id\":{id},\"method\":\"bg_set_rgb\",\"params\":[{packed},\"smooth\",{SmoothDurationMs}]}}"; + return SendCommandAsync(payload, cancellationToken); + } + + public Task SetBackgroundBrightnessAsync(int percent, CancellationToken cancellationToken = default) + { + percent = Math.Clamp(percent, 1, 100); + int id = NextId(); + string payload = $"{{\"id\":{id},\"method\":\"bg_set_bright\",\"params\":[{percent},\"smooth\",{SmoothDurationMs}]}}"; + return SendCommandAsync(payload, cancellationToken); + } + + public Task SetBackgroundPowerAsync(bool on, CancellationToken cancellationToken = default) + { + int id = NextId(); + string state = on ? "on" : "off"; + string payload = $"{{\"id\":{id},\"method\":\"bg_set_power\",\"params\":[\"{state}\",\"smooth\",{SmoothDurationMs}]}}"; + return SendCommandAsync(payload, cancellationToken); + } + + // Colour temperature in Kelvin (1700-6500 range per Yeelight spec). + // Used when the incoming colour is grey-scale; produces better white + // light than synthesising RGB(255,255,255) which the bulb interprets + // as full RGB and rendering with a slight tint. + public Task SetColorTemperatureAsync(int kelvin, CancellationToken cancellationToken = default) + { + kelvin = Math.Clamp(kelvin, 1700, 6500); + int id = NextId(); + string payload = $"{{\"id\":{id},\"method\":\"set_ct_abx\",\"params\":[{kelvin},\"smooth\",{SmoothDurationMs}]}}"; + return SendCommandAsync(payload, cancellationToken); + } + + // Best-effort write to whichever channel is active (Music Mode if up, + // outbound otherwise). Throws on a fully-broken connection; caller + // is expected to surface that to the UpdateQueue which will mark the + // device for reconnect. + private Task SendCommandAsync(string payload, CancellationToken cancellationToken) + { + NetworkStream target = _musicStream ?? _stream; + if (target == null) throw new InvalidOperationException("Yeelight connection is not open."); + return SendRawAsync(target, payload, cancellationToken); + } + + private async Task SendRawAsync(NetworkStream stream, string payload, CancellationToken cancellationToken) + { + byte[] bytes = Encoding.UTF8.GetBytes(payload); + await stream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false); + await stream.WriteAsync(LineTerminator, 0, LineTerminator.Length, cancellationToken).ConfigureAwait(false); + await stream.FlushAsync(cancellationToken).ConfigureAwait(false); + } + + private int NextId() => Interlocked.Increment(ref _nextId); + + public void Dispose() + { + try { _musicStream?.Dispose(); } catch { /* ignore */ } + try { _musicClient?.Dispose(); } catch { /* ignore */ } + try { _stream?.Dispose(); } catch { /* ignore */ } + try { _client?.Dispose(); } catch { /* ignore */ } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/Protocol/YeelightDiscovery.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/Protocol/YeelightDiscovery.cs new file mode 100644 index 00000000..0a72ae8f --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/Protocol/YeelightDiscovery.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight.Protocol +{ + // SSDP-based LAN discovery for Yeelight bulbs. Yeelight bulbs respond + // to an `M-SEARCH * HTTP/1.1` UDP datagram sent to 239.255.255.250:1982 + // (note: not the standard SSDP port 1900) with `ST: wifi_bulb`, and + // also emit unsolicited NOTIFY announces on the same multicast group + // when they come online. + // + // The user has to enable "LAN Control" in the Yeelight / Mi Home app + // before a bulb will respond. There's no host-side way to check for + // that — bulbs with LAN control disabled simply don't appear in + // discovery, indistinguishable from "no bulbs on the network". We + // surface a hint in the empty-result case from the provider. + // + // Response is a small HTTP-shaped block with one header per line. + // Relevant fields we parse: + // + // Location: yeelight://: — control endpoint (port is always 55443) + // id: 0x000000000d2a4b1c — stable 64-bit bulb id (hex) + // model: color | stripe | color1 | ... — bulb model family + // support: get_prop set_default ... — space-separated capability list + // power: on | off — current power state + // bright: 1..100 — current brightness + // rgb: 16777215 — packed RGB value (current) + // name: — friendly name (often empty) + internal static class YeelightDiscovery + { + public const int SsdpPort = 1982; + public const string SsdpMulticastAddress = "239.255.255.250"; + + public const string ControlPort = "55443"; // every Yeelight LAN bulb uses this + + public sealed class DiscoveredBulb + { + public string Id { get; set; } // hex id, lowercase, e.g. "0x000000000d2a4b1c" + public IPEndPoint Endpoint { get; set; } // ip + 55443 + public string Model { get; set; } + public string Name { get; set; } + public string FirmwareVersion { get; set; } + public IReadOnlyList Support { get; set; } = Array.Empty(); + public string PowerState { get; set; } // "on" / "off" + public int Brightness { get; set; } // 1..100, 0 if unknown + public uint Rgb { get; set; } // packed 24-bit RGB + + // Most user-visible identifier the Mapping tab will show. Falls + // back through Name → Model → Id when the user hasn't bothered + // setting a friendly name on the bulb. + public string DisplayLabel => !string.IsNullOrWhiteSpace(Name) + ? Name + : !string.IsNullOrWhiteSpace(Model) + ? $"Yeelight {Model}" + : Id ?? "Yeelight bulb"; + } + + // Active discovery. Sends one M-SEARCH and listens for replies up + // to `timeout`. Multiple bulbs answer in parallel; we de-duplicate + // by Id so a bulb that replies twice during the window only shows + // up once. + public static async Task> DiscoverAsync(TimeSpan timeout, CancellationToken cancellationToken = default) + { + var results = new Dictionary(StringComparer.OrdinalIgnoreCase); + + using var udp = new UdpClient(0) + { + EnableBroadcast = true, + }; + // Multicast TTL of 2 hops — bulbs are almost always on the same + // subnet, but some home routers put IoT VLANs one router-hop + // away and we want to reach those. Going higher than 2 risks + // discovery leaking into neighbouring networks for users on + // misconfigured routers. + udp.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2); + + var multicast = new IPEndPoint(IPAddress.Parse(SsdpMulticastAddress), SsdpPort); + + // The M-SEARCH packet Yeelight bulbs expect. Note the `\r\n` + // line endings and `ST: wifi_bulb` — that's the Yeelight-specific + // service type, not the generic UPnP `ssdp:all`. The bulb + // firmware filters by this value. + string mSearch = + "M-SEARCH * HTTP/1.1\r\n" + + $"HOST: {SsdpMulticastAddress}:{SsdpPort}\r\n" + + "MAN: \"ssdp:discover\"\r\n" + + "ST: wifi_bulb\r\n"; + byte[] payload = Encoding.UTF8.GetBytes(mSearch); + + try { await udp.SendAsync(payload, payload.Length, multicast).ConfigureAwait(false); } + catch { return Array.Empty(); } + + // Poll-based receive loop. We deliberately avoid awaiting + // ReceiveAsync(cancellationToken) directly because it throws + // OperationCanceledException on the timeout / cancel path, + // which surfaces as a noisy first-chance exception in the + // debugger even when caught. Polling Available + a plain + // Task.Delay keeps the loop exception-free in the common + // "no bulbs on the LAN" case. + DateTime deadline = DateTime.UtcNow + timeout; + while (DateTime.UtcNow < deadline && !cancellationToken.IsCancellationRequested) + { + if (udp.Available > 0) + { + UdpReceiveResult resp; + try { resp = await udp.ReceiveAsync().ConfigureAwait(false); } + catch { continue; } + + var bulb = ParseResponse(resp.Buffer); + if (bulb == null || string.IsNullOrEmpty(bulb.Id)) continue; + if (bulb.Endpoint == null) + { + // Location header was malformed or missing; fall back + // to the sender's address with the standard port so + // the bulb is still addressable. + bulb.Endpoint = new IPEndPoint(resp.RemoteEndPoint.Address, 55443); + } + results[bulb.Id] = bulb; // last response wins (most recent state) + } + else + { + // 50ms idle tick balances responsiveness (we want to pick + // up bulb replies promptly during the active discovery + // window) with not pegging a CPU core in the empty case. + await Task.Delay(50).ConfigureAwait(false); + } + } + + return new List(results.Values); + } + + // Parse one SSDP response into a DiscoveredBulb. Returns null on + // a clearly-malformed payload. Tolerant of header order and case + // — Yeelight firmware versions vary on both. + private static DiscoveredBulb ParseResponse(byte[] buffer) + { + string text; + try { text = Encoding.UTF8.GetString(buffer); } + catch { return null; } + + var bulb = new DiscoveredBulb(); + string[] lines = text.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var raw in lines) + { + int colon = raw.IndexOf(':'); + if (colon <= 0 || colon >= raw.Length - 1) continue; + string key = raw.Substring(0, colon).Trim().ToLowerInvariant(); + string value = raw.Substring(colon + 1).Trim(); + + switch (key) + { + case "location": + bulb.Endpoint = ParseYeelightUri(value); + break; + case "id": + bulb.Id = value; + break; + case "model": + bulb.Model = value; + break; + case "name": + bulb.Name = value; + break; + case "fw_ver": + bulb.FirmwareVersion = value; + break; + case "support": + bulb.Support = value.Split(' ', StringSplitOptions.RemoveEmptyEntries); + break; + case "power": + bulb.PowerState = value; + break; + case "bright": + if (int.TryParse(value, out int b)) bulb.Brightness = b; + break; + case "rgb": + if (uint.TryParse(value, out uint c)) bulb.Rgb = c; + break; + } + } + return bulb; + } + + // `yeelight://192.168.1.42:55443` → IPEndPoint(192.168.1.42, 55443). + // Returns null on any parse failure so the caller can fall back to + // the SSDP sender address. + private static IPEndPoint ParseYeelightUri(string uri) + { + const string prefix = "yeelight://"; + if (string.IsNullOrEmpty(uri) || !uri.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return null; + string body = uri.Substring(prefix.Length); + int colon = body.LastIndexOf(':'); + if (colon <= 0) return null; + string ipPart = body.Substring(0, colon); + string portPart = body.Substring(colon + 1); + if (!IPAddress.TryParse(ipPart, out var ip)) return null; + if (!int.TryParse(portPart, out int port)) return null; + return new IPEndPoint(ip, port); + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightAdoptedDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightAdoptedDevice.cs new file mode 100644 index 00000000..12c0aebc --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightAdoptedDevice.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + // Persisted (settings.json) record of a user-adopted Yeelight bulb / + // strip / lamp. Identity is the bulb's stable hex Id from SSDP, which + // survives IP changes; LastIp / Label / Model / Support are hints we + // re-verify on every provider start (DHCP renewals are common, users + // rename bulbs in the Yeelight app, firmware updates can change the + // supported-method list). + public class YeelightAdoptedDevice + { + public string Id { get; set; } + public string Label { get; set; } + public string LastIp { get; set; } + public int LastPort { get; set; } = 55443; + public string Model { get; set; } + public string FirmwareVersion { get; set; } + public List Support { get; set; } = new(); + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightClientDefinition.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightClientDefinition.cs new file mode 100644 index 00000000..53ec1cc5 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightClientDefinition.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Net; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + // Runtime descriptor for one adopted Yeelight bulb. Captures the + // identifying metadata from SSDP discovery plus the resolved control + // endpoint, so the provider and update queue don't have to re-discover + // on every Load. + public sealed class YeelightClientDefinition + { + public YeelightClientDefinition(string id, string label, IPEndPoint endpoint, string model, string firmwareVersion = null, IReadOnlyList support = null) + { + Id = id; + Label = label; + Endpoint = endpoint; + Model = model; + FirmwareVersion = firmwareVersion; + Support = support ?? System.Array.Empty(); + } + + // Stable hex id from the bulb (e.g. "0x000000000d2a4b1c"). Survives + // IP changes and is the only identity that can be persisted across + // restarts. + public string Id { get; } + + // User-visible label. SSDP `name` field if the user set one, + // otherwise "Yeelight {model}" or the bulb id. + public string Label { get; } + + // Last-known control endpoint (ip:55443). Updated by discovery + // sweeps so the provider can stomach DHCP renewals. + public IPEndPoint Endpoint { get; set; } + + // SSDP `model` field — "color", "stripe", "color1", "ceiling4", etc. + // Used for the Mapping-tab label and to gate Music Mode (some older + // firmware models don't support it). + public string Model { get; } + + public string FirmwareVersion { get; } + + // Space-separated capability list from SSDP `support` (e.g. + // "set_default set_rgb set_bright set_power set_music ..."). Used + // to gate optional protocol calls like Music Mode and color + // temperature. + public IReadOnlyList Support { get; } + + public bool SupportsMusicMode => HasSupport("set_music"); + + // True when the bulb exposes a secondary "background" light element + // (Bedside Lamp 2 main + bg, some ceiling lights). When present we + // expose two LEDs and route bg_set_* commands to the second one. + public bool HasBackgroundLight => HasSupport("bg_set_rgb"); + + // True when the bulb supports tunable-white via colour temperature. + // Used so monochrome / tunable-white bulbs (mono*, ct_bulb) get a + // sensible representation rather than just refusing colour writes. + public bool SupportsColorTemperature => HasSupport("set_ct_abx"); + + private bool HasSupport(string method) + { + foreach (var s in Support) + if (string.Equals(s, method, System.StringComparison.OrdinalIgnoreCase)) + return true; + return false; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDevice.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDevice.cs new file mode 100644 index 00000000..baeaef98 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDevice.cs @@ -0,0 +1,71 @@ +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using RGB.NET.Core; +using System.Threading.Tasks; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + public class YeelightDevice : AbstractRGBDevice + { + // Logical LED roles for a dual-light bulb. Single-light bulbs only + // use MainLight. Stored as the LED's CustomData so the UpdateQueue + // can dispatch a paint frame to set_rgb (main) vs bg_set_rgb (bg) + // without rebuilding a per-LedId mapping table. + public enum LightChannel { MainLight, BackgroundLight } + + private readonly YeelightUpdateQueue _updateQueue; + private readonly YeelightClientDefinition _def; + + public YeelightDevice(YeelightDeviceInfo info, YeelightUpdateQueue updateQueue, YeelightClientDefinition def) + : base(info, updateQueue) + { + _updateQueue = updateQueue; + _def = def; + InitializeLayout(); + } + + public YeelightClientDefinition Definition => _def; + + public void BeginShutdown() => _updateQueue.BeginShutdown(); + public Task RestoreOriginalStateAsync() => _updateQueue.RestoreOriginalStateAsync(); + + public void SetPerDeviceDisabled(bool disabled) => _updateQueue.SetPerDeviceDisabled(disabled); + public void ResetCache() => _updateQueue.ResetCache(); + + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _updateQueue.SetPerDeviceBrightness(correction); + + // Layout decisions: + // - Single-light bulbs / strips / ceiling lights → 1 LED at Custom1 + // driving the main light element via set_rgb. + // - Dual-light bulbs (Bedside Lamp 2 and any other with bg_set_rgb + // in their SSDP support list) → 2 LEDs: Custom1 = main, Custom2 + // = background. The UpdateQueue reads each LED's CustomData to + // pick which set_rgb variant to send. + // + // Strips / matrix devices intentionally still get 1 LED — Yeelight's + // LAN protocol can't address per-zone on those, and exposing N + // synthetic LEDs that all paint to the same set_rgb would just + // surprise users into thinking they had per-LED control they + // don't have. The Mapping tab still lets them position the single + // LED however they want. + private void InitializeLayout() + { + var main = AddLed(LedId.Custom1, new Point(0, 0), new Size(80)); + if (main != null) + { + main.Shape = Shape.Circle; + main.LayoutMetadata = LightChannel.MainLight; + } + + if (_def.HasBackgroundLight) + { + var bg = AddLed(LedId.Custom2, new Point(100, 0), new Size(80)); + if (bg != null) + { + bg.Shape = Shape.Circle; + bg.LayoutMetadata = LightChannel.BackgroundLight; + } + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDeviceInfo.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDeviceInfo.cs new file mode 100644 index 00000000..496abb9f --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDeviceInfo.cs @@ -0,0 +1,23 @@ +using RGB.NET.Core; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + public class YeelightDeviceInfo : IRGBDeviceInfo + { + public YeelightDeviceInfo(YeelightClientDefinition def) + { + var product = YeelightModelCatalog.GetOrDefault(def.Model); + + DeviceName = string.IsNullOrEmpty(def.Label) ? product.DisplayName : def.Label; + Manufacturer = "Yeelight"; + Model = product.DisplayName; + DeviceType = product.DeviceType; + } + + public RGBDeviceType DeviceType { get; } + public string DeviceName { get; } + public string Manufacturer { get; } + public string Model { get; } + public object LayoutMetadata { get; set; } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDeviceUpdateTrigger.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDeviceUpdateTrigger.cs new file mode 100644 index 00000000..750b73fb --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightDeviceUpdateTrigger.cs @@ -0,0 +1,49 @@ +using RGB.NET.Core; +using System; +using System.Diagnostics; +using System.Threading; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + // 30Hz trigger with a 50ms idle wake so per-device brightness changes + // still propagate when a bulb is sitting on a static base layer + // (HasDataEvent is only signalled when RGB.NET commits a colour that + // differs from the previous frame — without the idle refresh, slider + // changes wouldn't reach the bulb until something else dirtied an LED). + // + // Same shape as LifxDeviceUpdateTrigger / QmkRawHidUpdateTrigger. + public class YeelightDeviceUpdateTrigger : DeviceUpdateTrigger + { + private const int WaitOneTimeoutMs = 50; + + public YeelightDeviceUpdateTrigger() { } + + public YeelightDeviceUpdateTrigger(double updateRateHardLimit) + : base(updateRateHardLimit) { } + + protected override void UpdateLoop() + { + OnStartup(); + + while (!UpdateToken.IsCancellationRequested) + { + if (HasDataEvent.WaitOne(WaitOneTimeoutMs)) + { + long preUpdateTicks = Stopwatch.GetTimestamp(); + OnUpdate(); + + if (UpdateFrequency > 0) + { + double elapsedMs = (Stopwatch.GetTimestamp() - preUpdateTicks) / (double)TimeSpan.TicksPerMillisecond; + int sleep = (int)(UpdateFrequency * 1000.0 - elapsedMs); + if (sleep > 0) Thread.Sleep(sleep); + } + } + else + { + OnUpdate(new CustomUpdateData(("refresh", true))); + } + } + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightModelCatalog.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightModelCatalog.cs new file mode 100644 index 00000000..0ba6c9bf --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightModelCatalog.cs @@ -0,0 +1,119 @@ +using RGB.NET.Core; +using System.Collections.Generic; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + // Maps SSDP `model` strings reported by Yeelight bulbs to a friendly + // device-type classification for the Mapping tab. Lets a Lightstrip Plus + // show up as `LedStripe`, a Bedside Lamp as `Lamp`, a regular bulb as + // `LightBulb`, etc., rather than every device falling into a single + // generic bucket. + // + // Source for model strings: https://www.yeelight.com/en_US/developer + // (the Inter-Operation Spec) plus the LAN-spec community wiki. New + // models periodically ship with new strings — when an unknown one is + // encountered we fall back to LightBulb, which is the most common form. + // + // **Single-LED constraint.** The Yeelight LAN protocol's set_rgb / + // bg_set_rgb commands paint an entire device one colour at a time — + // there's no per-zone API for light strips, gradient bulbs, or matrix + // devices. Models that have a "background light" element (Bedside Lamp + // 2, some ceiling lights) are the only exception and get two LEDs via + // HasBackgroundLight. All other multi-zone devices expose one LED. + public static class YeelightModelCatalog + { + public sealed class ProductInfo + { + public string Model { get; } + public string DisplayName { get; } + public RGBDeviceType DeviceType { get; } + + public ProductInfo(string model, string displayName, RGBDeviceType deviceType) + { + Model = model; + DisplayName = displayName; + DeviceType = deviceType; + } + } + + // Entries keyed by lowercased model string. The Yeelight firmware + // is consistent on case but we lowercase the input before lookup + // to be defensive. + private static readonly Dictionary _byModel = new() + { + // RGB bulbs + ["color"] = new("color", "Color Bulb", RGBDeviceType.LedController), + ["color1"] = new("color1", "Color Bulb 1", RGBDeviceType.LedController), + ["color2"] = new("color2", "Color Bulb 2", RGBDeviceType.LedController), + ["color3"] = new("color3", "Color Bulb 3", RGBDeviceType.LedController), + ["color4"] = new("color4", "Color Bulb 4", RGBDeviceType.LedController), + ["color5"] = new("color5", "Color Bulb 5", RGBDeviceType.LedController), + ["color6"] = new("color6", "Smart LED Bulb 1S", RGBDeviceType.LedController), + ["colorc"] = new("colorc", "Color Bulb Pro", RGBDeviceType.LedController), + ["colora"] = new("colora", "Smart LED Bulb W3", RGBDeviceType.LedController), + ["colorb"] = new("colorb", "Smart LED Bulb", RGBDeviceType.LedController), + + // White-only / colour-temperature bulbs + ["mono"] = new("mono", "White Bulb", RGBDeviceType.LedController), + ["mono1"] = new("mono1", "White Bulb 1", RGBDeviceType.LedController), + ["mono4"] = new("mono4", "White Bulb 4", RGBDeviceType.LedController), + ["mono5"] = new("mono5", "White Bulb 5", RGBDeviceType.LedController), + ["mono6"] = new("mono6", "White Bulb 6", RGBDeviceType.LedController), + ["ct_bulb"] = new("ct_bulb", "Tunable White Bulb", RGBDeviceType.LedController), + ["ct2"] = new("ct2", "Tunable White Bulb 2", RGBDeviceType.LedController), + + // Light strips + ["stripe"] = new("stripe", "Light Strip", RGBDeviceType.LedStripe), + ["strip1"] = new("strip1", "Light Strip 1", RGBDeviceType.LedStripe), + ["strip2"] = new("strip2", "Light Strip 2", RGBDeviceType.LedStripe), + ["strip4"] = new("strip4", "Light Strip 4 (Pro)", RGBDeviceType.LedStripe), + ["strip6"] = new("strip6", "Light Strip 6", RGBDeviceType.LedStripe), + ["strip8"] = new("strip8", "Light Strip 8", RGBDeviceType.LedStripe), + + // Bedside / ambient lamps + ["bslamp"] = new("bslamp", "Bedside Lamp", RGBDeviceType.LedController), + ["bslamp1"] = new("bslamp1", "Bedside Lamp 1", RGBDeviceType.LedController), + ["bslamp2"] = new("bslamp2", "Bedside Lamp 2", RGBDeviceType.LedController), + ["bslamp3"] = new("bslamp3", "Bedside Lamp 3", RGBDeviceType.LedController), + ["lamp"] = new("lamp", "Lamp", RGBDeviceType.LedController), + ["lamp1"] = new("lamp1", "Lamp 1", RGBDeviceType.LedController), + ["lamp15"] = new("lamp15", "Smart Lamp", RGBDeviceType.LedController), + + // Ceiling lights — single-colour from the LAN protocol's perspective + ["ceiling"] = new("ceiling", "Ceiling Light", RGBDeviceType.LedController), + ["ceiling1"] = new("ceiling1", "Ceiling Light 1", RGBDeviceType.LedController), + ["ceiling2"] = new("ceiling2", "Ceiling Light 2", RGBDeviceType.LedController), + ["ceiling3"] = new("ceiling3", "Ceiling Light 3", RGBDeviceType.LedController), + ["ceiling4"] = new("ceiling4", "Ceiling Light 4", RGBDeviceType.LedController), + ["ceiling10"] = new("ceiling10", "Ceiling Light 10", RGBDeviceType.LedController), + ["ceiling11"] = new("ceiling11", "Ceiling Light 11", RGBDeviceType.LedController), + ["ceiling13"] = new("ceiling13", "Ceiling Light 13", RGBDeviceType.LedController), + ["ceiling15"] = new("ceiling15", "Ceiling Light 15", RGBDeviceType.LedController), + ["ceiling18"] = new("ceiling18", "Ceiling Light 18", RGBDeviceType.LedController), + ["ceiling19"] = new("ceiling19", "Ceiling Light 19", RGBDeviceType.LedController), + ["ceiling20"] = new("ceiling20", "Ceiling Light 20", RGBDeviceType.LedController), + ["ceiling22"] = new("ceiling22", "Ceiling Light 22", RGBDeviceType.LedController), + + // Monitor / desk bars + ["mlight"] = new("mlight", "Monitor Light Bar", RGBDeviceType.LedStripe), + ["mlight2"] = new("mlight2", "Monitor Light Bar Pro", RGBDeviceType.LedStripe), + + // Cube / matrix + ["cube"] = new("cube", "Cube Light", RGBDeviceType.LedMatrix), + ["cube1"] = new("cube1", "Cube Light 1", RGBDeviceType.LedMatrix), + }; + + // Look up a model. Unknown models fall back to a generic LightBulb + // entry — Yeelight ships new bulbs faster than we can catalog them + // and the LAN protocol behaviour is consistent across the line. + public static ProductInfo GetOrDefault(string model) + { + if (string.IsNullOrWhiteSpace(model)) + return new ProductInfo("", "Yeelight bulb", RGBDeviceType.LedController); + + string key = model.Trim().ToLowerInvariant(); + if (_byModel.TryGetValue(key, out var info)) return info; + return new ProductInfo(model, $"Yeelight {model}", RGBDeviceType.LedController); + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightRGBDeviceProvider.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightRGBDeviceProvider.cs new file mode 100644 index 00000000..c0249e21 --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightRGBDeviceProvider.cs @@ -0,0 +1,206 @@ +using Chromatics.Core; +using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.Devices.Yeelight.Protocol; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + public class YeelightRGBDeviceProvider : AbstractRGBDeviceProvider + { + #region Singleton + + private static YeelightRGBDeviceProvider _instance; + public static YeelightRGBDeviceProvider Instance => _instance ?? new YeelightRGBDeviceProvider(); + + public YeelightRGBDeviceProvider() + { + if (_instance != null) Throw(new Exception($"There can be only one instance of type {nameof(YeelightRGBDeviceProvider)}")); + _instance = this; + } + + #endregion + + // Bulbs the user has chosen to control. Hydrated from settings by + // RGBController.Setup before LoadDeviceProvider runs; cleared on + // Dispose so the next enable cycle can re-prompt with a fresh + // discovery sweep. + public List ClientDefinitions { get; } = new(); + + // Discovery sweep timeout when no last-known endpoints are stored. + // Yeelight bulbs respond within ~500ms typically; 2.5s gives slow + // responders headroom on busy networks. + private static readonly TimeSpan DiscoverySweepTimeout = TimeSpan.FromMilliseconds(2500); + + private readonly Dictionary _openConnections = new(); + + protected override void InitializeSDK() + { + // Yeelight LAN is a plain socket protocol — no SDK init required. + // Connection establishment happens per-bulb in LoadDevices. + } + + protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) + { + // 30Hz upper bound. Yeelight bulbs accept up to ~60Hz over Music + // Mode in practice, but going above 30 doesn't translate to a + // perceptible improvement and bumps lighter bulbs (Color 1S) + // closer to thermal cutoff during long colour-cycling layers. + return new YeelightDeviceUpdateTrigger(1.0 / 30.0); + } + + protected override IEnumerable LoadDevices() + { + return LoadDevicesAsync().GetAwaiter().GetResult(); + } + + private async Task> LoadDevicesAsync() + { + var devices = new List(); + if (ClientDefinitions.Count == 0) return devices; + + // Re-discover up-front so DHCP renewals don't strand us on a + // stale IP. Bulbs reply with their Id, which is stable across + // IP changes; we overlay the freshly-discovered endpoint onto + // the existing definitions for any id we recognise. + var resolved = await ResolveEndpointsAsync(ClientDefinitions, DiscoverySweepTimeout).ConfigureAwait(false); + foreach (var def in ClientDefinitions) + { + if (resolved.TryGetValue(def.Id, out var ep)) + def.Endpoint = ep; + } + + foreach (var def in ClientDefinitions) + { + if (def.Endpoint == null) + { + Logger.WriteConsole(LoggerTypes.Devices, + $"[Yeelight] {def.Label}: not reachable on the network — skipping. Will retry on next enable."); + continue; + } + + try + { + var connection = new YeelightConnection(def.Endpoint); + await connection.ConnectAsync(TimeSpan.FromSeconds(3)).ConfigureAwait(false); + + // Try Music Mode. If the bulb supports it and our reverse + // TCP is reachable from the bulb's network position, + // we'll be uncapped on send rate. Falls back to outbound + // (with the per-minute rate cap silently enforced by + // the bulb) when Music Mode setup fails. + if (def.SupportsMusicMode) + { + var localIp = ResolveLocalIpReachableTo(def.Endpoint.Address); + if (localIp != null) + { + bool ok = await connection.EnterMusicModeAsync(localIp, TimeSpan.FromMilliseconds(1500)).ConfigureAwait(false); + if (!ok) + { + Logger.WriteConsole(LoggerTypes.Devices, + $"[Yeelight] {def.Label}: Music Mode handshake failed (firewall blocking reverse TCP?); falling back to outbound (rate-capped).", + forwardToSentry: false); + } + } + } + + var trigger = (YeelightDeviceUpdateTrigger)GetUpdateTrigger(); + var queue = new YeelightUpdateQueue(trigger, def, connection); + var info = new YeelightDeviceInfo(def); + var dev = new YeelightDevice(info, queue, def); + + // Honour per-device disable from a prior session before + // the surface attaches. Same race window as LIFX/Hue: + // surface.Load attaches every device unconditionally, + // and a frame can drain between attach and our + // post-Load detach pass. Setting the gate flag here + // closes that window. + var deviceGuid = Chromatics.Helpers.DeviceHelper.GenerateDeviceGuid(info.DeviceName); + bool disabled = Chromatics.Layers.MappingLayers.IsDeviceDisabled(deviceGuid); + if (disabled) queue.SetPerDeviceDisabled(true); + + _openConnections[dev] = connection; + devices.Add(dev); + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, + $"[Yeelight] failed to set up {def.Label}: {ex.Message}"); + } + } + + return devices; + } + + // Overlay discovery results onto the existing definitions. Bulbs are + // identified by their stable hex Id, which survives IP changes. + private async Task> ResolveEndpointsAsync(IList defs, TimeSpan timeout) + { + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var d in defs) + if (d.Endpoint != null) result[d.Id] = d.Endpoint; + + try + { + var discovered = await YeelightDiscovery.DiscoverAsync(timeout).ConfigureAwait(false); + foreach (var d in discovered) + if (!string.IsNullOrEmpty(d.Id) && d.Endpoint != null) + result[d.Id] = d.Endpoint; + } + catch (Exception ex) + { + Logger.WriteConsole(LoggerTypes.Error, $"[Yeelight] discovery sweep failed: {ex.Message}"); + } + return result; + } + + // Pick the local IP address Windows would route to the bulb. We do + // this by opening a UDP socket and asking it to "connect" to the + // bulb's address — no packets are sent, but the OS resolves the + // outbound interface and we can read its local IP. This handles + // multi-NIC machines correctly without us having to enumerate + // interfaces and guess. + private static IPAddress ResolveLocalIpReachableTo(IPAddress remote) + { + try + { + using var probe = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + probe.Connect(remote, 55443); + if (probe.LocalEndPoint is IPEndPoint ep) + return ep.Address; + } + catch { /* no reachable interface — caller falls back to no-music-mode */ } + return null; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + try + { + var devices = Devices.OfType().ToList(); + foreach (var d in devices) d.BeginShutdown(); + } + catch { /* swallow during teardown */ } + + foreach (var conn in _openConnections.Values) + { + try { conn.Dispose(); } catch { /* ignore */ } + } + _openConnections.Clear(); + ClientDefinitions.Clear(); + } + + base.Dispose(disposing); + + if (ReferenceEquals(_instance, this)) + _instance = null; + } + } +} diff --git a/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightUpdateQueue.cs b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightUpdateQueue.cs new file mode 100644 index 00000000..b0283c9c --- /dev/null +++ b/Chromatics/Extensions/RGB.NET/Devices/Yeelight/YeelightUpdateQueue.cs @@ -0,0 +1,253 @@ +using Chromatics.Core; +using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.ColorCorrections; +using Chromatics.Extensions.RGB.NET.Devices.Yeelight.Protocol; +using RGB.NET.Core; +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Color = RGB.NET.Core.Color; + +namespace Chromatics.Extensions.RGB.NET.Devices.Yeelight +{ + public class YeelightUpdateQueue : UpdateQueue + { + #region Properties & Fields + + private readonly YeelightClientDefinition _def; + private readonly YeelightConnection _connection; + private readonly Lock _lock = new(); + + private volatile bool _shuttingDown; + // Per-device disable gate — parity with LifxUpdateQueue. Toggled + // from RGBController.RemoveDevice / AddDevice so paint frames are + // dropped while the user has the bulb disabled in the Mapping tab. + private volatile bool _perDeviceDisable; + + private PerDeviceBrightnessCorrection _perDeviceBrightness; + + // Throttle: Yeelight LAN protocol caps outbound commands at 60 per + // minute per bulb (1Hz). Music Mode removes the cap and lets us + // send at any rate. Either way 35ms (28Hz) is a sensible upper + // bound — faster doesn't translate to perceptible improvement, + // and on the non-music path it'd burn the per-minute budget in + // seconds. + private const int MinIntervalMs = 35; + private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); + private long _lastSendMs; + + // Same-frame dedup so a static layer doesn't pelt the bulb with + // identical set_rgb commands. Per-channel because main and bg + // are independent destinations. + private uint _lastSentRgbMain = uint.MaxValue; + private int _lastSentBrightnessMain = -1; + private uint _lastSentRgbBg = uint.MaxValue; + private int _lastSentBrightnessBg = -1; + private long _lastKeepAliveMs; + + // Yeelight bulbs auto-power-off if they don't receive a command for + // ~5 minutes when in Music Mode. Send a no-op keep-alive every 60s + // (set_rgb to the cached value) to keep them awake on slow-changing + // layers like Static. + private const int KeepAliveIntervalMs = 60_000; + + #endregion + + #region Constructors + + public YeelightUpdateQueue(IDeviceUpdateTrigger updateTrigger, YeelightClientDefinition def, YeelightConnection connection) + : base(updateTrigger) + { + _def = def; + _connection = connection; + } + + #endregion + + #region Methods + + public void BeginShutdown() => _shuttingDown = true; + + public void SetPerDeviceDisabled(bool disabled) => _perDeviceDisable = disabled; + + public void ResetCache() + { + lock (_lock) + { + _lastSentRgbMain = uint.MaxValue; + _lastSentBrightnessMain = -1; + _lastSentRgbBg = uint.MaxValue; + _lastSentBrightnessBg = -1; + _lastKeepAliveMs = 0; + } + } + + public void SetPerDeviceBrightness(PerDeviceBrightnessCorrection correction) + => _perDeviceBrightness = correction; + + // Best-effort restore on disable. Yeelight doesn't have a clean + // "original state" capture path the way LIFX does (the LAN protocol + // exposes `get_prop` but parsing the response requires a read pump + // we don't otherwise need), so for the v1 Beta we just stop + // sending. The bulb stays on whatever colour Chromatics last set. + // Users can re-establish their preferred state via the Yeelight + // app. Tracked as a 4.2.x patch follow-up. + public Task RestoreOriginalStateAsync() => Task.CompletedTask; + + protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet) + { + lock (_lock) + { + if (_shuttingDown || _perDeviceDisable) return true; + if (dataSet.IsEmpty) return true; + + long now = _stopwatch.ElapsedMilliseconds; + if (now - _lastSendMs < MinIntervalMs) return true; + + try + { + int globalPct = GlobalBrightnessCorrection.Instance.BrightnessPercent; + int perDevicePct = _perDeviceBrightness?.BrightnessPercent ?? 100; + double brightnessScale = (globalPct / 100.0) * (perDevicePct / 100.0); + + // Split the data set into main vs background based on + // each LED's LayoutMetadata. Single-light bulbs only + // ever have main entries. The brightest LED in each + // bucket wins (PickRepresentativeColor) so multiple + // Chromatics LEDs mapped to the same channel still + // produce one sensible colour per channel. + Color? mainColor = null; + Color? bgColor = null; + PickPerChannelColors(dataSet, ref mainColor, ref bgColor); + + bool sentSomething = false; + + if (mainColor.HasValue) + { + SendChannel(mainColor.Value, brightnessScale, + isBackground: false, + ref _lastSentRgbMain, ref _lastSentBrightnessMain, + out bool sentMain); + sentSomething |= sentMain; + } + if (bgColor.HasValue) + { + SendChannel(bgColor.Value, brightnessScale, + isBackground: true, + ref _lastSentRgbBg, ref _lastSentBrightnessBg, + out bool sentBg); + sentSomething |= sentBg; + } + + if (sentSomething) + { + _lastSendMs = now; + _lastKeepAliveMs = now; + } + else if (now - _lastKeepAliveMs >= KeepAliveIntervalMs) + { + // Nothing changed but we need to keep the bulb awake. + // Re-send the cached main RGB. Cheaper than get_prop + // and equivalent for the firmware's idle-shutoff + // timer. + _lastKeepAliveMs = now; + if (_lastSentRgbMain != uint.MaxValue) + { + byte r = (byte)((_lastSentRgbMain >> 16) & 0xFF); + byte g = (byte)((_lastSentRgbMain >> 8) & 0xFF); + byte b = (byte)(_lastSentRgbMain & 0xFF); + _ = _connection.SetRgbAsync(r, g, b); + } + } + return true; + } + catch (Exception ex) + { + YeelightRGBDeviceProvider.Instance?.Throw(ex); + return false; + } + } + } + + // Split the data set into a main-channel and bg-channel representative + // colour. Brightest LED in each bucket wins so multiple Chromatics + // LEDs mapped to one channel still produce a sensible single value. + // Updates `mainColor` and `bgColor` by reference; either or both may + // remain null if the corresponding bucket was empty. + private static void PickPerChannelColors( + ReadOnlySpan<(object key, Color color)> dataSet, + ref Color? mainColor, ref Color? bgColor) + { + double bestMainL = -1; + double bestBgL = -1; + for (int i = 0; i < dataSet.Length; i++) + { + var entry = dataSet[i]; + double l = entry.color.R + entry.color.G + entry.color.B; + + // The key is whatever object the surface bound this entry to. + // For RGB.NET devices that's the Led — its LayoutMetadata + // carries our YeelightDevice.LightChannel role enum. + var channel = ResolveChannel(entry.key); + if (channel == YeelightDevice.LightChannel.BackgroundLight) + { + if (l > bestBgL) { bestBgL = l; bgColor = entry.color; } + } + else + { + if (l > bestMainL) { bestMainL = l; mainColor = entry.color; } + } + } + } + + private static YeelightDevice.LightChannel ResolveChannel(object key) + { + // Surface uses the Led instance as the key; LayoutMetadata is + // the channel enum we stamped in YeelightDevice.InitializeLayout. + if (key is Led led && led.LayoutMetadata is YeelightDevice.LightChannel c) + return c; + return YeelightDevice.LightChannel.MainLight; + } + + // Send one channel (main or bg). Returns through `sent` whether any + // network traffic actually fired; caller uses this for the keep-alive + // and lastSendMs bookkeeping. + private void SendChannel(Color color, double brightnessScale, bool isBackground, + ref uint lastSentRgb, ref int lastSentBrightness, out bool sent) + { + ToRgb255(color, brightnessScale, out byte r, out byte g, out byte b); + uint packed = (uint)((r << 16) | (g << 8) | b); + int brightnessPct = Math.Max(1, (int)(Math.Max(r, Math.Max(g, b)) * 100.0 / 255.0)); + + bool changedRgb = packed != lastSentRgb; + bool changedBright = brightnessPct != lastSentBrightness; + sent = false; + + if (changedRgb) + { + if (isBackground) _ = _connection.SetBackgroundRgbAsync(r, g, b); + else _ = _connection.SetRgbAsync(r, g, b); + lastSentRgb = packed; + sent = true; + } + if (changedBright) + { + if (isBackground) _ = _connection.SetBackgroundBrightnessAsync(brightnessPct); + else _ = _connection.SetBrightnessAsync(brightnessPct); + lastSentBrightness = brightnessPct; + sent = true; + } + } + + private static void ToRgb255(Color rgb, double brightnessScale, out byte r, out byte g, out byte b) + { + double scale = Math.Clamp(brightnessScale, 0.0, 1.0); + r = (byte)Math.Round(Math.Clamp(rgb.R, 0.0, 1.0) * 255 * scale); + g = (byte)Math.Round(Math.Clamp(rgb.G, 0.0, 1.0) * 255 * scale); + b = (byte)Math.Round(Math.Clamp(rgb.B, 0.0, 1.0) * 255 * scale); + } + + #endregion + } +} diff --git a/Chromatics/Helpers/DefaultLayoutInference.cs b/Chromatics/Helpers/DefaultLayoutInference.cs new file mode 100644 index 00000000..0930ed07 --- /dev/null +++ b/Chromatics/Helpers/DefaultLayoutInference.cs @@ -0,0 +1,84 @@ +using Chromatics.Localization; +using RGB.NET.Core; +using System.Linq; + +namespace Chromatics.Helpers +{ + // Synthesise LEDs for devices that arrive from their RGB.NET provider with + // an empty LED set. The Chromatics surface needs at least one Led per + // device for any layer to paint anything, so without this fixup a 0-LED + // device shows up in the Mappings tab but can't be addressed. + // + // Replaces the legacy `Layouts/Default/Keyboard/*.xml` + + // `Layouts/Default/Headset/*.xml` fallback that loaded an Artemis-shaped + // default layout via RGB.NET.Layout. Those XMLs ship with the archived + // RGB.NET-Resources repo and aren't being maintained — and the headset + // path was already broken (the code pointed at `.../Keyboard/Artemis 4 + // LEDs headset.xml`, the file lives under `.../Headset/`). Deriving the + // layout algorithmically from KeyLocalization's QWERTY grid removes the + // dependency on the archived data while also fixing the headset path. + // + // Only the topological layout matters here — every decorator that reads + // Led.Location does so relative to other LEDs on the same device. + // CellSize=19 mirrors RGB.NET's own LogitechPerKeyRGBDevice spacing so + // synthesised devices behave the same way as real Logitech per-key + // boards after LogitechLayoutFixup applies. + public static class DefaultLayoutInference + { + private const float CellSize = 19f; + + /// + /// If the device has zero LEDs and is a supported type, populate it + /// with a synthetic LED grid so decorators have something to paint. + /// No-op for devices that already have LEDs or for unsupported types. + /// + public static void Apply(IRGBDevice device) + { + if (device == null) return; + if (device.Count() > 0) return; + + switch (device.DeviceInfo.DeviceType) + { + case RGBDeviceType.Keyboard: + ApplyKeyboard(device); + break; + case RGBDeviceType.Headset: + ApplyHeadset(device); + break; + } + } + + private static void ApplyKeyboard(IRGBDevice device) + { + // Same grid LogitechLayoutFixup uses — full ANSI 104 set of + // Keyboard_* LedIds with [row, col] coordinates. + var grid = KeyLocalization.QWERTY_Grid; + int maxRow = 0; + int maxCol = 0; + foreach (var kvp in grid) + { + int row = kvp.Value[0]; + int col = kvp.Value[1]; + device.AddLed(kvp.Key, new Point(col * CellSize, row * CellSize), new Size(CellSize, CellSize)); + if (row > maxRow) maxRow = row; + if (col > maxCol) maxCol = col; + } + device.Size = new Size((maxCol + 1) * CellSize, (maxRow + 1) * CellSize); + } + + private static void ApplyHeadset(IRGBDevice device) + { + // 2x2 grid: left ear top/bottom, right ear top/bottom. Mirrors the + // count and topology of the legacy Artemis 4-LED headset XML. The + // exact spacing doesn't matter — DeviceGridHelper's third-tier + // fallback normalises whatever positions we set into a row/col + // grid for decorators. + const float earGap = CellSize * 6f; + device.AddLed(LedId.Headset1, new Point(0, 0), new Size(CellSize, CellSize)); + device.AddLed(LedId.Headset2, new Point(0, CellSize), new Size(CellSize, CellSize)); + device.AddLed(LedId.Headset3, new Point(earGap, 0), new Size(CellSize, CellSize)); + device.AddLed(LedId.Headset4, new Point(earGap, CellSize), new Size(CellSize, CellSize)); + device.Size = new Size(earGap + CellSize, CellSize * 2f); + } + } +} diff --git a/Chromatics/Helpers/LayerCopier.cs b/Chromatics/Helpers/LayerCopier.cs new file mode 100644 index 00000000..49665091 --- /dev/null +++ b/Chromatics/Helpers/LayerCopier.cs @@ -0,0 +1,200 @@ +using Chromatics.Enums; +using Chromatics.Layers; +using Chromatics.Models; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Chromatics.Helpers +{ + // Layer-by-layer copy from one device to another. + // + // Caller builds a list of LayerCopyPlan entries from the dialog + // (one per source layer the user ticked, plus the per-LedId + // mapping for any Dynamic layers) and hands it to Apply. The + // engine handles Base/Effect uniqueness automatically — if the + // destination already has a Base or Effect layer, the existing + // one is removed before the new one is added, so the user + // doesn't end up with two of either. + // + // For Dynamic layers, multiple instances are allowed; the new + // layer is appended without touching anything pre-existing on + // the destination. + public static class LayerCopier + { + // Returns true iff this device pair is a legal copy target. + // Keyboards can only copy to keyboards — the consistent + // ANSI 104 layout across vendors lets per-key mappings + // project meaningfully. Other device types can cross-copy + // freely (mouse → headset, chassis → strip). + public static bool IsCopyAllowed(RGBDeviceType source, RGBDeviceType dest) + { + bool srcKb = source == RGBDeviceType.Keyboard; + bool dstKb = dest == RGBDeviceType.Keyboard; + if (srcKb != dstKb) return false; + return true; + } + + // Default LedId mapping for a SINGLE layer being copied. Only + // computes entries for LedIds in `usedSourceLedIds` — the set + // of LedIds the source layer actually paints. Keeps the per- + // layer mapping UI focused on the keys that matter for that + // specific layer rather than the entire source device. + public static Dictionary ComputeDefaultMappingForLayer( + IReadOnlyCollection usedSourceLedIds, + IRGBDevice source, + IRGBDevice dest) + { + var map = new Dictionary(); + if (usedSourceLedIds == null || source == null || dest == null) return map; + if (usedSourceLedIds.Count == 0) return map; + + bool keyboardPair = source.DeviceInfo.DeviceType == RGBDeviceType.Keyboard + && dest.DeviceInfo.DeviceType == RGBDeviceType.Keyboard; + + var destLeds = dest.OrderBy(l => (int)l.Id).ToList(); + var destIds = new HashSet(destLeds.Select(l => l.Id)); + + if (keyboardPair) + { + // Identity match by LedId for keyboard-pair copies. + foreach (var ledId in usedSourceLedIds) + if (destIds.Contains(ledId)) + map[ledId] = ledId; + return map; + } + + // Non-keyboard pair (same type or cross-type): exact match + // first; positional fallback otherwise (Nth LED in source + // ordering → Nth LED in dest ordering). + var sourceLeds = source.OrderBy(l => (int)l.Id).ToList(); + int n = Math.Min(sourceLeds.Count, destLeds.Count); + var positionalFallback = new Dictionary(); + for (int i = 0; i < n; i++) + positionalFallback[sourceLeds[i].Id] = destLeds[i].Id; + + foreach (var ledId in usedSourceLedIds) + { + if (destIds.Contains(ledId)) + map[ledId] = ledId; + else if (positionalFallback.TryGetValue(ledId, out var fallback)) + map[ledId] = fallback; + } + return map; + } + + // One copy operation. The view-model passes a list of these + // into Apply; each represents "copy this source layer onto + // the destination with this LedId mapping". + public sealed class LayerCopyPlan + { + public Layer SourceLayer { get; init; } + + // Source LedId → destination LedId. Entries missing for + // an LedId in the source layer's deviceLeds drop that + // LedId during copy (the destination layer simply + // doesn't cover it). + public IReadOnlyDictionary Mapping { get; init; } = new Dictionary(); + } + + public sealed class CopyResult + { + public int LayersAdded { get; init; } + public int LayersReplaced { get; init; } + public int LedMappingsDropped { get; init; } + } + + // True when the destination already has a layer of the + // given root type (Base or Effect). Dialog uses this to + // decide whether to show the "will replace existing" + // warning per-row. + public static bool DestinationAlreadyHasLayerOfType(Guid destGuid, LayerType rootLayerType) + { + if (destGuid == Guid.Empty) return false; + if (rootLayerType != LayerType.BaseLayer && rootLayerType != LayerType.EffectLayer) return false; + return MappingLayers.GetLayers().Values + .Any(l => l.deviceGuid == destGuid && l.rootLayerType == rootLayerType); + } + + public static CopyResult Apply( + Guid sourceGuid, + Guid destGuid, + RGBDeviceType destDeviceType, + IReadOnlyList plans) + { + if (sourceGuid == Guid.Empty || destGuid == Guid.Empty || sourceGuid == destGuid) + return new CopyResult(); + if (plans == null || plans.Count == 0) + return new CopyResult(); + + int added = 0; + int replaced = 0; + int dropped = 0; + + foreach (var plan in plans) + { + var src = plan.SourceLayer; + if (src == null) continue; + var mapping = plan.Mapping ?? new Dictionary(); + + // Base / Effect: at most one per device. Remove the + // existing one on dest (if any) before adding the + // copy. + bool isStructural = src.rootLayerType == LayerType.BaseLayer + || src.rootLayerType == LayerType.EffectLayer; + if (isStructural) + { + var existing = MappingLayers.GetLayers().Values + .Where(l => l.deviceGuid == destGuid && l.rootLayerType == src.rootLayerType) + .Select(l => l.layerID) + .ToList(); + foreach (var existingId in existing) + MappingLayers.RemoveLayer(existingId); + if (existing.Count > 0) replaced++; + else added++; + } + else + { + added++; + } + + // Remap deviceLeds: drop entries whose source LedId + // has no mapping; otherwise translate to the dest + // LedId. + var remapped = new Dictionary(); + if (src.deviceLeds != null) + { + foreach (var (positionIndex, sourceLedId) in src.deviceLeds) + { + if (mapping.TryGetValue(sourceLedId, out var destLedId)) + remapped[positionIndex] = destLedId; + else + dropped++; + } + } + + int newIndex = MappingLayers.GetLayers().Count; + MappingLayers.AddLayer( + index: newIndex, + rootLayerType: src.rootLayerType, + deviceGuid: destGuid, + deviceType: destDeviceType, + layerTypeIndex: src.layerTypeindex, + zindex: src.zindex, + enabled: src.Enabled, + deviceLeds: remapped, + allowBleed: src.allowBleed, + layerModes: src.layerModes); + } + + MappingLayers.SaveMappings(); + return new CopyResult + { + LayersAdded = added, + LayersReplaced = replaced, + LedMappingsDropped = dropped, + }; + } + } +} diff --git a/Chromatics/Helpers/LogitechLayoutFixup.cs b/Chromatics/Helpers/LogitechLayoutFixup.cs new file mode 100644 index 00000000..c6c231f0 --- /dev/null +++ b/Chromatics/Helpers/LogitechLayoutFixup.cs @@ -0,0 +1,83 @@ +using Chromatics.Localization; +using RGB.NET.Core; +using System; + +namespace Chromatics.Helpers +{ + // Rebind Led.Location for Logitech devices so position-aware decorators + // (conical gradients, radial pulses, anything reading Led.Location.Y) work + // correctly. + // + // Background: + // RGB.NET's LogitechPerKeyRGBDevice.InitializeLayout ships every LED as + // `new Point(pos++ * 19, 0)` — a flat single-row layout at Y=0 — with + // the comment "// TODO: ... they would need to be separated". The + // Logitech Lighting SDK has no API for "where is the F1 key?", so the + // provider has nothing to query and just lays LEDs out left-to-right. + // Conical gradients then collapse via atan2(0, dx) → left half / right + // half fade. + // + // Other providers (Razer, Corsair, etc.) read per-key positions + // directly from their vendor SDK and don't need this fixup. + // + // Historically RGB.NET shipped per-board layout XMLs for Logitech via + // the RGB.NET-Resources repo, but that repo is archived and isn't + // being maintained for new boards. Rather than depend on those XMLs + // we derive the layout algorithmically from KeyLocalization's QWERTY + // grid — which we already maintain for keyboard-localization purposes + // and which already encodes (row, col) per LedId for the entire ANSI + // 104. The only thing we need to invent is a cell size; multiplying + // the grid coordinates by that yields a topologically correct layout + // (F-row above number-row above QWERTY-row above ...), which is all + // the position-aware decorators care about. + // + // Trade-off versus the XML approach: we lose pixel-perfect + // per-keyboard accuracy (G513 vs G915 keycap offsets are slightly + // different in reality), and any non-keyboard LedIds (G-keys, media + // keys, mouse / headset LEDs) keep RGB.NET's default Y=0 because + // they're absent from the QWERTY grid. Acceptable trade — the + // alternative was either freezing on archived layout files or + // re-curating them ourselves. + public static class LogitechLayoutFixup + { + // Standard keycap pitch in arbitrary units. Anything > 0 works for + // the decorators (only ratios matter, not absolute scale); 19 mirrors + // the value RGB.NET's own LogitechPerKeyRGBDevice uses so existing + // decorator tunings (which assume a roughly 1u-per-key spacing in + // RGB.NET-default coordinates) keep behaving the same way. + private const float CellSize = 19f; + + /// + /// Derive Led.Location for a Logitech device from the standard QWERTY + /// grid so position-aware decorators (conical gradients, radial + /// pulses) render correctly. No-op for non-Logitech devices. + /// + public static void Apply(IRGBDevice device, string appDirectory = null, bool? ansi = null) + { + // appDirectory and ansi are kept on the signature for source + // compatibility with the previous XML-loading version — the + // grid-derived approach doesn't need either. + _ = appDirectory; _ = ansi; + + if (device == null) return; + if (!string.Equals(device.DeviceInfo?.Manufacturer, "Logitech", StringComparison.OrdinalIgnoreCase)) + return; + + // Mice, headsets, and speakers don't have a keyboard-grid analogue + // and aren't a target for radial / conical decorators in practice. + // Leaving them on RGB.NET's defaults keeps this method conservative. + if (device.DeviceInfo.DeviceType != RGBDeviceType.Keyboard) return; + + var grid = KeyLocalization.QWERTY_Grid; + foreach (Led led in device) + { + if (!grid.TryGetValue(led.Id, out int[] pos)) continue; + // grid stores [row, col]; physical x increases with col and + // physical y increases with row. CellSize is the spacing + // between adjacent keys. + led.Location = new Point(pos[1] * CellSize, pos[0] * CellSize); + led.Size = new Size(CellSize, CellSize); + } + } + } +} diff --git a/Chromatics/Models/SettingsModel.cs b/Chromatics/Models/SettingsModel.cs index 9e65b4d8..785fcb0d 100644 --- a/Chromatics/Models/SettingsModel.cs +++ b/Chromatics/Models/SettingsModel.cs @@ -1,4 +1,9 @@ using Chromatics.Enums; +using Chromatics.Extensions.RGB.NET.Devices.Alienware; +using Chromatics.Extensions.RGB.NET.Devices.Hue; +using Chromatics.Extensions.RGB.NET.Devices.LIFX; +using Chromatics.Extensions.RGB.NET.Devices.QmkRawHid; +using Chromatics.Extensions.RGB.NET.Devices.Yeelight; using System; using System.Collections.Generic; using System.Linq; @@ -49,6 +54,23 @@ public class SettingsModel public bool deviceLifxEnabled { get; set; } = false; public List deviceLifxAdoptedDevices { get; set; } = new(); public List deviceHueAdoptedDevices { get; set; } = new(); + public bool deviceQmkRawHidEnabled { get; set; } = false; + public List deviceQmkRawHidAdoptedDevices { get; set; } = new(); + public bool deviceYeelightEnabled { get; set; } = false; + public List deviceYeelightAdoptedDevices { get; set; } = new(); + public bool deviceAlienwareEnabled { get; set; } = false; + public List deviceAlienwareAdoptedDevices { get; set; } = new(); + public bool deviceDynamicLightingEnabled { get; set; } = false; + public bool dynamicLightingHintShown { get; set; } = false; + // Default: false (bypass off, conservative dedup is on). + // Dynamic Lighting silently skips devices that a Chromatics + // vendor provider could also drive — the vendor SDK retains + // exclusive control of overlapping hardware. Users who want + // Dynamic Lighting to claim every device Windows enumerates + // (and are willing to accept the risk of two providers writing + // to the same device simultaneously) can tick this in + // Settings -> Advanced to opt out of the dedup behaviour. + public bool dynamicLightingBypassConflictCheck { get; set; } = false; public string deviceHueBridgeIP { get; set; } = "127.0.0.1"; public string deviceHueBridgeClientKey { get; set; } = ""; public double deviceHueBridgeBrightness { get; set; } = -1; diff --git a/Chromatics/Program.cs b/Chromatics/Program.cs index 3e8d9a4a..2bc79a73 100644 --- a/Chromatics/Program.cs +++ b/Chromatics/Program.cs @@ -44,7 +44,18 @@ static void Main(string[] args) // that UpdateService depends on, so this must run even under a // debugger. Lifecycle args are never passed during debug sessions, // so Run() just registers the locator and returns cleanly. - VelopackApp.Build().Run(); + // + // OnBeforeUninstallFastCallback removes the Dynamic Lighting sparse + // package registration before Velopack kills the process, so the + // app stops appearing in Settings → Personalization → Dynamic + // Lighting → Background light control after uninstall. + VelopackApp.Build() + .OnBeforeUninstallFastCallback(_ => + { + if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)) + SparsePackageRegistrar.Deregister(); + }) + .Run(); if (!ThereCanOnlyBeOne()) { @@ -109,6 +120,16 @@ static void Main(string[] args) RunExpansionMigrationIfNeeded(appSettings); AppSettings.SaveSettings(appSettings); + // Re-register the Dynamic Lighting sparse package on startup if the + // user already had the DL provider enabled. Catches the upgrade + // path: a new Chromatics version ships a new sparse-package version, + // so the OS-side registration needs to be refreshed to match. + // Initial registration on first enable is driven from the Settings + // toggle (see SettingsViewModel); this is just the keep-in-sync + // pass on subsequent launches. + if (appSettings.deviceDynamicLightingEnabled && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)) + SparsePackageRegistrar.EnsureRegistered(); + try { BuildAvaloniaApp() diff --git a/Chromatics/Resources/SparsePackage/AppxManifest.xml b/Chromatics/Resources/SparsePackage/AppxManifest.xml new file mode 100644 index 00000000..e4e070e1 --- /dev/null +++ b/Chromatics/Resources/SparsePackage/AppxManifest.xml @@ -0,0 +1,74 @@ + + + + + + + + Chromatics + logicallysynced + Square150x150Logo.png + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Chromatics/Resources/SparsePackage/Public/.keep b/Chromatics/Resources/SparsePackage/Public/.keep new file mode 100644 index 00000000..16e122da --- /dev/null +++ b/Chromatics/Resources/SparsePackage/Public/.keep @@ -0,0 +1 @@ +# Required empty folder for AppExtension PublicFolder attribute. Do not delete. diff --git a/Chromatics/Resources/SparsePackage/Square150x150Logo.png b/Chromatics/Resources/SparsePackage/Square150x150Logo.png new file mode 100644 index 00000000..86f5a4c5 Binary files /dev/null and b/Chromatics/Resources/SparsePackage/Square150x150Logo.png differ diff --git a/Chromatics/Resources/SparsePackage/Square44x44Logo.png b/Chromatics/Resources/SparsePackage/Square44x44Logo.png new file mode 100644 index 00000000..a660b76c Binary files /dev/null and b/Chromatics/Resources/SparsePackage/Square44x44Logo.png differ diff --git a/Chromatics/Resources/qmk_keymap_data.json b/Chromatics/Resources/qmk_keymap_data.json new file mode 100644 index 00000000..73844ea7 --- /dev/null +++ b/Chromatics/Resources/qmk_keymap_data.json @@ -0,0 +1 @@ +{"_count":2650,"_generated_utc":"2026-05-14T11:06:13Z","_source":"github.com/snakkarike/qmk_firmware/master","_with_labels":506,"boards":{"0001:0001":[],"0004:0002":[[0,0,"`"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"\u2298"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[8,4,"Alt"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[10,0,"0"],[10,1,"P"],[10,2,"'"],[10,3,"/"],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"Enter"],[11,3,"Shift"],[12,0,"="],[12,1,"]"],[12,4,"\u2191"],[13,0,"Insert"],[13,1,"Insert"],[13,2,"Delete"],[13,4,"\u2190"],[14,0,"Home"],[14,1,"Home"],[14,2,"End"],[14,4,"\u2193"],[15,0,"Page Up"],[15,1,"Page Up"],[15,2,"Page Down"],[15,4,"\u2192"]],"0007:0002":[],"0007:0003":[],"0007:0004":[],"0007:0007":[],"0009:0001":[],"0011:0011":[[0,0,"Esc"],[0,1,"`~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1!"],[1,2,"Q"],[1,3,"A"],[1,4,"\\|"],[1,5,"Win"],[2,0,"F2"],[2,1,"2@"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3#"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4$"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5%"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6^"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7&"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8*"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9("],[9,2,"O"],[9,3,"L"],[9,4,",<"],[10,0,"F10"],[10,1,"0)"],[10,2,"P"],[10,3,";:"],[10,4,".>"],[10,5,"Alt"],[11,0,"F11"],[11,1,"-_"],[11,2,"[{"],[11,3,"'\""],[11,4,"/?"],[11,5,"Fn"],[12,0,"F12"],[12,1,"=+"],[12,2,"]}"],[12,3,"Bksp"],[12,4,"Shift"],[12,5,"Win"],[13,0,"F13"],[13,1,"Bksp"],[13,2,"\\|"],[13,3,"Enter"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"\u2192"]],"0015:414B":[],"0028:CA04":[],"0049:0049":[],"006A:0060":[],"006A:0088":[],"0076:0037":[],"00A5:AD96":[],"00D8:6060":[],"00D8:6066":[],"00D8:6068":[],"00D8:6072":[],"00D8:6074":[],"00D8:BD66":[],"00DE:0060":[],"00DE:0061":[],"00DE:0062":[],"00DE:0080":[],"00DE:0081":[],"00DE:0082":[],"00DE:0083":[],"00DE:5753":[[0,0,"Esc"],[0,1,"Tab"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"Caps Lock"],[1,0,"1!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\|"],[1,4,"Win"],[2,0,"2@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9("],[9,1,"O"],[9,2,"L"],[9,3,",<"],[9,4,"Alt"],[10,0,"0)"],[10,1,"P"],[10,2,":"],[10,3,".>"],[10,4,"Ctrl"],[11,0,"-_"],[11,1,"[{"],[11,2,"'\""],[11,3,"/?"],[11,4,"\u2190"],[12,0,"=+"],[12,1,"]}"],[12,2,"#~"],[12,3,"Shift"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\|"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2192"],[14,0,"Backspace"],[14,1,"Delete"],[14,2,"Page Down"],[14,3,"End"],[14,4,"Page Up"]],"00DE:5754":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,5,"Ctrl"],[1,0,"1!"],[1,1,"Q"],[1,2,"A"],[1,5,"Win"],[2,0,"2@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,5,"Alt"],[3,0,"3#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9("],[9,1,"O"],[9,2,"L"],[9,3,",<"],[9,4,"Alt"],[10,0,"0)"],[10,1,"P"],[10,2,";:"],[10,3,".>"],[10,4,"Ctrl"],[11,0,"-_"],[11,1,"[{"],[11,2,"'\""],[11,3,"/?"],[11,4,"\u2190"],[12,0,"=+"],[12,1,"]}"],[12,3,"Shift"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\|"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2192"],[14,0,"Del"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[15,5,"Space"]],"00DE:6566":[],"00DE:6574":[],"00DE:6583":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,5,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,5,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,5,"Fn"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[13,0,"Backspace"],[13,2,"#"],[13,5,"\u2190"],[14,0,"Backspace"],[14,1,"\\"],[14,2,"Enter"],[14,3,"\u2191"],[14,5,"\u2193"],[15,0,"Delete"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"End"],[15,5,"\u2192"]],"00DE:7572":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,6,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,6,"Alt"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,6,"Fn"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,4,"Shift"],[13,0,"F12"],[13,1,"Backspace"],[13,6,"\u2190"],[14,2,"\\"],[14,3,"Enter"],[14,4,"\u2191"],[14,6,"\u2193"],[15,0,"Delete"],[15,1,"Home"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"End"],[15,6,"\u2192"]],"00DE:7583":[],"00FA:2020":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,4,"GUI"],[2,0,"2"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[3,0,"3"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"Alt"],[4,0,"4"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[5,0,"5"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[6,0,"6"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"Y"],[7,2,"H"],[7,3,"N"],[8,0,"8"],[8,1,"U"],[8,2,"J"],[8,3,"M"],[9,0,"9"],[9,1,"I"],[9,2,"K"],[9,3,","],[10,0,"0"],[10,1,"O"],[10,2,"L"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"P"],[11,2,";"],[11,3,"/"],[12,0,"="],[12,1,"["],[12,2,"'"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"]"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"Backspace"],[14,1,"\\"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Home"],[15,1,"End"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"\u2192"]],"00FA:2322":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,4,"GUI"],[2,0,"2"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[3,0,"3"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"Alt"],[4,0,"4"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[5,0,"5"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[6,0,"6"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"Y"],[7,2,"H"],[7,3,"N"],[8,0,"8"],[8,1,"U"],[8,2,"J"],[8,3,"M"],[9,0,"9"],[9,1,"I"],[9,2,"K"],[9,3,","],[10,0,"0"],[10,1,"O"],[10,2,"L"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"P"],[11,2,";"],[11,3,"/"],[12,0,"="],[12,1,"["],[12,2,"'"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"]"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"\\"],[14,1,"\\"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Home"],[15,1,"End"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"\u2192"]],"0159:0165":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"`"],[14,1,"\\"],[15,0,"Home"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"Fn"],[15,4,"\u2192"]],"0159:0187":[],"0159:A71C":[],"0192:5154":[],"0200:E600":[],"0215:12E3":[],"0335:0021":[],"0361:0002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[2,0,"@"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[2,4,"Win"],[3,0,"#"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"Alt"],[4,0,"$"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[5,0,"%"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[6,0,"^"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[7,0,"&"],[7,1,"Y"],[7,2,"H"],[7,3,"N"],[8,0,"*"],[8,1,"U"],[8,2,"J"],[8,3,"M"],[9,0,"("],[9,1,"I"],[9,2,"K"],[9,3,"<"],[10,0,")"],[10,1,"O"],[10,2,"L"],[10,3,">"],[11,0,"_"],[11,1,"P"],[11,2,":"],[11,3,"?"],[11,4,"Alt"],[12,0,"+"],[12,1,"{"],[12,2,"\""],[13,1,"}"],[13,3,"Shift"],[13,4,"Left"],[14,0,"Backspace"],[14,1,"|"],[14,2,"Enter"],[14,3,"Up"],[14,4,"Down"],[15,0,"Home"],[15,1,"End"],[15,2,"PgUp"],[15,3,"PgDn"],[15,4,"Right"]],"03A7:0003":[],"03A7:0004":[],"03A8:0000":[],"03A8:25A7":[],"03A8:67F3":[],"03A8:A4F9":[],"03A8:A649":[],"03A8:AE01":[],"03A8:BEA2":[],"0410:6060":[],"0410:6061":[],"0416:0123":[],"0420:0420":[],"046A:B7D7":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[0,5,"F11"],[0,6,"F13"],[0,7,"F15"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,4,"F8"],[1,5,"F10"],[1,6,"F12"],[1,7,"F14"],[2,0,"`"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Ctrl"],[2,4,"Pg Up"],[2,5,"Pg Dn"],[2,6,"Up"],[2,7,"Down"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"Shift"],[3,4,"Backspace"],[3,5,"\\"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"="],[4,5,"]"],[4,6,"Enter"],[4,7,"Shift"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[5,4,"-"],[5,5,"["],[5,6,"'"],[5,7,"/"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[6,4,"0"],[6,5,"P"],[6,6,";"],[6,7,"."],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[7,4,"9"],[7,5,"O"],[7,6,"L"],[7,7,","],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[8,4,"8"],[8,5,"I"],[8,6,"K"],[8,7,"M"],[9,0,"7"],[9,2,"J"],[9,5,"U"],[9,7,"N"]],"0483:A33E":[],"0483:A372":[],"04D8:E678":[],"04D8:E6DD":[],"04D8:E79A":[],"04D8:E7F1":[],"04D8:E86A":[],"04D8:E873":[],"04D8:E881":[],"04D8:E88F":[[0,0,"Mute"],[0,1,"Esc"],[0,2,"F13"],[0,3,"Tab"],[0,4,"F14"],[0,5,"Caps Lock"],[0,6,"F15"],[0,7,"Shift"],[0,8,"F16"],[0,9,"Ctrl"],[1,0,"1"],[1,1,"2"],[1,2,"Q"],[1,3,"W"],[1,4,"A"],[1,5,"S"],[1,6,"Shift"],[1,7,"Z"],[1,8,"GUI"],[1,9,"Alt"],[2,0,"3"],[2,1,"4"],[2,2,"E"],[2,3,"R"],[2,4,"D"],[2,5,"F"],[2,6,"X"],[2,7,"C"],[2,8,"Fn"],[3,0,"5"],[3,1,"6"],[3,2,"T"],[3,3,"Y"],[3,4,"G"],[3,5,"H"],[3,6,"V"],[3,7,"B"],[3,8,"Space"],[4,0,"7"],[4,1,"8"],[4,2,"U"],[4,3,"I"],[4,4,"J"],[4,5,"K"],[4,6,"N"],[4,7,"M"],[4,8,"Fn"],[5,0,"9"],[5,1,"0"],[5,2,"O"],[5,3,"P"],[5,4,"L"],[5,5,";"],[5,6,","],[5,7,"."],[5,9,"Fn"],[6,0,"-"],[6,1,"="],[6,2,"["],[6,3,"]"],[6,4,"'"],[6,5,"Enter"],[6,6,"/"],[6,7,"Shift"],[6,8,"Fn"],[6,9,"\u2190"],[7,0,"Backspace"],[7,1,"Backspace"],[7,2,"\\"],[7,4,"Enter"],[7,5,"Insert"],[7,6,"\u2191"],[7,7,"Delete"],[7,8,"\u2193"],[7,9,"\u2192"]],"04D8:E890":[[0,0,"Esc"],[0,1,"F1"],[0,2,"`"],[0,3,"1"],[0,4,"Tab"],[0,5,"Q"],[0,6,"Caps Lock"],[0,7,"A"],[0,8,"Shift"],[0,9,"Z"],[0,10,"Ctrl"],[0,11,"GUI"],[1,0,"F2"],[1,1,"F3"],[1,2,"2"],[1,3,"3"],[1,4,"W"],[1,5,"E"],[1,6,"S"],[1,7,"D"],[1,8,"X"],[1,9,"C"],[1,10,"Alt"],[2,0,"F4"],[2,1,"F5"],[2,2,"4"],[2,3,"5"],[2,4,"R"],[2,5,"T"],[2,6,"F"],[2,7,"G"],[2,8,"V"],[2,9,"B"],[3,0,"F6"],[3,1,"F7"],[3,2,"6"],[3,3,"7"],[3,4,"Y"],[3,5,"U"],[3,6,"H"],[3,7,"J"],[3,8,"N"],[3,9,"M"],[3,11,"Space"],[4,0,"F8"],[4,1,"F9"],[4,2,"8"],[4,3,"9"],[4,4,"I"],[4,5,"O"],[4,6,"K"],[4,7,"L"],[4,8,","],[4,9,"."],[4,10,"Alt"],[4,11,"Ctrl"],[5,0,"F10"],[5,1,"F11"],[5,2,"0"],[5,3,"-"],[5,4,"P"],[5,5,"["],[5,6,";"],[5,7,"'"],[5,8,"/"],[5,9,"Shift"],[5,10,"\u2190"],[5,11,"\u2193"],[6,0,"F12"],[6,1,"Print Screen"],[6,2,"="],[6,3,"Backspace"],[6,4,"]"],[6,5,"\\"],[6,6,"Enter"],[6,8,"\u2191"],[6,9,"1"],[6,10,"\u2192"],[6,11,"0"],[7,0,"Scroll Lock"],[7,1,"Pause"],[7,2,"Insert"],[7,3,"Num Lock"],[7,4,"Page Up"],[7,5,"7"],[7,6,"4"],[7,7,"5"],[7,8,"2"],[7,9,"3"],[7,10,"."],[8,0,"Home"],[8,1,"End"],[8,2,"/"],[8,3,"*"],[8,4,"8"],[8,5,"9"],[8,6,"6"],[8,7,"Backspace"],[8,8,"Enter"],[9,0,"Delete"],[9,2,"-"],[9,4,"+"]],"04D8:E8B7":[],"04D8:E8BA":[],"04D8:E8BE":[],"04D8:E8CF":[],"04D8:E8D0":[],"04D8:E8D1":[],"04D8:E8E9":[],"04D8:E8F4":[],"04D8:E936":[],"04D8:E964":[],"04D8:E965":[],"04D8:E96C":[],"04D8:E972":[],"04D8:E984":[],"04D8:E9B9":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"GUI"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"Space"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Space"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"Alt"],[8,0,"I"],[8,1,"K"],[8,2,","],[9,0,"O"],[9,1,"L"],[9,2,"."],[9,3,"Ctrl"],[10,0,"P"],[10,1,";"],[10,2,"/"],[10,3,"Fn"],[11,0,"Backspace"],[11,1,"Enter"],[11,2,"Shift"],[12,0,"Mute"],[12,1,"Page Up"],[12,2,"Page Down"]],"04D8:E9E4":[],"04D8:EA2D":[[0,0,"Mute"],[0,1,"F13"],[0,2,"Esc"],[0,3,"F1"],[0,4,"`"],[0,5,"1"],[0,6,"Tab"],[0,7,"Q"],[0,8,"Caps Lock"],[0,9,"A"],[0,10,"Shift"],[0,11,"Z"],[0,12,"Ctrl"],[0,13,"GUI"],[1,0,"F14"],[1,1,"F15"],[1,2,"F2"],[1,3,"F3"],[1,4,"2"],[1,5,"3"],[1,6,"W"],[1,7,"E"],[1,8,"S"],[1,9,"D"],[1,10,"X"],[1,11,"C"],[1,12,"Alt"],[2,0,"F16"],[2,1,"F17"],[2,2,"F4"],[2,3,"F5"],[2,4,"4"],[2,5,"5"],[2,6,"R"],[2,7,"T"],[2,8,"F"],[2,9,"G"],[2,10,"V"],[2,11,"B"],[2,12,"Space"],[3,0,"F18"],[3,1,"F19"],[3,2,"F6"],[3,3,"F7"],[3,4,"6"],[3,5,"7"],[3,6,"Y"],[3,7,"U"],[3,8,"H"],[3,9,"J"],[3,10,"N"],[3,11,"M"],[4,0,"F20"],[4,1,"F21"],[4,2,"F8"],[4,3,"F9"],[4,4,"8"],[4,5,"9"],[4,6,"I"],[4,7,"O"],[4,8,"K"],[4,9,"L"],[4,10,","],[4,11,"."],[4,12,"Alt"],[4,13,"GUI"],[5,0,"F22"],[5,1,"F23"],[5,2,"F10"],[5,3,"F11"],[5,4,"0"],[5,5,"-"],[5,6,"P"],[5,7,"["],[5,8,";"],[5,9,"'"],[5,10,"/"],[5,12,"Ctrl"],[6,0,"F24"],[6,2,"F12"],[6,4,"="],[6,5,"Backspace"],[6,6,"]"],[6,7,"\\"],[6,8,"Enter"],[6,9,"Delete"],[6,10,"Shift"],[6,11,"\u2191"],[6,12,"\u2190"],[6,13,"\u2193"],[7,0,"Previous Track"],[7,1,"Volume Up"],[7,2,"Home"],[7,3,"Page Up"],[7,4,"Num Lock"],[7,5,"/"],[7,6,"7"],[7,7,"8"],[7,8,"4"],[7,9,"5"],[7,10,"1"],[7,11,"2"],[7,12,"\u2192"],[7,13,"0"],[8,0,"Volume Down"],[8,1,"Next Track"],[8,2,"Page Down"],[8,3,"End"],[8,4,"*"],[8,5,"-"],[8,6,"9"],[8,7,"+"],[8,8,"6"],[8,9,"+"],[8,10,"3"],[8,11,"Enter"],[8,12,"."],[8,13,"Enter"]],"04D8:EA3B":[],"04D8:EA44":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"Alt"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[9,5,"GUI"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"Ctrl"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[11,5,"\u2190"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"\u2190"],[12,5,"\u2193"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"\\"],[14,1,"Delete"],[14,2,"Insert"],[14,3,"Insert"],[14,4,"End"],[14,5,"\u2192"]],"04D8:EA4F":[],"04D8:EA51":[],"04D8:EA53":[],"04D8:EA54":[],"04D8:EA55":[],"04D8:EA56":[],"04D8:EA68":[],"04D8:EA6E":[],"04D8:EAA9":[],"04D8:EAB1":[],"04D8:EAC4":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,4,"Ctrl"],[13,0,"\\"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"Backspace"],[14,1,"\\"],[14,2,"Enter"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Insert"],[15,1,"Delete"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"\u2192"]],"04D8:EAC5":[],"04D8:EAC8":[],"04D8:EAE7":[],"04D8:EAEF":[],"04D8:EAF3":[],"04D8:EB0C":[],"04D8:EB0E":[],"04D8:EB1B":[],"04D8:EB2D":[],"04D8:EB4F":[],"04D8:EB53":[],"04D8:EB54":[],"04D8:EB59":[],"04D8:EB5C":[],"04D8:EB5F":[],"04D8:EB60":[],"04D8:EBBE":[],"04D8:EBD8":[],"04D8:EC15":[],"04D8:EC17":[],"04D8:EC81":[],"04D8:EC9A":[],"04D8:EC9F":[],"04D8:ECA2":[],"04D8:ECE8":[],"04D8:ECE9":[],"04D8:EE60":[],"0571:0001":[],"0645:0001":[],"0645:0002":[],"0666:2784":[],"0717:0001":[],"0717:0002":[],"0717:0003":[],"0777:0001":[],"0927:0001":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Fn"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"\\"],[13,1,"\\"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[15,0,"Home"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"Delete"],[15,4,"\u2192"]],"0927:0002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Shift"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[13,0,"\\"],[13,1,"Backspace"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"Delete"],[15,4,"\u2192"]],"0F6A:01B8":[],"1067:626C":[],"1117:0E0E":[],"1209:0002":[],"1209:2044":[],"1209:2201":[],"1209:2301":[],"1209:2303":[],"1209:2328":[[0,0,"k00"],[0,1,"k10"],[0,2,"k20"],[0,3,"k30"],[0,4,"k40"],[1,0,"k01"],[1,1,"k11"],[1,2,"k21"],[1,3,"k31"],[1,4,"k41"],[1,5,"k51"],[2,0,"k02"],[2,1,"k12"],[2,2,"k22"],[2,3,"k32"],[2,4,"k42"],[2,5,"k52"],[3,0,"k03"],[3,1,"k13"],[3,2,"k23"],[3,3,"k33"],[3,4,"k43"],[3,5,"k53"],[4,0,"k04"],[4,1,"k14"],[4,2,"k24"],[4,3,"k34"],[4,4,"k44"],[4,5,"k54"],[5,0,"k05"],[5,1,"k15"],[5,2,"k25"],[5,3,"k35"],[5,4,"k45"],[5,5,"k55"],[6,0,"k06"],[6,1,"k16"],[6,3,"k36"],[6,4,"k46"],[6,5,"k56"],[7,0,"k07"],[7,1,"k17"],[7,3,"k37"],[7,4,"k47"],[7,5,"k57"],[8,0,"k08"],[8,1,"k18"],[8,2,"k28"],[8,3,"k38"],[8,4,"k48"],[8,5,"k58"],[9,0,"k09"],[9,1,"k19"],[9,2,"k29"],[9,3,"k39"],[9,4,"k49"],[9,5,"k59"],[10,0,"k0A"],[10,1,"k1A"],[10,2,"k2A"],[10,3,"k3A"],[10,4,"k4A"],[10,5,"k5A"],[11,0,"k0B"],[11,1,"k1B"],[11,2,"k2B"],[11,3,"k3B"],[11,4,"k4B"],[11,5,"k5B"],[12,0,"k0C"],[12,1,"k1C"],[12,2,"k2C"],[12,3,"k3C"],[12,4,"k4C"],[12,5,"k5C"],[13,0,"k0D"],[13,1,"k1D"],[13,2,"k2D"],[13,3,"k3D"],[13,4,"k4D"]],"1209:2925":[],"1209:3270":[],"1209:3304":[],"1209:3336":[],"1209:345C":[],"1209:3735":[],"1209:4126":[],"1209:4919":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,6,"Bksp"],[0,7,"\\"],[0,8,"\""],[0,9,"Shift"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,5,"Up"],[1,6,"0"],[1,7,"P"],[1,8,";"],[1,9,"/"],[1,11,"Up"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,5,"Left"],[2,6,"9"],[2,7,"O"],[2,8,"L"],[2,9,"."],[2,11,"Left"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"GUI"],[3,5,"Down"],[3,6,"8"],[3,7,"I"],[3,8,"K"],[3,9,","],[3,10,"Alt"],[3,11,"Down"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Lower"],[4,5,"Right"],[4,6,"7"],[4,7,"U"],[4,8,"J"],[4,9,"M"],[4,10,"Raise"],[4,11,"Right"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[5,5,"Press"],[5,6,"6"],[5,7,"Y"],[5,8,"H"],[5,9,"N"],[5,10,"Space"],[5,11,"Press"],[6,0,"~"],[6,1,"["],[6,2,"Home"],[6,3,"End"],[6,5,"RGB"],[6,6,"Del"],[6,7,"]"],[6,8,"PgUp"],[6,9,"PgDn"],[6,11,"RGB"]],"1209:4920":[[0,0,"Q"],[0,1,"E"],[0,2,"T"],[0,3,"U"],[0,4,"O"],[0,5,"kEC"],[1,0,"A"],[1,1,"D"],[1,2,"G"],[1,3,"J"],[1,4,"L"],[2,0,"Z"],[2,1,"C"],[2,2,"B"],[2,3,"M"],[2,4,"."],[3,0,"Ctrl"],[3,1,"Super"],[3,2,"Space"],[3,3,"Raise"],[3,4,"↓"],[4,0,"W"],[4,1,"R"],[4,2,"Y"],[4,3,"I"],[4,4,"P"],[5,0,"S"],[5,1,"F"],[5,2,"H"],[5,3,"K"],[5,4,";"],[6,0,"X"],[6,1,"V"],[6,2,"N"],[6,3,","],[6,4,"/"],[7,0,"Alt"],[7,1,"Lower"],[7,2,"Space"],[7,3,"←"],[7,4,"↑"]],"1209:4921":[],"1209:5801":[],"1209:68A0":[],"1209:6969":[],"1209:6974":[],"1209:69A1":[],"1209:7337":[],"1209:9121":[],"1209:A1E5":[],"1209:A1F1":[],"1209:A457":[],"1209:A460":[],"1209:B195":[],"1209:BEE5":[],"1209:DB00":[],"1234:5678":[],"1234:5679":[],"1337:6006":[],"1337:6007":[],"1337:6012":[],"1337:6017":[],"1337:6969":[],"13BA:0017":[],"1434:3000":[[0,0,"Delete"],[0,1,"Page Up"],[0,2,"Page Down"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"Alt"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[4,4,"Space"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Fn"],[7,0,"7"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[7,4,"6"],[8,0,"8"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[8,4,"Space"],[9,0,"9"],[9,1,"I"],[9,2,"K"],[9,3,"M"],[10,0,"0"],[10,1,"O"],[10,2,"L"],[10,3,","],[10,4,"Alt"],[11,0,"-"],[11,1,"P"],[11,2,";"],[11,3,"."],[12,0,"="],[12,1,"["],[12,2,"'"],[12,3,"/"],[13,0,"Backspace"],[13,1,"]"],[13,3,"Shift"],[14,0,"Backspace"],[14,1,"\\"],[14,2,"Enter"],[14,3,"Fn"],[14,4,"Ctrl"]],"1480:6461":[[0,0,"ESC"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[2,0,"\""],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"\u00a3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"<"],[8,4,"AltGr"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,">"],[9,4,"Menu"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,"?"],[10,4,"Ctrl"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"Shift"],[12,0,"+"],[12,1,"}"],[12,2,"Enter"],[12,4,"Fn"],[13,0,"Backspace"],[13,1,"|"]],"16C0:27DB":[],"16D0:0DB8":[],"16D0:0F95":[],"16D0:1451":[],"17EF:6048":[],"1804:3046":[],"1A53:4F51":[],"1ABC:0001":[],"1C11:B04D":[],"1D50:6052":[],"1D50:617C":[],"1D50:6180":[[0,2,"Ctrl"],[0,6,"Ctrl"],[1,1,"Shift"],[1,6,"Shift"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"~"],[2,3,"!"],[2,4,"Q"],[2,5,"A"],[2,6,"Z"],[3,0,"NUBS"],[3,1,"Caps Lock"],[3,2,"F1"],[3,3,"@"],[3,4,"W"],[3,5,"S"],[3,6,"X"],[4,0,"F4"],[4,1,"F3"],[4,2,"F2"],[4,3,"#"],[4,4,"E"],[4,5,"D"],[4,6,"C"],[5,0,"G"],[5,1,"T"],[5,2,"%"],[5,3,"$"],[5,4,"R"],[5,5,"F"],[5,6,"V"],[5,7,"B"],[6,0,"F5"],[6,1,"Backspace"],[6,2,"F9"],[6,3,"F10"],[6,5,"|"],[6,6,"Enter"],[7,0,"H"],[7,1,"Y"],[7,2,"^"],[7,3,"&"],[7,4,"U"],[7,5,"J"],[7,6,"M"],[7,7,"N"],[8,0,"F6"],[8,1,"}"],[8,2,"+"],[8,3,"*"],[8,4,"I"],[8,5,"K"],[8,6,"<"],[9,1,"F7"],[9,2,"F8"],[9,3,"("],[9,4,"O"],[9,5,"L"],[9,6,">"],[10,0,"\""],[10,1,"{"],[10,2,"_"],[10,3,")"],[10,4,"P"],[10,5,":"],[10,6,"NUHS"],[10,7,"?"],[11,1,"4"],[11,2,"Delete"],[11,3,"F11"],[11,4,"7"],[11,5,"1"],[11,6,"Num Lock"],[11,7,"\u2193"],[12,0,"0"],[12,1,"5"],[12,2,"Insert"],[12,3,"F12"],[12,4,"8"],[12,5,"2"],[12,6,"/"],[12,7,"\u2192"],[13,0,"."],[13,1,"6"],[13,2,"PgUp"],[13,3,"PgDn"],[13,4,"9"],[13,5,"3"],[13,6,"*"],[13,7,"-"],[14,0,"\u2191"],[14,2,"Home"],[14,3,"End"],[14,4,"+"],[14,5,"Enter"],[14,6,"Pause"],[14,7,"\u2190"],[15,0,"Alt"],[15,3,"PrtSc"],[15,4,"Scroll Lock"],[15,7,"Alt"]],"1EA7:6021":[],"1EA7:6040":[],"1EA7:6061":[],"1EA7:6A61":[],"1EA7:6A62":[],"1EEE:1313":[],"1EF5:343F":[[0,0,"\u25bd"],[0,1,"\u25bd"],[0,2,"Num Lock"],[0,3,"/"],[0,4,"7"],[0,5,"8"],[0,6,"4"],[0,7,"5"],[0,8,"1"],[0,9,"2"],[0,10,"0"],[0,11,"."],[1,0,"\u25bd"],[1,1,"\u25bd"],[1,2,"*"],[1,3,"-"],[1,4,"9"],[1,5,"+"],[1,6,"6"],[1,7,"+"],[1,8,"3"],[1,9,"Enter"],[1,10,"."],[1,11,"0"],[2,0,"Esc"],[2,1,"F1"],[2,2,"`"],[2,3,"1"],[2,4,"Tab"],[2,5,"Q"],[2,6,"Caps Lock"],[2,7,"A"],[2,8,"Shift"],[2,9,"Z"],[2,10,"Ctrl"],[3,0,"F2"],[3,1,"F3"],[3,2,"2"],[3,3,"3"],[3,4,"W"],[3,5,"E"],[3,6,"S"],[3,7,"D"],[3,8,"X"],[3,9,"C"],[3,10,"Alt"],[4,0,"F4"],[4,2,"4"],[4,3,"5"],[4,4,"R"],[4,5,"T"],[4,6,"F"],[4,7,"G"],[4,8,"V"],[4,9,"B"],[4,10,"Space"],[4,11,"Fn"],[5,1,"F5"],[5,2,"6"],[5,3,"7"],[5,4,"Y"],[5,6,"H"],[5,9,"B"],[6,0,"F6"],[6,1,"F7"],[6,2,"8"],[6,3,"9"],[6,4,"U"],[6,5,"I"],[6,6,"J"],[6,7,"K"],[6,8,"N"],[6,9,"M"],[6,10,"Space"],[7,0,"F8"],[7,1,"F9"],[7,2,"0"],[7,3,"-"],[7,4,"O"],[7,5,"P"],[7,6,"L"],[7,7,";"],[7,8,","],[7,9,"."],[7,10,"Alt"],[8,0,"F10"],[8,1,"F11"],[8,2,"="],[8,3,"Backspace"],[8,4,"["],[8,5,"]"],[8,6,"'"],[8,8,"/"],[8,9,"Fn"],[9,0,"F12"],[9,1,"Print Screen"],[9,2,"Backspace"],[9,3,"Insert"],[9,4,"\\"],[9,5,"Delete"],[9,6,"Enter"],[9,8,"Shift"],[9,10,"Ctrl"],[9,11,"\u2190"],[10,0,"Scroll Lock"],[10,1,"Pause"],[10,2,"Home"],[10,3,"Page Up"],[10,4,"End"],[10,5,"Page Down"],[10,8,"\u2191"],[10,10,"\u2193"],[10,11,"\u2192"],[11,0,"\u25bd"],[11,1,"\u25bd"],[11,2,"\u25bd"],[11,3,"\u25bd"],[11,4,"\u25bd"],[11,5,"\u25bd"],[11,6,"\u25bd"],[11,7,"\u25bd"],[11,8,"\u25bd"],[11,9,"\u25bd"],[11,10,"\u25bd"],[11,11,"\u25bd"]],"2004:CB00":[[0,1,"K10"],[0,3,"K30"],[0,5,"K50"],[0,7,"K70"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[1,5,"K51"],[1,6,"K61"],[1,7,"K71"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[2,5,"K52"],[2,6,"K62"],[2,7,"K72"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"],[3,5,"K53"],[3,6,"K63"],[3,7,"K73"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[4,5,"K54"],[4,6,"K64"],[4,7,"K74"],[5,1,"K15"],[5,3,"K35"],[5,5,"K55"],[5,7,"K75"],[6,6,"K66"]],"2022:8086":[],"20A0:0B87":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[0,6,"F5"],[0,7,"F8"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"GUI"],[1,6,"6"],[1,7,"9"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[2,6,"Y"],[2,7,"O"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"\\"],[3,6,"H"],[3,7,"L"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,6,"N"],[4,7,"."],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,6,"Space"],[5,7,"Alt"],[6,1,"0"],[6,2,"P"],[6,3,";"],[6,4,"/"],[6,5,"GUI"],[6,6,"F6"],[6,7,"F7"],[7,0,"F9"],[7,1,"-"],[7,2,"["],[7,3,"'"],[7,4,"Shift"],[7,5,"Menu"],[7,6,"7"],[7,7,"8"],[8,0,"F10"],[8,1,"="],[8,2,"]"],[8,3,"\\"],[8,4,"Fn"],[8,5,"Ctrl"],[8,6,"U"],[8,7,"I"],[9,0,"F11"],[9,1,"\\"],[9,2,"\\"],[9,3,"Enter"],[9,4,"Print Screen"],[9,5,"Insert"],[9,6,"J"],[9,7,"K"],[10,0,"F12"],[10,1,"Backspace"],[10,3,"Pause"],[10,4,"Scroll Lock"],[10,5,"Home"],[10,6,"M"],[10,7,","],[11,6,"\u2192"],[11,7,"Page Up"],[12,6,"\u2191"],[12,7,"Page Down"],[13,6,"\u2193"],[13,7,"End"],[14,6,"\u2190"],[14,7,"Delete"]],"20A0:422D":[],"20A0:422E":[],"20A0:422F":[],"20A0:4246":[],"20A0:424D":[],"20A0:4258":[],"21C0:9901":[],"21FF:0A66":[],"21FF:AA01":[],"21FF:AA97":[],"21FF:AA98":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"0"],[0,6,"P"],[0,7,";"],[0,8,"."],[0,9,"Alt"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\u2298"],[1,4,"GUI"],[1,5,"-"],[1,6,"["],[1,7,"'"],[1,8,"/"],[1,9,"Fn"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[2,5,"="],[2,6,"]"],[2,7,"\u2298"],[2,8,"Shift"],[2,9,"\u2190"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,5,"Backspace"],[3,6,"\\"],[3,7,"Enter"],[3,8,"\u2191"],[3,9,"\u2193"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[4,5,"\u2298"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,5,"Num Lock"],[5,6,"7"],[5,7,"4"],[5,8,"1"],[5,9,"\u2192"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[6,5,"/"],[6,6,"8"],[6,7,"5"],[6,8,"2"],[6,9,"0"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[7,5,"*"],[7,6,"9"],[7,7,"6"],[7,8,"3"],[7,9,"."],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,5,"-"],[8,6,"+"],[8,7,"="],[8,8,"Enter"],[8,9,"Backspace"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"]],"2326:FEED":[[0,0,"GP0"],[0,1,"GP7"],[0,2,"GP14"],[1,0,"GP1"],[1,1,"GP8"],[1,2,"GP16"],[2,0,"GP2"],[2,1,"GP9"],[2,2,"GP17"],[3,0,"GP3"],[3,1,"GP10"],[3,2,"GP18"],[4,0,"GP4"],[4,1,"GP11"],[4,2,"GP19"],[5,0,"GP5"],[5,1,"GP12"],[5,2,"GP20"],[6,0,"GP6"],[6,1,"GP13"],[6,2,"GP21"]],"2365:0168":[],"2365:0169":[],"239A:0108":[],"28E9:3006":[],"2A34:672B":[[0,0,"Esc"],[0,1,"\u00ac"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,4,"|"],[1,5,"Win"],[2,0,"F2"],[2,1,"\""],[2,2,"Q"],[2,3,"A"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"\u00a3"],[3,2,"W"],[3,3,"S"],[3,4,"X"],[4,0,"F4"],[4,1,"$"],[4,2,"E"],[4,3,"D"],[4,4,"C"],[4,5,"Space"],[5,1,"%"],[5,2,"R"],[5,3,"F"],[5,4,"V"],[6,0,"F5"],[6,1,"^"],[6,2,"T"],[6,3,"G"],[6,4,"B"],[6,5,"Layer"],[7,0,"F6"],[7,1,"&"],[7,2,"Y"],[7,3,"H"],[7,4,"N"],[8,0,"F7"],[8,1,"*"],[8,2,"U"],[8,3,"J"],[8,4,"M"],[8,5,"Space"],[9,0,"F8"],[9,1,"("],[9,2,"I"],[9,3,"K"],[9,4,"<"],[10,0,"F9"],[10,1,")"],[10,2,"O"],[10,3,"L"],[10,4,">"],[10,5,"Alt"],[11,0,"F10"],[11,1,"_"],[11,2,"P"],[11,3,":"],[11,4,"?"],[11,5,"Win"],[12,0,"F11"],[12,1,"+"],[12,2,"{"],[12,3,"@"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"F12"],[13,2,"}"],[13,3,"~"],[14,0,"Del"],[14,1,"Backspace"],[14,2,"|"],[14,3,"Enter"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"Prev"],[15,1,"Play"],[15,2,"7"],[15,3,"4"],[15,4,"1"],[15,5,"\u2192"],[16,0,"Next"],[16,1,"/"],[16,2,"8"],[16,3,"5"],[16,4,"2"],[16,5,"0"],[17,0,"Vol -"],[17,1,"*"],[17,2,"9"],[17,3,"6"],[17,4,"3"],[17,5,"."],[18,0,"Vol +"],[18,1,"-"],[18,3,"+"],[18,5,"Enter"]],"3044:83A1":[],"308F:0038":[[0,0,"ESC"],[0,1,"TAB"],[0,2,"CAPS"],[0,3,"LSFT"],[0,4,"LCTL"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"LGUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"LALT"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"SPC"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"COMM"],[10,0,"0"],[10,1,"P"],[10,2,"SCLN"],[10,3,"DOT"],[10,4,"RALT"],[11,0,"MINS"],[11,1,"LBRC"],[11,2,"QUOT"],[11,3,"SLSH"],[11,4,"RGUI"],[12,0,"EQL"],[12,1,"RBRC"],[12,4,"RCTL"],[13,0,"BSPC"],[13,1,"BSLS"],[13,2,"ENT"],[13,3,"RSFT"],[13,4,"LEFT"],[14,0,"DEL"],[14,1,"HOME"],[14,2,"END"],[14,3,"UP"],[14,4,"DOWN"],[15,0,"INS"],[15,1,"PGUP"],[15,2,"PGDN"],[15,3,"MO(1)"],[15,4,"RGHT"]],"3141:4466":[],"3141:4467":[],"320F:5044":[],"320F:5045":[],"320F:504A":[],"320F:504B":[],"320F:505A":[],"320F:5088":[[0,0,"NUM"],[0,1,"7"],[0,2,"4"],[0,3,"1"],[0,4,"0"],[1,0,"/"],[1,1,"8"],[1,2,"5"],[1,3,"2"],[2,0,"*"],[2,1,"9"],[2,2,"6"],[2,3,"3"],[3,0,"-"],[3,1,"+"],[3,2,"CALC"],[3,3,"RET"],[3,4,"."]],"3233:000F":[[0,0,"L Shift"],[0,1,"Q"],[0,2,"W"],[0,3,"E"],[0,4,"R"],[0,5,"U"],[0,6,"I"],[0,7,"O"],[0,8,"P"],[0,9,"L Win"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"F3"],[1,4,"T"],[1,5,"Y"],[1,6,"]"],[1,7,"F7"],[1,8,"["],[1,9,"R Shift"],[1,10,"Backspace"],[2,0,"Home"],[2,1,"A"],[2,2,"S"],[2,3,"D"],[2,4,"F"],[2,5,"J"],[2,6,"K"],[2,7,"L"],[2,8,";"],[2,9,"FN"],[2,10,"\\"],[3,0,"Left"],[3,1,"Esc"],[3,3,"F4"],[3,4,"G"],[3,5,"H"],[3,6,"F6"],[3,7,"Down"],[3,8,"'"],[3,9,"L Alt"],[3,10,"F11"],[4,0,"R Ctrl"],[4,1,"Z"],[4,2,"X"],[4,3,"C"],[4,4,"V"],[4,5,"M"],[4,6,","],[4,7,"."],[4,9,"Space"],[4,10,"Enter"],[5,0,"Right"],[5,1,"PGUP"],[5,2,"PGDN"],[5,3,"Up"],[5,4,"B"],[5,5,"N"],[5,6,"Delete"],[5,7,"End"],[5,8,"/"],[5,9,"R Alt"],[5,10,"F12"],[6,0,"L Ctrl"],[6,1,"`"],[6,2,"F1"],[6,3,"F2"],[6,4,"5"],[6,5,"6"],[6,6,"="],[6,7,"F8"],[6,8,"-"],[6,10,"F9"],[7,0,"F5"],[7,1,"1"],[7,2,"2"],[7,3,"3"],[7,4,"4"],[7,5,"7"],[7,6,"8"],[7,7,"9"],[7,8,"0"],[7,9,"PrintScreen"],[7,10,"F10"]],"3233:0011":[[0,0,"L Shift"],[0,1,"Q"],[0,2,"W"],[0,3,"E"],[0,4,"R"],[0,5,"U"],[0,6,"I"],[0,7,"O"],[0,8,"P"],[0,9,"L Win"],[1,0,"|"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"F3"],[1,4,"T"],[1,5,"Y"],[1,6,"]"],[1,7,"F7"],[1,8,"["],[1,9,"R Shift"],[1,10,"Backspace"],[2,0,"Home"],[2,1,"A"],[2,2,"S"],[2,3,"D"],[2,4,"F"],[2,5,"J"],[2,6,"K"],[2,7,"L"],[2,8,";"],[2,9,"FN"],[2,10,"|"],[3,0,"Left"],[3,1,"Esc"],[3,3,"F4"],[3,4,"G"],[3,5,"H"],[3,6,"F6"],[3,7,"Down"],[3,8,"'"],[3,9,"L Alt"],[3,10,"F11"],[4,0,"R Ctrl"],[4,1,"Z"],[4,2,"X"],[4,3,"C"],[4,4,"V"],[4,5,"M"],[4,6,","],[4,7,"."],[4,9,"Space"],[4,10,"ENTER"],[5,0,"Right"],[5,1,"PGUP"],[5,2,"PGDN"],[5,3,"Up"],[5,4,"B"],[5,5,"N"],[5,6,"Delete"],[5,7,"End"],[5,8,"/"],[5,9,"R Alt"],[5,10,"F12"],[6,0,"L Ctrl"],[6,1,"`"],[6,2,"F1"],[6,3,"F2"],[6,4,"5"],[6,5,"6"],[6,6,"="],[6,7,"F8"],[6,8,"-"],[6,10,"F9"],[7,0,"F5"],[7,1,"1"],[7,2,"2"],[7,3,"3"],[7,4,"4"],[7,5,"7"],[7,6,"8"],[7,7,"9"],[7,8,"0"],[7,9,"PrintScreen"],[7,10,"F10"]],"3233:5319":[[0,0,"LShift"],[0,1,"Q"],[0,2,"W"],[0,3,"E"],[0,4,"R"],[0,5,"U"],[0,6,"I"],[0,7,"O"],[0,8,"P"],[1,0,"Space"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,4,"T"],[1,5,"Y"],[1,6,"]"],[1,7,"Backspace"],[1,8,"["],[2,0,"LAlt"],[2,1,"A"],[2,2,"S"],[2,3,"D"],[2,4,"F"],[2,5,"J"],[2,6,"K"],[2,7,"L"],[2,8,";"],[3,0,"Left"],[3,1,"Esc"],[3,2,"Del"],[3,3,"FN"],[3,4,"G"],[3,5,"H"],[3,6,"End"],[3,7,"PGUP"],[3,8,"'"],[4,1,"Z"],[4,2,"X"],[4,3,"C"],[4,4,"V"],[4,5,"M"],[4,6,","],[4,7,"."],[4,8,"Enter"],[5,0,"LWin"],[5,1,"Down"],[5,2,"Right"],[5,4,"B"],[5,5,"N"],[5,7,"\\"],[5,8,"/"],[6,0,"LCtrl"],[6,1,"Up"],[6,2,"PGDN"],[6,3,"RAlt"],[6,4,"5"],[6,5,"6"],[6,6,"="],[6,8,"-"],[7,0,"RShift"],[7,1,"1"],[7,2,"2"],[7,3,"3"],[7,4,"4"],[7,5,"7"],[7,6,"8"],[7,7,"9"],[7,8,"0"]],"3265:0002":[],"3265:0005":[],"3265:0006":[],"3265:0008":[],"3297:1969":[],"3297:1977":[[0,5,"k24"],[0,6,"k26"],[0,7,"k32"],[0,8,"k38"],[1,0,"k00"],[1,1,"k06"],[1,2,"k12"],[1,3,"k18"],[1,5,"k25"],[1,6,"k27"],[1,7,"k33"],[1,8,"k39"],[1,9,"k45"],[2,0,"k01"],[2,1,"k07"],[2,2,"k13"],[2,3,"k19"],[2,6,"k28"],[2,7,"k34"],[2,8,"k40"],[2,9,"k46"],[2,10,"k44"],[3,0,"k02"],[3,1,"k08"],[3,2,"k14"],[3,3,"k20"],[3,6,"k29"],[3,7,"k35"],[3,8,"k41"],[3,9,"k47"],[4,0,"k03"],[4,1,"k09"],[4,2,"k15"],[4,3,"k21"],[4,4,"k23"],[4,6,"k30"],[4,7,"k36"],[4,8,"k42"],[4,9,"k48"],[5,0,"k04"],[5,1,"k10"],[5,2,"k16"],[5,3,"k22"],[5,6,"k31"],[5,7,"k37"],[5,8,"k43"],[5,9,"k49"],[5,11,"k50"],[6,0,"k05"],[6,1,"k11"],[6,2,"k17"],[6,11,"k51"]],"3384:0001":[],"3415:0001":[],"342D:E392":[[0,0,"Shift"],[0,1,"Q"],[0,2,"W"],[0,3,"E"],[0,4,"R"],[0,5,"U"],[0,6,"I"],[0,7,"O"],[0,8,"P"],[0,9,"Win"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"F3"],[1,4,"T"],[1,5,"Y"],[1,6,"]"],[1,7,"F7"],[1,8,"["],[1,9,"Shift"],[1,10,"Backspace"],[2,0,"Del"],[2,1,"A"],[2,2,"S"],[2,3,"D"],[2,4,"F"],[2,5,"J"],[2,6,"K"],[2,7,"L"],[2,8,";"],[2,9,"FN"],[2,10,"\\"],[3,0,"Left"],[3,1,"ESC"],[3,3,"F4"],[3,4,"G"],[3,5,"H"],[3,6,"F6"],[3,7,"Down"],[3,8,"'"],[3,9,"Alt"],[3,10,"F11"],[4,0,"Ctrl"],[4,1,"Z"],[4,2,"X"],[4,3,"C"],[4,4,"V"],[4,5,"M"],[4,6,","],[4,7,"."],[4,9,"Space"],[4,10,"Enter"],[5,0,"Right"],[5,1,"PgUp"],[5,2,"PgDn"],[5,3,"Up"],[5,4,"B"],[5,5,"N"],[5,6,"End"],[5,8,"/"],[5,9,"Alt"],[5,10,"F12"],[6,0,"Ctrl"],[6,1,"`"],[6,2,"F1"],[6,3,"F2"],[6,4,"5"],[6,5,"6"],[6,6,"="],[6,7,"F8"],[6,8,"-"],[6,10,"F9"],[6,11,"Home"],[7,0,"F5"],[7,1,"1"],[7,2,"2"],[7,3,"3"],[7,4,"4"],[7,5,"7"],[7,6,"8"],[7,7,"9"],[7,8,"0"],[7,9,"Printscreen"],[7,10,"F10"]],"342D:E393":[[0,0,"Shift"],[0,1,"Q"],[0,2,"W"],[0,3,"E"],[0,4,"R"],[0,5,"U"],[0,6,"I"],[0,7,"O"],[0,8,"P"],[0,9,"Win"],[0,10,"Scroll Lock"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"F3"],[1,4,"T"],[1,5,"Y"],[1,6,"]"],[1,7,"F7"],[1,8,"["],[1,9,"Shift"],[1,10,"Backspace"],[2,0,"Home"],[2,1,"A"],[2,2,"S"],[2,3,"D"],[2,4,"F"],[2,5,"J"],[2,6,"K"],[2,7,"L"],[2,8,";"],[2,9,"FN"],[2,10,"\\"],[3,0,"Left"],[3,1,"ESC"],[3,3,"F4"],[3,4,"G"],[3,5,"H"],[3,6,"F6"],[3,7,"Down"],[3,8,"'"],[3,9,"Alt"],[3,10,"F11"],[4,0,"Ctrl"],[4,1,"Z"],[4,2,"X"],[4,3,"C"],[4,4,"V"],[4,5,"M"],[4,6,","],[4,7,"."],[4,8,"APP"],[4,9,"Space"],[4,10,"Enter"],[5,0,"Right"],[5,1,"PgUp"],[5,2,"PgDn"],[5,3,"Up"],[5,4,"B"],[5,5,"N"],[5,6,"Delete"],[5,7,"End"],[5,8,"/"],[5,9,"Alt"],[5,10,"F12"],[6,0,"Ctrl"],[6,1,"`"],[6,2,"F1"],[6,3,"F2"],[6,4,"5"],[6,5,"6"],[6,6,"="],[6,7,"F8"],[6,8,"-"],[6,9,"Pause Break"],[6,10,"F9"],[6,11,"INS"],[7,0,"F5"],[7,1,"1"],[7,2,"2"],[7,3,"3"],[7,4,"4"],[7,5,"7"],[7,6,"8"],[7,7,"9"],[7,8,"0"],[7,9,"Printscreen"],[7,10,"F10"]],"342D:E431":[],"342D:E463":[],"3434:0160":[],"3434:0161":[],"3434:0162":[],"3434:0163":[],"3434:01A1":[],"3434:01A3":[],"3434:01B1":[],"3434:01C0":[],"3434:01D1":[],"3434:01D3":[],"3434:0310":[],"3434:0311":[],"3434:0312":[],"3434:0313":[],"3434:0314":[],"3434:0315":[],"3434:0320":[],"3434:0321":[],"3434:0322":[],"3434:0323":[],"3434:0324":[],"3434:0325":[],"3434:0330":[],"3434:0331":[],"3434:0332":[],"3434:0333":[],"3434:0334":[],"3434:0335":[],"3434:0340":[],"3434:0342":[],"3434:0350":[],"3434:0351":[],"3434:0352":[],"3434:0353":[],"3434:0360":[],"3434:0361":[],"3434:0362":[],"3434:0363":[],"3434:0370":[],"3434:0372":[],"3434:0380":[],"3434:0381":[],"3434:0382":[],"3434:0383":[],"3434:03A1":[],"3434:03A3":[],"3434:0411":[],"3535:3505":[],"3535:3510":[],"3555:3671":[],"359B:0001":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[8,5,"Alt"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Fn"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Ctrl"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"\""],[11,4,"Shift"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[12,3,"Enter"],[12,5,"\u2190"],[13,0,"PrtSc"],[13,1,"Backspace"],[13,2,"|"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Mute"],[14,1,"Del"],[14,2,"Page Up"],[14,3,"Page Down"],[14,5,"\u2192"]],"359B:0002":[],"359B:0004":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"CapsLk"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Alt"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"\""],[11,5,"Fn"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[12,4,"Shift"],[12,5,"Menu"],[13,0,"F13"],[13,1,"Bksp"],[13,2,"|"],[13,3,"Enter"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"ScrLk"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Dn"],[16,5,"\u2192"]],"359B:0006":[[0,0,"ESCAPE"],[0,1,"TAB"],[0,2,"CAPS LOCK"],[0,3,"LEFT SHIFT"],[0,4,"LEFT CTRL"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"LEFT WIN"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"LEFT ALT"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"SPACEBAR"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"COMMA"],[10,0,"0"],[10,1,"P"],[10,2,"SEMICOLON"],[10,3,"PERIOD"],[10,4,"RIGHT ALT"],[11,0,"MINUS"],[11,1,"LEFT BRACKET"],[11,2,"SINGLE TICK"],[11,3,"FORWARD SLASH"],[11,4,"FN"],[12,0,"EQUALS"],[12,1,"RIGHT BRACKET"],[12,3,"RIGHT SHIFT"],[12,4,"LEFT ARROW"],[13,0,"BACKSPACE"],[13,1,"BACK SLASH"],[13,2,"ENTER"],[13,3,"UP ARROW"],[13,4,"DOWN ARROW"],[14,0,"DELETE"],[14,1,"HOME"],[14,2,"PAGE UP"],[14,3,"PAGE DOWN"],[14,4,"RIGHT ARROW"]],"359B:0009":[[0,0,"ESCAPE"],[0,1,"BACKTICK"],[0,2,"TAB"],[0,3,"CAPS LOCK"],[0,4,"LEFT SHIFT"],[0,5,"LEFT CTRL"],[0,6,"F8"],[0,7,"8"],[0,8,"I"],[0,9,"K"],[0,10,"COMMA"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"LEFT WIN"],[1,6,"F9"],[1,7,"9"],[1,8,"O"],[1,9,"L"],[1,10,"PERIOD"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"LEFT ALT"],[2,6,"F10"],[2,7,"0"],[2,8,"P"],[2,9,"SEMICOLON"],[2,10,"FORWARD SLASH"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"SPACEBAR"],[3,6,"F11"],[3,7,"MINUS"],[3,8,"LEFT BRACKET"],[3,9,"SINGLE TICK"],[3,10,"RIGHT SHIFT"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"RIGHT ALT"],[4,6,"F12"],[4,7,"EQUALS"],[4,8,"RIGHT BRACKET"],[4,9,"ENTER"],[4,10,"LEFT ARROW"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"FN"],[5,6,"PRINT SCREEN"],[5,7,"BACKSPACE"],[5,8,"BACK SLASH"],[5,9,"UP ARROW"],[5,10,"DOWN ARROW"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[6,5,"MENU"],[6,6,"SCROLL LOCK"],[6,7,"INSERT"],[6,8,"DELETE"],[6,9,"PAGE DOWN"],[6,10,"RIGHT ARROW"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[7,5,"RIGHT CTRL"],[7,6,"PAUSE BREAK"],[7,7,"HOME"],[7,8,"END"],[7,9,"PAGE UP"]],"359B:000C":[],"359B:000E":[],"359B:0010":[[0,0,"ESCAPE"],[0,1,"TAB"],[0,2,"CAPS LOCK"],[0,3,"LEFT SHIFT"],[0,4,"LEFT CTRL"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"LEFT WIN"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"LEFT ALT"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"SPACEBAR"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"COMMA"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"PERIOD"],[10,0,"0"],[10,1,"P"],[10,2,"SEMICOLON"],[10,3,"FORWARD SLASH"],[10,4,"RIGHT ALT"],[11,0,"MINUS"],[11,1,"LEFT BRACKET"],[11,2,"SINGLE TICK"],[11,4,"FN"],[12,0,"EQUALS"],[12,1,"RIGHT BRACKET"],[12,3,"RIGHT SHIFT"],[12,4,"LEFT ARROW"],[13,0,"BACKSPACE"],[13,1,"BACK SLASH"],[13,2,"ENTER"],[13,3,"UP ARROW"],[13,4,"DOWN ARROW"],[14,0,"DELETE"],[14,1,"HOME"],[14,2,"PAGE UP"],[14,3,"PAGE DOWN"],[14,4,"RIGHT ARROW"]],"362D:0200":[],"3680:5658":[],"369B:0021":[[0,0,"ESC"],[0,1,"GRV"],[0,2,"TAB"],[0,3,"CAPS"],[0,4,"LSFT"],[0,5,"LCTL"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"LGUI"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"LALT"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"SPC"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"COMM"],[9,5,"RALT"],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,"SCLN"],[10,4,"DOT"],[10,5,"MO(1)"],[11,0,"F10"],[11,1,"MINS"],[11,2,"LBRC"],[11,3,"QUOT"],[11,4,"SLSH"],[11,5,"RCTL"],[12,0,"F11"],[12,1,"EQL"],[12,2,"RBRC"],[12,4,"RSFT"],[12,5,"LEFT"],[13,0,"F12"],[13,1,"BSPC"],[13,2,"BSLS"],[13,3,"ENT"],[13,4,"UP"],[13,5,"DOWN"],[14,1,"HOME"],[14,2,"DEL"],[14,3,"PGUP"],[14,4,"PGDN"],[14,5,"RGHT"],[15,0,"END"]],"36B5:27D6":[[0,0,"Esc"],[0,1,"F10"],[0,2,"~"],[0,3,"0"],[0,4,"Tab"],[0,5,"P"],[0,6,"Caps Lock"],[0,7,";"],[0,8,"Shift1"],[0,9,"."],[0,10,"Ctrl"],[0,11,"Alt"],[1,0,"F1"],[1,1,"F11"],[1,2,"1"],[1,3,"-"],[1,4,"Q"],[1,5,"["],[1,6,"A"],[1,7,"'"],[1,8,"Shift2"],[1,9,"/"],[1,10,"Win"],[1,11,"Fn"],[2,0,"F2"],[2,1,"F12"],[2,2,"2"],[2,3,"="],[2,4,"W"],[2,5,"]"],[2,6,"S"],[2,7,"Enter"],[2,8,"Z"],[2,9,"Shift1"],[2,10,"Alt"],[2,11,"Ctrl"],[3,0,"F3"],[3,1,"F13"],[3,2,"3"],[3,3,"Backspace"],[3,4,"E"],[3,5,"\\"],[3,6,"D"],[3,8,"X"],[3,9,"Shift2"],[3,11,"\u2190"],[4,0,"F4"],[4,1,"F14"],[4,2,"4"],[4,3,"Ins"],[4,4,"R"],[4,5,"Delete"],[4,6,"F"],[4,7,"Backspace1"],[4,8,"C"],[4,9,"\u2191"],[4,11,"\u2193"],[5,0,"F5"],[5,1,"Mute"],[5,2,"5"],[5,3,"PageUp"],[5,4,"T"],[5,5,"PageDown"],[5,6,"G"],[5,8,"V"],[5,10,"Space"],[5,11,"\u2192"],[6,0,"F6"],[6,1,"Home"],[6,2,"6"],[6,3,"Num"],[6,4,"Y"],[6,5,"7"],[6,6,"H"],[6,7,"4"],[6,8,"B"],[6,9,"1"],[6,10,"Space"],[7,0,"F7"],[7,1,"Prtsc"],[7,2,"7"],[7,3,"//"],[7,4,"U"],[7,5,"8"],[7,6,"J"],[7,7,"5"],[7,8,"N"],[7,9,"2"],[7,10,"Space"],[7,11,"0"],[8,0,"F8"],[8,1,"Scroll"],[8,2,"8"],[8,3,"*"],[8,4,"I"],[8,5,"9"],[8,6,"K"],[8,7,"6"],[8,8,"M"],[8,9,"3"],[8,11,"."],[9,0,"F9"],[9,1,"Pause"],[9,2,"9"],[9,3,"-"],[9,4,"O"],[9,6,"L"],[9,7,"+"],[9,8,","],[9,11,"Enter"]],"36B6:0001":[],"36B6:0002":[],"3728:2949":[],"3A0E:4C82":[],"3A0E:4C83":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"\\"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[15,0,"Home"],[15,1,"End"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"\u2192"]],"3A0E:CBDC":[],"3A3C:0001":[[0,1,"L10"],[0,2,"L20"],[0,5,"R15"],[0,6,"R25"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,3,"L31"],[1,4,"R04"],[1,5,"R14"],[1,6,"R24"],[1,7,"R34"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"R03"],[2,5,"R13"],[2,6,"R23"],[2,7,"R33"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,4,"R02"],[3,5,"R12"],[3,6,"R22"],[3,7,"R32"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,4,"R01"],[4,5,"R11"],[4,6,"R21"],[4,7,"R31"],[5,0,"L05"],[5,1,"L15"],[5,2,"L25"],[5,3,"L35"],[5,4,"R00"],[5,5,"R10"],[5,6,"R20"],[5,7,"R30"]],"3A54:4F5D":[[0,0,"Num Lock"],[0,1,"7"],[0,2,"4"],[0,3,"1"],[0,4,"0"],[1,0,"/"],[1,1,"8"],[1,2,"5"],[1,3,"2"],[2,0,"*"],[2,1,"9"],[2,2,"6"],[2,3,"3"],[2,4,"."],[3,0,"-"],[3,1,"+"],[3,3,"Enter"]],"3C4D:1A2B":[],"4011:43C1":[],"4013:2022":[[0,0,"Esc"],[0,1,"TAB"],[0,2,"CAPS"],[0,3,"SFT"],[0,5,"BSL"],[0,6,"GRV"],[0,7,"'"],[0,8,"SFT"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"ALT"],[1,5,"0"],[1,6,"P"],[1,7,";"],[1,8,"/"],[1,9,"DEL"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"CTL"],[2,5,"9"],[2,6,"O"],[2,7,"L"],[2,8,"."],[2,9,"BSP"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"ENT"],[3,5,"8"],[3,6,"I"],[3,7,"K"],[3,8,","],[3,9,"SPC"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"MINS"],[4,5,"7"],[4,6,"U"],[4,7,"J"],[4,8,"M"],[4,9,"EQL"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"GUI"],[5,5,"6"],[5,6,"Y"],[5,7,"H"],[5,8,"N"],[5,9,"GUI"]],"4025:0000":[],"4025:0007":[],"4025:05B5":[],"4025:0A0C":[],"4025:0F00":[],"4025:0F25":[],"4025:0F61":[],"4025:4A1F":[],"4025:4C55":[],"4025:4D68":[],"4025:5350":[],"4025:546F":[],"4025:6060":[],"4025:7574":[],"4025:9999":[],"4040:AA66":[[0,0,"ESC"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"<"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,">"],[9,4,"K91"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,"?"],[10,4,"K92"],[11,0,"_"],[11,1,"{"],[11,2,"k90"],[11,3,"Shift"],[12,0,"+"],[12,1,"}"],[12,4,"Left"],[13,0,"Backspace"],[13,1,"|"],[13,2,"Enter"],[13,3,"Up"],[13,4,"Down"],[14,0,"Delete"],[14,1,"Home"],[14,2,"PgUp"],[14,3,"PgDn"],[14,4,"Right"]],"4048:0001":[],"404A:0002":[],"4069:0001":[],"4069:0002":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,"<"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,">"],[10,5,"Alt"],[11,0,"F10"],[11,1,"_"],[11,2,"{"],[11,3,"\""],[11,4,"?"],[11,5,"Alt"],[12,0,"F11"],[12,1,"+"],[12,2,"}"],[12,4,"Shift"],[12,5,"Win"],[13,0,"F12"],[13,1,"1U Split Bksp"],[13,2,"|"],[13,3,"Enter"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"F13"],[14,1,"Backspace"],[15,0,"PrtSc"],[15,1,"Insert"],[15,2,"Delete"],[15,5,"Left Arrow"],[16,0,"Scroll Lock"],[16,1,"Home"],[16,2,"End"],[16,4,"Up Arrow"],[16,5,"Down Arrow"],[17,0,"Pause"],[17,1,"PgUp"],[17,2,"PgDn"],[17,5,"Right Arrow"],[18,0,"KP 1"],[18,1,"Num Lock"],[18,2,"7"],[18,3,"4"],[18,4,"1"],[18,5,"0"],[19,0,"KP 2"],[19,1,"/"],[19,2,"8"],[19,3,"5"],[19,4,"2"],[19,5,"0"],[20,0,"KP 3"],[20,1,"*"],[20,2,"9"],[20,3,"6"],[20,4,"3"],[20,5,"."],[21,0,"KP 4"],[21,1,"-"],[21,2,"+"],[21,3,"+"],[21,4,"Enter"],[21,5,"Enter"]],"4131:5141":[],"4141:0002":[[0,0,"Shift"],[0,1,"Q"],[0,2,"W"],[0,3,"E"],[0,4,"R"],[0,5,"U"],[0,6,"I"],[0,7,"O"],[0,8,"P"],[0,9,"Win"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"F3"],[1,4,"T"],[1,5,"Y"],[1,6,"]"],[1,7,"F7"],[1,8,"["],[1,9,"Shift"],[1,10,"Backspace"],[2,0,"Del"],[2,1,"A"],[2,2,"S"],[2,3,"D"],[2,4,"F"],[2,5,"J"],[2,6,"K"],[2,7,"L"],[2,8,";"],[2,9,"FN"],[2,10,"\\"],[3,0,"Left"],[3,1,"ESC"],[3,3,"F4"],[3,4,"G"],[3,5,"H"],[3,6,"F6"],[3,7,"Down"],[3,8,"'"],[3,9,"Alt"],[3,10,"F11"],[4,0,"Ctrl"],[4,1,"Z"],[4,2,"X"],[4,3,"C"],[4,4,"V"],[4,5,"M"],[4,6,","],[4,7,"."],[4,9,"Space"],[4,10,"Enter"],[5,0,"Right"],[5,1,"PgUp"],[5,2,"PgDn"],[5,3,"Up"],[5,4,"B"],[5,5,"N"],[5,6,"End"],[5,8,"/"],[5,9,"Alt"],[5,10,"F12"],[6,0,"Ctrl"],[6,1,"`"],[6,2,"F1"],[6,3,"F2"],[6,4,"5"],[6,5,"6"],[6,6,"="],[6,7,"F8"],[6,8,"-"],[6,10,"F9"],[6,11,"Home"],[7,0,"F5"],[7,1,"1"],[7,2,"2"],[7,3,"3"],[7,4,"4"],[7,5,"7"],[7,6,"8"],[7,7,"9"],[7,8,"0"],[7,9,"Printscreen"],[7,10,"F10"]],"4141:6174":[],"4142:0000":[],"4142:4D55":[],"4145:065C":[],"4145:065D":[],"4145:0807":[[0,0,"End"],[0,1,"Home"],[0,2,"-"],[0,3,"*"],[0,4,"+"],[0,5,"9"],[0,6,"+"],[0,7,"6"],[0,8,"Enter"],[0,9,"3"],[0,10,"Enter"],[0,11,"."],[1,0,"Page Down"],[1,1,"Page Up"],[1,2,"/"],[1,3,"Backspace"],[1,4,"8"],[1,5,"7"],[1,6,"5"],[1,7,"4"],[1,8,"2"],[1,9,"1"],[1,10,"0"],[1,11,"\u2190"],[2,0,"Esc"],[2,1,"F1"],[2,2,"`"],[2,3,"1"],[2,4,"Tab"],[2,5,"Q"],[2,6,"Ctrl"],[2,7,"A"],[2,8,"\u2191"],[2,9,"Shift"],[2,10,"\u2193"],[2,11,"\u2192"],[3,0,"F2"],[3,1,"F3"],[3,2,"2"],[3,3,"3"],[3,4,"W"],[3,5,"E"],[3,6,"S"],[3,7,"D"],[3,8,"Z"],[3,9,"X"],[3,10,"Fn"],[3,11,"Alt"],[4,0,"F4"],[4,1,"F5"],[4,2,"4"],[4,3,"5"],[4,4,"R"],[4,5,"T"],[4,6,"F"],[4,7,"G"],[4,8,"C"],[4,9,"V"],[5,0,"F6"],[5,1,"F7"],[5,2,"6"],[5,3,"7"],[5,4,"Y"],[5,5,"U"],[5,6,"H"],[5,7,"J"],[5,8,"B"],[5,9,"N"],[5,11,"Space"],[6,0,"F8"],[6,1,"F9"],[6,2,"8"],[6,3,"9"],[6,4,"I"],[6,5,"O"],[6,6,"K"],[6,7,"L"],[6,8,"M"],[6,9,","],[7,0,"F10"],[7,1,"F11"],[7,2,"0"],[7,3,"-"],[7,4,"P"],[7,5,"["],[7,6,";"],[7,7,"'"],[7,8,"."],[7,9,"/"],[7,11,"Alt"],[8,0,"F12"],[8,1,"Delete"],[8,2,"="],[8,3,"\\"],[8,4,"]"],[8,5,"Backspace"],[8,6,"Enter"],[8,8,"Shift"],[8,9,"Fn"],[8,10,"GUI"],[8,11,"Ctrl"]],"4145:6553":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Fn"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"4146:0001":[],"414A:0084":[],"414B:0001":[],"414B:4F47":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"\\"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[9,4,"Space"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[12,4,"Alt"],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"Ctrl"],[14,0,"="],[14,1,"]"],[14,2,"#"],[14,3,"Shift"],[14,4,"\u2190"],[15,0,"Backspace"],[15,1,"\\"],[15,2,"Enter"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Delete"],[16,1,"Page Up"],[16,2,"Page Down"],[16,3,"End"],[16,4,"\u2192"],[17,0,"Home"]],"414B:4F4E":[],"414C:0004":[],"414C:0045":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Esc"],[0,3,"Shift"],[0,4,"1"],[0,5,"Q"],[0,6,"A"],[0,7,"Z"],[0,8,"Ctrl"],[1,0,"2"],[1,1,"W"],[1,2,"S"],[1,3,"X"],[1,4,"3"],[1,5,"E"],[1,6,"D"],[1,7,"C"],[1,8,"Fn"],[2,0,"4"],[2,1,"R"],[2,2,"F"],[2,3,"V"],[2,4,"5"],[2,5,"T"],[2,6,"G"],[2,7,"B"],[2,8,"Space"],[3,0,"6"],[3,1,"Y"],[3,2,"H"],[3,3,"N"],[3,4,"7"],[3,5,"U"],[3,6,"J"],[3,7,"M"],[3,8,"Fn2"],[4,0,"8"],[4,1,"I"],[4,2,"K"],[4,3,","],[4,4,"9"],[4,5,"O"],[4,6,"L"],[4,7,"."],[4,8,"Alt"],[5,0,"0"],[5,1,"P"],[5,2,";"],[5,3,"/"],[5,4,"Delete"],[5,5,"Backspace"],[5,6,"\\"],[5,7,"Enter"]],"414C:0050":[],"414C:0060":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Alt"],[13,0,"\\"],[13,1,"`"],[13,2,"Backspace"],[13,3,"Fn"],[13,4,"Ctrl"],[14,0,"\u25bd"],[14,1,"\u25bd"],[14,2,"\u25bd"],[14,3,"\u25bd"],[14,4,"\u25bd"],[15,0,"\u25bd"],[15,1,"\u25bd"],[15,2,"\u25bd"],[15,3,"\u25bd"],[15,4,"\u25bd"]],"414C:0065":[[0,0,"Esc"],[0,1,"Page Up"],[0,2,"Page Down"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"Alt"],[4,0,"3"],[4,1,"4"],[4,2,"E"],[4,3,"D"],[4,4,"C"],[5,0,"5"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Fn"],[7,0,"7"],[7,1,"Y"],[7,2,"H"],[7,3,"N"],[8,0,"8"],[8,1,"U"],[8,2,"J"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"I"],[9,2,"K"],[9,3,","],[10,0,"0"],[10,1,"O"],[10,2,"L"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"P"],[11,2,";"],[11,3,"/"],[12,0,"="],[12,1,"["],[12,2,"'"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"`"],[13,1,"]"],[13,2,"Enter"],[13,4,"\u2193"],[14,0,"Delete"],[14,1,"Backspace"],[14,3,"\u2191"],[14,4,"\u2192"]],"414C:0067":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Fn"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Shift"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[13,0,"Delete"],[14,0,"Backspace"],[14,1,"\\"],[14,2,"Enter"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Home"],[15,1,"End"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"\u2192"]],"414C:0075":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"Space"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"Fn"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"Alt"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[9,5,"Menu"],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"Ctrl"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[11,5,"\u2190"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"\\"],[14,0,"Insert"],[14,1,"Backspace"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"Play/Pause"],[15,1,"Home"],[15,2,"End"],[15,3,"Page Up"],[15,4,"Page Down"],[15,5,"\u2192"]],"414C:0080":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"GUI"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"Backspace"],[13,3,"\\"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,4,"\u25bd"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,4,"\u25bd"],[16,5,"\u2192"]],"414C:0765":[],"414C:0767":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"Delete"],[13,2,"\\"],[13,3,"\u2191"],[13,4,"\u2193"],[14,1,"End"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"414C:0768":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"Delete"],[13,2,"\\"],[13,3,"\u2191"],[13,4,"\u2193"],[14,1,"End"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"414C:0769":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"`"],[6,1,"P7"],[6,2,"P4"],[6,3,"P1"],[6,4,"Space"],[7,0,"-"],[7,1,"P8"],[7,2,"P5"],[7,3,"P2"],[8,0,"="],[8,1,"P9"],[8,2,"P6"],[8,3,"P3"],[9,0,"6"],[9,1,"Y"],[9,2,"H"],[9,3,"N"],[10,0,"7"],[10,1,"U"],[10,2,"J"],[10,3,"M"],[10,4,"Fn"],[11,0,"8"],[11,1,"I"],[11,2,"K"],[11,3,","],[11,4,"Ctrl"],[12,0,"9"],[12,1,"O"],[12,2,"L"],[12,3,"."],[13,0,"0"],[13,1,"P"],[13,2,":"],[13,3,"/"],[13,4,"\u2190"],[14,0,"Delete"],[14,1,"Backspace"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Home"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"Enter"],[15,4,"\u2192"]],"414C:0770":[],"414C:0795":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"Print Screen"],[13,1,"Backspace"],[13,2,"Backspace"],[13,3,"\\"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Scroll Lock"],[14,1,"Insert"],[14,2,"Page Up"],[14,3,"Page Down"],[14,5,"\u2192"],[15,0,"Pause"],[15,1,"Num Lock"],[15,2,"7"],[15,3,"4"],[15,4,"1"],[15,5,"0"],[16,0,"Home"],[16,1,"/"],[16,2,"8"],[16,3,"5"],[16,4,"2"],[17,0,"End"],[17,1,"*"],[17,2,"9"],[17,3,"6"],[17,4,"3"],[17,5,"."],[18,0,"Delete"],[18,1,"-"],[18,2,"+"],[18,4,"Enter"]],"414C:0799":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\u2298"],[1,5,"GUI"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[4,5,"Space"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"GUI"],[13,0,"F12"],[13,1,"\\"],[13,2,"Delete"],[13,3,"|"],[13,4,"Fn1"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"414C:4040":[],"414C:5050":[[0,0,"Esc"],[0,1,"Q"],[0,2,"Caps Lock"],[0,3,"A"],[0,4,"Shift"],[0,5,"/"],[0,6,"Ctrl"],[0,7,"GUI"],[1,0,"W"],[1,1,"E"],[1,2,"S"],[1,3,"D"],[1,4,"Z"],[1,5,"X"],[1,6,"Alt"],[2,0,"R"],[2,1,"T"],[2,2,"F"],[2,3,"G"],[2,4,"C"],[2,5,"V"],[2,6,"Space"],[3,0,"Y"],[3,1,"U"],[3,2,"H"],[3,3,"J"],[3,4,"B"],[3,5,"N"],[3,6,"Fn"],[4,0,"I"],[4,1,"O"],[4,2,"K"],[4,3,"L"],[4,4,"M"],[4,5,","],[4,6,"Space"],[4,7,"Fn2"],[5,0,"P"],[5,1,"["],[5,2,";"],[5,3,"'"],[5,4,"."],[5,5,"Shift"],[5,6,"Ctrl"],[5,7,"\u2190"],[6,0,"]"],[6,1,"Backspace"],[6,3,"Enter"],[6,4,"\u2191"],[6,5,"\\"],[6,6,"\u2193"],[6,7,"\u2192"]],"414C:5575":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"Space"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"Alt"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[9,5,"Fn"],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"Ctrl"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[11,5,"\u2190"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"\\"],[14,0,"Insert"],[14,1,"Backspace"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"Play/Pause"],[15,1,"Home"],[15,2,"End"],[15,3,"Page Up"],[15,4,"Page Down"],[15,5,"\u2192"]],"414C:6065":[],"414C:6067":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Caps Lock"],[0,5,"A"],[0,6,"Shift"],[0,7,"Z"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"X"],[1,7,"C"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"V"],[2,7,"B"],[3,0,"6"],[3,1,"7"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"N"],[3,7,"M"],[4,0,"8"],[4,1,"9"],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,","],[4,7,"."],[5,0,"0"],[5,1,"-"],[5,2,"P"],[5,3,"["],[5,4,";"],[5,5,"'"],[5,6,"/"],[5,7,"Shift"],[6,0,"="],[6,1,"Backspace"],[6,2,"]"],[6,3,"\\"],[6,4,"Enter"],[6,5,"Page Up"],[6,6,"\u2191"],[6,7,"Page Down"],[7,0,"Ctrl"],[7,1,"Alt"],[7,2,"Space"],[7,3,"Fn"],[7,4,"Ctrl"],[7,5,"\u2190"],[7,6,"\u2193"],[7,7,"\u2192"]],"414C:6075":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Fn3"],[0,4,"Fn2"],[0,5,"Fn"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"Caps Lock"],[1,4,"Shift"],[1,5,"Ctrl"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"A"],[2,4,"Z"],[2,5,"GUI"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"S"],[3,4,"X"],[3,5,"Alt"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"D"],[4,4,"C"],[4,5,"Space"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"F"],[5,4,"V"],[5,5,"Alt"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"G"],[6,4,"B"],[6,5,"Ctrl"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"H"],[7,4,"N"],[7,5,"\u2190"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"J"],[8,4,"M"],[8,5,"\u2193"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"K"],[9,4,","],[9,5,"\u2192"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,"L"],[10,4,"."],[10,5,"Page Down"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,";"],[11,4,"/"],[11,5,"Page Up"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"'"],[12,4,"Shift"],[12,5,"End"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"\u2191"],[13,5,"Home"]],"414C:7760":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"Backspace"],[13,1,"Delete"],[13,2,"\\"],[13,3,"Fn"],[13,4,"Ctrl"]],"414C:7762":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"Delete"],[13,2,"\\"],[13,3,"Fn"],[13,4,"Ctrl"]],"414C:7765":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"Delete"],[13,2,"\\"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"End"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"4150:4152":[],"4150:454C":[],"4150:454D":[],"4150:4B45":[],"4150:5645":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[13,0,"\\"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Fn"],[14,0,"`"]],"4150:7641":[],"4150:8776":[],"4150:8873":[],"4152:4F46":[],"4152:4F47":[[0,0,"k01"],[1,0,"k02"],[2,0,"k03"],[3,0,"k04"],[4,0,"k05"]],"4153:0001":[],"4154:4445":[],"4154:4454":[],"4154:4536":[],"4154:7A77":[],"4157:4930":[],"415A:0001":[],"415A:0004":[],"4161:3435":[],"416B:0001":[],"416B:0002":[],"416B:0003":[],"416B:0081":[],"41FA:AAEF":[],"41FF:AA99":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"0"],[0,6,"P"],[0,7,";"],[0,8,"."],[0,9,"GUI"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[1,5,"-"],[1,6,"["],[1,7,"'"],[1,8,"/"],[1,9,"Fn"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[2,5,"="],[2,6,"]"],[2,7,"#"],[2,8,"Shift"],[2,9,"\u2190"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,5,"Backspace"],[3,6,"\\"],[3,7,"Enter"],[3,8,"\u2191"],[3,9,"\u2193"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[4,5,"\u2298"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,5,"Num Lock"],[5,6,"7"],[5,7,"4"],[5,8,"1"],[5,9,"\u2192"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[6,5,"/"],[6,6,"8"],[6,7,"5"],[6,8,"2"],[6,9,"0"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[7,5,"*"],[7,6,"9"],[7,7,"6"],[7,8,"3"],[7,9,"."],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,5,"-"],[8,6,"+"],[8,7,"="],[8,8,"Enter"],[8,9,"Backspace"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"]],"420A:B0BA":[],"4242:5A4C":[[0,0,"K000"],[0,1,"K100"],[0,2,"K200"],[0,3,"K300"],[0,4,"K400"],[0,5,"K500"],[1,0,"K001"],[1,1,"K101"],[1,2,"K201"],[1,3,"K301"],[1,4,"K401"],[1,5,"K501"],[2,0,"K002"],[2,1,"K102"],[2,2,"K202"],[2,3,"K302"],[2,4,"K402"],[2,5,"K502"],[3,0,"K003"],[3,1,"K103"],[3,2,"K203"],[3,3,"K303"],[3,4,"K403"],[4,0,"K004"],[4,1,"K104"],[4,2,"K204"],[4,3,"K304"],[4,4,"K404"],[5,0,"K005"],[5,1,"K105"],[5,2,"K205"],[5,3,"K305"],[5,4,"K405"],[5,5,"K505"],[6,0,"K006"],[6,1,"K106"],[6,2,"K206"],[6,3,"K306"],[6,4,"K406"],[7,0,"K007"],[7,1,"K107"],[7,2,"K207"],[7,3,"K307"],[7,4,"K407"],[8,0,"K008"],[8,1,"K108"],[8,2,"K208"],[8,3,"K308"],[8,4,"K408"],[8,5,"K508"],[9,0,"K009"],[9,1,"K109"],[9,2,"K209"],[9,3,"K309"],[9,4,"K409"],[9,5,"K509"],[10,0,"K010"],[10,1,"K110"],[10,2,"K210"],[10,3,"K310"],[10,4,"K410"],[11,0,"K011"],[11,1,"K111"],[11,2,"K211"],[11,3,"K311"],[11,4,"K411"],[11,5,"K511"],[12,0,"K012"],[12,1,"K112"],[12,2,"K212"],[12,3,"K312"],[13,1,"K113"],[13,2,"K213"],[13,4,"K413"],[13,5,"K513"],[14,0,"K014"],[14,1,"K114"],[14,2,"K214"],[14,3,"K314"],[14,4,"K414"],[14,5,"K514"]],"4243:0001":[],"4243:0002":[],"4244:0001":[],"4245:544C":[],"4245:6050":[],"4249:4040":[],"4249:426E":[],"4249:4287":[],"4249:4295":[[0,0,"k00"],[0,1,"k10"],[0,2,"k20"],[1,0,"k01"],[1,1,"k11"],[1,2,"k21"],[2,0,"k02"],[2,1,"k12"],[2,2,"k22"]],"4249:4E39":[[0,0,"Knob"],[0,1,"1"],[0,2,"4"],[0,3,"7"],[1,1,"2"],[1,2,"5"],[1,3,"8"],[2,1,"3"],[2,2,"6"],[2,3,"9"]],"4249:4E41":[[0,0,"1"],[0,1,"3"],[0,2,"6"],[1,0,"2"],[1,1,"4"],[1,2,"7"],[2,0,"Knob"],[2,1,"5"],[2,2,"8"]],"4249:5078":[],"424B:D87A":[],"424C:4B01":[],"424C:5343":[],"424D:4D4E":[],"4250:4D4C":[],"4250:5245":[],"4250:5247":[],"4252:0002":[],"4252:3635":[],"4253:414C":[],"4253:5250":[],"4254:7070":[],"4273:0001":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"\\|"],[0,4,"Ctrl"],[1,0,"1!"],[1,3,"Shift"],[1,4,"GUI"],[2,0,"2@"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[3,0,"3#"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"Alt"],[4,0,"4$"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[4,4,"Space"],[5,0,"5%"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[6,0,"6^"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Space"],[7,0,"7&"],[7,1,"Y"],[7,2,"H"],[7,3,"N"],[8,0,"8*"],[8,1,"U"],[8,2,"J"],[8,3,"M"],[8,4,"Space"],[9,0,"9("],[9,1,"I"],[9,2,"K"],[9,3,",<"],[10,0,"0)"],[10,1,"O"],[10,2,"L"],[10,3,".>"],[10,4,"Alt"],[11,0,"-_"],[11,1,"P"],[11,2,";:"],[11,3,"/?"],[11,4,"Ctrl"],[12,0,"=+"],[12,1,"[{"],[12,2,"'\""],[12,4,"`~"],[13,0,"Backspace"],[13,1,"]}"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"Backspace"],[14,1,"\\|"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"RGB Toggle"],[15,1,"RGB Mode"],[15,2,"Fn"],[15,4,"\u2192"]],"4273:0066":[],"4273:0079":[],"4273:0083":[],"4273:0304":[],"4273:0412":[],"4273:0512":[],"4273:1031":[],"4273:17AC":[],"4273:7552":[],"4273:7563":[],"4273:7685":[],"4273:7688":[],"4335:0001":[],"4335:0002":[],"4341:0621":[],"4342:1075":[],"4342:1818":[[0,0,"Esc"],[0,1,"F11"],[0,2,"1"],[0,3,"="],[0,4,"R"],[0,5,"8"],[0,6,"K"],[0,7,"\\"],[0,8,"Shift"],[0,9,"GUI"],[1,0,"F1"],[1,1,"F12"],[1,2,"2"],[1,3,"Backspace"],[1,4,"T"],[1,5,"9"],[1,6,"L"],[1,7,"Z"],[1,8,"\u2191"],[1,9,"Menu"],[2,0,"F2"],[2,1,"Insert"],[2,2,"3"],[2,3,"Backspace"],[2,4,"Y"],[2,5,"-"],[2,6,";"],[2,7,"X"],[2,8,"1"],[2,9,"Ctrl"],[3,0,"F3"],[3,1,"Home"],[3,2,"4"],[3,3,"Num Lock"],[3,4,"U"],[3,5,"Caps Lock"],[3,6,"'"],[3,7,"C"],[3,8,"2"],[3,9,"\u2190"],[4,0,"F4"],[4,1,"Page Up"],[4,2,"5"],[4,3,"/"],[4,4,"I"],[4,5,"A"],[4,6,"#"],[4,7,"V"],[4,8,"3"],[4,9,"\u2193"],[5,0,"F5"],[5,1,"Print Screen"],[5,2,"6"],[5,3,"*"],[5,4,"O"],[5,5,"S"],[5,6,"Enter"],[5,7,"B"],[5,8,"Enter"],[5,9,"\u2192"],[6,0,"F6"],[6,1,"Delete"],[6,2,"7"],[6,3,"Pause"],[6,4,"P"],[6,5,"D"],[6,6,"4"],[6,7,"N"],[6,8,"Ctrl"],[6,9,"0"],[7,0,"F7"],[7,1,"End"],[7,2,"8"],[7,3,"Tab"],[7,4,"["],[7,5,"F"],[7,6,"5"],[7,7,"M"],[7,8,"GUI"],[7,9,"."],[8,0,"F8"],[8,1,"Page Down"],[8,2,"9"],[8,3,"Q"],[8,4,"]"],[8,5,"G"],[8,6,"6"],[8,7,","],[8,8,"Alt"],[8,9,"Enter"],[9,0,"F9"],[9,1,"Scroll Lock"],[9,2,"0"],[9,3,"W"],[9,4,"\\"],[9,5,"H"],[9,6,"+"],[9,7,"."],[9,8,"Space"],[9,9,"Reset"],[10,0,"F10"],[10,1,"`"],[10,2,"-"],[10,3,"E"],[10,4,"7"],[10,5,"J"],[10,6,"Shift"],[10,7,"/"],[10,8,"Alt"]],"4342:4356":[],"4342:6565":[[0,0,"Esc"],[0,1,"8"],[0,2,"Tab"],[0,3,"I"],[0,4,"A"],[0,5,"L"],[0,6,"Z"],[0,7,"."],[0,8,"Space"],[1,0,"1"],[1,1,"9"],[1,2,"Q"],[1,3,"O"],[1,4,"S"],[1,5,";"],[1,6,"X"],[1,7,"/"],[1,8,"Alt"],[2,0,"2"],[2,1,"0"],[2,2,"W"],[2,3,"P"],[2,4,"D"],[2,5,"'"],[2,6,"C"],[2,7,"Shift"],[2,8,"Fn"],[3,0,"3"],[3,1,"-"],[3,2,"E"],[3,3,"["],[3,4,"F"],[3,5,"#"],[3,6,"V"],[3,7,"\u2191"],[3,8,"\u2190"],[4,0,"4"],[4,1,"="],[4,2,"R"],[4,3,"]"],[4,4,"G"],[4,5,"Enter"],[4,6,"B"],[4,7,"End"],[4,8,"\u2193"],[5,0,"5"],[5,1,"Backspace"],[5,2,"T"],[5,3,"\\"],[5,4,"H"],[5,5,"Home"],[5,6,"N"],[5,7,"Ctrl"],[5,8,"\u2192"],[6,0,"6"],[6,1,"Backspace"],[6,2,"Y"],[6,3,"Delete"],[6,4,"J"],[6,5,"Shift"],[6,6,"M"],[6,7,"GUI"],[7,0,"7"],[7,1,"Reset"],[7,2,"U"],[7,3,"Caps Lock"],[7,4,"K"],[7,5,"\\"],[7,6,","],[7,7,"Alt"]],"4342:8785":[[0,0,"Esc"],[0,1,"F10"],[0,2,"4"],[0,3,"Backspace"],[0,4,"Y"],[0,5,"Page Down"],[0,6,"L"],[0,7,"V"],[0,8,"Ctrl"],[0,9,"\u2192"],[1,0,"F1"],[1,1,"F11"],[1,2,"5"],[1,3,"Insert"],[1,4,"U"],[1,5,"Caps Lock"],[1,6,";"],[1,7,"B"],[1,8,"GUI"],[1,9,"Reset"],[2,0,"F2"],[2,1,"F12"],[2,2,"6"],[2,3,"Home"],[2,4,"I"],[2,5,"A"],[2,6,"'"],[2,7,"N"],[2,8,"Alt"],[3,0,"F3"],[3,1,"Print Screen"],[3,2,"7"],[3,3,"Page Up"],[3,4,"O"],[3,5,"S"],[3,6,"#"],[3,7,"M"],[3,8,"Space"],[4,0,"F4"],[4,1,"Scroll Lock"],[4,2,"8"],[4,3,"Tab"],[4,4,"P"],[4,5,"D"],[4,6,"Enter"],[4,7,","],[4,8,"Alt"],[5,0,"F5"],[5,1,"Pause"],[5,2,"9"],[5,3,"Q"],[5,4,"["],[5,5,"F"],[5,6,"Shift"],[5,7,"."],[5,8,"GUI"],[6,0,"F6"],[6,1,"`"],[6,2,"0"],[6,3,"W"],[6,4,"]"],[6,5,"G"],[6,6,"\\"],[6,7,"/"],[6,8,"Menu"],[7,0,"F7"],[7,1,"1"],[7,2,"-"],[7,3,"E"],[7,4,"\\"],[7,5,"H"],[7,6,"Z"],[7,7,"Shift"],[7,8,"Ctrl"],[8,0,"F8"],[8,1,"2"],[8,2,"="],[8,3,"R"],[8,4,"Delete"],[8,5,"J"],[8,6,"X"],[8,7,"Shift"],[8,8,"\u2190"],[9,0,"F9"],[9,1,"3"],[9,2,"Backspace"],[9,3,"T"],[9,4,"End"],[9,5,"K"],[9,6,"C"],[9,7,"\u2191"],[9,8,"\u2193"]],"4342:8787":[],"4342:8788":[[0,0,"Esc"],[0,1,"F10"],[0,2,"4"],[0,3,"Backspace"],[0,4,"Y"],[0,5,"Page Down"],[0,6,"L"],[0,7,"V"],[0,8,"Ctrl"],[0,9,"\u2190"],[1,0,"F1"],[1,1,"F11"],[1,2,"5"],[1,3,"Insert"],[1,4,"U"],[1,5,"Caps Lock"],[1,6,";"],[1,7,"B"],[1,8,"GUI"],[1,9,"\u2193"],[2,0,"F2"],[2,1,"F12"],[2,2,"6"],[2,3,"Home"],[2,4,"I"],[2,5,"A"],[2,6,"'"],[2,7,"N"],[2,8,"Alt"],[2,9,"\u2192"],[3,0,"F3"],[3,1,"Print Screen"],[3,2,"7"],[3,3,"Page Up"],[3,4,"O"],[3,5,"S"],[3,6,"#"],[3,7,"M"],[3,8,"Space"],[4,0,"F4"],[4,1,"Scroll Lock"],[4,2,"8"],[4,3,"Tab"],[4,4,"P"],[4,5,"D"],[4,6,"Enter"],[4,7,","],[4,8,"Space"],[5,0,"F5"],[5,1,"Pause"],[5,2,"9"],[5,3,"Q"],[5,4,"["],[5,5,"F"],[5,6,"Shift"],[5,7,"."],[5,8,"Space"],[6,0,"F6"],[6,1,"`"],[6,2,"0"],[6,3,"W"],[6,4,"]"],[6,5,"G"],[6,6,"\\"],[6,7,"/"],[6,8,"Alt"],[7,0,"F7"],[7,1,"1"],[7,2,"-"],[7,3,"E"],[7,4,"\\"],[7,5,"H"],[7,6,"Z"],[7,7,"Shift"],[7,8,"GUI"],[8,0,"F8"],[8,1,"2"],[8,2,"="],[8,3,"R"],[8,4,"Delete"],[8,5,"J"],[8,6,"X"],[8,7,"Shift"],[8,8,"Menu"],[9,0,"F9"],[9,1,"3"],[9,2,"Backspace"],[9,3,"T"],[9,4,"End"],[9,5,"K"],[9,6,"C"],[9,7,"\u2191"],[9,8,"Ctrl"]],"4342:ABC0":[],"4344:4348":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"GUI"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"`"],[13,1,"\\"],[13,2,"Volume Down"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[14,1,"Volume Up"],[14,3,"Mute"],[14,4,"\u2192"]],"4344:5335":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"\\"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[5,4,"Space"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[7,4,"Fn"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[10,4,"Space"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[12,4,"Alt"],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"\u2190"],[14,0,"="],[14,1,"]"],[14,2,"Enter"],[14,3,"Shift"],[14,4,"\u2193"],[15,0,"`"],[15,1,"\\"],[15,2,"Volume Down"],[15,3,"Mute"],[15,4,"\u2192"],[16,0,"Backspace"],[16,1,"Volume Up"],[16,3,"\u2191"],[16,4,"Next Track"]],"4344:5353":[],"4345:2EC0":[],"434B:1401":[],"434B:4E49":[],"434B:4F50":[],"434B:6049":[],"434B:E590":[],"434C:464C":[],"434D:364D":[],"434D:5348":[],"434D:534B":[],"4353:6501":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Caps Lock"],[0,5,"A"],[0,6,"Shift"],[0,7,"\u25bd"],[0,8,"Ctrl"],[0,9,"GUI"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"Z"],[1,7,"X"],[1,8,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"C"],[2,7,"V"],[3,0,"6"],[3,1,"7"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"B"],[3,7,"N"],[3,8,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,"M"],[4,7,","],[5,0,"0"],[5,1,"-"],[5,2,"P"],[5,3,"["],[5,4,";"],[5,5,"'"],[5,6,"."],[5,7,"/"],[5,8,"Alt"],[5,9,"Fn"],[6,0,"="],[6,1,"`"],[6,2,"]"],[6,4,"\u25bd"],[6,6,"Shift"],[6,9,"\u2190"],[7,0,"\\"],[7,1,"Insert"],[7,2,"Backspace"],[7,3,"Delete"],[7,4,"Enter"],[7,5,"Page Up"],[7,6,"\u2191"],[7,8,"\u2193"],[7,9,"\u2192"]],"4354:0001":[[0,0,"Tab"],[0,1,"Esc"],[0,2,"Shift"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Ctrl"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Super"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"⇓"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"⇑"],[8,0,"I"],[8,1,"K"],[8,2,","],[8,3,"←"],[9,0,"O"],[9,1,"L"],[9,2,"."],[9,3,"↓"],[10,0,"P"],[10,1,";"],[10,2,"/"],[10,3,"↑"],[11,0,"BackSpace"],[11,1,"'"],[11,2,"Return"],[11,3,"→"]],"4355:0007":[],"4355:0065":[],"4357:0003":[],"4357:0004":[],"4357:0005":[],"4358:0601":[],"4358:0602":[],"4358:0603":[],"4358:0604":[],"4358:0611":[],"4358:3630":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Shift"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"\u2191"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\"],[13,3,"Delete"],[13,4,"\u2192"]],"4413:4A13":[[0,0,"`"],[0,1,"Tab"],[0,2,"Esc"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"-"],[0,6,"Enter"],[0,7,"'"],[0,8,"Shift"],[0,9,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[1,5,"0"],[1,6,"P"],[1,7,";"],[1,8,"/"],[1,9,"Win"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[2,5,"9"],[2,6,"O"],[2,7,"L"],[2,8,"."],[2,9,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Del"],[3,5,"8"],[3,6,"I"],[3,7,"K"],[3,8,","],[3,9,"Shift"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Spc"],[4,5,"7"],[4,6,"U"],[4,7,"J"],[4,8,"M"],[4,9,"Bspc"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Mute"],[5,5,"6"],[5,6,"Y"],[5,7,"H"],[5,8,"N"],[5,9,"XXX"]],"4442:6462":[],"4442:FF44":[],"4443:21D7":[[0,0,"k00"],[0,1,"k10"],[0,2,"k20"],[0,3,"k30"],[0,4,"k40"],[0,5,"k50"],[0,6,"k60"],[0,7,"k70"],[0,8,"k80"],[0,9,"k90"],[0,10,"kA0"],[0,11,"kB0"],[0,12,"kC0"],[0,13,"kD0"],[0,14,"kE0"],[1,0,"k01"],[1,1,"k11"],[1,2,"k21"],[1,3,"k31"],[1,4,"k41"],[1,5,"k51"],[1,6,"k61"],[1,7,"k71"],[1,8,"k81"],[1,9,"k91"],[1,10,"kA1"],[1,11,"kB1"],[1,12,"kC1"],[1,13,"kD1"],[1,14,"kE1"],[2,0,"k02"],[2,1,"k12"],[2,2,"k22"],[2,3,"k32"],[2,4,"k42"],[2,5,"k52"],[2,6,"k62"],[2,7,"k72"],[2,8,"k82"],[2,9,"k92"],[2,10,"kA2"],[2,11,"kB2"],[2,12,"kC2"],[2,13,"kD2"],[2,14,"kE2"],[3,0,"k03"],[3,1,"k13"],[3,2,"k23"],[3,3,"k33"],[3,4,"k43"],[3,5,"k53"],[3,6,"k63"],[3,7,"k73"],[3,8,"k83"],[3,9,"k93"],[3,10,"kA3"],[3,11,"kB3"],[3,12,"kC3"],[3,13,"kD3"],[3,14,"kE3"],[4,0,"k04"],[4,1,"k14"],[4,2,"k24"],[4,3,"k34"],[4,4,"k44"],[4,5,"k54"],[4,6,"k64"],[4,7,"k74"],[4,8,"k84"],[4,9,"k94"],[4,10,"kA4"],[4,11,"kB4"],[4,12,"kC4"],[4,13,"kD4"],[4,14,"kE4"],[5,0,"k05"],[5,1,"k15"],[5,2,"k25"],[5,3,"k35"],[5,4,"k45"],[5,5,"k55"],[5,6,"k65"],[5,7,"k75"],[5,8,"k85"],[5,9,"k95"],[5,10,"kA5"],[5,11,"kB5"],[5,12,"kC5"],[5,13,"kD5"],[5,14,"kE5"],[6,0,"k06"],[6,1,"k16"],[6,2,"k26"],[6,3,"k36"],[6,4,"k46"],[6,5,"k56"],[6,6,"k66"],[6,7,"k76"],[6,8,"k86"],[6,9,"k96"],[6,10,"kA6"],[6,11,"kB6"],[6,12,"kC6"],[6,13,"kD6"],[6,14,"kE6"],[7,0,"k07"],[7,1,"k17"],[7,2,"k27"],[7,3,"k37"],[7,4,"k47"],[7,5,"k57"],[7,6,"k67"],[7,7,"k77"],[7,8,"k87"],[7,9,"k97"],[7,10,"kA7"],[7,11,"kB7"],[7,12,"kC7"],[7,13,"kD7"],[7,14,"kE7"],[8,0,"k08"],[8,1,"k18"],[8,2,"k28"],[8,3,"k38"],[8,4,"k48"],[8,5,"k58"],[8,6,"k68"],[8,7,"k78"],[8,8,"k88"],[8,9,"k98"],[8,10,"kA8"],[8,11,"kB8"],[8,12,"kC8"],[8,13,"kD8"],[8,14,"kE8"],[9,0,"k09"],[9,1,"k19"],[9,2,"k29"],[9,3,"k39"],[9,4,"k49"],[9,5,"k59"],[9,6,"k69"],[9,7,"k79"],[9,8,"k89"],[9,9,"k99"],[9,10,"kA9"],[9,11,"kB9"],[9,12,"kC9"],[9,13,"kD9"],[9,14,"kE9"],[10,0,"k0A"],[10,1,"k1A"],[10,2,"k2A"],[10,3,"k3A"],[10,4,"k4A"],[10,5,"k5A"],[10,6,"k6A"],[10,7,"k7A"],[10,8,"k8A"],[10,9,"k9A"],[10,10,"kAA"],[10,11,"kBA"],[10,12,"kCA"],[10,13,"kDA"],[10,14,"kEA"],[11,0,"k0B"],[11,1,"k1B"],[11,2,"k2B"],[11,3,"k3B"],[11,4,"k4B"],[11,5,"k5B"],[11,6,"k6B"],[11,7,"k7B"],[11,8,"k8B"],[11,9,"k9B"],[11,10,"kAB"],[11,11,"kBB"],[11,12,"kCB"],[11,13,"kDB"],[11,14,"kEB"],[12,0,"k0C"],[12,1,"k1C"],[12,2,"k2C"],[12,3,"k3C"],[12,4,"k4C"],[12,5,"k5C"],[12,6,"k6C"],[12,7,"k7C"],[12,8,"k8C"],[12,9,"k9C"],[12,10,"kAC"],[12,11,"kBC"],[12,12,"kCC"],[12,13,"kDC"],[12,14,"kEC"],[13,0,"k0D"],[13,1,"k1D"],[13,2,"k2D"],[13,3,"k3D"],[13,4,"k4D"],[13,5,"k5D"],[13,6,"k6D"],[13,7,"k7D"],[13,8,"k8D"],[13,9,"k9D"],[13,10,"kAD"],[13,11,"kBD"],[13,12,"kCD"],[13,13,"kDD"],[13,14,"kED"],[14,0,"k0E"],[14,1,"k1E"],[14,2,"k2E"],[14,3,"k3E"],[14,4,"k4E"],[14,5,"k5E"],[14,6,"k6E"],[14,7,"k7E"],[14,8,"k8E"],[14,9,"k9E"],[14,10,"kAE"],[14,11,"kBE"],[14,12,"kCE"],[14,13,"kDE"],[14,14,"kEE"]],"4443:4C43":[],"4443:4C53":[],"4443:4D43":[],"4443:5350":[],"4443:B960":[],"4444:0002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"NUBS"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"None"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Alt"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"LSpace"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"RSpace"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Alt"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Win"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"None"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Menu"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Fn"],[12,0,"+"],[12,1,"}"],[12,2,"NUHS"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"|"],[13,1,"|"],[13,2,"Enter"],[13,3,"Up"],[13,4,"~"]],"4444:0003":[],"4444:0004":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space1"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space2"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space3"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Alt"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Menu"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Win"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"Ctrl"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[12,0,"+"],[12,1,"}"],[12,2,"Enter"],[12,3,"Shift"],[13,0,"|"],[13,1,"Backsp."],[13,3,"Fn"],[14,0,"~"]],"4444:0005":[],"4444:0007":[[0,0,"Esc"],[0,1,"!"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Caps Lock"],[0,5,"A"],[0,6,"Shift"],[0,7,"|"],[0,8,"Ctrl"],[0,9,"Win"],[1,0,"@"],[1,1,"#"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"Z"],[1,7,"X"],[1,9,"Alt"],[2,0,"$"],[2,1,"%"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"C"],[2,7,"V"],[3,0,"^"],[3,1,"&"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"B"],[3,7,"N"],[3,9,"Space"],[4,0,"*"],[4,1,"("],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,"M"],[4,7,"<"],[4,9,"Alt"],[5,0,")"],[5,1,"_"],[5,2,"P"],[5,3,"{"],[5,4,":"],[5,5,"\""],[5,6,">"],[5,7,"?"],[5,8,"Menu"],[5,9,"Win"],[6,0,"+"],[6,1,"|"],[6,2,"}"],[6,3,"~"],[6,4,"~"],[6,5,"Backsp."],[6,6,"Shift"],[6,7,"Enter"],[6,8,"Ctrl"],[6,9,"Fn"]],"4444:0008":[],"4444:0009":[],"4444:000A":[[0,0,"Esc"],[0,2,"`"],[0,3,"1"],[0,4,"Tab"],[0,5,"Q"],[0,6,"Caps Lock"],[0,7,"A"],[0,8,"Shift"],[0,9,"\\"],[0,10,"Ctrl"],[1,0,"F1"],[1,1,"F2"],[1,2,"2"],[1,3,"3"],[1,4,"W"],[1,5,"E"],[1,6,"S"],[1,7,"D"],[1,8,"Z"],[1,9,"X"],[1,10,"GUI"],[1,11,"Alt"],[2,0,"F3"],[2,1,"F4"],[2,2,"4"],[2,3,"5"],[2,4,"R"],[2,5,"T"],[2,6,"F"],[2,7,"G"],[2,8,"C"],[2,9,"V"],[2,11,"Space"],[3,0,"F5"],[3,1,"F6"],[3,2,"6"],[3,3,"7"],[3,4,"Y"],[3,5,"U"],[3,6,"H"],[3,7,"J"],[3,8,"B"],[3,9,"N"],[3,11,"Space"],[4,0,"F7"],[4,1,"F8"],[4,2,"8"],[4,3,"9"],[4,4,"I"],[4,5,"O"],[4,6,"K"],[4,7,"L"],[4,8,"M"],[4,9,","],[4,11,"Space"],[5,0,"F9"],[5,1,"F10"],[5,2,"0"],[5,3,"-"],[5,4,"P"],[5,5,"["],[5,6,";"],[5,7,"'"],[5,8,"."],[5,9,"/"],[5,11,"Alt"],[6,0,"F11"],[6,1,"F12"],[6,2,"="],[6,3,"\\"],[6,4,"]"],[6,5,"\\"],[6,6,"#"],[6,7,"Enter"],[6,8,"Shift"],[6,9,"Fn"],[6,10,"GUI"],[6,11,"Ctrl"],[7,0,"Print Screen"],[7,2,"Backspace"],[7,3,"Insert"],[7,4,"Delete"],[7,10,"\u2190"],[8,0,"Pause"],[8,1,"Scroll Lock"],[8,2,"Home"],[8,3,"Page Up"],[8,4,"End"],[8,5,"Page Down"],[8,9,"\u2191"],[8,10,"\u2192"],[8,11,"\u2193"]],"4444:000C":[],"4444:000D":[],"4444:000E":[],"4444:0010":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Caps Lock"],[0,5,"A"],[0,6,"Shift"],[0,7,"\\"],[0,8,"Ctrl"],[0,9,"GUI"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"Z"],[1,7,"X"],[1,9,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"C"],[2,7,"V"],[2,9,"Space"],[3,0,"6"],[3,1,"7"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"B"],[3,7,"N"],[3,9,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,"M"],[4,7,","],[4,8,"Space"],[4,9,"Alt"],[5,0,"0"],[5,1,"-"],[5,2,"P"],[5,3,"["],[5,4,";"],[5,5,"'"],[5,6,"."],[5,7,"/"],[5,8,"Alt"],[5,9,"GUI"],[6,0,"="],[6,1,"\\"],[6,2,"]"],[6,3,"`"],[6,4,"#"],[6,5,"Backspace"],[6,6,"Shift"],[6,7,"Enter"],[6,8,"Fn"],[6,9,"Fn"]],"4444:0012":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Caps"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"nubs"],[1,4,"opt"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Cmd"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"`"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"\\"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"\u2190"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"\u2192"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"\u2193"],[12,0,"+"],[12,1,"}"],[12,3,"Shift"],[12,4,"\u2191"],[13,0,"Backsp"],[13,1,"|"],[13,2,"Enter"],[13,3,"nubs"],[13,4,"\u2191"]],"4444:0013":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"NUBS"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"None"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Alt"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"LSpace"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"RSpace"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Alt"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Win"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"None"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Menu"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Fn"],[12,0,"+"],[12,1,"}"],[12,2,"NUHS"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"|"],[13,1,"|"],[13,2,"Enter"],[13,3,"Up"],[13,4,"~"]],"4444:0014":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"NUBS"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Alt"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"Alt"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Win"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Menu"],[12,0,"+"],[12,1,"}"],[12,2,"NUHS"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"|"],[13,1,"|"],[13,2,"Backspace"],[13,3,"Enter"],[13,4,"Fn"]],"4444:0016":[],"4445:0001":[],"4445:0002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"~"],[12,3,"Shift"],[12,4,"Left"],[13,0,"/"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Up"],[13,4,"Down"],[14,0,"Home"],[14,1,"End"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"Right"]],"4446:0001":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,4,"Caps Lock"],[0,6,"Shift"],[0,8,"Ctrl"],[1,0,"2"],[1,1,"3"],[1,2,"Q"],[1,3,"W"],[1,4,"A"],[1,5,"S"],[1,6,"Z"],[1,7,"X"],[1,8,"GUI"],[1,9,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"E"],[2,3,"R"],[2,4,"D"],[2,5,"F"],[2,6,"C"],[2,7,"V"],[3,0,"6"],[3,1,"7"],[3,2,"T"],[3,3,"Y"],[3,4,"G"],[3,5,"H"],[3,6,"B"],[3,7,"N"],[3,8,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"U"],[4,3,"I"],[4,4,"J"],[4,5,"K"],[4,6,"M"],[4,7,","],[4,9,"GUI"],[5,0,"0"],[5,1,"-"],[5,2,"O"],[5,3,"P"],[5,4,"L"],[5,5,";"],[5,6,"."],[5,7,"/"],[5,9,"Fn"],[6,0,"="],[6,2,"["],[6,3,"]"],[6,4,"'"],[6,6,"Shift"],[6,9,"\u2190"],[7,0,"Backspace"],[7,1,"Delete"],[7,2,"\\"],[7,3,"Insert"],[7,4,"Enter"],[7,5,"Page Up"],[7,6,"\u2191"],[7,7,"Page Down"],[7,8,"\u2193"],[7,9,"\u2192"]],"4446:0002":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,4,"Caps Lock"],[0,6,"Shift"],[0,7,"\\"],[0,8,"Ctrl"],[1,0,"2"],[1,1,"3"],[1,2,"Q"],[1,3,"W"],[1,4,"A"],[1,5,"S"],[1,6,"Z"],[1,7,"X"],[1,8,"GUI"],[1,9,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"E"],[2,3,"R"],[2,4,"D"],[2,5,"F"],[2,6,"C"],[2,7,"V"],[3,0,"6"],[3,1,"7"],[3,2,"T"],[3,3,"Y"],[3,4,"G"],[3,5,"H"],[3,6,"B"],[3,7,"N"],[3,8,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"U"],[4,3,"I"],[4,4,"J"],[4,5,"K"],[4,6,"M"],[4,7,","],[4,9,"GUI"],[5,0,"0"],[5,1,"-"],[5,2,"O"],[5,3,"P"],[5,4,"L"],[5,5,";"],[5,6,"."],[5,7,"/"],[5,9,"Fn"],[6,0,"="],[6,1,"`"],[6,2,"["],[6,3,"]"],[6,4,"'"],[6,5,"#"],[6,6,"Shift"],[6,9,"\u2190"],[7,0,"Backspace"],[7,1,"Delete"],[7,2,"\\"],[7,3,"Insert"],[7,4,"Enter"],[7,5,"Page Up"],[7,6,"\u2191"],[7,7,"Page Down"],[7,8,"\u2193"],[7,9,"\u2192"]],"4446:0003":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Alt"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,2,"|"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"|"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Ctrl"]],"4446:4660":[],"4446:4665":[[0,0,"Esc"],[0,1,"tab"],[0,2,"capslock"],[0,3,"leftshift"],[0,4,"lctrl"],[1,0,"1"],[1,1,"q"],[1,2,"a"],[1,4,"lwin"],[2,0,"2"],[2,1,"w"],[2,2,"s"],[2,3,"z"],[2,4,"lalt"],[3,0,"3"],[3,1,"e"],[3,2,"d"],[3,3,"x"],[4,0,"4"],[4,1,"r"],[4,2,"f"],[4,3,"c"],[5,0,"5"],[5,1,"t"],[5,2,"g"],[5,3,"v"],[6,0,"6"],[6,1,"y"],[6,2,"h"],[6,3,"b"],[6,4,"space"],[7,0,"7"],[7,1,"u"],[7,2,"j"],[7,3,"n"],[8,0,"8"],[8,1,"i"],[8,2,"k"],[8,3,"m"],[9,0,"9"],[9,1,"o"],[9,2,"l"],[9,3,","],[9,4,"ralt"],[10,0,"0"],[10,1,"p"],[10,2,";"],[10,3,"."],[10,4,"MO(1)"],[11,0,"-"],[11,1,"{"],[11,2,"'"],[11,3,"/"],[11,4,"left"],[12,0,"="],[12,1,"}"],[12,2,"enter"],[12,3,"rightshift"],[12,4,"down"],[13,0,"backspace"],[13,2,"|"],[13,3,"up"],[13,4,"right"],[14,0,"home"],[14,1,"insert"],[14,2,"delete"],[14,3,"end"]],"4446:4680":[[0,0,"Esc"],[0,1,"\uff5e"],[0,2,"tab"],[0,3,"capslock"],[0,4,"leftshift"],[0,5,"Pause"],[0,6,"pg up"],[0,7,"pg dn"],[0,9,"right"],[0,10,"lctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"q"],[1,3,"a"],[1,4,"z"],[1,5,"Scrlk"],[1,6,"home"],[1,7,"end"],[1,8,"up"],[1,9,"down"],[1,10,"lwin"],[2,0,"F2"],[2,1,"2"],[2,2,"w"],[2,3,"s"],[2,4,"x"],[2,5,"Prtsc"],[2,6,"insert"],[2,7,"delete"],[2,9,"left"],[2,10,"lalt"],[3,0,"F3"],[3,1,"3"],[3,2,"e"],[3,3,"d"],[3,4,"c"],[3,5,"F13"],[3,10,"space"],[4,0,"F4"],[4,1,"4"],[4,2,"r"],[4,3,"f"],[4,4,"v"],[4,5,"F12"],[4,6,"backspace"],[4,7,"|"],[5,0,"F5"],[5,1,"5"],[5,2,"t"],[5,3,"g"],[5,4,"b"],[5,5,"F11"],[5,6,"="],[5,7,"}"],[5,8,"enter"],[5,10,"ralt"],[6,0,"F6"],[6,1,"6"],[6,2,"y"],[6,3,"h"],[6,4,"n"],[6,5,"F10"],[6,6,"-"],[6,7,"{"],[6,8,"'"],[6,9,"rightshift"],[6,10,"rwin"],[7,0,"F7"],[7,1,"7"],[7,2,"u"],[7,3,"j"],[7,4,"m"],[7,5,"F9"],[7,6,"0"],[7,7,"p"],[7,8,";"],[7,9,"/"],[7,10,"rctrl"],[8,1,"8"],[8,2,"i"],[8,3,"k"],[8,4,","],[8,5,"F8"],[8,6,"9"],[8,7,"o"],[8,8,"l"],[8,9,"."]],"4446:4681":[[0,0,"Esc"],[0,1,"\uff5e"],[0,2,"tab"],[0,3,"capslock"],[0,4,"leftshift"],[0,5,"Pause"],[0,6,"pg up"],[0,7,"pg dn"],[0,9,"right"],[0,10,"lctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"q"],[1,3,"a"],[1,4,"z"],[1,5,"Scrlk"],[1,6,"home"],[1,7,"end"],[1,8,"up"],[1,9,"down"],[1,10,"lwin"],[2,0,"F2"],[2,1,"2"],[2,2,"w"],[2,3,"s"],[2,4,"x"],[2,5,"Prtsc"],[2,6,"insert"],[2,7,"delete"],[2,9,"left"],[2,10,"lalt"],[3,0,"F3"],[3,1,"3"],[3,2,"e"],[3,3,"d"],[3,4,"c"],[3,5,"F13"],[3,6,"backspace"],[3,9,"\\"],[3,10,"space"],[4,0,"F4"],[4,1,"4"],[4,2,"r"],[4,3,"f"],[4,4,"v"],[4,5,"F12"],[4,6,"backspace"],[4,7,"|"],[5,0,"F5"],[5,1,"5"],[5,2,"t"],[5,3,"g"],[5,4,"b"],[5,5,"F11"],[5,6,"="],[5,7,"}"],[5,8,"enter"],[5,9,"rightshift"],[5,10,"ralt"],[6,0,"F6"],[6,1,"6"],[6,2,"y"],[6,3,"h"],[6,4,"n"],[6,5,"F10"],[6,6,"-"],[6,7,"{"],[6,8,"'"],[6,9,"rightshift"],[6,10,"rwin"],[7,0,"F7"],[7,1,"7"],[7,2,"u"],[7,3,"j"],[7,4,"m"],[7,5,"F9"],[7,6,"0"],[7,7,"p"],[7,8,";"],[7,9,"/"],[7,10,"rctrl"],[8,1,"8"],[8,2,"i"],[8,3,"k"],[8,4,","],[8,5,"F8"],[8,6,"9"],[8,7,"o"],[8,8,"l"],[8,9,"."]],"4448:0001":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"Alt"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Win"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[12,0,"+"],[12,1,"}"],[12,3,"Shift"],[13,0,"|"],[13,1,"|"],[13,2,"~"],[13,3,"Enter"],[13,4,"Fn"]],"444B:4556":[],"444B:4A46":[],"444B:4C53":[],"444B:4F31":[],"444B:4F32":[],"444B:4F52":[],"444B:5443":[],"444C:4832":[[0,0,"lpu"],[0,1,"lpc"],[0,2,"lpl"],[0,3,"lpr"],[0,4,"lpd"],[0,5,"rpl"],[0,6,"rpc"],[0,7,"rpd"],[0,8,"rpu"],[0,9,"rpr"],[1,0,"lru"],[1,1,"lrc"],[1,2,"lrl"],[1,3,"lrr"],[1,4,"lrd"],[1,5,"rrl"],[1,6,"rrc"],[1,7,"rrd"],[1,8,"rru"],[1,9,"rrr"],[2,0,"lmu"],[2,1,"lmc"],[2,2,"lml"],[2,3,"lmr"],[2,4,"lmd"],[2,5,"rml"],[2,6,"rmc"],[2,7,"rmd"],[2,8,"rmu"],[2,9,"rmr"],[3,0,"liu"],[3,1,"lic"],[3,2,"lil"],[3,3,"lir"],[3,4,"lid"],[3,5,"ril"],[3,6,"ric"],[3,7,"rid"],[3,8,"riu"],[3,9,"rir"],[4,0,"ltu"],[4,1,"ltc"],[4,2,"ltl"],[4,3,"ltr"],[4,4,"ltd"],[4,5,"rtu"],[4,6,"rtc"],[4,7,"rtl"],[4,8,"rtr"],[4,9,"rtd"],[5,0,"lt2u"],[5,1,"lt2c"],[5,2,"lt2l"],[5,3,"lt2r"],[5,4,"lt2d"],[5,5,"rt2u"],[5,6,"rt2c"],[5,7,"rt2l"],[5,8,"rt2r"],[5,9,"rt2d"]],"444C:6868":[],"444C:A460":[],"444C:A57B":[],"444D:3435":[],"444D:3436":[],"444D:3536":[],"444D:3537":[],"444D:3632":[],"444D:3636":[],"444E:0002":[],"444E:0003":[],"444E:1307":[],"444E:1407":[],"444E:4450":[],"4450:0001":[],"4450:0002":[[0,0,"F1"],[0,1,"F2"],[0,2,"F3"],[0,3,"F4"],[1,0,"Tab"],[1,1,"Caps Lock"],[1,2,"Shift"],[1,3,"Ctrl"],[2,0,"Q"],[2,1,"A"],[2,2,"Z"],[2,3,"Win"],[3,0,"W"],[3,1,"S"],[3,2,"X"],[3,3,"Alt"],[4,0,"E"],[4,1,"D"],[4,2,"C"],[5,0,"R"],[5,1,"F"],[5,2,"V"],[5,3,"Spacebar"],[6,0,"T"],[6,1,"G"],[6,2,"B"],[6,3,"Spacebar"],[7,0,"Y"],[7,1,"H"],[7,2,"N"],[7,3,"Spacebar"],[8,0,"U"],[8,1,"J"],[8,2,"M"],[9,0,"I"],[9,1,"K"],[9,2,"<"],[10,0,"O"],[10,1,"L"],[10,2,"Shift"],[10,3,"Alt"],[11,0,"P"],[11,1,":"],[11,3,"Left"],[12,0,"{"],[12,2,"Up"],[12,3,"Down"],[13,0,"Backspace"],[13,1,"Enter"],[13,2,"?"],[13,3,"Right"]],"4450:0003":[],"4450:0004":[[0,0,"Fn"],[0,1,"Num Lock"],[0,2,"7"],[0,3,"4"],[0,4,"1"],[0,5,"0"],[1,0,"Fn2"],[1,1,"/"],[1,2,"8"],[1,3,"5"],[1,4,"2"],[1,5,"0"],[2,0,"Fn3"],[2,1,"*"],[2,2,"9"],[2,3,"6"],[2,4,"3"],[2,5,"."],[3,0,"Delete"],[3,1,"-"],[3,2,"+"],[3,3,"+"],[3,4,"Enter"],[3,5,"Enter"],[4,5,"Mute"]],"4450:0006":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"LCtrl"],[0,6,"LWin"],[0,7,"~"],[0,8,"A"],[0,9,"Q"],[0,10,"!"],[1,0,"F1"],[1,1,"F2"],[1,2,"@"],[1,3,"W"],[1,4,"S"],[1,5,"Z"],[1,6,"LAlt"],[1,7,"X"],[1,8,"D"],[1,9,"E"],[1,10,"#"],[2,0,"F3"],[2,1,"F4"],[2,2,"$"],[2,3,"R"],[2,4,"F"],[2,5,"C"],[2,6,"LSpacebar"],[2,7,"V"],[2,8,"G"],[2,9,"T"],[2,10,"%"],[3,0,"F5"],[3,1,"F6"],[3,2,"^"],[3,3,"B"],[3,4,"RSpacebar"],[3,5,"B"],[3,6,"H"],[3,7,"Y"],[3,8,"&"],[3,9,"F7"],[3,10,"F8"],[4,0,"F9"],[4,1,"*"],[4,2,"U"],[4,3,"J"],[4,4,"N"],[4,5,"M"],[4,6,"RAlt"],[4,7,"<"],[4,8,"K"],[4,9,"I"],[4,10,"("],[5,0,"F10"],[5,1,")"],[5,2,"O"],[5,3,"L"],[5,4,">"],[5,5,"RWin"],[5,6,"RCtrl"],[5,7,"?"],[5,8,":"],[5,9,"P"],[5,10,"_"],[6,0,"F11"],[6,1,"F12"],[6,2,"+"],[6,3,"{"],[6,4,"\\"],[6,5,"Shift"],[6,6,"#"],[6,7,"Enter"],[6,8,"}"],[6,9,"Backspace"],[6,10,"M1"],[7,0,"M2"],[7,1,"Num Lock"],[7,2,"7"],[7,3,"4"],[7,4,"1"],[7,5,"Up"],[7,6,"Left"],[7,7,"|"],[7,8,"Down"],[7,9,"Right"],[7,10,"0"],[8,0,"/"],[8,1,"8"],[8,2,"5"],[8,3,"2"],[8,4,"."],[8,5,"Enter"],[8,6,"3"],[8,7,"6"],[8,8,"+"],[8,9,"9"],[8,10,"*"],[9,0,"Enc"],[9,1,"-"]],"4452:534F":[],"4453:6060":[],"4454:4441":[],"4454:454C":[],"4454:4973":[],"4454:5343":[],"4454:5444":[],"445A:0002":[[0,0,"`"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[14,1,"Delete"],[14,2,"Insert"],[14,4,"\u2192"]],"445A:0006":[],"445A:0007":[],"445A:1010":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"Z"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"X"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"C"],[5,4,"\\"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"V"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"B"],[7,4,"Space"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"N"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"M"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,","],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,"."],[11,4,"Alt"],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"/"],[12,4,"Ctrl"],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"="],[14,1,"]"],[14,2,"Enter"],[14,4,"`"],[15,0,"Backspace"],[15,1,"\\"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Home"],[16,1,"Page Up"],[16,2,"Page Down"],[16,3,"End"],[16,4,"\u2192"]],"445A:1012":[],"445A:1013":[],"445A:1014":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"Q"],[2,3,"A"],[2,4,"Z"],[2,5,"\u2298"],[3,0,"F3"],[3,1,"3"],[3,2,"W"],[3,3,"S"],[3,4,"X"],[3,5,"Alt"],[4,0,"F4"],[4,1,"4"],[4,2,"E"],[4,3,"D"],[4,4,"C"],[5,1,"5"],[5,2,"R"],[5,3,"F"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"T"],[6,3,"G"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"Y"],[7,3,"H"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"U"],[8,3,"J"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"I"],[9,3,"K"],[9,4,","],[10,0,"F9"],[10,1,"0"],[10,2,"O"],[10,3,"L"],[10,4,"."],[10,5,"Alt"],[11,0,"F10"],[11,1,"-"],[11,2,"P"],[11,3,";"],[11,4,"/"],[11,5,"Fn"],[12,0,"F11"],[12,1,"="],[12,2,"["],[12,3,"'"],[12,5,"Ctrl"],[13,0,"F12"],[13,1,"Delete"],[13,2,"]"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"\u2190"],[14,1,"Backspace"],[14,2,"\\"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"PrtSc"],[15,1,"Home"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"End"],[15,5,"\u2192"]],"445A:1015":[],"445A:1425":[],"445A:1426":[],"445A:1427":[],"445A:2260":[],"445A:DB96":[],"445B:07AF":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Delete"],[14,1,"Page Up"],[14,2,"Page Down"],[14,4,"\u2192"]],"454B:0001":[],"454B:0002":[],"454B:0003":[],"454C:0001":[],"454C:3436":[],"4552:0001":[],"4552:0002":[],"4552:0005":[],"4552:0006":[],"4552:0008":[],"4552:0009":[],"4552:0011":[],"4552:0012":[],"4552:0013":[],"4552:0014":[],"4552:0015":[],"4552:6667":[[0,0,"ESC"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"<"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,">"],[9,4,"K91"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,"?"],[10,4,"K92"],[11,0,"_"],[11,1,"{"],[11,2,"k90"],[11,3,"Shift"],[12,0,"+"],[12,1,"}"],[12,4,"Left"],[13,0,"Backspace"],[13,1,"|"],[13,2,"Enter"],[13,3,"Up"],[13,4,"Down"],[14,0,"Delete"],[14,1,"Home"],[14,2,"PgUp"],[14,3,"PgDn"],[14,4,"Right"]],"4556:4D54":[],"4557:3665":[],"4558:E605":[],"4558:E62B":[],"4558:E62D":[],"4558:E701":[],"4558:E702":[],"4558:E851":[],"4558:E852":[],"456B:0001":[],"458F:14E2":[],"45D4:0062":[],"45D4:0110":[],"45D4:0428":[],"45D4:0911":[],"4642:6F21":[],"4642:776E":[],"4643:0001":[[0,0,"Esc"],[0,1,"^"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[0,6,"Win"],[0,7,"Alt"],[0,9,"AltGr"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"|"],[1,5,"Z"],[1,6,"S"],[1,7,"W"],[1,8,"2"],[1,9,"F2"],[2,0,"F3"],[2,1,"3"],[2,2,"E"],[2,3,"D"],[2,4,"X"],[2,5,"C"],[2,6,"F"],[2,7,"R"],[2,8,"4"],[2,9,"F4"],[3,0,"F5"],[3,1,"5"],[3,2,"T"],[3,3,"G"],[3,4,"V"],[3,5,"B"],[3,6,"H"],[3,7,"Y"],[3,8,"6"],[3,9,"F6"],[4,0,"F7"],[4,1,"7"],[4,2,"U"],[4,3,"J"],[4,4,"N"],[4,5,"M"],[4,6,"K"],[4,7,"I"],[4,8,"8"],[4,9,"F8"],[5,0,"F9"],[5,1,"9"],[5,2,"O"],[5,3,"L"],[5,4,"<"],[5,5,">"],[5,6,":"],[5,7,"P"],[5,8,"0"],[5,9,"F10"],[6,0,"F11"],[6,1,"\u00df"],[6,2,"{"],[6,3,"@"],[6,4,"?"],[6,5,"Shift"],[6,6,"~"],[6,7,"}"],[6,8,"\u00b4"],[6,9,"F12"],[7,0,"Extra1"],[7,1,"Backspace"],[7,2,"Enter"],[7,3,"\u2191"],[7,4,"\u2192"],[7,5,"\u2193"],[7,6,"\u2190"],[7,7,"Ctrl"],[7,8,"Menu"],[7,9,"Win"],[8,0,"PrtSc"],[8,1,"Insert"],[8,2,"Delete"],[8,3,"End"],[8,4,"PgDn"],[8,5,"PgUp"],[8,6,"Home"],[8,7,"Scroll Lock"],[8,8,"Pause"],[8,9,"Extra2"],[9,0,"7"],[9,1,"8"],[9,2,"9"],[9,3,"6"],[9,4,"5"],[9,5,"4"],[9,6,"1"],[9,7,"2"],[9,8,"3"],[9,9,"0"],[10,0,"Extra3"],[10,1,"Extra4"],[10,2,"Extra5"],[10,3,"Num Lock"],[10,4,"/"],[10,5,"*"],[10,6,"-"],[10,7,"+"],[10,8,"Enter"],[10,9,"."]],"4646:0002":[],"4646:FEED":[],"4648:4254":[],"4649:0721":[],"464C:0001":[],"464C:0002":[],"464C:0003":[],"464C:0004":[],"464C:0005":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Ctrl/Esc"],[0,4,"Shift"],[0,5,"Alt"],[1,0,"F12"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Alt"],[1,6,"Previous Track"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"GUI"],[2,6,"Next Track"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"Fn2/Space"],[4,6,"Page Up"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,6,"Home"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[6,6,"Insert"],[7,0,"F5"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[7,5,"\u2192"],[7,6,"Page Down"],[8,0,"F6"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"Fn3"],[8,6,"End"],[9,0,"F7"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[9,5,"Fn3"],[10,0,"F8"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"Fn4"],[11,0,"F9"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[11,5,"Fn4"],[12,0,"F11"],[12,1,"\\"],[12,2,"Backspace"],[12,3,"\u2298"],[12,4,"\u2191"],[12,5,"\u2193"],[12,6,"Delete"],[13,1,"Delete"],[13,4,"\u2298"],[14,0,"F10"],[14,1,"="],[14,2,"]"],[14,3,"Enter"],[14,4,"Fn4"],[14,5,"\u2190"],[14,6,"Play/Pause"]],"464C:0006":[],"4652:5558":[[0,0,"Esc"],[0,1,"9"],[0,2,"W"],[0,3,"["],[0,4,"H"],[0,5,"\\"],[0,6,"."],[1,0,"1"],[1,1,"0"],[1,2,"E"],[1,3,"]"],[1,4,"J"],[1,5,"Z"],[1,6,"/"],[2,0,"2"],[2,1,"-"],[2,2,"R"],[2,3,"\\"],[2,4,"K"],[2,5,"X"],[2,6,"Shift"],[3,0,"3"],[3,1,"="],[3,2,"T"],[3,3,"Caps Lock"],[3,4,"L"],[3,5,"C"],[3,6,"Fn"],[4,0,"4"],[4,1,"Backspace"],[4,2,"Y"],[4,3,"A"],[4,4,";"],[4,5,"V"],[4,6,"Alt"],[5,0,"5"],[5,1,"2u Backspace"],[5,2,"U"],[5,3,"S"],[5,4,"'"],[5,5,"B"],[5,6,"GUI"],[6,0,"6"],[6,1,"Backspace"],[6,2,"I"],[6,3,"D"],[6,4,"#"],[6,5,"N"],[6,6,"Space"],[7,0,"7"],[7,1,"Tab"],[7,2,"O"],[7,3,"F"],[7,4,"Enter"],[7,5,"M"],[7,6,"GUI"],[8,0,"8"],[8,1,"Q"],[8,2,"P"],[8,3,"G"],[8,4,"Shift"],[8,5,","],[8,6,"Alt"]],"4658:0000":[],"4658:4C53":[],"4658:5647":[],"4680:1357":[],"4705:0140":[],"4705:0143":[],"4705:0145":[],"4705:0160":[],"4705:0187":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Ctrl"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"Reset"],[13,0,"GUI"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"4705:0E6D":[],"4705:198B":[],"4705:1F02":[],"4705:3320":[],"4705:5160":[[0,0,"F1"],[0,1,"F2"],[0,2,"F3"],[0,3,"F4"],[0,4,"F5"],[0,5,"F6"],[0,6,"F7"],[0,7,"F8"],[0,8,"F9"],[0,9,"F10"],[1,0,"Esc"],[1,1,"1"],[1,2,"Tab"],[1,3,"Q"],[1,4,"Caps Lock"],[1,5,"A"],[1,6,"Shift"],[1,7,"\u25bd"],[1,8,"Ctrl"],[2,0,"2"],[2,1,"3"],[2,2,"W"],[2,3,"E"],[2,4,"S"],[2,5,"D"],[2,6,"Z"],[2,7,"X"],[2,8,"Alt"],[3,0,"4"],[3,1,"5"],[3,2,"R"],[3,3,"T"],[3,4,"F"],[3,5,"G"],[3,6,"C"],[3,7,"V"],[4,0,"6"],[4,1,"7"],[4,2,"Y"],[4,3,"U"],[4,4,"H"],[4,5,"J"],[4,6,"B"],[4,7,"N"],[4,9,"Space"],[5,0,"8"],[5,1,"9"],[5,2,"I"],[5,3,"O"],[5,4,"K"],[5,5,"L"],[5,6,"M"],[5,7,","],[6,0,"0"],[6,1,"-"],[6,2,"P"],[6,3,"["],[6,4,";"],[6,5,"'"],[6,6,"."],[6,7,"/"],[6,9,"Alt"],[7,0,"="],[7,1,"Backspace"],[7,2,"]"],[7,3,"\\"],[7,4,"\u25bd"],[7,5,"Enter"],[7,6,"Shift"],[7,7,"\u25bd"],[7,8,"\u25bd"],[7,9,"Fn"],[8,0,"Num Lock"],[8,1,"/"],[8,2,"7"],[8,3,"8"],[8,4,"4"],[8,5,"5"],[8,6,"1"],[8,7,"2"],[8,8,"0"],[8,9,"\u25bd"],[9,0,"*"],[9,1,"-"],[9,2,"9"],[9,3,"\u25bd"],[9,4,"6"],[9,5,"+"],[9,6,"3"],[9,8,"."],[9,9,"Enter"]],"4705:5C62":[],"4705:633A":[],"4705:7465":[],"4705:7BFF":[],"4705:8446":[],"4705:87C9":[],"4705:8A18":[],"4705:8B23":[],"4705:8E66":[],"4705:92EA":[],"4705:A6E2":[[0,0,"ESC"],[0,1,"NUM"],[0,2,"P7"],[0,3,"P4"],[0,4,"P1"],[0,5,"P0"],[1,0,"TAB"],[1,1,"PSLS"],[1,2,"P8"],[1,3,"P5"],[1,4,"P2"],[1,5,"P0"],[2,0,"PEQL"],[2,1,"PAST"],[2,2,"P9"],[2,3,"P6"],[2,4,"P3"],[2,5,"PDOT"],[3,0,"BSPC"],[3,1,"PMNS"],[3,2,"PPLS"],[3,3,"PPLS"],[3,4,"PENT"],[3,5,"PENT"]],"4705:A71C":[],"4705:AA6B":[],"4705:AAF8":[],"4705:AEB4":[],"4705:B00E":[],"4705:C474":[],"4705:D5DF":[[0,0,"ESC"],[0,1,"1"],[0,3,"TAB"],[0,4,"A"],[0,5,"Q"],[0,6,"Z"],[1,1,"2"],[1,3,"CAPS"],[1,4,"S"],[1,5,"W"],[1,6,"X"],[2,1,"3"],[2,4,"D"],[2,5,"E"],[2,6,"C"],[3,0,"G"],[3,1,"4"],[3,2,"5"],[3,3,"T"],[3,4,"F"],[3,5,"R"],[3,6,"V"],[3,7,"B"],[4,0,"H"],[4,1,"7"],[4,2,"6"],[4,3,"Y"],[4,4,"J"],[4,5,"U"],[4,6,"M"],[4,7,"N"],[5,1,"8"],[5,2,"EQL"],[5,3,"RBRC"],[5,4,"K"],[5,5,"I"],[5,6,"COMM"],[6,1,"9"],[6,4,"L"],[6,5,"O"],[6,6,"DOT"],[7,0,"QUOT"],[7,1,"0"],[7,2,"MINS"],[7,3,"LBRC"],[7,4,"SCLN"],[7,5,"P"],[7,7,"SLSH"],[8,3,"BSPC"],[8,4,"BSLS"],[8,6,"ENT"],[9,0,"LALT"],[9,3,"APP"],[9,6,"SPC"],[9,7,"RALT"],[10,3,"LSFT"],[10,4,"RSFT"],[11,2,"LCTL"],[11,3,"LGUI"],[11,6,"RCTL"],[12,0,"UP"],[12,7,"LEFT"],[13,0,"SPC"],[13,7,"DOWN"],[14,7,"RGHT"]],"4705:EA78":[],"4705:FA7D":[],"4743:0000":[],"4744:0001":[],"4744:4D45":[[0,0,"Esc"],[0,1,"Page Up"],[0,2,"Page Down"],[1,0,"`~"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"LCtrl"],[2,0,"1!"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[3,0,"2@"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"LAlt"],[4,0,"3#"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[4,4,"Space"],[5,0,"4$"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[5,4,"5%"],[6,0,"6^"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Space"],[7,5,"7&"],[7,6,"Y"],[7,7,"H"],[7,8,"B"],[8,5,"8*"],[8,6,"U"],[8,7,"J"],[8,8,"N"],[8,9,"Space"],[9,5,"9("],[9,6,"I"],[9,7,"K"],[9,8,"M"],[10,5,"0)"],[10,6,"O"],[10,7,"L"],[10,8,",<"],[10,9,"RAlt"],[11,5,"-_"],[11,6,"P"],[11,7,";:"],[11,8,".>"],[12,5,"=+"],[12,6,"[{"],[12,7,"'\""],[12,8,"/?"],[13,5,"Backspace"],[13,6,"]}"],[13,8,"Shift"],[14,5,"Backspace"],[14,6,"\\|"],[14,7,"Enter"],[14,8,"MO(1)"],[14,9,"RCtrl"]],"4744:6060":[],"4747:7012":[],"474B:0001":[],"474B:4201":[],"474B:4202":[],"474B:4203":[],"4752:4D49":[],"4752:5242":[],"4753:0001":[],"4753:1000":[],"4753:2000":[],"4753:3000":[],"4753:3001":[],"4753:3003":[],"4753:3075":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"Q"],[2,3,"A"],[2,4,"Z"],[3,0,"F3"],[3,1,"3"],[3,2,"W"],[3,3,"S"],[3,4,"X"],[3,5,"Alt"],[4,0,"F4"],[4,1,"4"],[4,2,"E"],[4,3,"D"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"R"],[5,3,"F"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"T"],[6,3,"G"],[6,4,"B"],[7,0,"F7"],[7,1,"7"],[7,2,"Y"],[7,3,"H"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"U"],[8,3,"J"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"I"],[9,3,"K"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"O"],[10,3,"L"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"P"],[11,3,";"],[11,4,"/"],[11,5,"Fn"],[12,1,"="],[12,2,"["],[12,3,"'"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"]"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"\u2190"],[14,2,"\\"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"PrtSc"],[15,1,"Home"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"End"],[15,5,"\u2192"]],"4753:4000":[],"4753:4001":[],"4753:4003":[],"4753:4060":[],"480E:408F":[],"4842:FB60":[],"4847:5054":[],"4848:0001":[],"4848:0002":[],"4849:0601":[],"4849:060F":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"Fn2"],[13,4,"Ctrl"]],"4849:0650":[],"4849:0651":[],"484C:0087":[],"484E:0001":[],"484F:0651":[],"484F:5350":[],"4853:660C":[],"4853:980C":[],"4859:0002":[],"4934:0101":[],"494B:0001":[],"494B:3031":[[0,0,"`"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"`"],[13,1,"\\"],[13,2,"Del"],[13,3,"Fn"],[13,4,"Ctrl"]],"4954:0001":[],"4954:0003":[],"49F5:3249":[[0,0,"Esc"],[0,1,"~`"],[0,2,"Tab"],[0,3,"Caps"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!1"],[1,2,"Q"],[1,3,"A"],[1,5,"Opt"],[2,0,"F2"],[2,1,"@2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Cmd"],[3,0,"F3"],[3,1,"#3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"$4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"%5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"^6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"&7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"*8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"(9"],[9,2,"O"],[9,3,"L"],[9,4,"<,"],[9,5,"Cmd"],[10,0,"F10"],[10,1,")0"],[10,2,"P"],[10,3,":"],[10,4,">."],[10,5,"Fn"],[11,0,"F11"],[11,1,"_-"],[11,2,"{["],[11,3,"\""],[11,4,"?/"],[12,0,"F12"],[12,1,"+="],[12,2,"}]"],[12,5,"Ctrl"],[13,1,"Backsp"],[13,2,"|\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"\u2190"],[14,1,"Ins"],[14,2,"Del"],[14,4,"\u2191"],[14,5,"\u2193"],[15,5,"\u2192"],[16,1,"PageUp"],[16,2,"PageDn"]],"4A16:4A16":[[0,0,"GRV"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"<"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,">"],[9,4,"Alt"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,"?"],[10,4,"Fn"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"Shift"],[11,4,"Left"],[12,0,"+"],[12,1,"}"],[12,2,"Enter"],[13,0,"Backspace"],[13,1,"|"],[14,0,"BSLS"],[14,1,"Del"],[14,3,"UP"],[14,4,"Down"],[15,0,"Backspace"],[15,1,"Home"],[15,2,"PGUP"],[15,3,"PGDN"],[15,4,"Right"]],"4A44:4447":[],"4A46:0000":[[0,0,"Esc"],[0,1,"\u00ac"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"|"],[1,5,"Win"],[2,0,"F2"],[2,1,"\""],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"\u00a3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,"<"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,">"],[10,5,"AltGr"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"@"],[11,4,"?"],[11,5,"Win"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[12,3,"~"],[12,4,"Shift"],[12,5,"Menu"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Del"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"\u2192"]],"4A46:0001":[[0,0,"\u00ac"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"\""],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"\u00a3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"AltGr"],[11,0,"_"],[11,1,"{"],[11,2,"@"],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,2,"~"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"Back"],[13,1,"Enter"],[13,2,"Delete"],[13,3,"Fn"],[13,4,"Ctrl"]],"4A46:0002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Win"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Fn"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"Alt"],[8,0,"I"],[8,1,"K"],[8,2,"<"],[8,3,"Ctrl"],[9,0,"O"],[9,1,"L"],[9,2,">"],[10,0,"P"],[10,1,":"],[10,2,"?"],[10,3,"\u2190"],[11,0,"Backspace"],[11,1,"Enter"],[11,2,"\u2191"],[11,3,"\u2193"],[12,2,"\u2191"],[12,3,"\u2192"]],"4A48:0001":[],"4A48:4257":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[5,4,"K45"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K46"],[7,2,"K27"],[7,3,"K37"],[7,4,"K47"]],"4A48:4258":[[0,0,"00"],[0,1,"10"],[0,2,"20"],[0,4,"40"],[0,5,"50"],[0,6,"60"],[1,0,"01"],[1,1,"11"],[1,2,"21"],[1,4,"41"],[1,5,"51"],[1,6,"61"],[2,0,"02"],[2,1,"12"],[2,2,"22"],[2,3,"32"],[2,4,"42"],[2,5,"52"],[2,6,"62"],[2,7,"72"],[3,0,"03"],[3,1,"13"],[3,2,"23"],[3,3,"33"],[3,4,"43"],[3,5,"53"],[3,6,"63"],[3,7,"73"],[4,0,"04"],[4,1,"14"],[4,2,"24"],[4,3,"34"],[4,4,"44"],[4,5,"54"],[4,6,"64"],[4,7,"74"]],"4A4B:3225":[],"4A4B:EF6A":[],"4A4C:0000":[[0,0,"Q"],[0,1,"A"],[0,2,"Shift/Z"],[0,3,"Ctrl"],[1,0,"W"],[1,1,"S"],[1,2,"X"],[1,3,"Alt"],[2,0,"E"],[2,1,"D"],[2,2,"C"],[3,0,"R"],[3,1,"F"],[3,2,"V"],[3,3,"Space"],[4,0,"T"],[4,1,"G"],[4,2,"B"],[5,0,"Y"],[5,1,"H"],[5,2,"N"],[5,3,"GUI"],[6,0,"U"],[6,1,"J"],[6,2,"M"],[6,3,"Fn"],[7,0,"I"],[7,1,"K"],[7,3,"\u2190"],[8,0,"O"],[8,1,"L"],[8,2,"\u2191"],[8,3,"\u2193"],[9,0,"P"],[9,1,"Enter"],[9,3,"\u2192"]],"4A4F:0001":[],"4A4F:0003":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[0,6,"Layer"],[0,7,"&"],[0,8,"Y"],[0,9,"H"],[0,10,"B"],[1,0,"LED"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[1,6,"F7"],[1,7,"*"],[1,8,"U"],[1,9,"J"],[1,10,"N"],[1,11,"Space"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[2,6,"F8"],[2,7,"("],[2,8,"I"],[2,9,"K"],[2,10,"M"],[2,11,"Space"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"L2"],[3,6,"F9"],[3,7,")"],[3,8,"O"],[3,9,"L"],[3,10,"<"],[3,11,"L2"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,6,"F10"],[4,7,"_"],[4,8,"P"],[4,9,":"],[4,10,">"],[4,11,"Win"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,6,"F11"],[5,7,"+"],[5,8,"{"],[5,9,"\""],[5,10,"?"],[5,11,"Menu"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[6,5,"Space"],[6,6,"Pause"],[6,7,"Backspace"],[6,8,"}"],[6,9,"Enter"],[6,10,"Shift"],[7,0,"F6"],[7,1,"7"],[7,6,"Delete"],[7,8,"|"],[7,11,"Ctrl"]],"4A4F:0005":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[0,6,"Layer"],[0,7,"&"],[0,8,"Y"],[0,9,"H"],[0,10,"B"],[1,0,"LED"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[1,6,"F7"],[1,7,"*"],[1,8,"U"],[1,9,"J"],[1,10,"N"],[1,11,"Space"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Layer"],[2,6,"F8"],[2,7,"("],[2,8,"I"],[2,9,"K"],[2,10,"M"],[2,11,"Arrows"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"Alt"],[3,6,"F9"],[3,7,")"],[3,8,"O"],[3,9,"L"],[3,10,"<"],[3,11,"Ctrl"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,6,"F10"],[4,7,"_"],[4,8,"P"],[4,9,":"],[4,10,">"],[4,11,"Win"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,6,"F11"],[5,7,"+"],[5,8,"{"],[5,9,"\""],[5,10,"?"],[5,11,"Menu"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[6,5,"Space"],[6,6,"Pause"],[6,7,"Backspace"],[6,8,"}"],[6,9,"Enter"],[6,10,"Shift"],[7,0,"F6"],[7,1,"7"],[7,6,"Delete"],[7,8,"|"],[7,11,"Ctrl"]],"4A4F:5458":[],"4A50:4554":[],"4A53:0001":[],"4A53:0002":[],"4A53:0003":[],"4A54:5350":[[0,0,"`"],[0,1,"Esc"],[0,2,"Tab"],[0,3,"LShift"],[0,4,"LCtrl"],[0,5,"`"],[0,6,"Bspc"],[0,7,"'"],[0,8,"RShift"],[0,9,"RCtrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"LGUI"],[1,5,"0"],[1,6,"P"],[1,7,";"],[1,8,"/"],[1,9,"RGui"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"LCmnd"],[2,5,"9"],[2,6,"O"],[2,7,"L"],[2,8,"."],[2,9,"RCmnd"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"LAlt"],[3,5,"8"],[3,6,"I"],[3,7,"K"],[3,8,","],[3,9,"RAlt"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Enter"],[4,5,"7"],[4,6,"U"],[4,7,"J"],[4,8,"M"],[4,9,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Mute"],[5,5,"6"],[5,6,"Y"],[5,7,"H"],[5,8,"N"],[5,9,"Pause"]],"4A56:0001":[],"4A56:0002":[],"4A56:0003":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[12,0,"="],[12,1,"]"],[12,2,"Delete"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"4A56:0004":[[0,0,"k000"],[0,1,"k100"],[0,2,"k200"],[0,3,"k300"],[0,4,"k400"],[1,0,"k001"],[1,1,"k101"],[1,2,"k201"],[1,3,"k301"],[1,4,"k401"],[2,0,"k002"],[2,1,"k102"],[2,2,"k202"],[2,3,"k302"],[2,4,"k402"],[3,0,"k003"],[3,1,"k103"],[3,2,"k203"],[3,3,"k303"],[4,0,"k004"],[4,1,"k104"],[4,2,"k204"],[4,3,"k304"],[5,0,"k005"],[5,1,"k105"],[5,2,"k205"],[5,3,"k305"],[5,4,"k405"],[6,0,"k006"],[6,1,"k106"],[6,2,"k206"],[6,3,"k306"],[7,0,"k007"],[7,1,"k107"],[7,2,"k207"],[7,3,"k307"],[7,4,"k407"],[8,0,"k008"],[8,1,"k108"],[8,2,"k208"],[8,3,"k308"],[9,0,"k009"],[9,1,"k109"],[9,2,"k209"],[9,3,"k309"],[9,4,"k409"],[10,0,"k010"],[10,1,"k110"],[10,2,"k210"],[10,3,"k310"],[10,4,"k410"],[11,0,"k011"],[11,1,"k111"],[11,2,"k211"],[11,3,"k311"],[11,4,"k411"],[12,0,"k012"],[12,1,"k112"],[12,2,"k212"],[12,3,"k312"],[12,4,"k412"],[13,0,"k013"],[13,1,"k113"],[13,2,"k213"],[13,3,"k313"],[13,4,"k413"]],"4A57:0000":[],"4A57:0002":[],"4B35:6060":[],"4B36:6060":[],"4B42:0006":[],"4B42:0007":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F9"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Ctrl"],[12,0,"F10"],[12,1,"="],[12,2,"]"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"F11"],[13,1,"`"],[13,2,"\\"],[13,3,"Enter"],[14,0,"F12"],[14,1,"Backspace"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"Page Up"],[15,1,"Insert"],[15,2,"Delete"],[15,3,"Page Down"],[15,5,"\u2192"]],"4B42:0008":[],"4B42:0009":[],"4B42:0011":[],"4B42:0012":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[0,5,"K50"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[2,5,"K52"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,4,"K43"]],"4B42:0101":[],"4B42:0102":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F5"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F6"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F7"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F8"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F9"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F10"],[12,1,"="],[12,2,"]"],[13,0,"F11"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"F12"],[14,5,"\u2190"],[15,0,"Print Screen"],[15,1,"Insert"],[15,2,"Delete"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Scroll Lock"],[16,1,"Num Lock"],[16,2,"7"],[16,3,"4"],[16,4,"1"],[16,5,"\u2192"],[17,0,"Pause"],[17,1,"/"],[17,2,"8"],[17,3,"5"],[17,4,"2"],[17,5,"0"],[18,0,"Page Up"],[18,1,"*"],[18,2,"9"],[18,3,"6"],[18,4,"3"],[18,5,"."],[19,0,"Page Down"],[19,1,"-"],[19,2,"+"],[19,4,"Enter"]],"4B42:0103":[],"4B42:0105":[],"4B42:0106":[],"4B42:0107":[],"4B42:0191":[],"4B42:0223":[],"4B42:1000":[],"4B42:3658":[],"4B42:6060":[],"4B42:6061":[],"4B42:6062":[],"4B42:6063":[],"4B42:6065":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[5,4,"K45"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[9,4,"K49"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[10,4,"K4A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,3,"K3C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"],[14,0,"K0E"],[14,1,"K1E"],[14,2,"K2E"],[14,3,"K3E"],[14,4,"K4E"]],"4B42:6066":[],"4B42:6067":[],"4B42:6068":[],"4B42:6069":[],"4B42:6071":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"K47"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Alt"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,2,"Backspace"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"Backspace"],[13,1,"|"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Ctrl"]],"4B42:6072":[],"4B42:6073":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Fn"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"k45"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"<"],[8,4,"Alt"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,">"],[9,4,"Menu"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,"?"],[10,4,"0"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"Shift"],[11,4,"."],[12,0,"+"],[12,1,"}"],[12,2,"Enter"],[12,3,"1"],[12,4,"\u2190"],[13,0,"Insert"],[13,1,"Delete"],[13,2,"Backspace"],[13,3,"|"],[14,0,"Num Lock"],[14,1,"7"],[14,2,"4"],[14,3,"2"],[14,4,"\u2193"],[15,0,"/"],[15,1,"8"],[15,2,"5"],[15,3,"3"],[15,4,"\u2192"],[16,0,"*"],[16,1,"9"],[16,2,"6"],[16,3,"Enter"],[17,0,"-"],[17,1,"+"],[17,2,"Del"],[17,3,"\u2191"]],"4B42:7000":[],"4B42:7001":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"Alt"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"Ctrl"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[11,5,"\u2190"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[13,0,"PrtSc"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Pause"],[14,1,"Home"],[14,2,"Page Up"],[14,3,"Page Down"],[14,5,"\u2192"]],"4B42:7002":[],"4B43:4152":[],"4B43:5036":[],"4B43:5050":[],"4B43:6061":[],"4B44:3738":[],"4B44:3935":[],"4B44:3938":[],"4B47:0000":[],"4B47:0001":[],"4B47:0002":[],"4B48:0002":[],"4B48:0101":[],"4B48:0201":[],"4B48:0301":[],"4B48:4D50":[],"4B49:1306":[],"4B49:534B":[],"4B4A:5253":[[0,0,"ESC"],[0,1,"CAPSLOCK"],[0,2,"LSHIFT"],[0,3,"LCTRL"],[1,0,"Q"],[1,1,"A"],[1,3,"FN2"],[2,0,"W"],[2,1,"S"],[2,2,"Z"],[2,3,"WIN"],[3,0,"E"],[3,1,"D"],[3,2,"X"],[4,0,"R"],[4,1,"F"],[4,2,"C"],[4,3,"SPACE"],[5,0,"T"],[5,1,"G"],[5,2,"V"],[6,0,"Y"],[6,1,"H"],[6,2,"B"],[7,0,"U"],[7,1,"J"],[7,2,"N"],[7,3,"FN"],[8,0,"I"],[8,1,"K"],[8,2,"M"],[9,0,"O"],[9,1,"L"],[9,2,"COMMA"],[9,3,"SLASH"],[10,0,"P"],[10,2,"PERIOD"],[10,3,"SEMICOLON"],[11,0,"BACKSPACE"],[11,1,"ENTER"],[11,2,"RSHIFT"],[11,3,"RCTRL"]],"4B4B:0001":[],"4B4B:0002":[],"4B4B:0003":[],"4B4B:1225":[],"4B4C:4742":[],"4B4D:4143":[],"4B4F:4B59":[],"4B50:0040":[],"4B50:0044":[],"4B50:0050":[],"4B50:0060":[],"4B50:00A2":[],"4B50:016A":[],"4B50:016B":[],"4B50:0600":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn2"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"Backspace"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Fn2"],[13,4,"Ctrl"]],"4B50:0601":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn2"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"Backspace"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Fn2"],[13,4,"Ctrl"]],"4B50:0602":[],"4B50:0603":[],"4B50:0650":[],"4B50:0651":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"\\"],[12,2,"]"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"4B50:0652":[],"4B50:065E":[[0,0,"\u25bd"],[0,1,"\u25bd"],[0,2,"\u25bd"],[0,3,"\u25bd"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,3,"\\"],[2,4,"GUI"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"Z"],[3,4,"Alt"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"X"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"C"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"V"],[7,0,"6"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[7,4,"Space"],[8,0,"7"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[9,0,"8"],[9,1,"I"],[9,2,"K"],[9,3,"M"],[10,0,"9"],[10,1,"O"],[10,2,"L"],[10,3,","],[11,0,"0"],[11,1,"P"],[11,2,";"],[11,3,"."],[11,4,"Alt"],[12,0,"-"],[12,1,"["],[12,2,"'"],[12,3,"/"],[12,4,"Fn"],[13,0,"="],[13,1,"]"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"Backspace"],[14,1,"Backspace"],[14,2,"\\"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Home"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"End"],[15,4,"\u2192"]],"4B50:1121":[],"4B50:1122":[],"4B50:1123":[],"4B50:1131":[],"4B50:1141":[],"4B50:1142":[],"4B50:3430":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"]],"4B50:6061":[],"4B50:8700":[],"4B50:8788":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"Backspace"],[12,3,"]"],[12,4,"Shift"],[12,5,"GUI"],[13,0,"\u25bd"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn2"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,4,"\u2192"]],"4B50:8800":[],"4B50:D7DC":[],"4B50:EF61":[],"4B50:EF6E":[],"4B50:EF83":[],"4B51:4712":[],"4B53:0001":[],"4B53:0002":[],"4B53:0003":[],"4B54:2323":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Fn"],[0,3,"Z"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"X"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"C"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"B"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[5,0,"5"],[5,1,"Y"],[5,2,"G"],[5,3,"Space"]],"4B57:0303":[],"4B57:424C":[],"4B57:574C":[],"4B59:414B":[],"4B5A:53FC":[],"4B5A:8008":[],"4B5C:B1E5":[],"4B65:6762":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"/"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[14,4,"\u2192"],[15,0,"Home"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"End"]],"4B72:4B4F":[],"4B72:4B6D":[],"4B72:6664":[],"4B72:706D":[],"4C17:5106":[],"4C23:2934":[],"4C23:2935":[],"4C23:2936":[],"4C23:2937":[],"4C27:2900":[],"4C27:2901":[],"4C27:2902":[],"4C27:8888":[],"4C27:8889":[],"4C41:0001":[],"4C43:0420":[],"4C44:0008":[],"4C44:0030":[],"4C44:0040":[],"4C44:0041":[],"4C44:0042":[],"4C44:0050":[],"4C44:0060":[],"4C44:0061":[],"4C44:0062":[],"4C46:3231":[],"4C46:3738":[],"4C47:0002":[],"4C47:0004":[],"4C4D:4B01":[],"4C4E:FEED":[],"4C50:1111":[],"4C50:2222":[[0,0,"Play"],[0,1,"Next"],[0,2,"Prev"],[1,0,"Mute"],[1,2,"Left"],[2,2,"Rght"]],"4C50:3333":[],"4C50:9998":[],"4C50:9999":[],"4C58:0001":[],"4C58:0002":[],"4C58:0003":[],"4C58:0004":[],"4C58:0005":[],"4C58:0006":[],"4C58:0007":[],"4C58:000A":[],"4C58:000B":[[0,0,"K00"],[0,1,"Num Lock"],[0,2,"7"],[0,3,"4"],[0,4,"1"],[0,5,"0"],[1,0,"K01"],[1,1,"/"],[1,2,"8"],[1,3,"5"],[1,4,"2"],[2,0,"K02"],[2,1,"*"],[2,2,"9"],[2,3,"6"],[2,4,"3"],[2,5,"Del"],[3,0,"K03"],[3,1,"-"],[3,2,"+"],[3,4,"Enter"]],"4C58:000C":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"K58"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Alt"],[12,0,"+"],[12,1,"}"],[12,4,"Fn"],[13,0,"Bksp"],[13,1,"|"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"Ctrl"],[14,0,"K14"],[14,3,"K54"]],"4C58:000D":[],"4C58:0100":[],"4D41:0001":[],"4D41:4D33":[],"4D42:0015":[],"4D42:0017":[],"4D43:6060":[],"4D44:5244":[],"4D44:5257":[],"4D45:4544":[],"4D47:5344":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\u25bd"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[5,5,"\u25bd"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"\u25bd"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"Fn"],[13,0,"Print Screen"],[13,1,"Insert"],[13,2,"Delete"],[13,3,"Backspace"],[13,4,"\\"],[13,5,"\u2190"],[14,0,"Scroll Lock"],[14,1,"Home"],[14,2,"End"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"Pause"],[15,1,"Page Up"],[15,2,"Page Down"],[15,4,"Ctrl"],[15,5,"\u2192"]],"4D47:584F":[],"4D4B:0001":[],"4D4B:3C4D":[],"4D4B:6063":[],"4D4B:6064":[],"4D4B:6067":[],"4D4B:6D6E":[],"4D4C:0180":[],"4D4C:0600":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"Delete"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"TO(1)"],[13,4,"Ctrl"]],"4D4C:0601":[],"4D4C:0602":[],"4D4C:0675":[],"4D4C:0870":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Fn"],[13,0,"Delete"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"4D4C:0875":[],"4D4C:1800":[],"4D4C:4B4E":[],"4D4C:6001":[],"4D4C:6002":[],"4D4C:6500":[],"4D4C:6501":[],"4D4C:6502":[],"4D4C:6503":[],"4D4C:6504":[],"4D4C:6505":[],"4D4C:6601":[],"4D4C:6602":[],"4D4C:6C01":[[0,0,"Calculator"],[0,1,"Num Lock"],[0,2,"7"],[0,3,"4"],[0,4,"1"],[0,5,"0"],[1,0,"Mail"],[1,1,"/"],[1,2,"8"],[1,3,"5"],[1,4,"2"],[1,5,","],[2,0,"My Computer"],[2,1,"*"],[2,2,"9"],[2,3,"6"],[2,4,"3"],[2,5,"."],[3,0,"Mute"],[3,1,"-"],[3,2,"+"],[3,3,"+"],[3,4,"Enter"],[3,5,"="],[4,0,"Esc"],[4,1,"`"],[4,2,"Tab"],[4,3,"Caps Lock"],[4,4,"Shift"],[4,5,"Ctrl"],[5,0,"F1"],[5,1,"1"],[5,2,"Q"],[5,3,"A"],[5,4,"\\"],[5,5,"GUI"],[6,0,"F2"],[6,1,"2"],[6,2,"W"],[6,3,"S"],[6,4,"Z"],[6,5,"Alt"],[7,0,"F3"],[7,1,"3"],[7,2,"E"],[7,3,"D"],[7,4,"X"],[8,0,"F4"],[8,1,"4"],[8,2,"R"],[8,3,"F"],[8,4,"C"],[9,0,"F5"],[9,1,"5"],[9,2,"T"],[9,3,"G"],[9,4,"V"],[10,0,"F6"],[10,1,"6"],[10,2,"Y"],[10,3,"H"],[10,4,"B"],[10,5,"Space"],[11,0,"F7"],[11,1,"7"],[11,2,"U"],[11,3,"J"],[11,4,"N"],[12,0,"F8"],[12,1,"8"],[12,2,"I"],[12,3,"K"],[12,4,"M"],[13,0,"F9"],[13,1,"9"],[13,2,"O"],[13,3,"L"],[13,4,","],[14,0,"F10"],[14,1,"0"],[14,2,"P"],[14,3,";"],[14,4,"."],[14,5,"Alt"],[15,0,"F11"],[15,1,"-"],[15,2,"["],[15,3,"'"],[15,4,"/"],[15,5,"GUI"],[16,0,"F12"],[16,1,"="],[16,2,"]"],[16,3,"\\"],[16,4,"Shift"],[16,5,"Fn"],[17,0,"F13"],[17,1,"Backspace"],[17,2,"Delete"],[17,3,"Enter"],[17,4,"Space"],[17,5,"Ctrl"],[18,0,"Print Screen"],[18,1,"Insert"],[18,2,"Delete"],[18,5,"\u2190"],[19,0,"Scroll Lock"],[19,1,"Home"],[19,2,"End"],[19,4,"\u2191"],[19,5,"\u2193"],[20,0,"Pause"],[20,1,"Page Up"],[20,2,"Page Down"],[20,5,"\u2192"]],"4D4C:8701":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Menu"],[13,0,"Backspace"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"4D4C:8702":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Fn"],[13,0,"Delete"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"4D4C:8703":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,5,"GUI"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"4D4C:8704":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"4D4C:8710":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Fn"],[13,0,"Delete"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"4D4C:8801":[],"4D4C:8802":[],"4D4C:9101":[],"4D4C:9102":[],"4D4C:9103":[],"4D4C:C601":[],"4D4C:D181":[],"4D4C:D750":[],"4D4C:D870":[],"4D4D:0458":[],"4D4D:4846":[],"4D4D:4852":[],"4D4D:545A":[],"4D52:0001":[],"4D53:0002":[],"4D53:0004":[],"4D53:0006":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"ISO \\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,">"],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[13,0,"\\"],[13,1,"\\"],[13,2,"Enter"],[13,4,"Left"],[14,0,"Backspace"],[14,3,"Up"],[14,4,"Down"],[15,0,"Encoder"],[15,1,"Page up"],[15,2,"Page Down"],[15,3,"Fn"],[15,4,"Right"]],"4D53:4450":[],"4D53:6844":[],"4D54:0001":[],"4D54:0002":[],"4D57:0001":[],"4D57:0002":[[0,0,"Bksp"],[0,1,"-"],[0,2,"+"],[0,4,"Enter"],[1,0,"="],[1,1,"*"],[1,2,"9"],[1,3,"6"],[1,4,"3"],[1,5,"."],[2,0,"("],[2,1,"/"],[2,2,"8"],[2,3,"5"],[2,4,"2"],[3,0,")"],[3,1,"Num Lock"],[3,2,"7"],[3,3,"4"],[3,4,"1"],[3,5,"0"]],"4D57:0003":[[0,0,"Bksp"],[0,1,"Num Lock"],[0,2,"7"],[0,3,"4"],[0,4,"1"],[0,5,"0"],[1,0,"="],[1,1,"/"],[1,2,"8"],[1,3,"5"],[1,4,"2"],[2,0,"("],[2,1,"*"],[2,2,"9"],[2,3,"6"],[2,4,"3"],[2,5,"."],[3,0,")"],[3,1,"-"],[3,2,"+"],[3,4,"Enter"]],"4D58:0065":[],"4D58:0106":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"F12"],[0,6,"Num Lock"],[0,7,"PrtSc"],[0,8,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Backspace"],[1,6,"/"],[1,7,"Scroll Lock"],[1,8,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"="],[2,6,"*"],[2,7,"Pause"],[2,8,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"]"],[3,6,"-"],[3,7,"Page Up"],[3,8,"Space"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"\\"],[4,6,"+"],[4,7,"Home"],[4,8,"Alt"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Enter"],[5,6,"9"],[5,7,"Insert"],[5,8,"Fn"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[6,5,"1"],[6,6,"8"],[6,7,"Delete"],[6,8,"Ctrl"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[7,5,"2"],[7,6,"7"],[7,7,"End"],[7,8,"0"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"3"],[8,6,"4"],[8,7,"Page Down"],[8,8,"0"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[9,5,"Enter"],[9,6,"5"],[9,7,"\u2190"],[9,8,"."],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"+"],[10,6,"\u2191"],[10,7,"\u2193"],[10,8,"Enter"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[11,5,"6"],[11,7,"\u2192"]],"4D58:0369":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[6,5,"Alt"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[7,5,"Fn"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"Ctrl"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"\u2191"],[13,0,"Print Screen"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"Insert"],[13,4,"\u2190"],[14,0,"Scroll Lock"],[14,1,"Home"],[14,2,"End"],[14,3,"Delete"],[14,4,"\u2193"],[15,0,"Pause"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"\u2192"]],"4D58:20AD":[],"4D58:454D":[],"4D58:474E":[],"4D58:8712":[],"4D58:AB87":[],"4D59:0001":[],"4D61:466C":[],"4D65:1200":[],"4D65:3222":[],"4D65:3232":[],"4D65:3241":[],"4D65:5543":[],"4D76:3031":[[0,0,"D0"],[0,1,"C6"],[0,2,"B4"],[1,0,"D1"],[1,1,"D7"],[1,2,"B5"],[2,0,"D4"],[2,1,"E6"],[2,2,"B6"]],"4D77:0001":[],"4D78:5353":[],"4DAE:1000":[],"4E21:4F21":[[0,0,"`~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2@"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3#"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8*"],[8,1,"I"],[8,2,"K"],[8,3,",<"],[9,0,"9("],[9,1,"O"],[9,2,"L"],[9,3,".>"],[9,4,"Alt"],[10,0,"0)"],[10,1,"P"],[10,2,";:"],[10,3,"/?"],[10,4,"FN"],[11,0,"-_"],[11,1,"[{"],[11,2,"'\""],[11,3,"Shift"],[11,4,"Ctrl"],[12,0,"=+"],[12,1,"]}"],[12,2,"Enter"],[12,3,"MO"],[13,0,"Backspace"],[13,1,"\\|"],[14,0,"BSLS"],[14,3,"RShift"],[14,4,"RCtrl"],[15,0,"Backspace"]],"4E45:3630":[],"4E45:5244":[],"4E49:0002":[],"4E4B:0001":[],"4E4B:5048":[],"4E4B:5049":[],"4E4B:5053":[],"4E50:4A57":[],"4E50:4A58":[],"4E50:4B30":[[0,0,"Esc"],[0,1,"Q"],[0,2,"Tab"],[0,3,"A"],[0,4,"Shift"],[0,5,"Z"],[0,6,"Ctrl"],[0,7,"Alt"],[1,0,"W"],[1,1,"E"],[1,2,"S"],[1,3,"D"],[1,4,"X"],[1,5,"C"],[1,6,"Fn2"],[1,7,"Fn2/Space"],[2,0,"R"],[2,1,"T"],[2,2,"F"],[2,3,"G"],[2,4,"V"],[2,5,"B"],[3,0,"Y"],[3,1,"U"],[3,2,"H"],[3,3,"J"],[3,4,"N"],[3,5,"M"],[3,7,"Fn3/Space"],[4,0,"I"],[4,1,"O"],[4,2,"K"],[4,3,"L"],[4,4,","],[4,5,"."],[4,6,"Fn3"],[4,7,"GUI/Alt"],[5,0,"P"],[5,1,"["],[5,2,";"],[5,3,"'"],[5,4,"/"],[5,5,"Shift"],[5,6,"Fn"],[5,7,"\u2190"],[6,0,"Backspace"],[6,2,"Enter"],[6,4,"\u2191"],[6,7,"\u2193"],[7,0,"Delete"],[7,2,"Page Up"],[7,4,"Page Down"],[7,6,"\u2192"]],"4E50:4B57":[[0,0,"Esc"],[0,1,"Q"],[0,2,"Tab"],[0,3,"A"],[0,4,"Shift"],[0,5,"Z"],[0,6,"Ctrl"],[0,7,"Alt"],[1,0,"W"],[1,1,"E"],[1,2,"S"],[1,3,"D"],[1,4,"X"],[1,5,"C"],[1,6,"Fn2"],[1,7,"Fn2/Space"],[2,0,"R"],[2,1,"T"],[2,2,"F"],[2,3,"G"],[2,4,"V"],[2,5,"B"],[3,0,"Y"],[3,1,"U"],[3,2,"H"],[3,3,"J"],[3,4,"N"],[3,5,"M"],[3,7,"Fn3/Space"],[4,0,"I"],[4,1,"O"],[4,2,"K"],[4,3,"L"],[4,4,","],[4,5,"."],[4,6,"Fn3"],[4,7,"GUI/Alt"],[5,0,"P"],[5,1,"["],[5,2,";"],[5,3,"'"],[5,4,"/"],[5,5,"Shift"],[5,6,"Fn"],[5,7,"\u2190"],[6,0,"Backspace"],[6,2,"Enter"],[6,4,"\u2191"],[6,7,"\u2193"],[7,0,"7"],[7,1,"8"],[7,2,"4"],[7,3,"5"],[7,4,"1"],[7,5,"2"],[7,6,"\u2192"],[7,7,"0"],[8,0,"9"],[8,1,"-"],[8,2,"6"],[8,3,"+"],[8,4,"3"],[8,5,"*"],[8,6,"."],[8,7,"Fn3/Enter"]],"4E50:5341":[],"4E50:9111":[],"4E53:0F65":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"<"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,">"],[9,4,"Alt"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,"?"],[10,4,"Ctrl"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"Shift"],[11,4,"Left"],[12,0,"+"],[12,1,"}"],[12,2,"Enter"],[13,0,"Backspace"],[13,1,"|"],[13,3,"Up"],[13,4,"Down"],[14,0,"Backspace"],[15,1,"Delete"],[15,2,"PgUp"],[15,3,"PgDn"],[15,4,"Right"]],"4E54:0000":[],"4E57:5450":[[0,0,"D1"],[0,1,"D0"],[0,2,"D4"],[0,3,"C6"]],"4E58:017A":[[0,0,"F1"],[0,1,"F2"],[0,2,"F3"],[0,3,"F4"],[0,4,"F5"],[1,0,"F6"],[1,1,"F7"],[1,2,"F8"],[1,3,"F9"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"Z"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"X"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"C"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"V"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"B"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"N"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"M"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,","],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,"."],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"/"],[12,4,"Alt"],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"Shift"],[14,0,"="],[14,1,"]"],[14,2,"Enter"],[14,3,"\u2191"],[14,4,"\u2190"],[15,0,"Backspace"],[15,1,"\\"],[15,2,"Home"],[15,4,"\u2193"],[16,0,"Backspace"],[16,1,"Print Screen"],[16,2,"Delete"],[16,3,"End"],[16,4,"\u2192"]],"4E58:0899":[],"4E58:0A29":[],"4E58:0A79":[],"4E58:0A7A":[],"4E58:0A7B":[],"4E58:0A7C":[],"4E58:0AF1":[],"4E58:5648":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Alt"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"GUI"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Ctrl"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Page Down"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[14,1,"Page Up"],[14,2,"Delete"],[14,3,"Fn"],[14,4,"\u2192"]],"4E58:5649":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"6"],[6,5,"7"],[6,6,"Y"],[6,7,"H"],[6,8,"B"],[6,9,"Space"],[7,5,"8"],[7,6,"U"],[7,7,"J"],[7,8,"N"],[7,9,"Space"],[8,5,"9"],[8,6,"I"],[8,7,"K"],[8,8,"M"],[8,9,"Alt"],[9,5,"0"],[9,6,"O"],[9,7,"L"],[9,8,","],[9,9,"GUI"],[10,5,"-"],[10,6,"P"],[10,7,";"],[10,8,"."],[10,9,"Ctrl"],[11,5,"="],[11,6,"["],[11,7,"'"],[11,8,"/"],[11,9,"\u2190"],[12,5,"Backspace"],[12,6,"]"],[12,7,"Enter"],[12,8,"Shift"],[12,9,"\u2193"],[13,5,"Backspace"],[13,6,"\\"],[13,8,"\u2191"],[13,9,"\u2192"],[14,6,"Page Up"],[14,7,"Page Down"],[14,8,"Delete"],[14,9,"Fn"]],"4E5A:8001":[],"4E65:4E36":[],"4E65:6E65":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[8,4,"K48"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[9,4,"K49"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[10,4,"K4A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,3,"K3C"],[12,4,"K4C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"],[14,0,"K0E"],[14,1,"K1E"],[14,2,"K2E"],[14,3,"K3E"],[14,4,"K4E"],[15,0,"K017"],[15,1,"K116"],[15,2,"K216"],[15,3,"K316"],[15,4,"K416"],[16,0,"K018"],[16,1,"K117"],[16,2,"K217"],[16,3,"K317"],[16,4,"K417"]],"4E65:700E":[],"4E65:810E":[],"4E94:4E09":[],"4E95:4E19":[],"4F4A:0002":[],"4F4D:0001":[],"4F4E:0001":[],"4F53:464B":[],"4F53:4A4C":[],"4F53:4A53":[],"4F53:514B":[],"4F53:5153":[],"4F53:5349":[],"4F53:5350":[],"4F53:5355":[],"4F53:564F":[],"4F53:5657":[],"4F66:3876":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,5,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,5,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,5,"Menu"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,5,"Ctrl"],[14,0,"Delete"],[14,3,"Fn"]],"5001:0001":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Control"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[2,0,"2"],[2,1,"W)"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Alt"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"6"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"7"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"8"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"9"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"0"],[11,1,"["],[11,2,"'"],[11,3,"?"],[11,4,"App"],[12,0,"-"],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"="],[13,1,"Backspace"],[13,2,"|"],[13,3,"Shift"],[13,4,"Control"]],"5001:0002":[[0,0,"F1"],[0,1,"F2"],[0,2,"F3"],[0,3,"F4"],[0,4,"F5"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,4,"GUI"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"Z"],[3,4,"Alt"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"X"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"C"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"V"],[7,0,"6"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[7,4,"Space"],[8,0,"7"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[9,0,"8"],[9,1,"I"],[9,2,"K"],[9,3,"M"],[10,0,"9"],[10,1,"O"],[10,2,"L"],[10,3,","],[11,0,"0"],[11,1,"P"],[11,2,";"],[11,3,"."],[11,4,"Alt"],[12,0,"-"],[12,1,"["],[12,2,"'"],[12,3,"/"],[12,4,"Ctrl"],[13,0,"="],[13,1,"]"],[13,3,"Shift"],[14,0,"Backspace"],[14,2,"Enter"],[14,4,"\u2190"],[15,0,"Backspace"],[15,1,"\\"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Delete"],[16,1,"Page Up"],[16,2,"Page Down"],[16,3,"Fn"],[16,4,"\u2192"]],"5001:0003":[],"5003:0001":[],"5004:0001":[],"5006:E002":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,1,"!"],[1,2,"Q"],[2,0,"F1"],[2,1,"@"],[2,2,"W"],[2,3,"A"],[2,4,"Z"],[2,5,"Win"],[3,0,"F2"],[3,1,"#"],[3,2,"E"],[3,3,"S"],[3,4,"X"],[3,5,"Alt"],[4,0,"F3"],[4,1,"$"],[4,2,"R"],[4,3,"D"],[4,4,"C"],[5,0,"F4"],[5,1,"%"],[5,2,"T"],[5,3,"F"],[5,4,"V"],[6,0,"F5"],[6,1,"^"],[6,2,"Y"],[6,3,"G"],[6,4,"B"],[7,0,"F6"],[7,1,"&"],[7,2,"U"],[7,3,"H"],[7,4,"N"],[8,0,"F7"],[8,1,"*"],[8,2,"I"],[8,3,"J"],[8,4,"M"],[9,0,"F8"],[9,1,"("],[9,2,"O"],[9,3,"K"],[9,4,"<"],[10,0,"F9"],[10,1,")"],[10,2,"P"],[10,3,"L"],[10,4,">"],[10,5,"Alt"],[11,0,"F10"],[11,1,"_"],[11,2,"{"],[11,3,":"],[11,4,"?"],[11,5,"Fn"],[12,0,"F11"],[12,1,"+"],[12,2,"}"],[12,3,"\""],[13,0,"F12"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"|"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,5,"\u2190"],[15,0,"Delete"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Home"],[16,5,"\u2192"],[17,0,"Insert"],[17,1,"Num Lock"],[17,2,"7"],[17,3,"4"],[17,4,"1"],[17,5,"0"],[18,0,"PgUp"],[18,1,"/"],[18,2,"8"],[18,3,"5"],[18,4,"2"],[19,0,"PgDn"],[19,1,"*"],[19,2,"9"],[19,3,"6"],[19,4,"3"],[19,5,"."],[20,1,"-"],[20,2,"+"],[20,4,"Enter"]],"5012:1501":[],"503D:5457":[],"5040:7320":[],"5042:4552":[],"5043:1EAB":[],"5043:4CE5":[],"5043:4D6F":[],"5043:5442":[],"5043:54A3":[],"5043:5C46":[],"5043:5C47":[[0,0,"Bottom Left"],[1,0,"Top Left Left"],[2,0,"Top Left"],[3,0,"Top Right"],[4,0,"Top Right Right"],[5,0,"Bottom Right"]],"5044:0001":[],"5047:0001":[],"5048:0001":[],"5048:5887":[],"504B:1000":[],"504B:707A":[],"504B:707C":[[0,0,"ESC"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Capslock"],[0,5,"A"],[0,6,"Shift"],[0,8,"Ctrl"],[0,9,"Win"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"Z"],[1,7,"X"],[1,8,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"C"],[2,7,"V"],[3,0,"6"],[3,1,"7"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"B"],[3,7,"N"],[3,8,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,"M"],[4,7,","],[5,0,"0"],[5,1,"-"],[5,2,"P"],[5,3,"["],[5,4,";"],[5,5,"'"],[5,6,"."],[5,7,"/"],[5,8,"Alt"],[5,9,"Ctrl"],[6,0,"="],[6,1,"Backspace"],[6,2,"]"],[6,3,"\\"],[6,5,"Enter"],[6,6,"Shift"],[6,7,"Up"],[6,8,"Left"],[6,9,"Down"],[7,0,"Home"],[7,2,"End"],[7,4,"PgUp"],[7,6,"PgDn"],[7,8,"Right"]],"504C:5066":[],"504C:5067":[],"504C:5068":[],"504C:5069":[],"504D:0002":[],"5050:65AC":[],"5052:0042":[],"5052:004D":[],"5052:504D":[],"5052:6578":[],"5052:6579":[],"5053:422D":[],"5053:4253":[],"5053:434E":[[0,0,"K00"],[0,1,"K10"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[8,4,"K48"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[10,4,"K4A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,3,"K3C"],[12,4,"K4C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"],[14,0,"K0E"],[14,1,"K1E"],[14,2,"K2E"],[14,3,"K3E"],[14,4,"K4E"]],"5054:BB91":[],"5054:BB92":[],"5057:0001":[],"5058:4250":[],"5058:5445":[],"5064:0001":[],"5069:4784":[],"5072:6062":[[0,0,"k00"],[0,1,"k10"],[0,2,"k20"],[0,3,"k30"],[0,4,"k40"],[1,0,"k01"],[1,1,"k11"],[1,2,"k21"],[1,3,"k31"],[1,4,"k41"],[2,0,"k02"],[2,1,"k12"],[2,2,"k22"],[2,3,"k32"],[2,4,"k42"],[3,0,"k03"],[3,1,"k13"],[3,2,"k23"],[3,3,"k33"],[3,4,"k43"],[4,0,"k04"],[4,1,"k14"],[4,2,"k24"],[4,3,"k34"],[4,4,"k44"],[5,0,"k05"],[5,1,"k15"],[5,2,"k25"],[5,3,"k35"],[5,4,"k45"],[6,3,"k46"],[6,4,"k47"],[7,0,"k06"],[7,1,"k16"],[7,2,"k26"],[7,3,"k36"],[7,4,"k48"],[8,0,"k07"],[8,1,"k17"],[8,2,"k27"],[8,3,"k37"],[8,4,"k49"],[9,0,"k08"],[9,1,"k18"],[9,2,"k28"],[9,3,"k38"],[9,4,"k4a"],[10,0,"k09"],[10,1,"k19"],[10,2,"k29"],[10,3,"k39"],[10,4,"k4b"],[11,0,"k0a"],[11,1,"k1a"],[11,2,"k2a"],[11,3,"k3a"],[11,4,"k4c"],[12,0,"k0b"],[12,1,"k1b"],[12,2,"k2b"],[12,3,"k3b"],[12,4,"k4d"]],"5102:0001":[],"5143:4134":[],"5143:4558":[],"514B:5341":[],"5154:0009":[],"5154:0010":[],"5156:4C50":[],"515A:4D4D":[],"515A:5331":[],"515A:5657":[],"5241:004A":[],"5241:006A":[],"5241:006B":[],"5241:00AA":[],"5241:00AB":[],"5241:00AC":[],"5241:050A":[],"5241:060A":[],"5241:065B":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"Fn"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn2"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"\\"],[13,1,"Backspace"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"5241:080A":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"Fn"],[13,1,"Backspace"],[13,2,"\\"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"5241:150A":[],"5241:165B":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn2"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"5241:4B52":[],"5241:4B59":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"Fn"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,","],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn2"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"5242:6D64":[],"5247:8C9C":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Fn/Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Toggle RGB"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Fn3"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Fn2"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"\u2190"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"\u2193"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"\u2191"],[11,0,"Backspace"],[11,1,"\\"],[11,2,"Enter"],[11,3,"/"],[12,0,"Delete"],[12,3,"Shift"],[12,4,"\u2192"]],"524B:4362":[],"524B:4D41":[],"524B:4E31":[],"524D:0001":[],"5253:4450":[],"5255:D0C2":[],"5255:E212":[],"5255:F40C":[],"525C:9F9E":[],"525C:9F9F":[],"525C:C89F":[],"525C:E3EB":[],"530A:6FFC":[],"5342:0001":[],"5342:0002":[],"5342:0003":[],"5342:0004":[],"5342:0005":[],"5342:0006":[],"5342:0012":[],"5342:3225":[],"5342:4355":[],"5342:5032":[],"5342:504B":[],"5342:594E":[],"5343:0001":[],"5344:4548":[],"5348:0001":[[0,6,"F6"],[0,7,"7&"],[0,8,"U"],[0,9,"Y"],[0,10,"H"],[0,11,"N"],[1,6,"F7"],[1,7,"8*"],[1,8,"I"],[1,9,"J"],[1,10,"M"],[1,11,"Right Space"],[2,6,"F8"],[2,7,"9("],[2,8,"O"],[2,9,"K"],[2,10,"<"],[3,6,"F9"],[3,7,"0)"],[3,8,"P"],[3,9,"L"],[3,10,">"],[3,11,"Right Alt"],[4,0,"Esc"],[4,1,"1!"],[4,2,"~"],[4,3,"Tab"],[4,4,"Caps Lock"],[4,5,"Left Shift"],[4,6,"F10"],[4,7,"-_"],[4,8,"{"],[4,9,":"],[4,10,"?"],[4,11,"Right Win"],[5,0,"F1"],[5,1,"2@"],[5,2,"Q"],[5,3,"A"],[5,4,"Z"],[5,5,"Left Ctrl"],[5,6,"F11"],[5,7,"=+"],[5,8,"}"],[5,9,"\""],[5,11,"Menu"],[6,0,"F2"],[6,1,"3#"],[6,2,"W"],[6,3,"S"],[6,4,"X"],[6,5,"Fn"],[6,6,"F12"],[6,7,"Backspace"],[6,8,"|"],[6,9,"Enter"],[6,10,"Right Shift"],[6,11,"Right Ctrl"],[7,0,"F3"],[7,1,"4$"],[7,2,"E"],[7,3,"D"],[7,4,"C"],[7,5,"Left Alt"],[7,6,"PrtSc"],[7,7,"Insert"],[7,8,"Delete"],[7,11,"Left"],[8,0,"F4"],[8,1,"5%"],[8,2,"R"],[8,3,"F"],[8,4,"V"],[8,5,"Left Win"],[8,6,"Scroll Lock"],[8,7,"Home"],[8,8,"End"],[8,10,"Up"],[8,11,"Down"],[9,0,"F5"],[9,1,"6^"],[9,2,"T"],[9,3,"G"],[9,4,"B"],[9,5,"Left Space"],[9,6,"Pause"],[9,7,"PgUp"],[9,8,"PgDn"],[9,11,"Right"]],"5348:4B39":[],"534B:0001":[],"534B:0002":[],"534B:0007":[],"534B:0014":[],"534B:0017":[],"534B:0023":[],"534B:0027":[],"534B:0028":[],"534B:0030":[],"534B:1019":[],"534B:1020":[],"534B:1021":[],"534B:1026":[],"534B:534B":[],"534C:087A":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[0,5,"K50"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,5,"K51"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[2,5,"K52"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[5,4,"K45"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K46"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[7,4,"K47"],[7,5,"K57"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[8,4,"K48"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[9,4,"K49"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[10,4,"K4A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[11,5,"K5B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,4,"K4C"],[12,5,"K5C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"],[13,5,"K5D"],[14,1,"K1E"],[14,2,"K2E"],[14,5,"K5E"],[15,1,"K1F"],[15,2,"K2F"],[15,4,"K4F"],[15,5,"K5F"],[16,1,"K1G"],[16,2,"K2G"],[16,5,"K5G"]],"534C:0A01":[[0,0,"K00"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[7,4,"K47"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[9,4,"K49"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,3,"K3C"],[12,4,"K4C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"],[14,0,"K0E"],[14,1,"K1E"],[14,2,"K2E"],[14,3,"K3E"],[14,4,"K4E"],[15,0,"K0F"],[15,1,"K1F"],[15,2,"K2F"],[15,3,"K3F"],[15,4,"K4F"],[16,0,"K0G"],[16,1,"K1G"],[16,4,"K4G"],[17,0,"K0H"],[17,1,"K1H"],[17,3,"K3H"],[17,4,"K4H"],[18,0,"K0I"],[18,1,"K1I"],[18,4,"K4I"]],"534C:0C65":[],"534C:5E99":[],"534C:E160":[[0,0,"K00 (B1,C7)"],[0,1,"K10 (B2,C7)"],[0,2,"K20 (B7,C7)"],[0,3,"K30 (B3,C7)"],[0,4,"K40 (D1,C7)"],[0,5,"K50 (D0,C7)"],[0,6,"K60 (F6,C7)"],[0,7,"K70 (F7,C7)"],[0,8,"K80 (F4,C7)"],[0,9,"K90 (F5,C7)"],[1,0,"K01 (B1,C6)"],[1,1,"K11 (B2,C6)"],[1,2,"K21 (B7,C6)"],[1,3,"K31 (B3,C6)"],[1,4,"K41 (D1,C6)"],[1,5,"K51 (D0,C6)"],[1,6,"K61 (F6,C6)"],[1,7,"K71 (F7,C6)"],[1,8,"K81 (F4,C6)"],[2,0,"K02 (B1,B6)"],[2,1,"K12 (B2,B6)"],[2,2,"K22 (B7,B6)"],[2,3,"K32 (B3,B6)"],[2,4,"K42 (D1,B6)"],[2,5,"K52 (D0,B6)"],[2,6,"K62 (F6,B6)"],[2,7,"K72 (F7,B6)"],[3,0,"K03 (B1,B5)"],[3,1,"K13 (B2,B5)"],[3,2,"K23 (B7,B5)"],[3,3,"K33 (B3,B5)"],[3,4,"K43 (D1,B5)"],[3,5,"K53 (D0,B5)"],[3,6,"K63 (F6,B5)"],[3,7,"K73 (F7,B5)"],[3,8,"K83 (F4,B5)"],[4,0,"K04 (B1,B4)"],[4,1,"K14 (B2,B4)"],[4,2,"K24 (B7,B4)"],[4,3,"K34 (B3,B4)"],[4,4,"K44 (D1,B4)"],[4,5,"K54 (D0,B4)"],[4,6,"K64 (F6,B4)"],[4,7,"K74 (F7,B4)"],[4,9,"K94 (F5,B4)"],[5,0,"K05 (B1,D7)"],[5,1,"K15 (B2,D7)"],[5,2,"K25 (B7,D7)"],[5,3,"K35 (B3,D7)"],[5,4,"K45 (D1,D7)"],[5,5,"K55 (D0,D7)"],[5,6,"K65 (F6,D7)"],[5,7,"K75 (F7,D7)"],[5,8,"K85 (F4,D7)"],[5,9,"K95 (F5,D7)"],[6,0,"K06 (B1,D6)"],[6,1,"K16 (B2,D6)"],[6,2,"K26 (B7,D6)"],[6,3,"K36 (B3,D6)"],[6,4,"K46 (D1,D6)"],[6,5,"K56 (D0,D6)"],[6,6,"K66 (F6,D6)"],[6,7,"K76 (F7,D6)"],[6,8,"K86 (F4,D6)"],[6,9,"K96 (F5,D6)"]],"534C:E260":[[0,0,"K00 (B1,C7)"],[0,1,"K10 (B2,C7)"],[0,2,"K20 (B7,C7)"],[0,3,"K30 (B3,C7)"],[0,4,"K40 (D1,C7)"],[0,5,"K50 (D0,C7)"],[0,6,"K60 (F6,C7)"],[0,7,"K70 (F7,C7)"],[0,8,"K80 (F4,C7)"],[0,9,"K90 (F5,C7)"],[1,0,"K01 (B1,C6)"],[1,1,"K11 (B2,C6)"],[1,2,"K21 (B7,C6)"],[1,3,"K31 (B3,C6)"],[1,4,"K41 (D1,C6)"],[1,5,"K51 (D0,C6)"],[1,6,"K61 (F6,C6)"],[1,7,"K71 (F7,C6)"],[1,8,"K81 (F4,C6)"],[2,0,"K02 (B1,B6)"],[2,1,"K12 (B2,B6)"],[2,2,"K22 (B7,B6)"],[2,3,"K32 (B3,B6)"],[2,4,"K42 (D1,B6)"],[2,5,"K52 (D0,B6)"],[2,6,"K62 (F6,B6)"],[2,7,"K72 (F7,B6)"],[3,0,"K03 (B1,B5)"],[3,1,"K13 (B2,B5)"],[3,2,"K23 (B7,B5)"],[3,3,"K33 (B3,B5)"],[3,4,"K43 (D1,B5)"],[3,5,"K53 (D0,B5)"],[3,6,"K63 (F6,B5)"],[3,7,"K73 (F7,B5)"],[3,8,"K83 (F4,B5)"],[4,0,"K04 (B1,B4)"],[4,1,"K14 (B2,B4)"],[4,2,"K24 (B7,B4)"],[4,3,"K34 (B3,B4)"],[4,4,"K44 (D1,B4)"],[4,5,"K54 (D0,B4)"],[4,6,"K64 (F6,B4)"],[4,7,"K74 (F7,B4)"],[4,9,"K94 (F5,B4)"],[5,0,"K05 (B1,D7)"],[5,1,"K15 (B2,D7)"],[5,2,"K25 (B7,D7)"],[5,3,"K35 (B3,D7)"],[5,4,"K45 (D1,D7)"],[5,5,"K55 (D0,D7)"],[5,6,"K65 (F6,D7)"],[5,7,"K75 (F7,D7)"],[5,8,"K85 (F4,D7)"],[5,9,"K95 (F5,D7)"],[6,0,"K06 (B1,D6)"],[6,1,"K16 (B2,D6)"],[6,2,"K26 (B7,D6)"],[6,3,"K36 (B3,D6)"],[6,4,"K46 (D1,D6)"],[6,5,"K56 (D0,D6)"],[6,6,"K66 (F6,D6)"],[6,7,"K76 (F7,D6)"],[6,8,"K86 (F4,D6)"],[6,9,"K96 (F5,D6)"]],"534D:3830":[],"534D:3831":[],"534E:3031":[[0,0,"P2 1"],[0,2,"P1 1"],[1,0,"P1 2"],[1,1,"Knob Press"],[1,2,"P2 2"],[2,0,"P2 3"],[2,2,"P1 3"],[3,0,"P1 4"],[3,2,"P2 4"],[4,0,"P2 5"],[4,2,"P1 5"],[5,0,"P1 6"],[5,2,"P2 6"],[6,0,"P2 7"],[6,2,"P1 7"]],"534E:3630":[],"534E:3635":[],"534F:0001":[],"5350:00A1":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K46"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[10,4,"K4A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,3,"K3C"],[12,4,"K4C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"]],"5350:00A2":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[7,4,"K46"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,3,"K3C"],[12,4,"K4C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"],[14,0,"K0E"],[14,1,"K1E"],[14,2,"K2E"],[14,3,"K3E"],[14,4,"K4E"]],"5350:0727":[],"5350:0801":[[0,0,"K00 (D3,C0)"],[0,1,"K10 (D5,C0)"],[0,2,"K20 (B1,C0)"],[0,3,"K30 (B2,C0)"],[0,4,"K40 (B3,C0)"],[0,5,"K50 (B7,C0)"],[0,6,"K60 (D1,C0)"],[0,7,"K70 (D0,C0)"],[0,8,"K80 (F4,C0)"],[0,9,"K90 (F5,C0)"],[0,10,"KA0 (F6,C0)"],[0,11,"KB0 (F7,C0)"],[1,0,"K01 (D3,C7)"],[1,1,"K11 (D5,C7)"],[1,2,"K21 (B1,C7)"],[1,3,"K31 (B2,C7)"],[1,4,"K41 (B3,C7)"],[1,5,"K51 (B7,C7)"],[1,6,"K61 (D1,C7)"],[1,7,"K71 (D0,C7)"],[1,8,"K81 (F4,C7)"],[1,9,"K91 (F5,C7)"],[1,10,"KA1 (F6,C7)"],[2,0,"K02 (D3,C6)"],[2,1,"K12 (D5,C6)"],[2,2,"K22 (B1,C6)"],[2,3,"K32 (B2,C6)"],[2,4,"K42 (B3,C6)"],[2,5,"K52 (B7,C6)"],[2,6,"K62 (D1,C6)"],[2,7,"K72 (D0,C6)"],[2,8,"K82 (F4,C6)"],[2,9,"K92 (F5,C6)"],[3,0,"K03 (D3,B6)"],[3,1,"K13 (D5,B6)"],[3,2,"K23 (B1,B6)"],[3,3,"K33 (B2,B6)"],[3,4,"K43 (B3,B6)"],[3,5,"K53 (B7,B6)"],[3,6,"K63 (D1,B6)"],[3,7,"K73 (D0,B6)"],[3,8,"K83 (F4,B6)"],[3,9,"K93 (F5,B6)"],[3,10,"KA3 (F6,B6)"],[4,0,"K04 (D3,B5)"],[4,1,"K14 (D5,B5)"],[4,2,"K24 (B1,B5)"],[4,3,"K34 (B2,B5)"],[4,4,"K44 (B3,B5)"],[4,5,"K54 (B7,B5)"],[4,6,"K64 (D1,B5)"],[4,7,"K74 (D0,B5)"],[4,8,"K84 (F4,B5)"],[4,9,"K94 (F5,B5)"],[5,0,"K05 (D3,B4)"],[5,1,"K15 (D5,B4)"],[5,2,"K25 (B1,B4)"],[5,3,"K35 (B2,B4)"],[5,4,"K45 (B3,B4)"],[5,5,"K55 (B7,B4)"],[5,6,"K65 (D1,B4)"],[5,7,"K75 (D0,B4)"],[5,8,"K85 (F4,B4)"],[5,9,"K95 (F5,B4)"],[5,10,"KA5 (F6,B4)"],[5,11,"KB5 (F7,B4)"],[6,0,"K06 (D3,D7)"],[6,1,"K16 (D5,D7)"],[6,2,"K26 (B1,D7)"],[6,3,"K36 (B2,D7)"],[6,4,"K46 (B3,D7)"],[6,5,"K56 (B7,D7)"],[6,6,"K66 (D1,D7)"],[6,7,"K76 (D0,D7)"],[6,8,"K86 (F4,D7)"],[6,9,"K96 (F5,D7)"],[6,10,"KA6 (F6,D7)"],[6,11,"KB6 (F7,D7)"],[7,0,"K07 (D3,D6)"],[7,1,"K17 (D5,D6)"],[7,2,"K27 (B1,D6)"],[7,3,"K37 (B2,D6)"],[7,4,"K47 (B3,D6)"],[7,5,"K57 (B7,D6)"],[7,9,"K97 (F5,D6)"],[7,10,"KA7 (F6,D6)"],[7,11,"KB7 (F7,D6)"],[8,0,"K08 (D3,D4)"],[8,2,"K28 (B1,D4)"],[8,4,"K48 (B3,D4)"],[8,10,"KA8 (F6,D4)"]],"5350:1727":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"Print Screen"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"`"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"Delete"],[14,4,"\u2192"]],"5350:5B31":[],"5350:6B31":[],"5350:6B32":[],"5350:A801":[[0,0,"Esc"],[0,1,"F1"],[0,2,"`"],[0,3,"1"],[0,4,"Tab"],[0,5,"Q"],[0,6,"Caps Lock"],[0,7,"A"],[0,8,"Shift"],[0,9,"Kana"],[0,10,"Ctrl"],[0,11,"GUI"],[1,0,"F2"],[1,1,"F3"],[1,2,"2"],[1,3,"3"],[1,4,"W"],[1,5,"E"],[1,6,"S"],[1,7,"D"],[1,8,"Z"],[1,9,"X"],[1,10,"Alt"],[2,0,"F4"],[2,1,"F5"],[2,2,"4"],[2,3,"5"],[2,4,"R"],[2,5,"T"],[2,6,"F"],[2,7,"G"],[2,8,"C"],[2,9,"V"],[3,0,"F6"],[3,1,"F7"],[3,2,"6"],[3,3,"7"],[3,4,"Y"],[3,5,"U"],[3,6,"H"],[3,7,"J"],[3,8,"B"],[3,9,"N"],[3,11,"Space"],[4,0,"F8"],[4,1,"F9"],[4,2,"8"],[4,3,"9"],[4,4,"I"],[4,5,"O"],[4,6,"K"],[4,7,"L"],[4,8,"M"],[4,9,","],[5,0,"F10"],[5,1,"F11"],[5,2,"0"],[5,3,"-"],[5,4,"P"],[5,5,"["],[5,6,";"],[5,7,"'"],[5,8,"."],[5,9,"/"],[6,0,"F12"],[6,1,"F13"],[6,2,"="],[6,3,"Backspace"],[6,4,"]"],[6,5,"\\"],[6,7,"Enter"],[6,8,"Shift"],[6,9,"Fn"],[6,10,"Alt"],[6,11,"GUI"],[7,1,"Print Screen"],[7,2,"Backspace"],[7,3,"Insert"],[7,5,"Delete"],[7,10,"Ctrl"],[7,11,"\u2190"],[8,0,"Scroll Lock"],[8,1,"Pause"],[8,2,"Home"],[8,3,"Page Up"],[8,4,"End"],[8,5,"Page Down"],[8,8,"\u2191"],[8,10,"\u2193"],[8,11,"\u2192"]],"5351:4657":[],"5351:5458":[],"5352:0201":[],"5352:0202":[],"5352:0203":[],"5353:0001":[[0,0,"k00"],[0,1,"k10"],[0,2,"k20"],[1,0,"k01"],[1,1,"k11"],[1,2,"k21"],[2,0,"k02"],[2,1,"k12"],[2,2,"k22"]],"5354:556B":[],"5355:4558":[],"5355:4652":[],"5355:544B":[],"5357:0001":[],"5357:4637":[[0,0,"Esc"],[0,1,"\uff5e"],[0,2,"tab"],[0,3,"capslock"],[0,5,"lctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"q"],[1,3,"a"],[1,4,"leftshift"],[1,5,"lwin"],[2,0,"F2"],[2,1,"2"],[2,2,"w"],[2,3,"s"],[2,4,"z"],[2,5,"lalt"],[3,0,"F3"],[3,1,"3"],[3,2,"e"],[3,3,"d"],[3,4,"x"],[4,0,"F4"],[4,1,"4"],[4,2,"r"],[4,3,"f"],[4,4,"c"],[5,0,"F5"],[5,1,"5"],[5,2,"t"],[5,3,"g"],[5,4,"v"],[6,0,"F6"],[6,1,"6"],[6,2,"y"],[6,3,"h"],[6,4,"b"],[6,5,"space"],[7,0,"F7"],[7,1,"7"],[7,2,"u"],[7,3,"j"],[7,4,"n"],[8,0,"F8"],[8,1,"8"],[8,2,"i"],[8,3,"k"],[8,4,"m"],[9,0,"F9"],[9,1,"9"],[9,2,"o"],[9,3,"l"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"p"],[10,3,";"],[10,4,"."],[10,5,"ralt"],[11,0,"F11"],[11,1,"-"],[11,2,"{"],[11,3,"'"],[11,4,"/"],[11,5,"rctrl"],[12,0,"F12"],[12,1,"="],[12,2,"}"],[12,3,"enter"],[12,4,"rightshift"],[12,5,"left"],[13,0,"F13"],[13,1,"backspace"],[13,3,"|"],[13,4,"up"],[13,5,"down"],[14,1,"home"],[14,2,"end"],[14,3,"insert"],[14,4,"delete"],[14,5,"right"]],"5357:4638":[[0,0,"Esc"],[0,1,"\uff5e"],[0,2,"tab"],[0,3,"capslock"],[0,5,"lctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"q"],[1,3,"a"],[1,4,"leftshift"],[1,5,"lwin"],[2,0,"F2"],[2,1,"2"],[2,2,"w"],[2,3,"s"],[2,4,"z"],[2,5,"lalt"],[3,0,"F3"],[3,1,"3"],[3,2,"e"],[3,3,"d"],[3,4,"x"],[4,0,"F4"],[4,1,"4"],[4,2,"r"],[4,3,"f"],[4,4,"c"],[5,0,"F5"],[5,1,"5"],[5,2,"t"],[5,3,"g"],[5,4,"v"],[6,0,"F6"],[6,1,"6"],[6,2,"y"],[6,3,"h"],[6,4,"b"],[6,5,"space"],[7,0,"F7"],[7,1,"7"],[7,2,"u"],[7,3,"j"],[7,4,"n"],[8,0,"F8"],[8,1,"8"],[8,2,"i"],[8,3,"k"],[8,4,"m"],[9,0,"F9"],[9,1,"9"],[9,2,"o"],[9,3,"l"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"p"],[10,3,";"],[10,4,"."],[10,5,"ralt"],[11,0,"F11"],[11,1,"-"],[11,2,"{"],[11,3,"'"],[11,4,"/"],[11,5,"rctrl"],[12,0,"F12"],[12,1,"="],[12,2,"}"],[12,3,"enter"],[12,4,"rightshift"],[12,5,"left"],[13,0,"F13"],[13,1,"backspace"],[13,3,"|"],[13,4,"up"],[13,5,"down"],[14,1,"home"],[14,2,"end"],[14,3,"insert"],[14,4,"delete"],[14,5,"right"]],"5359:3735":[],"5359:4256":[],"5359:4E34":[],"5361:0090":[[0,0,"ESC"],[0,1,"TAB"],[0,2,"LCTRL"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"SPACE"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"WIN"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"LALT"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"RAISE"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[5,3,"LSHIFT"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"RSHIFT"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"LOWER"],[8,0,"I"],[8,1,"K"],[8,2,","],[8,3,"RALT"],[9,0,"O"],[9,1,"L"],[9,2,"."],[9,3,"MENU"],[10,0,"P"],[10,1,";"],[10,2,"/"],[10,3,"SPACE"],[11,0,"BKSPC"],[11,1,"ENTER"],[11,2,"RCTRL"]],"5363:0001":[[0,0,"\u2191"],[0,1,"\u2193"],[0,2,"\u2192"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Fn"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"Alt"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[4,4,"Fn2"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Fn3"],[7,0,"6"]],"5363:3333":[],"5363:6503":[[1,3,"encoder"]],"5363:7503":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Capslock"],[0,4,"Shift"],[0,5,"Control"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"Win"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F10"],[11,1,"-"],[11,2,"LB"],[11,3,"Quote"],[11,4,"/"],[12,0,"F11"],[12,1,"="],[12,2,"RB"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"Left"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"Pipe"],[13,4,"Up"],[13,5,"Down"],[14,0,"Del"],[14,1,"Home"],[14,2,"PgUp"],[14,3,"PgDn"],[14,4,"End"],[14,5,"Right"]],"5363:8888":[],"5369:0001":[[0,0,"Middle Click"],[1,0,"F16"],[1,1,"F20"],[1,2,"/"],[1,3,"*"],[1,4,"-"],[1,5,"+"],[1,6,"Win"],[1,7,"F12"],[1,8,"0"],[1,9,"P"],[1,10,";"],[2,0,"F17"],[2,1,"F21"],[2,2,"7"],[2,3,"4"],[2,4,"1"],[2,5,"0"],[2,6,"Ctrl"],[2,7,"F13"],[2,8,"-"],[2,9,"["],[2,10,"'"],[3,0,"F18"],[3,1,"F22"],[3,2,"8"],[3,3,"5"],[3,4,"2"],[3,5,"."],[3,6,"Print"],[3,7,"F14"],[3,8,"="],[3,9,"]"],[3,10,"\\"],[4,0,"F19"],[4,1,"F23"],[4,2,"9"],[4,3,"6"],[4,4,"3"],[4,5,"Enter"],[4,6,"Muhenkan"],[4,7,"F15"],[4,8,"Delete"],[4,9,"Enter"],[4,10,"."],[5,0,"F1"],[5,1,"F24"],[5,2,"Home"],[5,3,"End"],[5,4,"Page Up"],[5,5,"Page Down"],[5,6,"Space"],[5,7,"Backspace"],[5,8,"Shift"],[5,9,"`"],[5,10,"/"],[6,0,"F2"],[6,1,"Esc"],[6,2,"Tab"],[6,3,"Alt"],[6,4,"Shift"],[6,5,"F7"],[6,6,"5"],[6,7,"T"],[6,8,"G"],[6,9,"V"],[6,10,"Henkan"],[7,0,"F3"],[7,1,"1"],[7,2,"Q"],[7,3,"A"],[7,4,"\\"],[7,5,"F8"],[7,6,"6"],[7,7,"Y"],[7,8,"H"],[7,9,"B"],[7,10,"Left"],[8,0,"F4"],[8,1,"2"],[8,2,"W"],[8,3,"S"],[8,4,"Z"],[8,5,"F9"],[8,6,"7"],[8,7,"U"],[8,8,"J"],[8,9,"N"],[8,10,"Up"],[9,0,"F5"],[9,1,"3"],[9,2,"E"],[9,3,"D"],[9,4,"X"],[9,5,"F10"],[9,6,"8"],[9,7,"I"],[9,8,"K"],[9,9,"M"],[9,10,"Down"],[10,0,"F6"],[10,1,"4"],[10,2,"R"],[10,3,"F"],[10,4,"C"],[10,5,"F11"],[10,6,"9"],[10,7,"O"],[10,8,"L"],[10,9,","],[10,10,"Right"]],"5373:4173":[],"5373:6172":[],"5375:0001":[],"5436:6060":[],"5441:0001":[],"5447:4A43":[],"5447:4A4E":[],"5447:5452":[],"5447:9100":[],"5447:910C":[],"5448:4141":[[0,0,"Esc"],[0,1,"~"],[0,2,"tab"],[0,3,"capslock"],[0,4,"leftshift"],[0,10,"lctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"q"],[1,3,"a"],[1,4,"z"],[1,5,"Pause"],[1,6,"pg up"],[1,7,"pg dn"],[1,9,"right"],[1,10,"lwin"],[2,0,"F2"],[2,1,"2"],[2,2,"w"],[2,3,"s"],[2,4,"x"],[2,5,"Scrlk"],[2,6,"home"],[2,7,"end"],[2,8,"up"],[2,9,"down"],[2,10,"lalt"],[3,0,"F3"],[3,1,"3"],[3,2,"e"],[3,3,"d"],[3,4,"c"],[3,5,"Prtsc"],[3,6,"insert"],[3,7,"delete"],[3,9,"left"],[3,10,"space"],[4,0,"F4"],[4,1,"4"],[4,2,"r"],[4,3,"f"],[4,4,"v"],[4,5,"F13"],[4,6,"backspace"],[4,7,"|"],[4,10,"ralt"],[5,0,"F5"],[5,1,"5"],[5,2,"t"],[5,3,"g"],[5,4,"b"],[5,5,"F12"],[5,6,"="],[5,7,"}"],[5,8,"enter"],[5,10,"rwin"],[6,0,"F6"],[6,1,"6"],[6,2,"y"],[6,3,"h"],[6,4,"n"],[6,5,"F11"],[6,6,"-"],[6,7,"{"],[6,8,"'"],[6,9,"rightshift"],[7,0,"F7"],[7,1,"7"],[7,2,"u"],[7,3,"j"],[7,4,"m"],[7,5,"F10"],[7,6,"0"],[7,7,"p"],[7,8,";"],[7,9,"/"],[8,0,"F8"],[8,1,"8"],[8,2,"i"],[8,3,"k"],[8,4,","],[8,5,"F9"],[8,6,"9"],[8,7,"o"],[8,8,"l"],[8,9,"."],[8,10,"rctrl"]],"544B:0001":[],"544B:0002":[],"544B:0003":[],"544B:0004":[[0,0,"`"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\u2298"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"\u2298"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2298"],[13,4,"Ctrl"],[14,0,"\u2298"],[15,0,"Num Lock"],[15,1,"7"],[15,2,"4"],[15,3,"1"],[15,4,"0"],[16,0,"/"],[16,1,"8"],[16,2,"5"],[16,3,"2"],[16,4,"\u2298"],[17,0,"*"],[17,1,"9"],[17,2,"6"],[17,3,"3"],[17,4,"."],[18,0,"-"],[18,1,"\u2298"],[18,2,"+"],[18,3,"\u2298"],[18,4,"Enter"]],"544B:0005":[],"544B:0006":[],"544B:0007":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[3,5,"\u2192"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[4,5,"Page Down"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[5,5,"Page Up"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Pause"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Menu"],[13,0,"Delete"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Delete"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"]],"544B:0008":[],"544B:0009":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[0,7,"0"],[0,8,"O"],[0,9,"L"],[0,10,"."],[0,11,"Menu"],[1,1,"1"],[1,5,"GUI"],[1,6,"F9"],[1,7,"-"],[1,8,"P"],[1,9,";"],[1,10,"/"],[2,0,"F1"],[2,1,"2"],[2,2,"Q"],[2,3,"A"],[2,4,"Z"],[2,5,"Alt"],[2,6,"F10"],[2,7,"="],[2,8,"["],[2,9,"'"],[2,10,"Shift"],[2,11,"Ctrl"],[3,0,"F2"],[3,1,"3"],[3,2,"W"],[3,3,"S"],[3,4,"X"],[3,6,"F11"],[3,7,"Delete"],[3,8,"]"],[3,9,"Enter"],[4,0,"F3"],[4,1,"4"],[4,2,"E"],[4,3,"D"],[4,4,"C"],[4,6,"F12"],[4,7,"Backspace"],[4,8,"\\"],[4,10,"Fn"],[4,11,"\u2190"],[5,0,"F4"],[5,1,"5"],[5,2,"R"],[5,3,"F"],[5,4,"V"],[5,5,"Space"],[5,6,"Print Screen"],[5,7,"Page Up"],[5,8,"Page Down"],[5,10,"\u2191"],[5,11,"\u2193"],[6,0,"F5"],[6,1,"6"],[6,2,"T"],[6,3,"G"],[6,4,"B"],[6,6,"Home"],[6,7,"Num Lock"],[6,8,"7"],[6,9,"4"],[6,10,"1"],[6,11,"\u2192"],[7,0,"F6"],[7,1,"7"],[7,2,"Y"],[7,3,"H"],[7,4,"N"],[7,6,"End"],[7,7,"/"],[7,8,"8"],[7,9,"5"],[7,10,"2"],[7,11,"0"],[8,0,"F7"],[8,1,"8"],[8,2,"U"],[8,3,"J"],[8,4,"M"],[8,5,"Alt"],[8,6,"Scroll Lock"],[8,7,"*"],[8,8,"9"],[8,9,"6"],[8,10,"3"],[8,11,"."],[9,0,"F8"],[9,1,"9"],[9,2,"I"],[9,3,"K"],[9,4,","],[9,6,"Pause"],[9,7,"-"],[9,8,"-"],[9,9,"+"],[9,10,"Enter"],[9,11,"Enter"]],"544B:0011":[],"544B:0012":[],"544C:6050":[],"544D:C000":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"LShift"],[0,4,"LCtrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"<"],[1,4,"Win"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Y"],[2,4,"LAlt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Z"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,"\u00d6"],[10,3,"."],[10,4,"RAlt"],[11,0,"?"],[11,1,"\u00dc"],[11,2,"\u00c4"],[11,3,"-"],[11,4,"Fn1"],[12,0,"`"],[12,1,"*"],[12,2,"'"],[12,3,"RShift"],[12,4,"RCtrl"],[13,4,"\u2190"],[14,0,"Backspace"],[14,2,"Enter"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Del"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"Fn2"],[15,4,"\u2192"]],"544E:3931":[],"544E:7033":[],"544E:7034":[],"5450:6A31":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"\\"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[6,4,"Space"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[11,4,"Alt"],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[12,4,"GUI"],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"Fn"],[14,0,"="],[14,1,"]"],[14,2,"#"],[14,3,"Shift"],[15,0,"Backspace"],[15,1,"\\"],[15,2,"Enter"],[15,4,"\u2190"],[16,0,"Backspace"],[16,3,"\u2191"],[16,4,"\u2193"],[17,0,"Print Screen"],[17,1,"Delete"],[17,2,"Page Up"],[17,3,"Page Down"],[17,4,"\u2192"]],"5452:0001":[],"5452:0002":[],"5452:3330":[],"5452:5492":[],"5452:5493":[],"5453:0004":[],"5453:0050":[],"5453:0052":[],"5453:0055":[],"5453:0059":[],"5453:0060":[],"5453:0071":[],"5453:0077":[],"5453:0080":[],"5453:0084":[],"5453:0100":[],"5453:0200":[],"5453:2311":[],"5453:3633":[],"5453:3666":[],"5453:3830":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Shift"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Backspace"],[12,4,"Shift"],[12,5,"GUI"],[13,0,"Play/Pause"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"Left"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"Up"],[15,5,"Down"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"Right"]],"5453:4E45":[],"5453:5336":[],"5453:5400":[],"5453:6533":[],"5453:6F38":[],"5453:7934":[],"5454:5649":[],"5457:6060":[],"5458:0001":[],"54F3:2065":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[8,4,"Alt"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Fn"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Shift"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"\u2191"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"\u25bd"],[14,0,"Backspace"],[14,1,"Delete"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"5544:4C50":[],"5544:544E":[],"554B:004E":[],"5559:0001":[],"5559:0002":[],"5559:0003":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Caps Lock"],[0,5,"A"],[0,6,"Shift"],[0,7,"\\"],[0,8,"Ctrl"],[0,9,"GUI"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"Z"],[1,7,"X"],[1,8,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"C"],[2,7,"V"],[3,0,"6"],[3,1,"7"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"B"],[3,7,"N"],[3,8,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,"M"],[4,7,","],[4,9,"Alt"],[5,0,"0"],[5,1,"-"],[5,2,"P"],[5,3,"["],[5,4,";"],[5,5,"'"],[5,6,"."],[5,7,"/"],[5,9,"Ctrl"],[6,0,"="],[6,1,"Backspace"],[6,2,"]"],[6,3,"\\"],[6,5,"Enter"],[6,6,"Shift"],[6,7,"\u2191"],[6,8,"\u2190"],[6,9,"\u2193"],[7,0,"Delete"],[7,1,"Home"],[7,3,"End"],[7,5,"Page Up"],[7,7,"Page Down"],[7,9,"\u2192"]],"5559:0004":[],"5559:0005":[],"5633:1024":[],"5641:2045":[],"5644:0001":[],"5644:0010":[[0,1,"F1"],[0,3,"F2"],[0,5,"F3"],[0,7,"F4"],[1,0,"Q"],[1,1,"Esc"],[1,2,"A"],[1,3,"Tab"],[1,4,"Z"],[1,5,"Shift"],[1,6,"Fn"],[1,7,"Ctrl"],[2,0,"W"],[2,1,"E"],[2,2,"S"],[2,3,"D"],[2,4,"X"],[2,5,"C"],[2,6,"Alt"],[3,0,"T"],[3,1,"R"],[3,2,"G"],[3,3,"F"],[3,4,"B"],[3,5,"V"],[3,6,"\u25bd"],[3,7,"Space"],[4,0,"Y"],[4,1,"U"],[4,2,"H"],[4,3,"J"],[4,4,"N"],[4,5,"M"],[4,7,"Space"],[5,0,"O"],[5,1,"I"],[5,2,"L"],[5,3,"K"],[5,4,"."],[5,5,","],[5,6,"Alt"],[5,7,"\u25bd"],[6,0,"P"],[6,1,"["],[6,2,";"],[6,5,"Shift"],[6,7,"\u2190"],[7,0,"Delete"],[7,1,"Backspace"],[7,2,"Home"],[7,3,"Enter"],[7,4,"End"],[7,5,"\u2191"],[7,6,"\u2192"],[7,7,"\u2193"]],"5644:3934":[],"5644:446F":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K44"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[5,4,"K46"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K46"],[7,0,"K07"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[9,4,"K49"],[10,0,"K010"],[10,1,"K110"],[10,2,"K210"],[10,3,"K310"],[11,0,"K011"],[11,1,"K111"],[11,2,"K211"],[11,3,"K311"],[11,4,"K411"],[12,0,"K012"],[12,1,"K112"],[12,2,"K212"],[12,3,"K312"],[13,0,"K013"],[13,1,"K113"],[13,2,"K213"],[13,3,"K313"],[14,0,"K014"],[14,1,"K114"],[14,3,"K314"],[14,4,"K414"],[15,0,"K015"],[15,1,"K115"],[15,2,"K215"],[15,3,"K315"],[15,4,"K415"]],"5644:4D49":[[0,1,"K10"],[0,3,"K30"],[0,5,"K50"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[1,5,"K51"],[1,6,"K61"],[1,7,"K71"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[2,5,"K52"],[2,6,"K62"],[2,7,"K72"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"],[3,5,"K53"],[3,6,"K63"],[3,7,"K73"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[4,5,"K54"],[4,6,"K64"],[4,7,"K74"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[5,4,"K45"],[5,5,"K55"],[5,7,"K75"],[6,0,"K06"],[6,2,"K26"],[6,4,"K46"]],"5644:4D54":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"]],"5644:4E54":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"]],"5644:4F4E":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"]],"5644:5111":[[0,0,"F13"],[0,1,"Num Lock"],[0,2,"7"],[0,3,"4"],[0,4,"1"],[0,5,"0"],[0,7,"7"],[0,8,"Y"],[0,9,"H"],[1,0,"F14"],[1,1,"/"],[1,2,"8"],[1,3,"5"],[1,4,"2"],[1,5,"0"],[1,6,"F7"],[1,7,"8"],[1,8,"U"],[1,9,"J"],[1,10,"N"],[2,0,"F15"],[2,1,"*"],[2,2,"9"],[2,3,"6"],[2,4,"3"],[2,5,"00"],[2,6,"F8"],[2,7,"9"],[2,8,"I"],[2,9,"K"],[2,10,"M"],[2,11,"Space"],[3,0,"F16"],[3,1,"-"],[3,2,"+"],[3,3,"="],[3,4,"Enter"],[3,5,"."],[3,6,"F9"],[3,7,"0"],[3,8,"O"],[3,9,"L"],[3,10,","],[3,11,"Menu"],[4,0,"Esc"],[4,1,"`"],[4,2,"Tab"],[4,3,"Caps Lock"],[4,4,"Shift"],[4,5,"Ctrl"],[4,6,"F10"],[4,7,"-"],[4,8,"P"],[4,9,";"],[4,10,"."],[4,11,"Alt"],[5,0,"F1"],[5,1,"1"],[5,2,"Q"],[5,3,"A"],[5,4,"\\"],[5,5,"GUI"],[5,6,"F11"],[5,7,"="],[5,8,"["],[5,9,"'"],[5,10,"/"],[5,11,"GUI"],[6,0,"F2"],[6,1,"2"],[6,2,"W"],[6,3,"S"],[6,4,"Z"],[6,5,"Alt"],[6,6,"F12"],[6,7,"Backspace"],[6,8,"]"],[6,9,"#"],[6,10,"Shift"],[6,11,"Ctrl"],[7,0,"F3"],[7,1,"3"],[7,2,"E"],[7,3,"D"],[7,4,"X"],[7,5,"Mute"],[7,6,"Print Screen"],[7,7,"Delete"],[7,8,"\\"],[7,9,"Enter"],[7,10,"Fn"],[7,11,"\u2190"],[8,0,"F4"],[8,1,"4"],[8,2,"R"],[8,3,"F"],[8,4,"C"],[8,5,"Space"],[8,6,"Scroll Lock"],[8,7,"Home"],[8,8,"End"],[8,9,"Page Up"],[8,10,"\u2191"],[8,11,"\u2193"],[9,0,"F5"],[9,1,"5"],[9,2,"T"],[9,3,"G"],[9,4,"V"],[9,6,"Pause"],[9,7,"Insert"],[9,8,"Delete"],[9,9,"Page Down"],[9,11,"\u2192"],[10,0,"F6"],[10,1,"6"],[10,4,"B"]],"5644:5112":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[0,5,"5.0"],[0,6,"6,0"],[0,7,"7,0"],[0,8,"8,0"],[0,9,"9,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[1,5,"5,1"],[1,6,"6,1"],[1,7,"7,1"],[1,8,"8,1"],[1,9,"9,1"],[1,10,"10,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[2,5,"5,2"],[2,7,"7,2"],[2,8,"8,2"],[2,9,"9,2"],[2,10,"10,1"],[2,11,"11,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[3,5,"5,3"],[3,6,"6,3"],[3,7,"7,3"],[3,8,"8,3"],[3,9,"9,3"],[3,10,"10,2"],[3,11,"11,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[4,5,"5,4"],[4,6,"6,4"],[4,7,"7,4"],[4,8,"8,4"],[4,9,"9,4"],[4,10,"10,3"],[4,11,"11,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[5,5,"5,5"],[5,6,"6,5"],[5,7,"7,5"],[5,8,"8,5"],[5,9,"9,5"],[5,10,"10,4"],[5,11,"11,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[6,6,"6,6"],[6,7,"7,6"],[6,8,"8,6"],[6,9,"9,6"],[6,10,"10,6"],[6,11,"11,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[7,5,"5,7"],[7,6,"6,7"],[7,7,"7,7"],[7,8,"8,7"],[7,9,"9,7"],[7,10,"10,7"],[7,11,"11,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[8,5,"5,8"],[8,6,"6,8"],[8,7,"7,8"],[8,8,"8,8"],[8,9,"9,8"],[8,10,"10,8"],[8,11,"11,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[9,5,"5,9"],[9,6,"6,9"],[9,7,"7,9"],[9,8,"8,9"],[9,9,"9,9"],[9,11,"11,9"],[10,0,"0,10"],[10,1,"1,10"],[10,4,"4,10"]],"5644:534D":[[0,0,"\u25bd"],[0,1,"Fn"],[0,2,"Fn2"],[0,3,"\u25bd"],[0,4,"\u25bd"],[0,5,"\u25bd"],[0,6,"Y"],[0,7,"H"],[1,0,"\u25bd"],[1,1,"Esc"],[1,2,"Tab"],[1,3,"Shift"],[1,4,"Ctrl"],[1,5,"\u25bd"],[1,6,"U"],[1,7,"J"],[1,8,"N"],[2,0,"\u25bd"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[2,4,"Alt"],[2,5,"\u25bd"],[2,6,"I"],[2,7,"K"],[2,8,"M"],[2,9,"Fn2/Backspace"],[3,0,"\u25bd"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[3,4,"GUI"],[3,5,"\u25bd"],[3,6,"O"],[3,7,"L"],[3,8,","],[3,9,"Alt"],[4,0,"\u25bd"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[4,4,"Fn1"],[4,5,"\u25bd"],[4,6,"P"],[4,7,"'"],[4,8,"."],[4,9,"Fn2"],[5,0,"\u25bd"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[5,4,"Fn/Space"],[5,5,"F24"],[5,6,"Delete"],[5,8,"Shift"],[5,9,"\u2190"],[6,0,"\u25bd"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,5,"\u25bd"],[6,6,"Backspace"],[6,7,"Enter"],[6,8,"\u2191"],[6,9,"\u2193"],[7,5,"\u25bd"],[7,6,"\u25bd"],[7,7,"\u25bd"],[7,9,"\u2192"]],"5644:5354":[[0,0,"K000"],[0,1,"K100"],[0,2,"K200"],[0,3,"K300"],[0,4,"K400"],[1,0,"K001"],[1,1,"K101"],[1,2,"K201"],[1,3,"K301"],[1,4,"K401"],[2,0,"K002"],[2,1,"K102"],[2,2,"K202"],[2,3,"K302"],[2,4,"K402"],[3,0,"K003"],[3,1,"K103"],[3,2,"K203"],[3,4,"K403"],[4,0,"K004"],[4,1,"K104"],[4,2,"K204"],[4,3,"K304"],[4,4,"K404"],[5,0,"K005"],[5,1,"K105"],[5,2,"K205"],[5,3,"K305"],[6,0,"K006"],[6,1,"K106"],[6,2,"K206"],[6,3,"K306"],[7,0,"K007"],[7,1,"K107"],[7,2,"K207"],[7,3,"K307"],[8,0,"K008"],[8,1,"K108"],[8,2,"K208"],[8,3,"K308"],[8,4,"K408"],[9,0,"K009"],[9,1,"K109"],[9,2,"K209"],[9,3,"K309"],[10,0,"K00A"],[10,1,"K10A"],[10,2,"K20A"],[10,3,"K30A"],[11,0,"K00B"],[11,1,"K10B"],[11,2,"K20B"],[11,3,"K30B"],[12,0,"K00C"],[12,1,"K10C"],[12,2,"K20C"],[12,3,"K30C"],[12,4,"K40C"],[13,0,"K00D"],[13,1,"K10D"],[13,2,"K20D"],[13,3,"K30D"],[13,4,"K40D"],[14,0,"K00E"],[14,1,"K10E"],[14,3,"K30E"],[14,4,"K40E"],[15,0,"K00F"],[15,2,"K20F"],[16,0,"K010"],[16,1,"K110"],[16,3,"K310"],[16,4,"K410"],[17,0,"K011"],[17,1,"K111"],[17,2,"K211"],[17,3,"K311"],[17,4,"K411"]],"5644:5458":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[1,5,"K51"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[2,5,"K52"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,5,"K53"]],"5644:5632":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,5,"K50"],[0,6,"K60"],[0,8,"K80"],[0,9,"K90"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[1,5,"K51"],[1,6,"K61"],[1,7,"K71"],[1,8,"K81"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,5,"K52"],[2,6,"K62"],[2,7,"K72"],[2,8,"K82"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[3,4,"K43"],[3,5,"K53"],[3,6,"K63"],[3,7,"K73"],[3,8,"K83"],[3,9,"K93"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,5,"K54"],[4,6,"K64"],[4,7,"K74"],[4,8,"K84"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[5,4,"K45"],[5,5,"K55"],[5,6,"K65"],[5,7,"K75"],[5,8,"K85"],[5,9,"K95"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K46"],[6,5,"K56"],[6,6,"K66"],[6,7,"K76"],[6,8,"K86"],[7,5,"K57"],[7,6,"K67"],[7,7,"K77"],[7,8,"K87"]],"564B:0001":[],"564B:0602":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps"],[0,4,"Shift"],[0,5,"Ctrl"],[0,6,"F6"],[0,7,"^"],[0,8,"Y"],[0,9,"H"],[0,10,"N"],[0,11,"space2"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[1,6,"F7"],[1,7,"&"],[1,8,"U"],[1,9,"J"],[1,10,"M"],[1,11,"fn"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[2,6,"F8"],[2,7,"*"],[2,8,"I"],[2,9,"K"],[2,10,"<"],[2,11,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"Menu"],[3,6,"F9"],[3,7,"("],[3,8,"O"],[3,9,"L"],[3,10,">"],[3,11,"Win"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"space"],[4,6,"F10"],[4,7,")"],[4,8,"P"],[4,9,":"],[4,10,"?"],[4,11,"Ctrl"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"fn"],[5,6,"F11"],[5,7,"_"],[5,8,"{"],[5,9,"\""],[5,10,"Shift"],[5,11,"\u2190"],[6,6,"F12"],[6,7,"+"],[6,8,"}"],[6,9,"Enter"],[6,10,"\u2191"],[6,11,"\u2193"],[7,7,"Backspace"],[7,8,"|"],[7,10,"mx"],[7,11,"\u2192"]],"564C:0000":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[0,5,"5,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[1,5,"5,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[2,5,"5,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[3,5,"5,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[6,5,"5,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[7,5,"5,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[10,5,"5,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[11,5,"5,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[12,5,"5,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[13,5,"5,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[14,5,"5,14"],[15,0,"0,15"],[15,1,"1,15"],[15,2,"2,15"],[15,3,"3,15"],[15,4,"4,15"],[15,5,"5,15"],[16,0,"0,16"],[16,1,"1,16"],[16,2,"2,16"],[16,3,"3,16"],[16,4,"4,16"],[16,5,"5,16"],[17,0,"0,17"],[17,1,"1,17"],[17,2,"2,17"],[17,3,"3,17"],[17,4,"4,17"],[17,5,"5,17"]],"5678:5058":[],"5742:6361":[],"5742:6E75":[],"5746:0001":[],"5749:5048":[],"5749:5053":[],"574A:4B50":[[0,0,"GRV"],[0,1,"A"],[1,0,"1"],[1,1,"S"],[2,0,"2"],[2,1,"D"],[3,0,"3"],[3,1,"F"],[4,0,"4"],[4,1,"ENT"],[5,0,"ESC"],[5,1,"G"],[6,0,"LSFT"],[6,1,"SPC"],[7,0,"Q"],[7,1,"TAB"],[8,0,"W"],[8,1,"Z"],[9,0,"E"],[9,1,"X"],[10,0,"R"],[10,1,"C"],[11,0,"LBRC"],[11,1,"RBRC"],[12,0,"LCTL"],[12,1,"M"]],"574B:7770":[[0,0,"F1"],[0,1,"F5"],[1,0,"F2"],[1,1,"F6"],[2,0,"F3"],[2,1,"F7"],[3,0,"F4"],[3,1,"F8"]],"574C:1DF9":[[0,0,"k00"],[1,0,"k01"],[2,0,"k02"],[3,0,"k03"],[4,0,"k04"],[5,0,"k05"],[6,0,"k06"],[7,0,"k07"],[8,0,"k08"],[9,0,"k09"],[10,0,"k0a"],[11,0,"k0b"]],"574C:99EB":[],"574C:E6E3":[],"574C:E6F0":[],"574D:0201":[],"5753:56D9":[],"5753:63CC":[],"5753:692A":[],"5754:C401":[],"5757:0001":[],"5757:0002":[],"5757:0003":[],"5757:0004":[],"5757:0005":[],"57EF:6063":[[0,0,"Esc"],[0,1,"Caps Lock"],[0,2,"Ctrl"],[0,3,"Y"],[0,4,"N"],[0,5,"["],[0,6,"F3"],[0,7,"]"],[0,8,"F4"],[0,9,"Ctrl"],[1,0,"1"],[1,1,"A"],[1,2,"Ctrl"],[1,3,"U"],[1,4,"M"],[1,5,"T"],[1,6,"B"],[1,7,"Backspace"],[1,8,"Enter"],[1,9,"Ctrl"],[2,0,"2"],[2,1,"S"],[2,2,"Gui"],[2,3,"I"],[2,4,","],[2,5,"R"],[2,6,"V"],[2,7,"0"],[2,8,";"],[2,9,"Fn"],[3,0,"3"],[3,1,"D"],[3,2,"Alt"],[3,3,"O"],[3,4,"."],[3,5,"E"],[3,6,"C"],[3,7,"9"],[3,8,"L"],[3,9,"AltGr"],[4,0,"4"],[4,1,"F"],[4,2,"Space"],[4,3,"P"],[4,5,"W"],[4,6,"X"],[4,7,"8"],[4,8,"K"],[5,0,"5"],[5,1,"G"],[5,2,"F5"],[5,3,"\\"],[5,4,"/"],[5,5,"Q"],[5,6,"Z"],[5,7,"7"],[5,8,"J"],[5,9,"Space"],[6,0,"F1"],[6,1,"="],[6,2,"F2"],[6,3,"-"],[6,4,"Shift"],[6,5,"Tab"],[6,6,"Shift"],[6,7,"6"],[6,8,"H"],[6,9,"F5"]],"5831:4249":[],"5842:4B50":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"Space"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Ctrl"],[6,0,"F6"],[6,2,"Y"],[6,3,"Backspace"],[6,4,"Enter"],[6,5,"Shift"],[7,0,"F7"],[7,1,"^"],[7,2,"U"],[7,3,"H"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"&"],[8,2,"I"],[8,3,"J"],[8,4,"M"],[9,0,"F9"],[9,1,"*"],[9,2,"O"],[9,3,"K"],[9,4,"<"],[9,5,"Alt"],[10,0,"F10"],[10,1,"("],[10,2,"P"],[10,3,"L"],[10,4,">"],[10,5,"Fn"],[11,0,"F11"],[11,1,")"],[11,2,"{"],[11,3,":"],[11,4,"?"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"_"],[12,2,"}"],[12,3,"\""],[12,4,"Shift"],[12,5,"Left"],[13,0,"Delete"],[13,1,"+"],[13,2,"|"],[13,3,"Enter"],[13,4,"Up"],[13,5,"Down"],[14,0,"Print Screen"],[14,1,"Backspace"],[14,2,"Page Up"],[14,3,"Page Down"],[14,5,"Right"]],"5842:4B6E":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"Space"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Ctrl"],[6,0,"F6"],[6,2,"Page Up"],[6,3,"Backspace"],[6,4,"Enter"],[6,5,"Shift"],[7,0,"F7"],[7,1,"^"],[7,2,"Y"],[7,3,"H"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"&"],[8,2,"U"],[8,3,"J"],[8,4,"M"],[9,0,"F9"],[9,1,"*"],[9,2,"I"],[9,3,"K"],[9,4,"<"],[9,5,"Alt"],[10,0,"F10"],[10,1,"("],[10,2,"O"],[10,3,"L"],[10,4,">"],[10,5,"Fn"],[11,0,"F11"],[11,1,")"],[11,2,"P"],[11,3,":"],[11,4,"?"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"_"],[12,2,"{"],[12,3,"\""],[12,4,"Shift"],[12,5,"Left"],[13,0,"Delete"],[13,1,"+"],[13,2,"}"],[13,3,"Enter"],[13,4,"Up"],[13,5,"Down"],[14,0,"Print Screen"],[14,1,"Backspace"],[14,2,"|"],[14,3,"Page Down"],[14,5,"Right"]],"5842:4E61":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"Space"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Ctrl"],[6,0,"F6"],[6,2,"Page Up"],[6,3,"Backspace"],[6,4,"Enter"],[6,5,"Shift"],[7,0,"F7"],[7,1,"^"],[7,2,"Y"],[7,3,"H"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"&"],[8,2,"U"],[8,3,"J"],[8,4,"M"],[9,0,"F9"],[9,1,"*"],[9,2,"I"],[9,3,"K"],[9,4,"<"],[9,5,"Alt"],[10,0,"F10"],[10,1,"("],[10,2,"O"],[10,3,"L"],[10,4,">"],[10,5,"Fn"],[11,0,"F11"],[11,1,")"],[11,2,"P"],[11,3,":"],[11,4,"?"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"_"],[12,2,"{"],[12,3,"\""],[12,4,"Shift"],[12,5,"Left"],[13,0,"Delete"],[13,1,"+"],[13,2,"}"],[13,3,"Enter"],[13,4,"Up"],[13,5,"Down"],[14,0,"Print Screen"],[14,1,"Backspace"],[14,2,"|"],[14,3,"Page Down"],[14,5,"Right"]],"5842:4E75":[],"5842:5261":[],"5845:0060":[],"5845:0108":[],"5845:4654":[[0,0,"`"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Fn"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"GUI"],[14,0,"Insert"],[14,1,"Delete"],[14,4,"\u2190"],[15,0,"Home"],[15,1,"End"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Page Up"],[16,1,"Page Down"],[16,4,"\u2192"]],"5845:4C50":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Fn"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"5845:4E4A":[],"5845:5041":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F13"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Menu"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"Menu (Legacy)"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Backspace"],[13,4,"Fn"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"5845:5052":[],"5845:5053":[],"5845:5208":[],"5845:524F":[[0,0,"Mute"],[0,1,"Volume Down"],[0,2,"Num Lock"],[0,3,"/"],[0,4,"+"],[0,5,"7"],[0,6,"+"],[0,7,"4"],[0,8,"Enter"],[0,9,"1"],[0,10,"Enter"],[0,11,"."],[1,0,"Volume Up"],[1,1,"\u25bd"],[1,2,"*"],[1,3,"-"],[1,4,"8"],[1,5,"9"],[1,6,"5"],[1,7,"6"],[1,8,"2"],[1,9,"3"],[1,10,"0"],[1,11,"0"],[2,0,"Print Screen"],[2,1,"Scroll Lock"],[2,2,"Insert"],[2,3,"Home"],[2,4,"Delete"],[2,5,"End"],[2,9,"\u2191"],[2,10,"\u2190"],[2,11,"\u2193"],[3,0,"Pause"],[3,1,"Esc"],[3,2,"Page Up"],[3,3,"`"],[3,4,"Page Down"],[3,5,"Tab"],[3,7,"Caps Lock"],[3,9,"Shift"],[3,10,"\u2192"],[3,11,"Ctrl"],[4,0,"F1"],[4,1,"F2"],[4,2,"1"],[4,3,"2"],[4,4,"Q"],[4,5,"W"],[4,6,"A"],[4,7,"S"],[4,8,"Z"],[4,9,"X"],[4,10,"GUI"],[4,11,"Alt"],[5,0,"F3"],[5,1,"F4"],[5,2,"3"],[5,3,"4"],[5,4,"E"],[5,5,"R"],[5,6,"D"],[5,7,"F"],[5,8,"C"],[5,9,"V"],[6,0,"F5"],[6,1,"F6"],[6,2,"5"],[6,3,"6"],[6,4,"T"],[6,5,"Y"],[6,6,"G"],[6,7,"H"],[6,8,"B"],[6,9,"N"],[6,11,"Space"],[7,0,"F7"],[7,1,"F8"],[7,2,"7"],[7,3,"8"],[7,4,"U"],[7,5,"I"],[7,6,"J"],[7,7,"K"],[7,8,"M"],[7,9,","],[8,0,"F9"],[8,1,"F10"],[8,2,"9"],[8,3,"0"],[8,4,"O"],[8,5,"P"],[8,6,"L"],[8,7,";"],[8,8,"."],[8,9,"/"],[8,10,"Alt"],[8,11,"GUI"],[9,0,"F11"],[9,1,"F12"],[9,2,"-"],[9,3,"="],[9,4,"["],[9,5,"]"],[9,6,"'"],[9,7,"Enter"],[9,8,"Shift"],[9,9,"Fn"],[9,10,"Menu"],[9,11,"Ctrl"],[10,0,"Backspace"],[10,2,"Backspace"],[10,4,"\\"]],"5845:5253":[],"5845:5396":[],"5845:5652":[],"5845:5653":[],"5845:5854":[[0,0,"F13"],[0,1,"F15"],[0,2,"F17"],[0,3,"F19"],[0,4,"F21"],[0,5,"F23"],[1,0,"F14"],[1,1,"F16"],[1,2,"F18"],[1,3,"F20"],[1,4,"F22"],[1,5,"F24"],[2,0,"Esc"],[2,1,"`"],[2,2,"Tab"],[2,3,"Caps Lock"],[2,4,"Shift"],[2,5,"Ctrl"],[3,1,"1"],[3,2,"Q"],[3,3,"A"],[3,4,"Z"],[3,5,"Alt"],[4,0,"F1"],[4,1,"2"],[4,2,"W"],[4,3,"S"],[4,4,"X"],[4,5,"Space"],[5,0,"F2"],[5,1,"3"],[5,2,"E"],[5,3,"D"],[5,4,"C"],[5,5,"Space"],[6,0,"F3"],[6,1,"4"],[6,2,"R"],[6,3,"F"],[6,4,"V"],[7,0,"F4"],[7,1,"5"],[7,2,"T"],[7,3,"G"],[7,4,"B"],[8,0,"F5"],[8,1,"6"],[8,2,"Y"],[8,3,"H"],[8,4,"N"],[9,0,"F6"],[9,1,"7"],[9,2,"U"],[9,3,"J"],[9,4,"M"],[10,0,"F7"],[10,1,"8"],[10,2,"I"],[10,3,"K"],[10,4,","],[11,0,"F8"],[11,1,"9"],[11,2,"O"],[11,3,"L"],[11,4,"."],[11,5,"Space"],[12,0,"F9"],[12,1,"0"],[12,2,"P"],[12,3,";"],[12,4,"/"],[12,5,"Alt"],[13,0,"F10"],[13,1,"-"],[13,2,"["],[13,3,"'"],[14,0,"F11"],[14,1,"="],[14,2,"]"],[14,3,"Enter"],[14,4,"Shift"],[15,0,"F12"],[15,1,"Backspace"],[15,2,"\\"],[15,3,"Backspace"],[15,4,"Fn"],[15,5,"Ctrl"],[16,0,"Print Screen"],[16,1,"Insert"],[16,2,"Delete"],[16,5,"\u2190"],[17,0,"Scroll Lock"],[17,1,"Home"],[17,2,"End"],[17,4,"\u2191"],[17,5,"\u2193"],[18,0,"Pause"],[18,1,"Page Up"],[18,2,"Page Down"],[18,5,"\u2192"]],"5845:5860":[],"5845:5861":[],"5845:A04B":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"5845:DAAA":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Alt"],[10,0,"="],[10,1,"P"],[10,2,";"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"0"],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Num Lock"],[14,1,"7"],[14,2,"4"],[14,3,"1"],[14,4,"\u2192"],[15,0,"/"],[15,1,"8"],[15,2,"5"],[15,3,"2"],[15,4,"0"],[16,0,"*"],[16,1,"9"],[16,2,"6"],[16,3,"3"],[16,4,"."],[17,0,"-"],[17,1,"+"],[17,2,"+"],[17,3,"Enter"]],"586A:0003":[],"586A:0040":[],"586A:0065":[],"586A:A001":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Left Shift"],[0,5,"Left Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"ISO \\"],[1,5,"Left GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Left Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Right Alt"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Right GUI"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,4,"Right Shift"],[12,5,"Menu"],[13,0,"F12"],[13,1,"\\"],[13,2,"\\"],[13,3,"ANSI Enter"],[14,1,"Delete"],[14,3,"ISO Enter"],[14,4,"\u2298"],[14,5,"Right Ctrl"],[15,0,"Print Screen"],[15,1,"Insert"],[15,2,"Delete"],[15,5,"\u2190"],[16,0,"Scroll Lock"],[16,1,"Home"],[16,2,"End"],[16,4,"\u2191"],[16,5,"\u2193"],[17,0,"Pause"],[17,1,"Page Up"],[17,2,"Page Down"],[17,5,"\u2192"]],"586A:A002":[],"586A:A003":[],"586A:B001":[],"5892:1233":[],"5918:0001":[],"5943:0005":[],"5945:0001":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[0,6,"-"],[0,7,"\u2298"],[0,8,"9"],[0,9,"+"],[0,10,"Enter"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[1,6,"*"],[1,7,"6"],[1,8,"8"],[1,9,"3"],[1,10,"."],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[2,6,"/"],[2,7,"Page Up"],[2,8,"7"],[2,9,"5"],[2,10,"\u2298"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[3,5,"\u2298"],[3,6,"Num Lock"],[3,7,"Home"],[3,8,"Page Down"],[3,9,"2"],[3,10,"0"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[4,5,"Space"],[4,6,"Pause"],[4,7,"Insert"],[4,8,"End"],[4,9,"1"],[4,10,"\u2192"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[5,5,"Alt"],[5,6,"Scroll Lock"],[5,7,"\u2298"],[5,8,"Delete"],[5,9,"4"],[5,10,"\u2193"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"GUI"],[6,6,"Print Screen"],[6,7,"Backspace"],[6,8,"\\"],[6,9,"\u2191"],[6,10,"\u2298"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Menu"],[7,6,"F12"],[7,7,"="],[7,8,"]"],[7,9,"Enter"],[7,10,"Shift"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[8,5,"Ctrl"],[8,6,"F11"],[8,7,"-"],[8,8,"["],[8,9,"'"],[8,10,"/"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"\u2190"],[9,6,"F10"],[9,7,"0"],[9,8,"P"],[9,9,";"],[9,10,"."]],"5945:6772":[[0,0,"Esc"],[0,2,"`"],[0,3,"Tab"],[0,4,"Caps Lock"],[0,5,"Shift"],[0,6,"Ctrl"],[1,2,"1"],[1,3,"Q"],[1,4,"A"],[1,5,"Shift"],[1,6,"GUI"],[2,0,"F1"],[2,1,"F7"],[2,2,"2"],[2,3,"W"],[2,4,"S"],[2,5,"Z"],[2,6,"Alt"],[3,0,"F2"],[3,1,"F8"],[3,2,"3"],[3,3,"E"],[3,4,"D"],[3,5,"X"],[4,0,"F3"],[4,1,"F9"],[4,2,"4"],[4,3,"R"],[4,4,"F"],[4,5,"C"],[4,6,"Space"],[5,0,"F4"],[5,1,"F10"],[5,2,"5"],[5,3,"T"],[5,4,"G"],[5,5,"V"],[5,6,"Space"],[6,0,"F5"],[6,1,"F11"],[6,2,"6"],[6,3,"Y"],[6,4,"H"],[6,5,"B"],[7,0,"F6"],[7,1,"F12"],[7,2,"7"],[7,3,"U"],[7,4,"J"],[7,5,"N"],[7,6,"Alt"],[8,0,"Insert"],[8,1,"Delete"],[8,2,"8"],[8,3,"I"],[8,4,"K"],[8,5,"M"],[8,6,"GUI"],[9,0,"Home"],[9,1,"End"],[9,2,"9"],[9,3,"O"],[9,4,"L"],[9,5,","],[9,6,"Menu"],[10,0,"Page Up"],[10,1,"Page Down"],[10,2,"0"],[10,3,"P"],[10,4,";"],[10,5,"."],[10,6,"Ctrl"],[11,0,"Print Screen"],[11,1,"Scroll Lock"],[11,2,"-"],[11,3,"["],[11,4,"'"],[11,5,"/"],[11,6,"\u2190"],[12,2,"="],[12,3,"]"],[12,4,"Shift"],[12,5,"Shift"],[12,6,"\u2193"],[13,0,"Pause"],[13,1,"Backspace"],[13,2,"Backspace"],[13,3,"\\"],[13,4,"Enter"],[13,5,"\u2191"],[13,6,"\u2192"],[14,0,"Num Lock"],[14,1,"7"],[14,2,"4"],[14,3,"1"],[14,4,"0"],[14,5,"Mouse 1"],[14,6,"Mouse 2"],[15,0,"/"],[15,1,"8"],[15,2,"5"],[15,3,"2"],[15,4,"0"],[15,5,"F13"],[15,6,"F16"],[16,0,"*"],[16,1,"9"],[16,2,"6"],[16,3,"3"],[16,4,"."],[16,5,"F14"],[16,6,"F17"],[17,0,"-"],[17,1,"+"],[17,2,"+"],[17,3,"Enter"],[17,4,"Enter"],[17,5,"F15"],[17,6,"F18"]],"5946:0001":[],"5946:0002":[],"5946:0003":[],"5946:0004":[],"5946:0005":[],"5946:0008":[],"5946:0009":[],"5946:0010":[],"5946:0011":[],"594D:0001":[],"594D:0075":[[0,0,"k00"],[0,1,"k10"],[0,2,"k20"],[0,3,"k30"],[0,4,"k40"],[1,0,"k01"],[1,1,"k11"],[1,2,"k21"],[1,3,"k31"],[1,4,"k41"],[2,0,"k02"],[2,1,"k12"],[2,2,"k22"],[2,3,"k32"],[2,4,"k42"],[3,0,"k03"],[3,1,"k13"],[3,2,"k23"],[3,3,"k33"],[3,4,"k43"],[4,0,"k04"],[4,1,"k14"],[4,2,"k24"],[4,3,"k34"],[4,4,"k44"],[5,0,"k05"],[5,1,"k15"],[5,2,"k25"],[5,3,"k35"],[5,4,"k45"],[6,0,"k06"],[6,1,"k16"],[6,2,"k26"],[6,3,"k36"],[6,4,"k46"],[7,0,"k07"],[7,1,"k17"],[7,2,"k27"],[7,3,"k37"],[7,4,"k47"],[8,0,"k08"],[8,1,"k18"],[8,2,"k28"],[8,3,"k38"],[8,4,"k48"],[9,0,"k09"],[9,1,"k19"],[9,2,"k29"],[9,3,"k39"],[9,4,"k49"],[10,0,"k0A"],[10,1,"k1A"],[10,2,"k2A"],[10,3,"k3A"],[10,4,"k4A"],[11,0,"k0B"],[11,1,"k1B"],[11,2,"k2B"],[11,3,"k3B"],[11,4,"k4B"],[12,0,"k0C"],[12,1,"k1C"],[12,2,"k2C"],[12,3,"k3C"],[12,4,"k4C"],[13,0,"k0D"],[13,1,"k1D"],[13,2,"k2D"],[13,3,"k3D"],[13,4,"k4D"],[14,0,"k0E"],[14,1,"k1E"],[14,2,"k2E"],[14,3,"k3E"],[14,4,"k4E"]],"594D:2975":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"GUI"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Space"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2192"],[14,0,"`"],[14,1,"Page Down"],[14,2,"Fn"],[14,4,"Page Up"]],"594D:4266":[],"594D:4440":[],"594D:4975":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"GUI"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Shift"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2192"],[14,1,"Page Down"],[14,2,"Fn"],[14,4,"Page Up"]],"594D:4D96":[],"594D:4D97":[],"594D:5021":[],"594D:5024":[],"594D:5364":[],"594D:604D":[],"594D:6060":[],"594D:7549":[],"594D:D896":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Alt"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Menu"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"\u2193"],[13,0,"`"],[13,1,"Enter"],[13,3,"\u2191"],[13,4,"\u2192"],[14,0,"Backspace"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"Fn"],[14,4,"Delete"]],"5950:8369":[],"5954:0001":[],"5954:0002":[],"5954:0003":[],"5961:1470":[],"5A12:5165":[],"5A45:0060":[],"5A45:0065":[],"5A4C:4953":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[15,0,"0,15"]],"5A56:0001":[],"5A56:0048":[],"5C06:4F0D":[],"5D66:22CF":[],"5E68:5F00":[],"6033:1D50":[[0,0,"K"],[0,1,"H"],[0,2,"X"],[0,4,"P"],[0,5,"D"],[0,6,"B"],[0,7,"L2"],[1,0,"U"],[1,1,"I"],[1,2,"Y"],[1,4,"C"],[1,5,"T"],[1,6,"G"],[1,7,"Sh"],[2,0,"Q"],[2,1,"E"],[2,2,"-"],[2,3,"Gui"],[2,4,"L"],[2,5,"R"],[2,6,"W"],[2,7,"L3"],[3,0,"."],[3,1,"A"],[3,2,","],[3,3,"Tab"],[3,4,"M"],[3,5,"N"],[3,6,"V"],[4,0,"J"],[4,1,"O"],[4,2,"/"],[4,3,"Spc"],[4,4,"F"],[4,5,"S"],[4,6,"Z"],[4,7,"Fx"]],"60BE:00BE":[],"6108:0001":[],"6108:0002":[],"614D:0001":[],"614D:1000":[],"6166:0001":[],"6166:0010":[],"6167:0001":[],"6168:7066":[],"6168:7068":[],"616C:0001":[],"616C:0002":[],"616C:0003":[],"616C:0004":[],"616C:0005":[],"616D:01A6":[],"6172:6060":[],"6178:0001":[[0,0,"K00 (F5,F4)"],[0,1,"K10 (F7,F4)"],[0,2,"K20 (B3,F4)"],[0,3,"K30 (B6,F4)"],[0,4,"K40 (B5,F4)"],[1,0,"K01 (F5,F6)"],[1,1,"K11 (F7,F6)"],[1,2,"K21 (B3,F6)"],[1,3,"K31 (B6,F6)"],[1,4,"K41 (B5,F6)"],[2,0,"K02 (F5,B1)"],[2,1,"K12 (F7,B1)"],[2,2,"K22 (B3,B1)"],[2,3,"K32 (B6,B1)"],[2,4,"K42 (B5,B1)"],[3,0,"K03 (F5,B2)"],[3,1,"K13 (F7,B2)"],[3,2,"K23 (B3,B2)"],[3,3,"K33 (B6,B2)"],[3,4,"K43 (B5,B2)"]],"6262:0001":[],"6265:0001":[],"626D:656B":[],"6274:720D":[],"6332:1020":[],"6332:3662":[],"6332:3663":[],"6369:6B7A":[],"6369:6B7E":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[0,5,"5,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[1,5,"5,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[2,5,"5,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[5,5,"5,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[10,5,"5,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,5,"5,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,5,"5,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[13,5,"5,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[14,5,"5,14"],[15,0,"0,15"],[15,1,"1,15"],[15,2,"2,15"],[15,3,"3,15"],[15,4,"4,15"],[15,5,"5,15"]],"6369:6B7F":[],"6369:6B84":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[14,0,"0,14"],[14,3,"3,14"],[14,4,"4,14"]],"6369:6B8B":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[0,5,"5,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[1,5,"5,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[2,5,"5,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[4,5,"5,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[6,5,"5,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[7,5,"5,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[8,5,"5,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[9,5,"5,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[10,5,"5,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[11,5,"5,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[12,5,"5,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[13,5,"5,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[14,5,"5,14"],[15,0,"0,15"],[15,1,"1,15"],[15,2,"2,15"],[15,3,"3,15"],[15,4,"4,15"],[15,5,"5,15"]],"6369:6B8E":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[14,0,"0,14"],[14,3,"3,14"]],"6369:6B90":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,4,"4,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,4,"4,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[15,0,"0,15"],[15,1,"1,15"],[15,2,"2,15"],[15,3,"3,15"],[15,4,"4,15"]],"6369:6B95":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"]],"6369:6B98":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[14,0,"0,14"],[14,3,"3,14"]],"6369:6B99":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"]],"6369:6BA4":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,4,"4,11"],[12,0,"0,12"],[12,1,"1,12"],[12,4,"4,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[15,0,"0,15"],[15,1,"1,15"],[15,2,"2,15"],[15,3,"3,15"],[15,4,"4,15"]],"6369:6BA6":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,4,"4,14"]],"6369:6BAA":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[12,0,"0,12"],[12,1,"1,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[14,0,"0,14"],[14,3,"3,14"]],"6369:6BB4":[],"6369:6BB5":[],"6369:6BB6":[],"6369:6BB8":[],"6369:6BB9":[],"6369:6BBE":[],"6369:6BBF":[],"6369:6BC0":[],"6369:6BC1":[],"6369:6BC2":[],"6369:6BC3":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[0,5,"5,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[1,5,"5,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[2,5,"5,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[4,5,"5,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[6,5,"5,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[7,5,"5,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[8,5,"5,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[9,5,"5,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[10,5,"5,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[11,5,"5,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[12,5,"5,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[13,5,"5,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[14,5,"5,14"],[15,0,"0,15"],[15,1,"1,15"],[15,2,"2,15"],[15,3,"3,15"],[15,4,"4,15"],[15,5,"5,15"]],"6369:6BC7":[],"6369:6BC8":[],"6369:6BC9":[],"6369:6BCA":[],"6369:6BCE":[],"6369:6BD1":[],"636A:0001":[],"636C:6374":[[0,0,"ESC K00 (B10,B12)"],[0,1,"TAB (B1,B12)"],[0,2,"CAPSLOCK (B0,B12)"],[0,3,"LSHIFT (A7,B12)"],[0,4,"LCTRL (A6,B12)"],[1,0,"1 K01 (B10,B14)"],[1,1,"Q (B1,B14)"],[1,2,"A (B0,B14)"],[1,3,"Z (A7,B14)"],[1,4,"WIN (A6,B14)"],[2,0,"2 K02 (B10,B15)"],[2,1,"W (B1,B15)"],[2,2,"S (B0,B15)"],[2,3,"X (A7,B15)"],[2,4,"ALT (A6,B15)"],[3,0,"3 K03 (B10,B5)"],[3,1,"E (B1,B5)"],[3,2,"D (B0,B5)"],[3,3,"C (A7,B5)"],[3,4,"SPACE (A6,B5)"],[4,0,"4 K04 (B10,B13)"],[4,1,"R (B1,B13)"],[4,2,"F (B0,B13)"],[4,3,"V (A7,B13)"],[5,0,"5 K05 (B10,B3)"],[5,1,"T (B1,B3)"],[5,2,"G (B0,B3)"],[5,3,"B (A7,B3)"],[6,0,"6 K06 (B10,B4)"],[6,1,"Y (B1,B4)"],[6,2,"H (B0,B4)"],[6,3,"N (A7,B4)"],[7,0,"7 K07 (B10,B5)"],[7,1,"U (B1,B5)"],[7,2,"J (B0,B5)"],[7,3,"M (A7,B5)"],[8,0,"8 K08 (B10,A1)"],[8,1,"I (B1,A1)"],[8,2,"K (B0,A1)"],[8,3,", (A7,A1)"],[9,0,"9 K09 (B10,A2)"],[9,1,"O (B1,A2)"],[9,2,"L (B0,A2)"],[9,3,". (A7,A2)"],[10,0,"0 K0A (B10,A0)"],[10,1,"P (B1,A0)"],[10,2,"; (B0,A0)"],[10,3,"/ (A7,A0)"],[10,4,"FN (A6,A0)"],[11,0,"- K0B (B10,A3)"],[11,1,"[ (B1,A3)"],[11,2,"' (B0,A3)"],[12,0,"= K0C (B10,A4)"],[12,1,"] (B1,A4)"],[12,3,"RSHIFT (A7,A4)"],[12,4,"LEFT (A6,A4)"],[13,0,"BACKSPACE K0D (B10,A5)"],[13,1,"\" (B1,A5)"],[13,2,"ENTER (B0,A5)"],[13,3,"UP (A7,A5)"],[13,4,"DOWN (A6,A5)"],[14,0,"INS (B10,B11)"],[14,1,"DEL (B1,B11)"],[14,2,"PGUP (B0,B11)"],[14,3,"PGDN (A7,B11)"],[14,4,"RIGHT (A6,B11)"]],"636F:0001":[],"636F:0002":[],"6400:2371":[],"6400:CC11":[],"6431:6060":[],"6463:0000":[],"6473:4C50":[],"6481:B4A2":[],"6532:0001":[],"6532:0017":[],"6532:0069":[[0,0,"K00 (C6,F4)"],[0,1,"K10 (D4,F4)"],[0,2,"K20 (D0,F4)"],[0,3,"K30 (D1,F4)"],[1,0,"K01 (C6,F5)"],[1,1,"K11 (D4,F5)"],[1,3,"K31 (D1,F5)"],[2,0,"K02 (C6,F6)"],[2,1,"K12 (D4,F6)"],[2,2,"K22 (D0,F6)"],[2,3,"K32 (D1,F6)"],[3,0,"K03 (C6,F7)"],[3,1,"K13 (D4,F7)"],[3,2,"K23 (D0,F7)"],[4,0,"K04 (C6,B1)"],[4,1,"K14 (D4,B1)"],[4,2,"K24 (D0,B1)"],[5,0,"K05 (C6,B3)"],[5,1,"K15 (D4,B3)"],[5,2,"K25 (D0,B3)"],[6,0,"K06 (C6,D7)"],[6,1,"K16 (D4,D7)"],[6,2,"K26 (D0,D7)"],[6,3,"K36 (D1,D7)"],[7,0,"K07 (C6,B2)"],[7,1,"K17 (D4,B2)"],[7,2,"K27 (D0,B2)"],[8,0,"K08 (C6,B6)"],[8,1,"K18 (D4,B6)"],[8,2,"K28 (D0,B6)"],[9,0,"K09 (C6,B5)"],[9,1,"K19 (D4,B5)"],[9,2,"K29 (D0,B5)"],[10,0,"K0A (C6,B4)"],[10,2,"K2A (D0,B4)"],[10,3,"K3A (D1,B4)"],[11,0,"K0B (C6,E6)"],[11,1,"K1B (D4,E6)"],[11,2,"K2B (D0,E6)"],[11,3,"K3B (D1,E6)"]],"6562:1337":[],"6562:1338":[[0,0,"Esc"],[0,2,"tild"],[0,3,"Tab"],[0,4,"Caps Lock"],[0,5,"Shift"],[0,6,"Ctrl"],[1,0,"F1"],[1,2,"1"],[1,5,"|"],[1,6,"Win"],[2,0,"F2"],[2,2,"2"],[2,3,"Q"],[2,4,"A"],[2,5,"Z"],[2,6,"Alt"],[3,0,"F3"],[3,2,"3"],[3,3,"W"],[3,4,"S"],[3,5,"X"],[4,0,"F4"],[4,2,"4"],[4,3,"E"],[4,4,"D"],[4,5,"C"],[5,2,"5"],[5,3,"R"],[5,4,"F"],[5,5,"V"],[6,0,"F5"],[6,2,"6"],[6,3,"T"],[6,4,"G"],[6,5,"B"],[6,6,"Space"],[7,0,"F6"],[7,2,"7"],[7,3,"Y"],[7,4,"H"],[7,5,"N"],[8,0,"F7"],[8,2,"8"],[8,3,"U"],[8,4,"J"],[8,5,"M"],[9,0,"F8"],[9,2,"9"],[9,3,"I"],[9,4,"K"],[9,5,"<"],[9,6,"AltGr"],[10,0,"F9"],[10,2,"0"],[10,3,"O"],[10,4,"L"],[10,5,">"],[10,6,"Win"],[11,0,"F10"],[11,2,"-"],[11,3,"P"],[11,4,";"],[11,5,"?"],[11,6,"Menu"],[12,0,"F11"],[12,2,"="],[12,3,"["],[12,4,"'"],[12,6,"Ctrl"],[13,0,"F12"],[13,3,"]"],[13,4,"#"],[13,5,"Shift"],[13,6,"left"],[14,2,"Backspace"],[14,3,"|"],[14,4,"Enter"],[14,5,"up"],[14,6,"down"],[15,0,"Insert"],[15,1,"Delete"],[15,2,"Num Lock"],[15,3,"7"],[15,4,"4"],[15,5,"1"],[15,6,"right"],[16,0,"Home"],[16,1,"End"],[16,2,"/"],[16,3,"8"],[16,4,"5"],[16,5,"2"],[16,6,"0"],[17,0,"PgUp"],[17,1,"PgDn"],[17,2,"*"],[17,3,"9"],[17,4,"6"],[17,5,"3"],[17,6,"."],[18,0,"PrtSc"],[18,1,"Scroll Lock"],[18,2,"Pause"],[18,3,"-"],[18,4,"+"],[18,5,"Enter"]],"6565:1000":[],"6565:6520":[],"6571:5343":[],"6582:001C":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"\u2298"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[12,4,"Alt"],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"GUI"],[14,0,"="],[14,1,"]"],[14,2,"Enter"],[14,3,"Shift"],[14,4,"Fn"],[15,0,"Backspace"],[15,1,"\\"],[15,2,"Delete"],[15,3,"Fn"],[15,4,"Ctrl"]],"6582:001D":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"Fn"],[14,0,"="],[14,1,"]"],[14,2,"Enter"],[14,3,"Shift"],[14,4,"\u2190"],[15,0,"Backspace"],[15,1,"\\"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Home"],[16,1,"Page Up"],[16,2,"Page Down"],[16,3,"End"],[16,4,"\u2192"]],"6582:001E":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[12,4,"Fn"],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"Fn"],[14,0,"="],[14,1,"]"],[14,2,"Enter"],[14,3,"Shift"],[14,4,"\u2190"],[15,0,"Backspace"],[15,1,"\\"],[15,2,"Backspace"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Home"],[16,1,"Page Up"],[16,2,"Page Down"],[16,3,"End"],[16,4,"\u2192"]],"6582:001F":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"Fn"],[13,4,"Ctrl"],[14,0,"Insert"],[14,1,"Delete"],[14,4,"\u2190"],[15,0,"Home"],[15,1,"End"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Page Up"],[16,1,"Page Down"],[16,4,"\u2192"]],"6582:0021":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\u2298"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"Fn"],[13,4,"Ctrl"]],"6582:0022":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\u2298"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"6582:0023":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\u2298"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"Menu"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Backspace"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"6582:0024":[],"6582:0025":[],"6582:002A":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"GUI"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\u2298"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"\\"],[13,1,"Backspace"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"6582:002B":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,3,"Fn"],[13,4,"Ctrl"]],"6582:002C":[],"6582:002D":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"6582:002E":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"6582:002F":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"Fn"],[13,4,"Ctrl"]],"6582:0030":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"GUI"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"6582:0031":[],"6582:0036":[],"6582:003A":[],"6582:0041":[],"6582:0045":[],"6582:008A":[],"6582:060A":[],"6582:060D":[[0,0,"`"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"3"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"1"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"="],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"0"],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Del"],[13,3,"Fn"],[13,4,"Ctrl"]],"6582:065A":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"6582:065B":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"GUI"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"6582:069A":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"Fn"],[14,0,"="],[14,1,"]"],[14,2,"Enter"],[14,3,"Shift"],[14,4,"\u2190"],[15,0,"Backspace"],[15,1,"\\"],[15,2,"Backspace"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Home"],[16,1,"Page Up"],[16,2,"Page Down"],[16,3,"End"],[16,4,"\u2192"]],"6582:075A":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"\u2190"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Backspace"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Delete"],[14,1,"Home"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"End"],[14,5,"\u2192"]],"6582:075B":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"Print Screen"],[13,1,"Backspace"],[13,2,"\\"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Pause"],[14,1,"Backspace"],[15,0,"Delete"],[15,1,"Home"],[15,2,"Page Up"],[15,3,"Page Down"],[15,4,"End"],[15,5,"\u2192"]],"6582:075C":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"\u2190"],[13,1,"Backspace"],[13,2,"\\"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Print Screen"],[14,1,"Backspace"],[15,1,"Delete"],[15,2,"Page Up"],[15,3,"Page Down"],[15,5,"\u2192"]],"6582:080A":[],"6582:60B0":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"\u2298"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Fn2"],[13,0,"\\"],[13,1,"Backspace"],[13,2,"Delete"],[13,3,"Fn"],[13,4,"\u2298"]],"6582:60B1":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Fn2"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"Fn"],[13,4,"Ctrl"]],"6582:60C0":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Fn2"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"Fn"],[13,4,"Ctrl"]],"6582:80B0":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"GUI"],[13,1,"Backspace"],[13,2,"\\"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"6583:6080":[],"6653:001A":[],"6653:0070":[],"6653:012A":[],"6653:063A":[],"6653:3365":[],"6653:3366":[],"6653:3370":[],"6653:3371":[],"6653:3380":[],"6662:3661":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"*"],[0,6,"I"],[0,7,"K"],[0,8,"M"],[0,9,"HENKAN"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Win"],[1,5,"("],[1,6,"O"],[1,7,"L"],[1,8,"<"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[2,5,")"],[2,6,"P"],[2,7,":"],[2,8,">"],[2,9,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"MUHENKAN"],[3,5,"_"],[3,6,"{"],[3,7,"\""],[3,8,"?"],[3,9,"Win"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,5,"+"],[4,6,"}"],[4,7,"ISOHASH"],[4,8,"JPBACKSLASH"],[4,9,"Menu"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"SPACE1"],[5,5,"YEN"],[5,6,"|"],[5,7,"Enter"],[5,8,"Shift"],[5,9,"Left"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[6,5,"Backspace"],[6,8,"Up"],[6,9,"Down"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,5,"Page Up"],[7,6,"Page Down"],[7,9,"Up"]],"6662:3D14":[],"6662:7370":[],"6662:7740":[[0,0,"Tab"],[0,1,"Caps Lock"],[0,2,"Shift"],[0,3,"Ctrl"],[1,1,"A"],[1,2,"Z"],[1,3,"GUI"],[2,0,"Q"],[2,1,"S"],[2,2,"X"],[3,0,"W"],[3,1,"D"],[3,2,"C"],[3,3,"Alt"],[4,0,"E"],[4,1,"F"],[4,2,"V"],[5,0,"R"],[5,1,"G"],[5,2,"B"],[5,3,"Space1"],[6,0,"T"],[6,2,"Esc"],[7,0,"Y"],[7,1,"H"],[7,2,"N"],[7,3,"Space2"],[8,0,"U"],[8,1,"J"],[8,2,"M"],[9,0,"I"],[9,1,"K"],[9,2,","],[9,3,"Alt"],[10,0,"O"],[10,1,"L"],[10,2,"."],[11,0,"P"],[11,1,";"],[11,2,"/"],[11,3,"Menu (Legacy)"],[12,0,"Backspace"],[12,1,"Enter"],[12,2,"Shift"],[12,3,"Ctrl"]],"6666:6666":[],"6666:6667":[],"6666:6668":[],"6666:6669":[],"6666:6670":[],"666B:626F":[],"666B:7273":[],"6680:0065":[],"6761:3332":[],"6761:3432":[],"6761:3433":[],"676D:0001":[],"676D:0004":[],"676F:3660":[],"6770:6501":[],"6776:5342":[],"6776:6135":[],"6777:2D28":[],"6777:2D33":[],"6863:0075":[],"6869:0001":[],"6873:6464":[],"6877:0001":[[0,0,"LENC"],[0,1,"M1"],[0,2,"M2"],[0,3,"M3"],[0,4,"M4"],[0,5,"M5"],[0,6,"F7"],[0,7,"7"],[0,8,"Y"],[0,9,"H"],[0,10,"N"],[1,0,"ESC"],[1,1,"GRAV"],[1,2,"Tab"],[1,3,"Caps"],[1,4,"Shift"],[1,5,"Ctrl"],[1,6,"F8"],[1,7,"8"],[1,8,"U"],[1,9,"J"],[1,10,"M"],[1,11,"Space"],[2,0,"F1"],[2,1,"1"],[2,4,"NUBS"],[2,5,"Gui"],[2,6,"F9"],[2,7,"9"],[2,8,"I"],[2,9,"K"],[2,10,","],[3,0,"F2"],[3,1,"2"],[3,2,"Q"],[3,3,"A"],[3,4,"Z"],[3,5,"Alt"],[3,6,"F10"],[3,7,"0"],[3,8,"O"],[3,9,"L"],[3,10,"."],[3,11,"Alt"],[4,0,"F3"],[4,1,"3"],[4,2,"W"],[4,3,"S"],[4,4,"X"],[4,5,"Space"],[4,6,"F11"],[4,7,"-"],[4,8,"P"],[4,9,";"],[4,10,"/"],[4,11,"Gui"],[5,0,"F4"],[5,1,"4"],[5,2,"E"],[5,3,"D"],[5,4,"C"],[5,6,"F12"],[5,7,"="],[5,8,"["],[5,9,"'"],[5,11,"Ctrl"],[6,0,"F5"],[6,1,"5"],[6,2,"R"],[6,3,"F"],[6,4,"V"],[6,6,"F13"],[6,7,"Back"],[6,8,"]"],[6,9,"NUHS"],[6,10,"Shift"],[6,11,"Left"],[7,0,"F6"],[7,1,"6"],[7,2,"T"],[7,3,"G"],[7,4,"B"],[7,5,"FN"],[7,7,"Del"],[7,8,"BSLS"],[7,9,"Enter"],[7,10,"Up"],[7,11,"Down"],[8,6,"RENC"],[8,7,"Home"],[8,8,"PgUp"],[8,9,"PgDn"],[8,10,"End"],[8,11,"Rght"]],"68F4:70A0":[],"694B:6952":[],"694E:5336":[],"694E:6060":[],"6961:3031":[],"6961:3032":[],"6961:3033":[],"6963:6963":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"Delete"],[13,1,"\\"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Ctrl"],[14,0,"Backspace"]],"6963:6964":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Play/Pause"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Delete"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Backspace"],[15,0,"Copy"],[15,1,"Paste"],[15,2,"Find"],[15,3,"Fn"],[15,4,"\u2192"]],"6963:6965":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Alt"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"GUI"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Space"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"Backspace"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[5,3,"Menu"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Fn"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[8,0,"I"],[8,1,"K"],[8,2,","],[9,0,"O"],[9,1,"L"],[9,2,"."],[10,0,"P"],[10,1,";"],[10,2,"/"],[11,0,"-"],[11,1,"Enter"],[11,2,"Shift"],[12,0,"Backspace"]],"6963:6966":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"GUI"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Ctrl"],[13,1,"Delete"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn"],[14,1,"Backspace"],[15,1,"Insert"],[15,2,"Delete"],[15,4,"Play/Pause"],[15,5,"\u2190"],[16,1,"Home"],[16,2,"End"],[16,4,"\u2191"],[16,5,"\u2193"],[17,1,"Page Up"],[17,2,"Page Down"],[17,5,"\u2192"]],"6963:6967":[],"6964:0042":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Shft"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Win"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Fn"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[8,0,"I"],[8,1,"K"],[8,2,"Shft"],[9,0,"O"],[9,1,"L"],[9,3,"\u21e6"],[10,0,"P"],[10,2,"\u21e7"],[10,3,"\u21e9"],[11,0,"BSpc"],[11,1,"Ent"],[11,2,"Del"],[11,3,"\u21e8"]],"6964:0061":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1!"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9("],[9,1,"O"],[9,2,"L"],[9,3,",<"],[10,0,"0)"],[10,1,"P"],[10,2,";:"],[10,3,".>"],[10,4,"Fn"],[11,0,"-_"],[11,1,"[{"],[11,2,"'\""],[11,3,"/?"],[11,4,"Alt"],[12,0,"=+"],[12,1,"]}"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"Backspace"],[13,1,"\\|"],[13,4,"Ctrl"]],"6964:0063":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1!"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[3,0,"3#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Alt"],[4,0,"4$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9("],[9,1,"O"],[9,2,"L"],[9,3,",<"],[9,4,"Fn"],[10,0,"0)"],[10,1,"P"],[10,2,";:"],[10,3,".>"],[10,4,"Menu"],[11,0,"-_"],[11,1,"[{"],[11,2,"'\""],[11,3,"Shift"],[11,4,"\u2190"],[12,0,"=+"],[12,1,"]}"],[12,3,"\u2191"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\|"],[13,2,"Enter"],[13,3,"/?"],[13,4,"\u2192"]],"6964:0075":[],"6964:0087":[],"6964:0096":[],"6964:0127":[],"6964:0227":[],"6964:0267":[],"6964:0287":[],"6964:0380":[],"6964:6060":[],"6967:0000":[],"6969:0001":[],"696B:0003":[],"6986:C583":[],"69CC:6BF6":[],"69F9:0005":[],"69F9:0006":[],"69F9:0009":[],"6A6A:000C":[],"6A6A:4414":[],"6A6A:4810":[],"6A6B:000B":[[0,3,"A"],[0,4,"Tab"],[0,5,"Q"],[0,6,"Esc"],[1,3,"S"],[1,4,"Z"],[1,5,"W"],[1,6,"Caps"],[2,3,"D"],[2,4,"X"],[2,5,"E"],[2,6,"Shift"],[3,3,"F"],[3,4,"C"],[3,5,"R"],[3,6,"Ctl"],[4,0,"4"],[4,1,"1"],[4,2,"0"],[4,3,"G"],[4,4,"V"],[4,5,"T"],[4,6,"Alt"],[5,0,"5"],[5,1,"2"],[5,2,"00"],[5,3,"Y"],[5,4,"H"],[5,5,"B"],[6,0,"6"],[6,1,"3"],[6,2,"."],[6,3,"U"],[6,4,"J"],[6,5,"N"],[7,0,"+"],[7,1,"Ent"],[7,2,"Ent"],[7,3,"I"],[7,4,"K"],[7,5,"M"],[8,0,"7"],[8,1,"/"],[8,2,"="],[8,3,"O"],[8,4,"L"],[8,5,"<"],[8,6,"Alt"],[9,0,"8"],[9,1,"*"],[9,2,"Back"],[9,3,"P"],[9,4,":"],[9,5,"Shift"],[9,6,"Ctl"],[10,0,"9"],[10,1,"-"],[10,2,"Num Lock"],[10,3,"Back"],[10,4,"Enter"],[10,5,"Del"]],"6A6C:0001":[],"6A6C:0002":[],"6A6C:0012":[[3,0,"Encoder"]],"6A6C:0021":[[1,0,"Encoder"]],"6A6E:0001":[],"6A70:0001":[],"6B0A:0002":[],"6B62:1769":[],"6B62:4069":[],"6B62:6869":[],"6B62:8769":[],"6B62:8989":[],"6B66:1013":[],"6B66:1014":[],"6B66:5341":[],"6B66:7575":[],"6B6B:0001":[],"6B6E:0000":[],"6B6E:0001":[],"6B70:6273":[[0,0,"1"],[0,1,"5"],[1,0,"2"],[1,1,"6"],[2,0,"3"],[2,1,"7"],[3,0,"4"],[3,1,"8"]],"6B77:0001":[],"6B7A:7563":[],"6BE3:A129":[[0,0,"F2"],[0,1,"F1"],[0,2,"F4"],[0,3,"F3"],[0,4,"F5"],[0,5,"F6"],[0,6,"F7"],[0,7,"F8"],[0,8,"F9"],[0,9,"F10"],[1,0,"1"],[1,1,"Esc"],[1,2,"Q"],[1,3,"Tab"],[1,4,"Caps Lock"],[1,5,"A"],[1,6,"Shift"],[1,7,"Z"],[1,8,"Ctrl"],[1,9,"GUI"],[2,0,"3"],[2,1,"2"],[2,2,"E"],[2,3,"W"],[2,4,"S"],[2,5,"D"],[2,6,"X"],[2,7,"C"],[2,8,"Alt"],[3,0,"5"],[3,1,"4"],[3,2,"T"],[3,3,"R"],[3,4,"F"],[3,5,"G"],[3,6,"V"],[3,7,"B"],[3,9,"Space"],[4,0,"7"],[4,1,"6"],[4,2,"U"],[4,3,"Y"],[4,4,"H"],[4,5,"J"],[4,6,"N"],[4,7,"M"],[5,0,"9"],[5,1,"8"],[5,2,"O"],[5,3,"I"],[5,4,"K"],[5,5,"L"],[5,6,","],[5,7,"."],[6,0,"-"],[6,1,"0"],[6,2,"["],[6,3,"P"],[6,4,";"],[6,5,"'"],[6,6,"/"],[6,7,"Shift"],[6,8,"Alt"],[6,9,"\u2190"],[7,0,"Backspace"],[7,1,"="],[7,2,"\\"],[7,3,"]"],[7,4,"Enter"],[7,6,"\u2191"],[7,8,"\u2193"],[8,0,"\u25bd"],[8,1,"Delete"],[8,2,"\u25bd"],[8,3,"End"],[8,4,"\u25bd"],[8,5,"Page Up"],[8,6,"\u25bd"],[8,7,"Page Down"],[8,8,"\u25bd"],[8,9,"\u2192"],[9,1,"\u25bd"],[9,3,"\u25bd"],[9,5,"\u25bd"],[9,7,"\u25bd"],[9,9,"\u25bd"]],"6C63:6C62":[],"6C63:6C69":[],"6C63:6C70":[],"6C63:6C71":[],"6C6E:7070":[],"6C75:0001":[],"6C7A:0002":[],"6D4B:7056":[],"6D62:6D62":[],"6D64:2323":[],"6D64:2809":[],"6D64:6470":[],"6D64:6D76":[],"6D65:6060":[],"6D66:0868":[],"6D66:087C":[],"6D66:087D":[],"6D6D:0001":[],"6D6D:5754":[],"6D73:AFFE":[],"6D77:1703":[[0,0,"Tab"],[0,1,"Fn"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"/"],[1,3,"Alt"],[1,4,"'"],[1,5,"GUI"],[1,6,"Z"],[2,0,"W"],[2,1,"S"],[2,2,"Ctrl"],[2,3,"Fn2"],[2,4,"Mute"],[2,5,"Backspace"],[2,6,"Shift"],[3,0,"E"],[3,1,"D"],[3,2,"X"],[3,3,"Alt"],[3,4,"P"],[3,5,"Enter"],[3,6,"."],[4,0,"R"],[4,1,"F"],[4,2,"C"],[4,3,"Space"],[4,4,"O"],[4,5,"L"],[4,6,","],[5,0,"T"],[5,1,"G"],[5,2,"V"],[5,3,"Space"],[5,4,"I"],[5,5,"K"],[5,6,"M"],[6,0,"Y"],[6,1,"H"],[6,2,"B"],[6,3,"Space"],[6,4,"U"],[6,5,"J"],[6,6,"N"]],"6D77:1705":[],"6D77:1707":[],"6D77:1709":[],"6D77:170B":[],"6D77:170C":[],"6D77:170E":[],"6D77:170F":[],"6D77:1710":[],"6D77:1711":[],"6D77:1712":[],"6D77:1713":[],"6D77:1714":[],"6D77:C456":[],"6DD4:7501":[],"6E61:6060":[],"6E61:6062":[],"6E61:6063":[],"6E61:6064":[],"6E61:636C":[],"6E64:4D36":[],"6E6B:444F":[[0,2,"Play/Pause"],[0,3,"Next Track"],[0,4,"Previous Track"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,3,"\\"],[2,4,"Alt"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"Z"],[3,4,"GUI"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"X"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"C"],[5,4,"Space"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"V"],[7,0,"6"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[7,4,"Space"],[8,0,"7"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[8,4,"Space"],[9,0,"8"],[9,1,"I"],[9,2,"K"],[9,3,"M"],[10,0,"9"],[10,1,"O"],[10,2,"L"],[10,3,","],[10,4,"GUI"],[11,0,"0"],[11,1,"P"],[11,2,";"],[11,3,"."],[11,4,"Alt"],[12,0,"-"],[12,1,"["],[12,2,"'"],[12,3,"/"],[12,4,"Menu"],[13,0,"="],[13,1,"]"],[13,2,"\\"],[13,3,"Shift"],[13,4,"Ctrl"],[14,0,"Backspace"],[14,1,"Backspace"],[14,2,"Enter"],[14,3,"\\"],[14,4,"Reset"]],"6E6C:0001":[],"6E6C:0010":[],"6E6C:0011":[],"6E6D:0001":[],"6E74:3060":[],"6E78:3630":[],"6E78:3830":[],"6E78:4C49":[],"6F52:0000":[],"6F6A:4C54":[],"6F6A:6475":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"Z"],[3,4,"GUI"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"X"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"C"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"V"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"B"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"N"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"M"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,","],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,"."],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"/"],[12,4,"Alt"],[13,0,"-"],[13,1,"["],[13,2,"'"],[14,0,"="],[14,1,"]"],[14,3,"Shift"],[14,4,"GUI"],[15,0,"Backspace"],[15,2,"Enter"],[16,0,"Delete"],[16,1,"\\"],[16,3,"Fn"],[16,4,"Ctrl"]],"6F75:0161":[],"6F75:5516":[],"6F75:5517":[],"6F75:5518":[],"6F75:5600":[],"6F75:5602":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps"],[0,3,"LShift"],[0,4,"LCtrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"LGui"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"LAlt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,5,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,5,"RAlt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,5,"RGui"],[11,0,"-"],[11,1,"["],[11,2,"'"],[12,0,"="],[12,1,"]"],[12,5,"FN"],[13,0,"BS"],[13,1,"|"],[13,2,"Enter"],[13,3,"RShift"],[13,5,"RCtrl"]],"6F75:5603":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps"],[0,3,"LShift"],[0,4,"LCtrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"LGui"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"LAlt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,5,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,5,"RAlt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,5,"RGui"],[11,0,"-"],[11,1,"["],[11,2,"'"],[12,0,"="],[12,1,"]"],[12,2,"|"],[12,3,"RShift"],[12,5,"Menu"],[13,0,"BS"],[13,1,"~"],[13,2,"Enter"],[13,3,"FN"],[13,5,"RCtrl"]],"6F75:5604":[[0,0,"Esc"],[0,1,"Tab"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"ISO<>"],[1,4,"LGui"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"LAlt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"LSpace"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"CSpace"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"RSpace"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"RAlt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"FN"],[12,0,"="],[12,1,"]"],[12,2,"ISO'"],[12,3,"RShift"],[12,4,"Mid1U"],[13,0,"BS"],[13,1,"|"],[13,2,"Enter"],[13,4,"Menu"],[14,0,"~"],[14,3,"FN"],[14,4,"RCtrl"],[15,2,"Caps"],[15,3,"LShift"],[15,4,"LCtrl"]],"6F75:5606":[],"6F75:5607":[[0,0,"z"],[1,0,"x"],[2,0,"esc"],[3,0,"c"],[4,0,"v"]],"6F75:5610":[[0,0,"00"],[0,1,"10"],[0,2,"20"],[0,3,"30"],[1,0,"01"],[1,1,"11"],[1,2,"21"],[1,3,"31"],[2,0,"02"],[2,1,"12"],[2,2,"22"],[2,3,"32"],[3,0,"03"],[3,1,"13"],[3,2,"23"],[3,3,"33"]],"6F75:5611":[[0,0,"enc"],[1,0,"1"],[2,0,"2"],[3,0,"3"],[4,0,"4"],[5,0,"5"],[6,0,"6"],[7,0,"7"],[8,0,"8"]],"6F75:6801":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"GUI"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Ctrl"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Left"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Down"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Right"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Del"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"PgUp"],[13,0,"Backspace"],[13,1,"`"],[13,2,"Return"],[13,3,"Up"],[13,4,"PgDn"],[14,0,"NumLock"],[14,1,"KP7"],[14,2,"KP4"],[14,3,"KP1"],[15,0,"KP/"],[15,1,"KP8"],[15,2,"KP5"],[15,3,"KP2"],[16,0,"KP*"],[16,1,"KP9"],[16,2,"KP6"],[16,3,"KP3"],[16,4,"KP0"],[17,0,"KP-"],[17,1,"KP+"],[17,2,"KP+"],[17,3,"Enter"],[17,4,"KP."]],"6F75:6873":[],"6F75:6874":[],"6F75:6900":[],"6F75:7267":[],"6F77:0002":[],"6F7A:6276":[],"7033:3568":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Caps Lock"],[0,5,"A"],[0,6,"Shift"],[0,8,"Ctrl"],[0,9,"GUI"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"Z"],[1,7,"X"],[1,9,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"C"],[2,7,"V"],[2,9,"Space"],[3,0,"6"],[3,1,"7"],[3,3,"Y"],[3,5,"H"],[3,6,"B"],[3,7,"B"],[3,9,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"U"],[4,3,"I"],[4,4,"J"],[4,5,"K"],[4,6,"N"],[4,7,"M"],[4,9,"Alt"],[5,0,"0"],[5,1,"-"],[5,2,"O"],[5,3,"P"],[5,4,"L"],[5,5,";"],[5,6,","],[5,7,"."],[5,9,"GUI"],[6,0,"="],[6,1,"Backspace"],[6,2,"["],[6,3,"]"],[6,4,"'"],[6,6,"/"],[6,7,"Shift"],[6,8,"Ctrl"],[6,9,"\u2190"],[7,0,"Delete"],[7,1,"Mute"],[7,2,"\\"],[7,3,"Page Up"],[7,4,"Enter"],[7,5,"Page Down"],[7,6,"\u2191"],[7,7,"End"],[7,8,"\u2193"],[7,9,"\u2192"]],"7033:4749":[],"706A:0001":[],"706A:0002":[],"706A:0003":[],"706B:0011":[],"706B:3634":[],"706B:4845":[],"706C:7901":[[0,0,"Delete"],[0,1,"Esc"],[0,2,"Page Up"],[0,3,"Tab"],[0,4,"Page Down"],[0,5,"Caps Lock"],[0,7,"Shift"],[0,8,"Ctrl"],[1,0,"1"],[1,1,"2"],[1,2,"Q"],[1,3,"W"],[1,4,"A"],[1,5,"S"],[1,6,"Z"],[1,7,"X"],[1,8,"Alt"],[2,0,"3"],[2,1,"4"],[2,2,"E"],[2,3,"R"],[2,4,"D"],[2,5,"F"],[2,6,"C"],[2,7,"V"],[2,8,"Space"],[3,0,"5"],[3,1,"6"],[3,2,"T"],[3,4,"G"],[3,6,"B"],[3,8,"Fn"],[4,0,"7"],[4,1,"8"],[4,2,"Y"],[4,3,"U"],[4,4,"H"],[4,5,"J"],[4,6,"B"],[4,7,"N"],[4,8,"Space"],[5,0,"9"],[5,1,"0"],[5,2,"I"],[5,3,"O"],[5,4,"K"],[5,5,"L"],[5,6,"M"],[5,7,","],[5,8,"Alt"],[6,0,"-"],[6,1,"="],[6,2,"P"],[6,3,"["],[6,4,";"],[6,5,"'"],[6,6,"."],[6,7,"/"],[7,0,"Backspace"],[7,1,"Backspace"],[7,2,"]"],[7,3,"\\"],[7,5,"Enter"],[7,6,"Shift"],[7,7,"Fn"],[7,8,"Ctrl"]],"706C:7902":[],"706C:7903":[],"706C:7904":[],"706C:7905":[],"706C:7915":[],"7070:1119":[],"7070:1416":[],"7070:1620":[],"7070:1849":[],"7070:2416":[],"7070:3215":[],"7070:3508":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Shift"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"TT(1)"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"Backspace"],[13,2,"Delete"]],"7070:5338":[],"7070:5339":[],"7070:5340":[],"7070:5342":[],"7070:5344":[],"7070:5354":[],"7070:7030":[],"7071:6331":[],"7072:6F64":[],"7074:0001":[],"7074:0002":[],"7074:0006":[],"7074:0010":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"`"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"7074:0014":[],"7074:0015":[[0,0,"F1"],[0,1,"F2"],[0,2,"F3"],[0,3,"F4"],[0,4,"F5"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,3,"Shift"],[2,4,"Alt"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"Z"],[3,4,"GUI"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"X"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"C"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"V"],[7,0,"6"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[7,4,"Space"],[8,0,"7"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[9,0,"8"],[9,1,"I"],[9,2,"K"],[9,3,"M"],[10,0,"9"],[10,1,"O"],[10,2,"L"],[10,3,","],[10,4,"Alt"],[11,0,"0"],[11,1,"P"],[11,2,";"],[11,3,"."],[11,4,"Fn"],[12,0,"-"],[12,1,"["],[12,2,"'"],[12,3,"/"],[13,0,"="],[13,1,"]"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"Backspace"],[14,1,"\\"],[14,2,"Delete"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"`"],[15,1,"Page Up"],[15,2,"Page Down"],[15,4,"\u2192"]],"7074:0017":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[4,5,"Space"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[8,5,"Space"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[9,5,"Alt"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"GUI"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,5,"Menu (Legacy)"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,4,"Shift"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,3,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"7074:0020":[],"7074:0024":[],"7074:0099":[],"7074:1001":[],"7074:1002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"Ctrl"]],"7074:1003":[],"7074:1004":[],"7074:1005":[],"7074:1007":[],"7074:1011":[],"7074:1012":[],"7074:1022":[],"7074:1023":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"Fn"],[13,4,"Ctrl"]],"7074:1823":[],"7074:9001":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u25bd"],[13,4,"Ctrl"]],"7076:0001":[],"7079:F10B":[],"7079:F10C":[],"70F5:4A01":[[0,0,"F1"],[0,1,"Esc"],[0,2,"1"],[0,3,"~"],[0,4,"Q"],[0,5,"Tab"],[0,6,"A"],[0,7,"Caps Lock"],[0,8,"Z"],[0,9,"Left Shift"],[0,10,"Left Win"],[0,11,"Left Ctrl"],[1,0,"F3"],[1,1,"F2"],[1,2,"3"],[1,3,"2"],[1,4,"E"],[1,5,"W"],[1,6,"D"],[1,7,"S"],[1,8,"C"],[1,9,"X"],[1,11,"Left Alt"],[2,0,"F5"],[2,1,"F4"],[2,2,"5"],[2,3,"4"],[2,4,"T"],[2,5,"R"],[2,6,"G"],[2,7,"F"],[2,8,"B"],[2,9,"V"],[2,10,"Space"],[3,0,"F7"],[3,1,"F6"],[3,2,"7"],[3,3,"6"],[3,4,"U"],[3,5,"Y"],[3,6,"J"],[3,7,"H"],[3,8,"M"],[3,9,"N"],[4,1,"F8"],[4,2,"9"],[4,3,"8"],[4,4,"O"],[4,5,"I"],[4,6,"L"],[4,7,"K"],[4,8,"."],[4,9,","],[4,10,"Right Alt"],[5,0,"F10"],[5,1,"F9"],[5,2,"-"],[5,3,"0"],[5,4,"["],[5,5,"P"],[5,6,"'"],[5,7,";"],[5,9,"/"],[5,10,"Right Ctrl"],[6,0,"F12"],[6,1,"F11"],[6,2,"|"],[6,3,"="],[6,5,"]"],[6,6,"Enter"],[6,9,"Right Shift"],[6,10,"Left"],[7,0,"Scroll Lock"],[7,1,"F13"],[7,2,"Page Up"],[7,3,"Delete"],[7,4,"Page Down"],[7,5,"Backspace"],[7,6,"Delete"],[7,9,"Up"],[7,10,"Right"],[7,11,"Down"],[8,0,"Insert"],[8,1,"Pause Break"],[8,2,"/"],[8,3,"Num Lock"],[8,4,"Num 8"],[8,5,"Num 7"],[8,6,"Num 5"],[8,7,"Num 4"],[8,8,"Num 2"],[8,9,"Num 1"],[8,10,"Num 0"],[9,0,"Print Screen"],[9,1,"Home"],[9,2,"-"],[9,3,"*"],[9,4,"Num Plus"],[9,5,"Num 9"],[9,7,"Num 6"],[9,8,"Enter"],[9,9,"Num 3"],[9,11,"Num Del"]],"716B:0001":[[0,0,"F1"],[0,1,"Esc"],[0,2,"1"],[0,3,"`"],[0,4,"Q"],[0,5,"Tab"],[0,6,"A"],[0,7,"Caps Lock"],[0,8,"Z"],[0,9,"Shift"],[0,10,"Alt"],[0,11,"Ctrl"],[1,0,"F3"],[1,1,"F2"],[1,2,"3"],[1,3,"2"],[1,4,"E"],[1,5,"W"],[1,6,"D"],[1,7,"S"],[1,8,"C"],[1,9,"X"],[2,0,"F5"],[2,1,"F4"],[2,2,"5"],[2,3,"4"],[2,4,"T"],[2,5,"R"],[2,6,"G"],[2,7,"F"],[2,8,"B"],[2,9,"V"],[2,10,"Fn"],[2,11,"Space"],[3,1,"F6"],[3,3,"6"],[3,5,"Y"],[3,7,"H"],[3,9,"B"],[4,0,"F7"],[4,1,"F8"],[4,2,"7"],[4,3,"8"],[4,4,"U"],[4,5,"I"],[4,6,"J"],[4,7,"K"],[4,8,"N"],[4,9,"M"],[4,10,"Space"],[5,0,"F9"],[5,1,"F10"],[5,2,"9"],[5,3,"0"],[5,4,"O"],[5,5,"P"],[5,6,"L"],[5,7,";"],[5,8,","],[5,9,"."],[5,10,"Alt"],[6,0,"F11"],[6,1,"F12"],[6,2,"-"],[6,3,"="],[6,4,"["],[6,5,"Backspace"],[6,6,"'"],[6,7,"]"],[6,8,"/"],[6,9,"Shift"],[6,11,"\u2190"],[7,0,"F13"],[7,1,"Delete"],[7,2,"`"],[7,3,"Home"],[7,4,"\\"],[7,5,"Page Up"],[7,6,"Enter"],[7,7,"Page Down"],[7,8,"\u2191"],[7,10,"\u2193"],[7,11,"\u2192"]],"7170:5359":[],"7170:656D":[],"7170:7373":[],"7170:7774":[],"7171:0002":[],"7171:0003":[],"7179:8475":[[0,0,"Esc"],[0,1,"Page Up"],[0,2,"Page Down"],[0,3,"End"],[1,0,"`~"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Control"],[2,0,"1!"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[2,4,"Alt"],[3,0,"2@"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[4,0,"3#"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[4,4,"Space"],[5,0,"4$"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[5,4,"Left GUI"],[6,0,"5%"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"^6"],[7,0,"7&"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[7,4,"Space"],[8,0,"8*"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[8,4,"Space"],[9,0,"9("],[9,1,"I"],[9,2,"K"],[9,3,"M"],[9,4,"Alt"],[10,0,"0)"],[10,1,"O"],[10,2,"L"],[10,3,",<"],[10,4,"Backspace"],[11,0,"-_"],[11,1,"P"],[11,2,";:"],[11,3,".>"],[11,4,"Enter"],[12,0,"=+"],[12,1,"[{"],[12,2,"\""],[12,3,"/?"],[12,4,"MO(1)"],[13,0,"\\|"],[13,1,"]}"],[13,2,"Del"],[13,3,"Shift"],[13,4,"Control"]],"722D:0001":[],"722E:0001":[],"7262:0001":[],"7262:0018":[],"7262:0069":[],"7262:0086":[],"7262:0087":[],"726B:645C":[],"726B:726B":[],"726B:7363":[[0,0,"L00"],[0,1,"L10"],[0,2,"L20"],[0,3,"L30"],[0,4,"R00"],[0,5,"R10"],[0,6,"R20"],[0,7,"R30"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,3,"L31"],[1,4,"R01"],[1,5,"R11"],[1,6,"R21"],[1,7,"R31"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"R02"],[2,5,"R12"],[2,6,"R22"],[2,7,"R32"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,4,"R03"],[3,5,"R13"],[3,6,"R23"],[3,7,"R33"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,4,"R04"],[4,5,"R14"],[4,6,"R24"],[4,7,"R34"],[5,2,"L25"],[5,6,"R25"]],"726B:7973":[],"726E:736B":[],"726E:7661":[],"726F:0001":[],"726F:0002":[],"7272:0C2C":[],"7272:F03B":[],"7273:0064":[],"7274:0001":[],"732D:0C70":[],"7331:4200":[],"7335:0200":[],"7353:0160":[],"7362:0002":[],"7363:1213":[],"7363:1214":[],"7363:1215":[],"7364:2E8F":[],"736B:7575":[[0,0,"K05"],[0,1,"K04"],[0,2,"K03"],[0,3,"K02"],[0,4,"K01"],[0,5,"K00"],[1,0,"K25"],[1,1,"K14"],[1,2,"K13"],[1,3,"K12"],[1,4,"K01"],[1,5,"K00"],[2,0,"K35"],[2,1,"K24"],[2,2,"K23"],[2,3,"K22"],[2,4,"K11"],[2,5,"K20"],[3,0,"K45"],[3,1,"K34"],[3,2,"K33"],[3,3,"K32"],[3,4,"K21"],[3,5,"K56"],[4,0,"K55"],[4,1,"K44"],[4,2,"K43"],[4,3,"K42"],[4,4,"K31"],[4,5,"K56"],[5,0,"K06"],[5,1,"K54"],[5,2,"K53"],[5,3,"K52"],[5,4,"K41"],[5,5,"K20"],[6,0,"KA6"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K51"],[7,0,"KA7"],[7,1,"KB6"],[7,2,"KC6"],[7,3,"KD6"],[7,4,"K46"],[7,5,"K56"],[8,0,"K07"],[8,1,"KB7"],[8,2,"KC7"],[8,3,"KD7"],[8,4,"KE6"],[8,5,"K56"],[9,0,"KB5"],[9,1,"K17"],[9,2,"K27"],[9,3,"K37"],[9,4,"KE7"],[9,5,"K57"],[10,0,"KC5"],[10,1,"KA4"],[10,2,"KA3"],[10,3,"KA2"],[10,4,"K47"],[10,5,"K57"],[11,0,"KD5"],[11,1,"KB4"],[11,2,"KB3"],[11,3,"KB2"],[11,4,"KA1"],[11,5,"K57"],[12,0,"KE5"],[12,1,"KC4"],[12,2,"KC3"],[12,3,"KD2"],[12,4,"KB1"],[12,5,"K66"],[13,0,"KD1"],[13,1,"KE4"],[13,2,"KD3"],[13,3,"KD2"],[13,4,"K86"],[13,5,"K76"],[13,6,"KE2"],[14,0,"KE1"],[14,1,"KE4"],[14,2,"K67"],[14,3,"KE0"],[14,4,"K77"],[14,5,"K96"],[14,6,"KD0"]],"736C:6E70":[],"736D:000A":[],"7372:6F64":[],"7373:0001":[],"7373:0002":[],"7374:9770":[],"73CA:6F64":[[0,0,"ESC"],[0,1,"TAB"],[0,2,"CAPS"],[0,3,"LSFT"],[0,4,"RCTL"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"LGUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"LALT"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"SPC"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"MUTE"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"ENT"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"RALT"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[7,4,"MO(1)"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"COMM"],[8,4,"RCTL"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"DOT"],[9,4,"LEFT"],[10,0,"0"],[10,1,"P"],[10,2,"SCLN"],[10,3,"SLSH"],[10,4,"DOWN"],[11,0,"MINS"],[11,1,"LBRC"],[11,2,"QLOT"],[11,3,"RSFT"],[11,4,"RGHT"],[12,0,"EQL"],[12,1,"RBRC"],[12,2,"GRV"],[12,3,"INS"],[13,0,"BSPC"],[13,1,"BSLS"],[13,2,"DEL"],[13,3,"UP"],[14,2,"PGUP"],[14,3,"PGDN"]],"7431:0001":[],"7431:3301":[],"7431:3302":[],"7431:6164":[],"7431:6262":[],"7431:6C78":[],"7431:D645":[],"7432:0658":[],"7463:0006":[],"7463:0012":[],"7463:0013":[],"7463:0014":[],"7463:0015":[],"7463:0018":[],"7463:0019":[],"7463:0021":[],"7463:0023":[],"7463:0025":[],"7463:0029":[],"7463:0037":[],"7463:0044":[],"7463:0045":[],"7463:0049":[],"7463:0054":[],"7463:0056":[],"7463:0062":[],"7463:0063":[],"7463:0065":[],"7463:0066":[],"7463:1001":[],"7463:1002":[],"746B:736B":[],"7470:0001":[],"7470:0004":[],"7474:6270":[],"7516:2434":[],"7516:5005":[],"7516:5104":[],"7516:6001":[],"7516:6002":[],"7516:6060":[],"7516:7000":[],"7516:7001":[],"75FA:0088":[],"7654:4321":[[0,0,"ESC"],[0,1,"GRV"],[0,2,"TAB"],[0,3,"CAPS"],[0,4,"LSFT"],[0,5,"LCTL"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"LGUI"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"LALT"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"SPC"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"COMM"],[9,5,"RALT"],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,"SCLN"],[10,4,"DOT"],[10,5,"MO(1)"],[11,0,"F10"],[11,1,"MINS"],[11,2,"LBRC"],[11,3,"QUOT"],[11,4,"SLSH"],[11,5,"RCTL"],[12,0,"F11"],[12,1,"EQL"],[12,2,"RBRC"],[12,4,"RSFT"],[12,5,"LEFT"],[13,0,"F12"],[13,1,"BSPC"],[13,2,"BSLS"],[13,3,"ENT"],[13,4,"UP"],[13,5,"DOWN"],[14,1,"HOME"],[14,2,"DEL"],[14,3,"PGUP"],[14,4,"PGDN"],[14,5,"RGHT"],[15,0,"END"]],"7667:0001":[],"7667:0002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"`"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"7667:0003":[],"7667:0004":[],"7667:0005":[],"7667:0006":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Delete"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"`"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"7667:0007":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Left Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Left Shift"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,"<"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,">"],[10,5,"Win"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"SQ"],[11,4,"?"],[11,5,"Menu"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[12,4,"Right Shift"],[13,0,"F13"],[13,1,"Back Space"],[13,2,"|"],[13,3,"Enter"],[13,4,"Right Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Insert"],[14,2,"Delete"],[14,3,"Back Space"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"\u2192"]],"7667:0008":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Left Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Win"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"SQ"],[11,5,"Menu"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[12,3,"Back Space"],[12,4,"Right Shift"],[13,0,"F13"],[13,1,"Back Space"],[13,2,"|"],[13,3,"Enter"],[13,4,"Right Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"\u2192"]],"7668:B075":[],"7764:4C53":[],"7764:4C64":[],"7764:5447":[],"7764:676D":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Ctrl"],[14,0,"Backspace"]],"7764:7064":[],"7764:7068":[],"7764:706D":[],"7767:0000":[],"7767:481C":[],"7767:7E94":[],"7767:8C78":[],"7774:0001":[[0,0,"Esc"],[0,1,"`"],[0,2,"TAB"],[0,3,"CAPS"],[0,4,"SHIFT"],[0,5,"CTRL"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"NUBS"],[1,5,"SUPER"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"ALT"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[4,5,"SPACE"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"SPACE"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[8,5,"SPACE"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"ALT"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"FUNC"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"ENTER"],[12,4,"SHIFT"],[12,5,"LEFT"],[13,0,"PRSC"],[13,2,"\""],[13,3,"DIAL"],[13,4,"UP"],[13,5,"DOWN"],[14,0,"BKSP"],[14,1,"HOME"],[14,2,"PG UP"],[14,3,"PG DN"],[14,5,"RIGHT"]],"7786:0101":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"NUBS"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Alt"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"Alt"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Win"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Menu"],[12,0,"+"],[12,1,"}"],[12,2,"NUHS"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"|"],[13,1,"|"],[13,2,"Backspace"],[13,3,"Enter"],[13,4,"Fn"]],"7786:0102":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Alt"],[12,0,"+"],[12,1,"}"],[12,2,"|"],[12,3,"Shift"],[12,4,"Win"],[13,0,"|"],[13,1,"~"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Ctrl"]],"77C8:0001":[],"7807:DCCB":[],"7844:0202":[],"7844:0404":[[0,0,"L"],[1,0,"O"],[2,0,"V"],[3,0,"E"]],"7844:6868":[],"7844:7575":[],"7844:8450":[],"7844:8484":[],"7844:8787":[],"7844:9696":[],"7856:6163":[],"7856:6169":[],"7865:0E75":[],"7877:0001":[],"7877:0002":[],"7877:0003":[],"7877:0004":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Super"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"Meta"],[10,0,"0"],[10,1,"P"],[10,2,":"],[10,3,"/"],[10,4,"Win"],[11,0,"_"],[11,1,"{"],[11,2,"'"],[11,3,"Shift"],[11,4,"Ctrl"],[12,0,"+"],[12,1,"}"],[12,2,"Enter"],[12,3,"Up"],[12,4,"Left"],[13,0,"Backspace"],[13,1,"|"],[13,4,"Down"],[14,0,"Del"],[14,1,"Ins"],[14,2,"Pgup"],[14,3,"Pgdn"],[14,4,"Right"]],"7877:1000":[],"7934:6D54":[],"7979:6602":[],"7983:0512":[],"7983:3357":[[0,0,"L00"],[0,1,"L10"],[0,2,"L20"],[0,4,"R00"],[0,5,"R10"],[0,6,"R20"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,4,"R01"],[1,5,"R11"],[1,6,"R21"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"R02"],[2,5,"R12"],[2,6,"R22"],[2,7,"R32"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,4,"R03"],[3,5,"R13"],[3,6,"R23"],[3,7,"R33"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,4,"R04"],[4,5,"R14"],[4,6,"R24"],[4,7,"R34"]],"7983:4B69":[[0,0,"L00"],[0,1,"L10"],[0,2,"L20"],[0,3,"L30"],[0,4,"L41"],[0,6,"R05"],[0,7,"R15"],[0,8,"R25"],[0,9,"R35"],[0,10,"R45"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,3,"L31"],[1,4,"L42"],[1,6,"R04"],[1,7,"R14"],[1,8,"R24"],[1,9,"R34"],[1,10,"R44"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"L43"],[2,6,"R03"],[2,7,"R13"],[2,8,"R23"],[2,9,"R33"],[2,10,"R43"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,4,"L44"],[3,6,"R02"],[3,7,"R12"],[3,8,"R22"],[3,9,"R32"],[3,10,"R42"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,4,"L45"],[4,6,"R01"],[4,7,"R11"],[4,8,"R21"],[4,9,"R31"],[4,10,"R41"],[5,0,"L05"],[5,1,"L15"],[5,2,"L25"],[5,3,"L35"],[5,4,"L40"],[5,5,"L50"],[5,6,"R00"],[5,7,"R10"],[5,8,"R20"],[5,9,"R30"],[5,10,"R40"],[5,11,"R50"]],"7983:4C4C":[],"7983:5050":[],"7A71:736B":[],"7A74:0001":[],"7A74:0002":[],"7A79:0087":[],"7A79:4261":[],"7A79:4648":[],"7A79:5050":[],"7A79:5388":[],"7A79:5450":[],"7BA1:3201":[],"7BA1:6500":[],"7BA1:6502":[],"7BA1:6505":[],"7BA1:6601":[],"7BA1:7501":[],"7BA1:7502":[],"7BA1:8001":[],"7C10:0165":[],"7C10:0701":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Menu (Legacy)"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Fn"]],"7C10:0F84":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Caps Lock"],[0,5,"A"],[0,6,"Shift"],[0,7,"Z"],[0,8,"Ctrl"],[0,9,"Win"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"X"],[1,7,"C"],[1,8,"Alt"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"V"],[2,7,"B"],[3,0,"6"],[3,1,"7"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"N"],[3,7,"M"],[3,8,"Space"],[4,0,"8"],[4,1,"9"],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,"<"],[4,7,">"],[4,8,"Alt"],[5,0,"0"],[5,1,"_"],[5,2,"P"],[5,3,"{"],[5,4,":"],[5,5,"\""],[5,6,"?"],[5,7,"Shift"],[5,8,"Ctrl"],[6,0,"+"],[6,1,"|"],[6,2,"}"],[6,3,"Backspace"],[6,4,"Enter"],[6,6,"\u2191"],[6,8,"\u2190"],[6,9,"\u2193"],[7,0,"~"],[7,1,"Num Lock"],[7,2,"7"],[7,3,"8"],[7,4,"4"],[7,5,"5"],[7,6,"1"],[7,7,"2"],[7,8,"\u2192"],[7,9,"0"],[8,0,"/"],[8,1,"*"],[8,2,"9"],[8,3,"-"],[8,4,"6"],[8,5,"+"],[8,6,"3"],[8,7,"Enter"],[8,8,"."]],"7C10:6001":[],"7C10:6002":[],"7C10:7501":[],"7C10:8704":[],"7C10:8801":[],"7C10:8802":[],"7C10:8803":[],"7C88:7C96":[],"7C88:7C97":[],"7C88:7C98":[],"7C88:7C99":[],"7E7E:FCD4":[],"800C:239A":[[0,0,"ESC"],[0,1,"1"],[0,2,"Q"],[0,3,"A"],[0,4,"Z"],[0,5,"Up"],[0,6,"Right"],[1,0,"TAB"],[1,1,"2"],[1,2,"W"],[1,3,"S"],[1,4,"X"],[1,5,"Left"],[1,6,"Down"],[2,0,"Control"],[2,1,"3"],[2,2,"E"],[2,3,"D"],[2,4,"C"],[2,5,"0"],[2,6,"-"],[3,1,"4"],[3,2,"R"],[3,3,"F"],[3,4,"V"],[3,5,"Space"],[3,6,"Slash"],[3,7,"Capslock"],[4,0,"LShift"],[4,1,"5"],[4,2,"T"],[4,3,"G"],[4,4,"B"],[4,5,"Period"],[4,6,"Semicolon"],[5,0,"Return"],[5,1,"6"],[5,2,"Y"],[5,3,"H"],[5,4,"N"],[5,5,"P"],[5,6,"Backslash"],[6,0,"Quote"],[6,1,"7"],[6,2,"U"],[6,3,"J"],[6,4,"M"],[6,5,"O"],[6,6,"L"],[7,0,"["],[7,1,"8"],[7,2,"I"],[7,3,"K"],[7,4,"Comma"],[7,5,"9"],[7,6,"="]],"806B:0004":[],"806C:0005":[],"806D:0006":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift1"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Shift2"],[1,5,"Win"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[5,5,"Space"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift1"],[12,5,"\u2190"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Backspace1"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Encoder"],[14,1,"Delect"],[14,2,"PageUp"],[14,3,"PageDown"],[14,5,"\u2192"]],"807C:0005":[],"8086:5353":[],"8086:5656":[[0,0,"Esc"],[0,1,"ENC1"],[0,2,"Delete"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"ENC2"],[1,2,"Caps Lock"],[1,3,"/"],[1,4,"Alt"],[2,0,"2"],[2,1,"Tab"],[2,2,"A"],[2,3,"Z"],[2,4,"Cmd"],[3,0,"3"],[3,1,"Q"],[3,2,"S"],[3,3,"X"],[4,0,"4"],[4,1,"W"],[4,2,"D"],[4,3,"C"],[4,4,"Space"],[5,0,"5"],[5,1,"E"],[5,2,"F"],[5,3,"V"],[6,0,"6"],[6,1,"R"],[6,2,"G"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"T"],[7,2,"H"],[7,3,"N"],[8,0,"8"],[8,1,"Y"],[8,2,"J"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"U"],[9,2,"K"],[9,3,"<"],[10,0,"0"],[10,1,"I"],[10,2,"L"],[10,3,">"],[10,4,"Cmd"],[11,0,"-"],[11,1,"O"],[11,2,";"],[11,3,"?"],[11,4,"Alt"],[12,0,"="],[12,1,"P"],[12,2,"\""],[12,3,"Shift"],[12,4,"Left"],[13,0,"Backspace"],[13,1,"{"],[13,2,"\""],[13,3,"Up"],[13,4,"Down"],[14,0,"Backspace"],[14,1,"}"],[14,2,"Enter"],[14,3,"PgDn"],[14,4,"Right"],[15,0,"Home"],[15,1,"|"],[15,2,"PgUp"]],"8101:4660":[],"8101:5365":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Menu"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"\u2190"],[14,0,"Insert"],[14,1,"Delete"],[14,2,"Page Down"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Home"],[15,1,"End"],[15,2,"Page Up"],[15,4,"\u2192"]],"8101:6080":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"\u2191"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"\u2190"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"`"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Fn"],[12,4,"Menu"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"Ctrl"]],"8101:6581":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"F1"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"F2"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Alt"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"F3"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"F4"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"`"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2192"]],"8181:0001":[],"8354:8370":[],"8367:7783":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Shift"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[3,5,"Alt"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,","],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,"."],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"/"],[10,5,"Fn"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"Shift"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Backspace"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"8372:0651":[],"8384:1180":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"GUI"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Ctrl"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn"],[14,0,"Pause"],[14,1,"Backspace"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Insert"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Print Screen"],[16,1,"Home"],[16,2,"Page Down"],[16,3,"Page Up"],[16,5,"\u2192"]],"8384:1181":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"GUI"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"Ctrl"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn"],[14,0,"Print Screen"],[14,3,"Backspace"],[14,5,"\u2190"],[14,6,"Insert"],[14,7,"Delete"],[15,0,"Scroll Lock"],[15,6,"Home"],[15,7,"End"],[16,0,"Pause"],[16,5,"\u2192"],[16,6,"Page Up"],[16,7,"Page Down"],[17,4,"\u2191"],[17,5,"\u2193"]],"8384:1182":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"GUI"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,4,"Shift"],[12,5,"Ctrl"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Fn"],[14,0,"Print Screen"],[14,3,"Backspace"],[14,5,"\u2190"],[14,6,"Insert"],[14,7,"Delete"],[15,0,"Scroll Lock"],[15,6,"Home"],[15,7,"End"],[16,0,"Pause"],[16,5,"\u2192"],[16,6,"Page Up"],[16,7,"Page Down"],[17,4,"\u2191"],[17,5,"\u2193"]],"8384:1648":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"Win"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,"0"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Alt"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Bspc"],[13,1,"|"],[13,2,"Enter"],[13,3,"MO(1)"],[13,4,"Bspc"]],"8384:1652":[],"8384:1653":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"Alt"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Win"],[11,0,"_"],[11,1,"]"],[11,2,"\""],[11,3,"?"],[11,4,"Menu"],[12,0,"+"],[12,1,"["],[12,2,"~"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Bspc"],[13,1,"|"],[13,2,"Enter"],[13,3,"MO(1)"],[13,4,"Bspc"]],"8384:1676":[],"8476:0075":[],"8484:6049":[],"8490:2801":[],"8490:3C01":[],"8490:3C02":[],"8490:4101":[],"8490:4102":[],"8673:0877":[[0,0,"Mute"],[0,1,"-"],[0,2,"+"],[0,3,"Enter"],[0,4,"Enter"],[1,0,"/"],[1,1,"7"],[1,2,"4"],[1,3,"1"],[1,4,"0"],[2,0,"*"],[2,1,"8"],[2,2,"5"],[2,3,"2"],[2,4,"0"],[3,0,"Backspace"],[3,1,"9"],[3,2,"6"],[3,3,"3"],[3,4,"."],[4,0,"Esc"],[4,1,"Tab"],[4,2,"Caps Lock"],[4,3,"Shift"],[4,4,"Ctrl"],[5,0,"1"],[5,1,"Q"],[5,2,"A"],[5,3,"\\"],[6,0,"2"],[6,1,"W"],[6,2,"S"],[6,3,"Z"],[6,4,"GUI"],[7,0,"3"],[7,1,"E"],[7,2,"D"],[7,3,"X"],[7,4,"Alt"],[8,0,"4"],[8,1,"R"],[8,2,"F"],[8,3,"C"],[9,0,"5"],[9,1,"T"],[9,2,"G"],[9,3,"V"],[10,0,"6"],[10,1,"Y"],[10,2,"H"],[10,3,"B"],[10,5,"Space"],[11,0,"7"],[11,1,"U"],[11,2,"J"],[11,3,"N"],[12,0,"8"],[12,1,"I"],[12,2,"K"],[12,3,"M"],[12,5,"TG(1)"],[13,0,"9"],[13,1,"O"],[13,2,"L"],[13,3,","],[13,5,"Fn2"],[14,0,"0"],[14,1,"P"],[14,2,";"],[14,3,"."],[14,5,"\u2190"],[15,0,"-"],[15,1,"["],[15,2,"'"],[15,3,"Shift"],[15,5,"\u2193"],[16,0,"="],[16,1,"]"],[16,2,"Enter"],[16,3,"\u2191"],[16,5,"\u2192"],[17,0,"Backspace"],[17,1,"\\"],[17,2,"Backspace"],[17,3,"#"],[17,5,"Fn2"]],"8686:0001":[[0,1,"8*"],[0,2,"Tab"],[0,3,"I"],[0,4,"Caps Lock"],[0,5,"K"],[0,6,"Shift"],[0,7,",<"],[0,8,"Ctrl"],[1,0,"ESC"],[1,2,"Q"],[1,3,"O"],[1,4,"A"],[1,5,"L"],[1,6,"Z"],[1,7,".>"],[1,8,"Win"],[2,0,"1!"],[2,1,"9("],[2,3,"P"],[2,4,"S"],[2,5,";:"],[2,6,"X"],[2,7,"/?"],[2,8,"Alt"],[3,0,"2@"],[3,1,"0)"],[3,2,"W"],[3,4,"D"],[3,5,"'\""],[3,6,"C"],[3,7,"Shift"],[3,8,"Space"],[4,0,"3#"],[4,1,"-_"],[4,2,"E"],[4,3,"[{"],[4,5,"Enter"],[4,6,"V"],[4,7,"Up"],[4,8,"MO(2)"],[5,0,"4$"],[5,1,"=+"],[5,2,"R"],[5,3,"]}"],[5,4,"F"],[5,6,"B"],[5,7,"Right"],[5,8,"MO(1)"],[6,0,"5%"],[6,1,"Backspace"],[6,2,"T"],[6,3,"\\|"],[6,4,"G"],[6,8,"Left"],[7,0,"6^"],[7,2,"Y"],[7,4,"H"],[7,6,"N"],[7,8,"Down"],[8,0,"7&"],[8,2,"U"],[8,4,"J"],[8,6,"M"]],"8767:5F89":[],"88B2:88B2":[],"8968:0001":[],"8968:1010":[],"8968:1011":[],"8968:1012":[],"8968:1013":[],"8968:3138":[[0,0,"Num Lock"],[0,1,"7"],[0,2,"4"],[0,3,"1"],[0,4,"0"],[1,0,"/"],[1,1,"8"],[1,2,"5"],[1,3,"2"],[1,4,"0"],[2,0,"*"],[2,1,"9"],[2,2,"6"],[2,3,"3"],[2,4,"."],[3,0,"-"],[3,1,"+"],[3,2,"Enter"],[3,3,"\u2191"],[3,4,"\u2190"],[4,0,"Esc"],[4,1,"Tab"],[4,2,"Ctrl"],[4,3,"Shift"],[4,4,"\u2193"],[5,0,"1"],[5,1,"Q"],[5,2,"A"],[5,3,"Z"],[5,4,"\u2192"],[6,0,"2"],[6,1,"W"],[6,2,"S"],[6,3,"X"],[6,4,"GUI"],[7,0,"3"],[7,1,"E"],[7,2,"D"],[7,3,"C"],[7,4,"Alt"],[8,0,"4"],[8,1,"R"],[8,2,"F"],[8,3,"V"],[8,4,"Enter"],[9,0,"5"],[9,1,"T"],[9,2,"G"],[9,3,"B"],[10,0,"6"],[10,1,"Y"],[10,2,"H"],[10,3,"N"],[10,4,"Space"],[11,0,"7"],[11,1,"U"],[11,2,"J"],[11,3,"M"],[12,0,"8"],[12,1,"I"],[12,2,"K"],[12,3,","],[13,0,"9"],[13,1,"O"],[13,2,"L"],[13,3,"."],[14,0,"0"],[14,1,"P"],[14,2,";"],[14,3,"/"],[15,0,"-"],[15,1,"["],[15,2,"'"],[15,3,"Shift"],[15,4,"Alt"],[16,0,"="],[16,1,"]"],[16,2,"Enter"],[16,3,"Fn"],[16,4,"Menu (Legacy)"],[17,0,"Backspace"],[17,1,"\\"],[17,2,"Delete"]],"8968:3535":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"Caps Lock"],[1,0,"1!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\|"],[1,4,"Alt"],[2,0,"2@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"`~"],[4,0,"4$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9("],[9,1,"O"],[9,2,"L"],[9,3,",<"],[9,4,"\\|"],[10,0,"0)"],[10,1,"P"],[10,2,";:"],[10,3,".>"],[10,4,"\u2190"],[11,0,"-_"],[11,1,"[{"],[11,2,"'\""],[11,3,"/?"],[11,4,"\u2192"],[12,0,"=+"],[12,1,"]}"],[12,2,"#~"],[12,3,"Shift"],[12,4,"\u2193"],[13,0,"Delete"],[13,1,"\\|"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"\u2191"]],"8968:3838":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"Menu"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"Delete"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"8968:4136":[],"8968:414C":[],"8968:414D":[[0,0,"Esc"],[0,1,"Home"],[0,2,"Page Up"],[0,3,"Page Down"],[0,4,"End"],[0,5,"GUI"],[1,0,"F1"],[1,1,"`"],[1,2,"Tab"],[1,3,"Caps Lock"],[1,4,"Shift"],[1,5,"Ctrl"],[2,0,"F2"],[2,1,"1"],[2,2,"Q"],[2,3,"A"],[2,4,"\\"],[2,5,"GUI"],[3,0,"F3"],[3,1,"2"],[3,2,"W"],[3,3,"S"],[3,4,"Z"],[3,5,"Alt"],[4,0,"F4"],[4,1,"3"],[4,2,"E"],[4,3,"D"],[4,4,"X"],[5,0,"F5"],[5,1,"4"],[5,2,"R"],[5,3,"F"],[5,4,"C"],[6,0,"F6"],[6,1,"5"],[6,2,"T"],[6,3,"G"],[6,4,"V"],[7,0,"F7"],[7,1,"6"],[7,2,"Y"],[7,3,"H"],[7,4,"B"],[8,0,"F8"],[8,1,"7"],[8,2,"U"],[8,3,"J"],[8,4,"N"],[8,5,"Space"],[9,0,"F9"],[9,1,"8"],[9,2,"I"],[9,3,"K"],[9,4,"M"],[10,0,"F10"],[10,1,"9"],[10,2,"O"],[10,3,"L"],[10,4,","],[11,0,"F11"],[11,1,"0"],[11,2,"P"],[11,3,";"],[11,4,"."],[12,0,"F12"],[12,1,"-"],[12,2,"["],[12,3,"'"],[12,4,"/"],[12,5,"Alt"],[13,0,"Insert"],[13,1,"="],[13,2,"]"],[13,3,"#"],[13,4,"Shift"],[13,5,"Menu"],[14,0,"Delete"],[14,1,"\\"],[14,2,"Backspace"],[14,3,"Enter"],[14,4,"Fn"],[14,5,"Ctrl"]],"8968:414E":[],"8968:4152":[],"8968:4238":[],"8968:432A":[[0,0,"F1"],[0,1,"F2"],[0,2,"F3"],[0,3,"F4"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"Z"],[3,4,"Ctrl"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"X"],[4,4,"Alt"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"C"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"V"],[6,4,"Space"],[7,0,"6"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[8,0,"7"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[8,4,"Space"],[9,0,"8"],[9,1,"I"],[9,2,"K"],[9,3,"M"],[10,0,"9"],[10,1,"O"],[10,2,"L"],[10,3,","],[11,0,"0"],[11,1,"P"],[11,2,";"],[11,3,"."],[11,4,"Alt"],[12,0,"-"],[12,1,"["],[12,2,"'"],[12,3,"/"],[12,4,"Ctrl"],[13,0,"="],[13,1,"]"],[13,2,"\\"],[13,3,"Shift"],[14,0,"Backspace"],[14,1,"Delete"],[14,2,"Enter"],[14,3,"Fn"],[15,0,"Insert"],[15,1,"Delete"],[15,4,"\u2190"],[16,0,"Home"],[16,1,"End"],[16,3,"\u2191"],[16,4,"\u2193"],[17,0,"Page Up"],[17,1,"Page Down"],[17,4,"\u2192"]],"8968:4336":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"8968:4341":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Menu"],[12,0,"="],[12,1,"]"],[12,2,"Delete"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Fn"]],"8968:434D":[],"8968:4353":[],"8968:4447":[],"8968:4536":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"Delete"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"8968:4648":[],"8968:4748":[],"8968:4749":[],"8968:4750":[],"8968:4853":[],"8968:4854":[],"8968:4855":[],"8968:4B41":[],"8968:4C36":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Delete"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"\u2192"]],"8968:4C56":[],"8968:4D35":[],"8968:4D37":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[4,5,"Space"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[8,5,"Space"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Menu"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"F13"],[13,1,"Backspace"],[13,2,"Delete"],[13,3,"Enter"],[13,4,"\u2191"],[13,5,"\u2193"],[14,1,"Home"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"End"],[14,5,"\u2192"]],"8968:4D43":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Control"],[0,4,"Shift"],[0,5,"Caps Lock"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"GUI"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[3,5,"Alt"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[7,5,"Space"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Delete"],[12,4,"Shift"],[12,5,"GUI"],[13,0,"F13"],[13,1,"\\"],[13,2,"Backspace"],[13,3,"Enter"],[13,4,"Fn"],[13,5,"Ctrl"]],"8968:4E4B":[],"8968:4E4C":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"Fn"],[13,0,"F13"],[13,1,"Backspace"],[13,3,"Enter"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"8968:4E4D":[],"8968:4E4E":[],"8968:4E4F":[],"8968:4E50":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"Fn"],[13,0,"F13"],[13,1,"Backspace"],[13,3,"Enter"],[13,5,"Ctrl"],[14,0,"Print Screen"],[14,1,"Insert"],[14,2,"Delete"],[14,5,"\u2190"],[15,0,"Scroll Lock"],[15,1,"Home"],[15,2,"End"],[15,4,"\u2191"],[15,5,"\u2193"],[16,0,"Pause"],[16,1,"Page Up"],[16,2,"Page Down"],[16,5,"\u2192"]],"8968:4E51":[],"8968:4E53":[],"8968:4E54":[],"8968:4E55":[],"8968:5031":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F1"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F2"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F3"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F4"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F9"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[12,0,"F10"],[12,1,"="],[12,2,"]"],[12,5,"Menu"],[13,0,"F11"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Shift"],[14,0,"F12"],[14,3,"Delete"],[14,4,"Shift"],[14,5,"Ctrl"],[15,0,"Print Screen"],[15,1,"Insert"],[15,2,"Delete"],[15,5,"\u2190"],[16,0,"Scroll Lock"],[16,1,"Home"],[16,2,"End"],[16,4,"\u2191"],[16,5,"\u2193"],[17,0,"Mute"],[17,1,"Page Up"],[17,2,"Page Down"],[17,5,"\u2192"]],"8968:5048":[],"8968:5332":[[0,0,"7"],[0,1,"4"],[0,2,"1"],[0,3,"Fn"],[1,0,"8"],[1,1,"5"],[1,2,"2"],[1,3,"0"],[2,0,"9"],[2,1,"6"],[2,2,"3"],[2,3,"."]],"8968:5336":[],"8968:5337":[],"8968:5338":[],"8968:5754":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,3,"\\"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[8,0,"6"],[8,1,"Y"],[8,2,"H"],[8,3,"B"],[8,4,"Space"],[9,0,"7"],[9,1,"U"],[9,2,"J"],[9,3,"N"],[10,0,"8"],[10,1,"I"],[10,2,"K"],[10,3,"M"],[11,0,"9"],[11,1,"O"],[11,2,"L"],[11,3,","],[12,0,"0"],[12,1,"P"],[12,2,";"],[12,3,"."],[13,0,"-"],[13,1,"["],[13,2,"'"],[13,3,"/"],[13,4,"Alt"],[14,0,"="],[14,1,"]"],[14,2,"Delete"],[14,3,"Shift"],[15,0,"Backspace"],[15,1,"\\"],[15,2,"Enter"],[15,3,"Fn"],[15,4,"Ctrl"],[16,0,"Num Lock"],[16,1,"7"],[16,2,"4"],[16,3,"1"],[16,4,"0"],[17,0,"-"],[17,1,"8"],[17,2,"5"],[17,3,"2"],[17,4,"00"],[18,0,"/"],[18,1,"9"],[18,2,"6"],[18,3,"3"],[18,4,"."],[19,0,"*"],[19,1,"+"],[19,2,"-"],[19,3,"-"],[19,4,"Enter"]],"8968:5755":[],"8968:6335":[],"8968:6336":[],"8968:6337":[],"8968:6338":[],"8968:6339":[],"8968:6837":[],"8968:7336":[],"8968:7337":[],"8A5B:3349":[],"8B1E:0C00":[],"8C27:3449":[],"8D1D:F75B":[],"8F5D:5258":[],"9000:0001":[],"906B:0003":[],"906D:0005":[],"906D:0006":[],"906F:0007":[],"9133:6AAB":[],"916D:0001":[],"9624:0003":[],"9624:0004":[],"9624:0005":[],"9624:0008":[],"9624:0009":[],"9624:0010":[],"9624:0011":[],"9624:0012":[],"9650:2800":[[0,0,"Num Lock"],[0,1,"7"],[0,2,"4"],[0,3,"1"],[0,4,"0"],[1,0,"/"],[1,1,"8"],[1,2,"5"],[1,3,"2"],[2,0,"*"],[2,1,"9"],[2,2,"6"],[2,3,"3"],[2,4,"."],[3,0,"Play"],[3,1,"-"],[3,2,"+"],[3,3,"Enter"]],"980E:998F":[[0,0,"K00 (D0,D6)"],[0,1,"K10 (D1,D6)"],[0,2,"K20 (D2,D6)"],[0,3,"K30 (D3,D6)"],[0,4,"K40 (D5,D6)"],[0,5,"K50 (D4,D6)"],[1,0,"K01 (D0,D7)"],[1,1,"K11 (D1,D7)"],[1,2,"K21 (D2,D7)"],[1,3,"K31 (D3,D7)"],[1,4,"K41 (D5,D7)"],[1,5,"K51 (D4,D7)"],[2,0,"K02 (D0,B4)"],[2,1,"K12 (D1,B4)"],[2,2,"K22 (D2,B4)"],[2,3,"K32 (D3,B4)"],[2,4,"K42 (D5,B4)"],[2,5,"K52 (D4,B4)"],[3,0,"K03 (D0,B5)"],[3,1,"K13 (D1,B5)"],[3,2,"K23 (D2,B5)"],[3,3,"K33 (D3,B5)"],[3,4,"K43 (D5,B5)"],[4,0,"K04 (D0,B6)"],[4,1,"K14 (D1,B6)"],[4,2,"K24 (D2,B6)"],[4,3,"K34 (D3,B6)"],[4,4,"K44 (D5,B6)"],[5,0,"K05 (D0,C6)"],[5,1,"K15 (D1,C6)"],[5,2,"K25 (D2,C6)"],[5,3,"K35 (D3,C6)"],[5,4,"K45 (D5,C6)"],[6,0,"K06 (D0,C7)"],[6,1,"K16 (D1,C7)"],[6,2,"K26 (D2,C7)"],[6,3,"K36 (D3,C7)"],[6,4,"K46 (D5,C7)"],[6,5,"K56 (D4,C7)"],[7,0,"K07 (D0,E2)"],[7,1,"K17 (D1,E2)"],[7,2,"K27 (D2,E2)"],[7,3,"K37 (D3,E2)"],[7,4,"K47 (D5,E2)"],[7,5,"K57 (D4,E2)"],[8,0,"K08 (D0,F7)"],[8,1,"K18 (D1,F7)"],[8,2,"K28 (D2,F7)"],[8,3,"K38 (D3,F7)"],[8,4,"K48 (D5,F7)"],[8,5,"K58 (D4,F7)"],[9,0,"K09 (D0,F6)"],[9,1,"K19 (D1,F6)"],[9,2,"K29 (D2,F6)"],[9,3,"K39 (D3,F6)"],[9,4,"K49 (D5,F6)"],[9,5,"K59 (D4,F6)"],[10,0,"K0A (D0,F5)"],[10,1,"K1A (D1,F5)"],[10,2,"K2A (D2,F5)"],[10,3,"K3A (D3,F5)"],[10,4,"K4A (D5,F5)"],[10,5,"K5A (D4,F5)"],[11,0,"K0B (D0,F4)"],[11,1,"K1B (D1,F4)"],[11,2,"K2B (D2,F4)"],[11,3,"K3B (D3,F4)"],[11,4,"K4B (D5,F4)"],[11,5,"K5B (D4,F4)"],[12,0,"K0C (D0,B0)"],[12,1,"K1C (D1,B0)"],[12,2,"K2C (D2,B0)"],[12,3,"K3C (D3,B0)"],[12,4,"K4C (D5,B0)"],[12,5,"K5C (D4,B0)"],[13,0,"K0D (D0,B1)"],[13,1,"K1D (D1,B1)"],[13,2,"K2D (D2,B1)"],[13,5,"K5D (D4,B1)"],[14,0,"K0E (D0,B2)"],[14,1,"K1E (D1,B2)"],[14,2,"K2E (D2,B2)"],[14,4,"K4E (D5,B2)"],[14,5,"K5E (D4,B2)"],[15,0,"K0F (D0,B3)"],[15,1,"K1F (D1,B3)"],[15,2,"K2F (D2,B3)"],[15,5,"K5F (D4,B3)"]],"9856:7070":[],"9879:0001":[],"9906:0000":[],"9906:0001":[],"9906:0002":[],"9906:0011":[],"9906:0012":[],"9906:0013":[],"9907:5366":[],"9954:9970":[[0,0,"K00 (B10,B9)"],[0,1,"K10 (B1,B9)"],[0,2,"K20 (B0,B9)"],[0,3,"K30 (A7,B9)"],[0,4,"K40 (A6,B9)"],[1,0,"K01 (B10,B8)"],[1,1,"K11 (B1,B8)"],[1,2,"K21 (B0,B8)"],[1,3,"K31 (A7,B8)"],[1,4,"K41 (A6,B8)"],[2,0,"K02 (B10,B7)"],[2,1,"K12 (B1,B7)"],[2,2,"K22 (B0,B7)"],[2,3,"K32 (A7,B7)"],[2,4,"K42 (A6,B7)"],[3,0,"K03 (B10,B6)"],[3,1,"K13 (B1,B6)"],[3,2,"K23 (B0,B6)"],[3,3,"K33 (A7,B6)"],[4,0,"K04 (B10,B5)"],[4,1,"K14 (B1,B5)"],[4,2,"K24 (B0,B5)"],[4,3,"K34 (A7,B5)"],[5,0,"K05 (B10,B4)"],[5,1,"K15 (B1,B4)"],[5,2,"K25 (B0,B4)"],[5,3,"K35 (A7,B4)"],[6,0,"K06 (B10,B3)"],[6,1,"K16 (B1,B3)"],[6,2,"K26 (B0,B3)"],[6,3,"K36 (A7,B3)"],[6,4,"K46 (A6,B3)"],[7,0,"K07 (B10,B11)"],[7,1,"K17 (B1,B11)"],[7,2,"K27 (B0,B11)"],[7,3,"K37 (A7,B11)"],[8,0,"K08 (B10,A15)"],[8,1,"K18 (B1,A15)"],[8,2,"K28 (B0,A15)"],[8,3,"K38 (A7,A15)"],[9,0,"K09 (B10,A10)"],[9,1,"K19 (B1,A10)"],[9,2,"K29 (B0,A10)"],[9,3,"K39 (A7,A10)"],[10,0,"K0A (B10,A9)"],[10,1,"K1A (B1,A9)"],[10,2,"K2A (B0,A9)"],[10,3,"K3A (A7,A9)"],[10,4,"K4A (A6,A9)"],[11,0,"K0B (B10,B14)"],[11,1,"K1B (B1,B14)"],[11,2,"K2B (B0,B14)"],[11,3,"K3B (A7,B14)"],[11,4,"K4B (A6,B14)"],[12,0,"K0C (B10,B13)"],[12,1,"K1C (B1,B13)"],[12,2,"K2C (B0,B13)"],[12,3,"K3C (A7,B13)"],[12,4,"K4C (A6,B13)"],[13,0,"K0D (B10,B12)"],[13,1,"K1D (B1,B12)"],[13,2,"K2D (B0,B12)"],[13,3,"K3D (A7,B12)"],[13,4,"K4D (A6,B12)"],[14,0,"K0E (B10,A5)"],[14,1,"K1E (B1,A5)"],[14,2,"K2E (B0,A5)"],[14,3,"K3E (A7,A5)"],[14,4,"K4E (A6,A5)"]],"9991:9038":[],"9991:D408":[],"9C12:89F0":[],"A059:2567":[[0,2,"L20"],[0,3,"L30"],[0,4,"L40"],[0,7,"R20"],[0,8,"R30"],[0,9,"R40"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,3,"L31"],[1,4,"L41"],[1,5,"R01"],[1,6,"R11"],[1,7,"R21"],[1,8,"R31"],[1,9,"R41"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"L42"],[2,5,"R02"],[2,6,"R12"],[2,7,"R22"],[2,8,"R32"],[2,9,"R42"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,5,"R03"],[3,6,"R13"],[3,7,"R23"],[3,8,"R33"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,5,"R04"],[4,6,"R14"],[4,7,"R24"],[4,8,"R34"],[5,0,"L05"],[5,1,"L15"],[5,2,"L25"],[5,3,"L35"],[5,4,"L45"],[5,5,"R05"],[5,6,"R15"],[5,7,"R25"],[5,8,"R35"],[5,9,"R45"],[6,0,"L06"],[6,1,"L16"],[6,2,"L26"],[6,3,"L36"],[6,4,"L46"],[6,5,"R06"],[6,6,"R16"],[6,7,"R26"],[6,8,"R36"],[6,9,"R46"],[7,0,"L07"],[7,1,"L17"],[7,2,"L27"],[7,3,"L37"],[7,4,"L47"],[7,5,"R07"],[7,6,"R17"],[7,7,"R27"],[7,8,"R37"],[7,9,"R47"]],"A059:4564":[],"A06B:0004":[],"A103:0001":[],"A103:0002":[],"A103:0003":[],"A103:0004":[[0,0,"Fn2"],[0,1,"Fn"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"\\"],[1,3,"GUI"],[2,0,"W"],[2,1,"S"],[2,2,"Z"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"X"],[4,0,"R"],[4,1,"F"],[4,2,"C"],[4,3,"Space"],[5,0,"T"],[5,1,"G"],[5,2,"V"],[6,0,"Y"],[6,1,"H"],[6,2,"B"],[6,3,"Space"],[7,0,"U"],[7,1,"J"],[7,2,"N"],[8,0,"I"],[8,1,"K"],[8,2,"M"],[8,3,"Space"],[9,0,"O"],[9,1,"L"],[9,2,","],[9,3,"`"],[10,0,"P"],[10,1,";"],[10,2,"."],[10,3,"GUI"],[11,0,"Backspace"],[11,1,"Enter"],[11,2,"Shift"],[11,3,"Delete"]],"A103:0005":[],"A103:0006":[],"A103:0007":[],"A103:000A":[],"A103:0010":[],"A103:0011":[],"A103:0012":[],"A103:0013":[],"A103:0014":[],"A103:0015":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Fn"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"Delete"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"End"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"A103:0016":[],"A103:0017":[],"A103:0018":[],"A103:0020":[],"A103:0022":[],"A103:0023":[],"A103:0024":[],"A103:0026":[],"A103:0028":[],"A103:0472":[],"A103:060A":[],"A122:B075":[],"A13B:0007":[],"A13B:0008":[],"A13B:000A":[],"A22A:6600":[],"A455:0001":[],"A4A4:4401":[],"A68C:1DB0":[],"A68C:4EE6":[],"A68C:675F":[],"A68C:6B47":[],"A68C:7BB2":[],"A68C:8B35":[],"A68C:8F7E":[],"A68C:9879":[],"A68C:C762":[],"A68C:D03E":[],"A68C:DB4B":[],"A68C:DB52":[],"A68C:DC9B":[],"A68C:E2BD":[],"A880:3134":[],"A8F7:1827":[],"AA04:BB04":[],"AA05:BB05":[],"AA06:BF06":[],"AA12:0001":[],"AA96:AAA9":[[0,1,"L40"],[0,2,"L30"],[0,3,"L20"],[0,4,"L10"],[0,5,"L00"],[0,7,"R40"],[0,8,"R30"],[0,9,"R20"],[0,10,"R10"],[0,11,"R00"],[1,0,"L51"],[1,1,"L41"],[1,2,"L31"],[1,3,"L21"],[1,4,"L11"],[1,5,"L01"],[1,6,"R51"],[1,7,"R41"],[1,8,"R31"],[1,9,"R21"],[1,10,"R11"],[1,11,"R01"],[2,0,"L52"],[2,1,"L42"],[2,2,"L32"],[2,3,"L22"],[2,4,"L12"],[2,5,"L02"],[2,6,"R52"],[2,7,"R42"],[2,8,"R32"],[2,9,"R22"],[2,10,"R12"],[2,11,"R02"],[3,0,"L53"],[3,1,"L43"],[3,2,"L33"],[3,3,"L23"],[3,4,"L13"],[3,5,"L03"],[3,6,"R53"],[3,7,"R43"],[3,8,"R33"],[3,9,"R23"],[3,10,"R13"],[3,11,"R03"],[4,0,"L54"],[4,1,"L44"],[4,2,"L34"],[4,3,"L24"],[4,4,"L14"],[4,5,"L04"],[4,6,"R54"],[4,7,"R44"],[4,8,"R34"],[4,9,"R24"],[4,10,"R14"],[4,11,"R04"],[5,0,"L55"],[5,2,"L35"],[5,3,"L25"],[5,4,"L15"],[5,5,"L05"],[5,6,"R55"],[5,8,"R35"],[5,9,"R25"],[5,10,"R15"],[5,11,"R05"],[6,0,"L56"],[6,2,"L36"],[6,4,"L16"],[6,5,"L06"],[6,6,"R56"],[6,8,"R36"],[6,10,"R16"],[6,11,"R06"]],"AB13:4511":[],"AB69:8585":[],"ABA7:0001":[],"ABBA:9690":[],"ABBA:9691":[],"ABBA:9693":[],"ABBA:9696":[],"ABBE:4C4D":[],"ABCD:0001":[],"AC11:4172":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"Fn"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"GUI"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[7,4,"GUI"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[8,4,"Fn"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"GUI"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"\u2190"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Shift"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"\u2191"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"\\"],[13,4,"\u2192"],[14,0,"Delete"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"Home"],[14,4,"End"]],"AC11:4173":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,4,"Space"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Alt"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Fn"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Ctrl"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"\u2190"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"\u2193"],[13,0,"Backspace"],[13,1,"Enter"],[13,3,"\u2191"],[13,4,"\u2192"],[14,0,"Backspace"],[14,1,"Home"],[14,2,"End"],[14,3,"Page Up"],[14,4,"Page Down"]],"AC11:4175":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[5,5,"Space"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[9,5,"Alt"],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Ctrl"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"\u2190"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Enter"],[12,4,"Shift"],[12,5,"\u2193"],[13,0,"Print Screen"],[13,1,"Backspace"],[13,2,"\\"],[13,4,"\u2191"],[14,0,"Scroll Lock"],[14,1,"Backspace"],[14,2,"Page Up"],[14,3,"Page Down"],[14,5,"\u2192"],[15,0,"Pause"],[15,1,"Insert"],[15,2,"7"],[15,3,"4"],[15,4,"1"],[15,5,"0"],[16,0,"Home"],[16,1,"Num Lock"],[16,2,"8"],[16,3,"5"],[16,4,"2"],[16,5,"0"],[17,0,"End"],[17,1,"/"],[17,2,"9"],[17,3,"6"],[17,4,"3"],[17,5,"."],[18,0,"Delete"],[18,1,"*"],[18,3,"+"],[18,4,"Enter"],[18,5,"-"]],"AC12:2236":[],"AC12:4176":[[0,0,"Mute"],[0,1,"Esc"],[0,2,"`"],[0,3,"Tab"],[0,4,"Caps Lock"],[0,5,"Shift"],[0,6,"Ctrl"],[1,0,"F13"],[1,1,"F1"],[1,2,"1"],[1,3,"Q"],[1,4,"A"],[1,5,"\\"],[1,6,"GUI"],[2,0,"F14"],[2,1,"F2"],[2,2,"2"],[2,3,"W"],[2,4,"S"],[2,5,"Z"],[2,6,"Alt"],[3,0,"F15"],[3,1,"F3"],[3,2,"3"],[3,3,"E"],[3,4,"D"],[3,5,"X"],[4,0,"F16"],[4,1,"F4"],[4,2,"4"],[4,3,"R"],[4,4,"F"],[4,5,"C"],[4,6,"Space"],[5,0,"F17"],[5,1,"F5"],[5,2,"5"],[5,3,"T"],[5,4,"G"],[5,5,"V"],[5,6,"Space"],[6,0,"F18"],[6,1,"F6"],[6,2,"6"],[6,3,"Y"],[6,4,"H"],[6,5,"B"],[7,0,"F19"],[7,1,"F7"],[7,2,"7"],[7,3,"U"],[7,4,"J"],[7,5,"N"],[7,6,"Space"],[8,0,"F20"],[8,1,"F8"],[8,2,"8"],[8,3,"I"],[8,4,"K"],[8,5,"M"],[9,0,"F21"],[9,1,"F9"],[9,2,"9"],[9,3,"O"],[9,4,"L"],[9,5,","],[9,6,"Alt"],[10,0,"F22"],[10,1,"F10"],[10,2,"0"],[10,3,"P"],[10,4,";"],[10,5,"."],[10,6,"Menu"],[11,0,"F23"],[11,1,"F11"],[11,2,"-"],[11,3,"["],[11,4,"'"],[11,5,"/"],[11,6,"Ctrl"],[12,0,"F24"],[12,1,"F12"],[12,2,"="],[12,3,"]"],[12,4,"Enter"],[12,5,"Shift"],[12,6,"\u2190"],[13,0,"Previous Track"],[13,1,"Print Screen"],[13,2,"Backspace"],[13,3,"\\"],[13,4,"Enter"],[13,5,"\u2191"],[13,6,"\u2193"],[14,0,"Play/Pause"],[14,1,"Scroll Lock"],[14,2,"Calculator"],[14,3,"Toggle RGB"],[14,4,"Media Select"],[14,5,"Backspace"],[14,6,"\u2192"],[15,0,"Next Track"],[15,1,"Pause"],[15,2,"Num Lock"],[15,3,"7"],[15,4,"4"],[15,5,"1"],[15,6,"0"],[16,0,"Insert"],[16,1,"Delete"],[16,2,"/"],[16,3,"8"],[16,4,"5"],[16,5,"2"],[16,6,"0"],[17,0,"Home"],[17,1,"End"],[17,2,"*"],[17,3,"9"],[17,4,"6"],[17,5,"3"],[17,6,"."],[18,0,"Page Up"],[18,1,"Page Down"],[18,2,"-"],[18,3,"="],[18,4,"+"],[18,5,"Enter"]],"ACE1:5449":[],"AD80:FF65":[],"ADA0:0081":[],"ADA0:1800":[],"ADAD:FB60":[],"AF01:0001":[],"AF99:CA40":[],"AFC2:BFC2":[],"B00B:FEED":[],"B030:0001":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"L Shift"],[0,3,"L Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"L Alt"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"MO(2)"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"MO(1)"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"MO(3)"],[6,3,"Space"],[7,0,"U"],[7,1,"J"],[7,2,"N"],[8,0,"I"],[8,1,"K"],[8,2,"M"],[8,3,"R Alt"],[9,0,"O"],[9,1,"L"],[9,2,","],[10,0,"P"],[10,1,";"],[10,2,"."],[11,0,"Del"],[11,2,"/"],[11,3,"R GUI"],[12,0,"Bspc"],[12,1,"Enter"],[12,2,"R Shift"],[12,3,"R Ctrl"]],"B034:FF16":[],"B06B:0005":[],"B141:0602":[],"B16B:00B1":[],"B16B:00B3":[],"B16B:00B5":[],"B16B:04E5":[],"B16B:10B5":[],"B16B:4032":[],"B16B:404A":[],"B16B:404B":[],"B16B:440B":[],"B16B:4BE5":[],"B16B:C4EE":[],"B16B:E0A1":[],"B16B:E460":[],"B23B:1688":[],"B33F:58E4":[],"B501:0001":[[0,0,"ESC"],[0,1,"`"],[0,2,"TAB"],[0,3,"CAPS"],[0,4,"SHIFT"],[0,5,"FN"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,5,"CTRL"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"ALT"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[3,5,"GUI"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"SPACE"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"GUI"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"LEFT"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,3,"RETURN"],[12,4,"UP"],[12,5,"DOWN"],[13,0,"F12"],[13,1,"BACKSPACE"],[13,2,"\\"],[13,5,"RIGHT"]],"B62C:6146":[],"B727:B727":[[0,0,"Esc"],[0,1,"`~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1!"],[1,2,"Q"],[1,3,"A"],[1,5,"Win"],[2,0,"F2"],[2,1,"2@"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3#"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4$"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,1,"5%"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6^"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7&"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8*"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9("],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F9"],[10,1,"0)"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F10"],[11,1,"-_"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F11"],[12,1,"=+"],[12,2,"]"],[12,4,"Shift"],[12,5,"Left"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"Up"],[13,5,"Down"],[14,0,"Home"],[14,1,"Page Up"],[14,2,"Page Down"],[14,3,"End"],[14,4,"End"],[14,5,"Right"]],"B9DD:175A":[],"B9DD:176A":[],"B9F7:B44C":[],"BA00:8701":[],"BA60:AB06":[[0,0,"ESC"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[6,4,"Space"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"<"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,">"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,"?"],[10,4,"Alt"],[11,0,"_"],[11,1,"{"],[11,2,"k90"],[12,0,"+"],[12,1,"}"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Delete"],[13,1,"|"],[13,2,"Enter"],[13,3,"Up"]],"BABA:6061":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"#"],[0,3,"Left Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"q"],[1,2,"a"],[1,3,"\\"],[1,4,"Menu"],[2,0,"2"],[2,1,"w"],[2,2,"s"],[2,3,"z"],[2,4,"Lower"],[3,0,"3"],[3,1,"e"],[3,2,"d"],[3,3,"x"],[3,4,"Alt"],[4,0,"4"],[4,1,"r"],[4,2,"f"],[4,3,"c"],[4,4,"Raise"],[5,0,"5"],[5,1,"t"],[5,2,"g"],[5,3,"v"],[5,4,"Space"],[6,0,"6"],[6,1,"y"],[6,2,"h"],[6,3,"b"],[6,4,"Space"],[7,0,"7"],[7,1,"u"],[7,2,"j"],[7,3,"n"],[7,4,"Space"],[8,0,"8"],[8,1,"i"],[8,2,"k"],[8,3,"m"],[8,4,"Alt Gr"],[9,0,"9"],[9,1,"o"],[9,2,"l"],[9,3,","],[9,4,"Right Shift"],[10,0,"0"],[10,1,"p"],[10,2,";"],[10,3,"."],[10,4,"Left"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Up"],[11,4,"Down"],[12,0,"Backspace"],[12,1,"]"],[12,2,"Enter"],[12,3,"/"],[12,4,"Right"]],"BABA:6062":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"#"],[0,3,"Left Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"q"],[1,2,"a"],[1,3,"\\"],[1,4,"Menu"],[2,0,"2"],[2,1,"w"],[2,2,"s"],[2,3,"z"],[2,4,"Lower"],[3,0,"3"],[3,1,"e"],[3,2,"d"],[3,3,"x"],[3,4,"Alt"],[4,0,"4"],[4,1,"r"],[4,2,"f"],[4,3,"c"],[4,4,"Raise"],[5,0,"5"],[5,1,"t"],[5,2,"g"],[5,3,"v"],[5,4,"Space"],[6,0,"6"],[6,1,"y"],[6,2,"h"],[6,3,"b"],[6,4,"Space"],[7,0,"7"],[7,1,"u"],[7,2,"j"],[7,3,"n"],[7,4,"Space"],[8,0,"8"],[8,1,"i"],[8,2,"k"],[8,3,"m"],[8,4,"Alt Gr"],[9,0,"9"],[9,1,"o"],[9,2,"l"],[9,3,","],[9,4,"Right Shift"],[10,0,"0"],[10,1,"p"],[10,2,";"],[10,3,"."],[10,4,"Left"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"Up"],[11,4,"Down"],[12,0,"Backspace"],[12,1,"]"],[12,2,"Enter"],[12,3,"/"],[12,4,"Right"]],"BABE:2012":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Alt"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Space"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"GUI"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"`"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Alt"],[13,0,"\\"],[13,1,"Backspace"],[13,3,"Fn"],[13,4,"Ctrl"]],"BACA:6970":[],"BADD:AA55":[[0,0,"Fn"],[0,1,"Print Screen"],[0,2,"-"],[0,3,"*"],[0,4,"+"],[0,5,"9"],[0,6,"="],[0,7,"6"],[0,8,"Enter"],[0,9,"3"],[0,10,"."],[1,0,"Scroll Lock"],[1,1,"Pause"],[1,2,"/"],[1,3,"Num Lock"],[1,4,"8"],[1,5,"7"],[1,6,"5"],[1,7,"4"],[1,8,"2"],[1,9,"1"],[1,10,"0"],[2,0,"Esc"],[2,1,"F1"],[2,2,"`"],[2,3,"1"],[2,4,"Tab"],[2,5,"Q"],[2,6,"Caps Lock"],[2,7,"A"],[2,8,"Shift"],[2,9,"\\"],[2,10,"Ctrl"],[3,0,"F2"],[3,1,"F3"],[3,2,"2"],[3,3,"3"],[3,4,"W"],[3,5,"E"],[3,6,"S"],[3,7,"D"],[3,8,"Z"],[3,9,"X"],[3,10,"GUI"],[4,0,"F4"],[4,1,"F5"],[4,2,"4"],[4,3,"5"],[4,4,"R"],[4,5,"T"],[4,6,"F"],[4,7,"G"],[4,8,"C"],[4,9,"V"],[4,10,"Alt"],[5,0,"F7"],[5,1,"F6"],[5,2,"7"],[5,3,"6"],[5,4,"U"],[5,5,"Y"],[5,6,"J"],[5,7,"H"],[5,8,"N"],[5,9,"B"],[5,10,"Space"],[6,0,"F8"],[6,1,"F9"],[6,2,"8"],[6,3,"9"],[6,4,"I"],[6,5,"O"],[6,6,"K"],[6,7,"L"],[6,8,"M"],[6,9,","],[6,10,"Alt"],[7,0,"F10"],[7,1,"F11"],[7,2,"0"],[7,3,"-"],[7,4,"P"],[7,5,"["],[7,6,";"],[7,7,"'"],[7,8,"."],[7,9,"/"],[7,10,"Menu"],[8,0,"F12"],[8,1,"Home"],[8,2,"="],[8,3,"Backspace"],[8,4,"]"],[8,5,"\\"],[8,6,"#"],[8,7,"Enter"],[8,8,"Shift"],[8,9,"\u2191"],[8,10,"Ctrl"],[9,0,"Page Up"],[9,1,"\\"],[9,2,"Insert"],[9,3,"Tab"],[9,4,"Delete"],[9,5,","],[9,6,"Page Down"],[9,7,"\u2192"],[9,8,"End"],[9,9,"\u2193"],[9,10,"\u2190"]],"BB00:D4D2":[],"BB00:D4D3":[],"BB07:AA07":[],"BB4F:0001":[],"BB4F:0002":[],"BB80:040D":[],"BB80:0504":[],"BB80:050D":[],"BBB0:0002":[],"BBEB:D4C3":[],"BBEB:D4C4":[],"BC42:0002":[],"BC42:0003":[],"BC42:0042":[],"BDD1:1919":[],"BDE0:B155":[],"BEAD:0001":[],"BEAF:0001":[],"BEEB:0001":[],"BEEB:0002":[],"BEEB:0003":[],"BEEF:5051":[[0,0,"L01"],[0,1,"L06"],[0,2,"L11"],[0,3,"L16"],[0,4,"R01"],[0,5,"R06"],[0,6,"R11"],[0,7,"R16"],[1,0,"L02"],[1,1,"L07"],[1,2,"L12"],[1,3,"L17"],[1,4,"R02"],[1,5,"R07"],[1,6,"R12"],[1,7,"R17"],[2,0,"L03"],[2,1,"L08"],[2,2,"L13"],[2,4,"R03"],[2,5,"R08"],[2,6,"R13"],[3,0,"L04"],[3,1,"L09"],[3,2,"L14"],[3,4,"R04"],[3,5,"R09"],[3,6,"R14"],[4,0,"L05"],[4,1,"L10"],[4,2,"L15"],[4,4,"R05"],[4,5,"R10"],[4,6,"R15"]],"BEEF:6969":[],"BEEF:BABE":[],"BEEF:BEEF":[[0,0,"Ctrl"]],"BEEF:CACA":[],"BEEF:CAFE":[],"BEEF:FED0":[],"BEEF:FFFF":[],"BF00:BF22":[],"BF00:BFFA":[],"C001:3667":[],"C01D:FC87":[],"C0B0:6060":[],"C0C0:4000":[],"C0DE:1337":[],"C1ED:2301":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"MUHENKAN"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"SPACE1"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"k46"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"HENKAN"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Alt"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,2,"ISOHASH"],[12,3,"JPBACKSLASH"],[12,4,"Menu"],[13,0,"YEN"],[13,1,"|"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"k4D"],[14,0,"Backspace"],[14,3,"k3E"],[14,4,"k4E"],[15,0,"k0F"],[15,1,"k1F"],[15,4,"k4F"]],"C1ED:2312":[[0,0,"Num Lock"],[0,1,"7"],[0,2,"4"],[0,3,"1"],[0,4,"0"],[1,0,"/"],[1,1,"8"],[1,2,"5"],[1,3,"2"],[2,0,"*"],[2,1,"9"],[2,2,"6"],[2,3,"3"],[2,4,"."],[3,0,"-"],[3,1,"+"],[3,3,"Enter"]],"C1ED:2320":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"*"],[0,6,"I"],[0,7,"K"],[0,8,"M"],[0,9,"HENKAN"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Win"],[1,5,"("],[1,6,"O"],[1,7,"L"],[1,8,"<"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[2,5,")"],[2,6,"P"],[2,7,":"],[2,8,">"],[2,9,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"MUHENKAN"],[3,5,"_"],[3,6,"{"],[3,7,"\""],[3,8,"?"],[3,9,"Win"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,5,"+"],[4,6,"}"],[4,7,"ISOHASH"],[4,8,"JPBACKSLASH"],[4,9,"Menu"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"SPACE1"],[5,5,"YEN"],[5,6,"|"],[5,7,"Enter"],[5,8,"Shift"],[5,9,"k95"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"k46"],[6,5,"Backspace"],[6,8,"k86"],[6,9,"k96"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,5,"k57"],[7,6,"k67"],[7,9,"k97"]],"C1ED:2330":[[0,0,"ON/OFF"],[0,1,"HUE-"],[0,2,"MODE"],[0,3,"MX1"],[1,0,"SAT+"],[1,1,"LAYER"],[1,2,"SAT-"],[1,3,"MX2"],[2,0,"BRIGHT+"],[2,1,"HUE+"],[2,2,"BRIGHT-"],[2,3,"MX3"]],"C1ED:2350":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"k47"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Alt"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,2,"@"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"k0d"],[14,0,"Backspace"],[14,1,"|"],[14,2,"Enter"],[14,3,"k3e"],[14,4,"Ctrl"]],"C1ED:2370":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"*"],[0,6,"I"],[0,7,"K"],[0,8,"M"],[0,9,"HENKAN"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Win"],[1,5,"("],[1,6,"O"],[1,7,"L"],[1,8,"<"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[2,5,")"],[2,6,"P"],[2,7,":"],[2,8,">"],[2,9,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"MUHENKAN"],[3,5,"_"],[3,6,"{"],[3,7,"\""],[3,8,"?"],[3,9,"Win"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,5,"+"],[4,6,"}"],[4,7,"ISOHASH"],[4,8,"JPBACKSLASH"],[4,9,"Menu"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"SPACE1"],[5,5,"YEN"],[5,6,"|"],[5,7,"Enter"],[5,8,"Shift"],[5,9,"k95"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"k46"],[6,5,"Backspace"],[6,8,"k86"],[6,9,"k96"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,5,"k57"],[7,6,"k67"],[7,9,"k97"]],"C1ED:2390":[[0,0,"~"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[0,5,"*"],[0,6,"I"],[0,7,"K"],[0,8,"M"],[0,9,"HENKAN"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Win"],[1,5,"("],[1,6,"O"],[1,7,"L"],[1,8,"<"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[2,5,")"],[2,6,"P"],[2,7,":"],[2,8,">"],[2,9,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"MUHENKAN"],[3,5,"_"],[3,6,"{"],[3,7,"\""],[3,8,"?"],[3,9,"Win"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[4,5,"+"],[4,6,"}"],[4,7,"ISOHASH"],[4,8,"JPBACKSLASH"],[4,9,"Menu"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"SPACE1"],[5,5,"YEN"],[5,6,"|"],[5,7,"Enter"],[5,8,"Shift"],[5,9,"Left"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[6,5,"Backspace"],[6,8,"Up"],[6,9,"Down"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,5,"Page Up"],[7,6,"Page Down"],[7,9,"Up"]],"C1ED:2391":[[0,0,"k00"],[0,1,"k10"],[0,2,"k20"],[0,3,"k30"],[0,4,"k40"],[0,5,"k50"],[0,6,"k60"],[0,7,"k70"],[0,8,"k80"],[0,9,"k90"],[1,0,"k01"],[1,1,"k11"],[1,2,"k21"],[1,4,"k41"],[1,5,"k51"],[1,6,"k61"],[1,7,"k71"],[1,8,"k81"],[2,0,"k02"],[2,1,"k12"],[2,2,"k22"],[2,3,"k32"],[2,4,"k42"],[2,5,"k52"],[2,6,"k62"],[2,7,"k72"],[2,8,"k82"],[2,9,"k92"],[3,0,"k03"],[3,1,"k13"],[3,2,"k23"],[3,3,"k33"],[3,5,"k53"],[3,6,"k63"],[3,7,"k73"],[3,8,"k83"],[3,9,"k93"],[4,0,"k04"],[4,1,"k14"],[4,2,"k24"],[4,3,"k34"],[4,5,"k54"],[4,6,"k64"],[4,9,"k94"],[5,0,"k05"],[5,1,"k15"],[5,2,"k25"],[5,3,"k35"],[5,4,"k45"],[5,5,"k55"],[5,6,"k65"],[5,7,"k75"],[5,8,"k85"],[5,9,"k95"],[6,0,"k06"],[6,1,"k16"],[6,2,"k26"],[6,3,"k36"],[6,4,"k46"],[6,8,"k86"],[6,9,"k96"],[7,0,"k07"],[7,1,"k17"],[7,2,"k27"],[7,3,"k37"],[7,5,"k57"],[7,6,"k67"],[7,9,"k97"]],"C1ED:23A0":[],"C2AB:0000":[],"C2AB:3939":[[0,0,"L01"],[0,1,"L06"],[0,2,"L11"],[0,3,"L16"],[0,4,"R01"],[0,5,"R06"],[0,6,"R11"],[0,7,"R16"],[1,0,"L02"],[1,1,"L07"],[1,2,"L12"],[1,3,"L17"],[1,4,"R02"],[1,5,"R07"],[1,6,"R12"],[1,7,"R17"],[2,0,"L03"],[2,1,"L08"],[2,2,"L13"],[2,4,"R03"],[2,5,"R08"],[2,6,"R13"],[3,0,"L04"],[3,1,"L09"],[3,2,"L14"],[3,4,"R04"],[3,5,"R09"],[3,6,"R14"],[4,0,"L05"],[4,1,"L10"],[4,2,"L15"],[4,4,"R05"],[4,5,"R10"],[4,6,"R15"]],"C2AB:50AD":[],"C3AB:3139":[],"C3AC:3140":[],"C3C3:C361":[],"C3C3:C364":[],"C41C:0001":[],"C41C:0002":[[0,0,"K00 (E6,F6)"],[0,1,"K10 (B7,F6)"],[0,2,"K20 (F7,F6)"],[0,3,"K30 (F4,F6)"],[0,4,"K40 (F5,F6)"],[1,0,"K01 (E6,B0)"],[1,1,"K11 (B7,B0)"],[1,2,"K21 (F7,B0)"],[1,4,"K41 (F5,B0)"],[2,0,"K02 (E6,F1)"],[2,1,"K12 (B7,F1)"],[2,2,"K22 (F7,F1)"],[2,3,"K32 (F4,F1)"],[2,4,"K42 (F5,F1)"],[3,0,"K03 (E6,C7)"],[3,1,"K13 (B7,C7)"],[3,2,"K23 (F7,C7)"],[3,3,"K33 (F4,C7)"],[4,0,"K04 (E6,C6)"],[4,1,"K14 (B7,C6)"],[4,2,"K24 (F7,C6)"],[4,3,"K34 (F4,C6)"],[5,0,"K05 (E6,B6)"],[5,1,"K15 (B7,B6)"],[5,2,"K25 (F7,B6)"],[5,3,"K35 (F4,B6)"],[6,0,"K06 (E6,B5)"],[6,1,"K16 (B7,B5)"],[6,2,"K26 (F7,B5)"],[6,3,"K36 (F4,B5)"],[6,4,"K46 (F5,B5)"],[7,0,"K07 (E6,B4)"],[7,1,"K17 (B7,B4)"],[7,2,"K27 (F7,B4)"],[7,3,"K37 (F4,B4)"],[8,0,"K08 (E6,D7)"],[8,1,"K18 (B7,D7)"],[8,2,"K28 (F7,D7)"],[8,3,"K38 (F4,D7)"],[9,0,"K09 (E6,D6)"],[9,1,"K19 (B7,D6)"],[9,2,"K29 (F7,D6)"],[9,3,"K39 (F4,D6)"],[9,4,"K49 (F5,D6)"],[10,0,"K0A (E6,D4)"],[10,1,"K1A (B7,D4)"],[10,2,"K2A (F7,D4)"],[10,3,"K3A (F4,D4)"],[10,4,"K4A (F5,D4)"],[11,0,"K0B (E6,D5)"],[11,1,"K1B (B7,D5)"],[11,2,"K2B (F7,D5)"],[11,3,"K3B (F4,D5)"],[12,0,"K0C (E6,D3)"],[12,1,"K1C (B7,D3)"],[12,3,"K3C (F4,D3)"],[12,4,"K4C (F5,D3)"],[13,0,"K0D (E6,D2)"],[13,1,"K1D (B7,D2)"],[13,2,"K2D (F7,D2)"],[13,3,"K3D (F4,D2)"],[13,4,"K4D (F5,D2)"],[14,0,"K0E (E6,D1)"],[15,0,"K0F (E6,D0)"],[15,1,"K1F (B7,D0)"],[15,2,"K2F (F7,D0)"],[15,3,"K3F (F4,D0)"],[15,4,"K4F (F5,D0)"]],"C41C:00A1":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[0,3,"K30"],[0,4,"K40"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[2,2,"K22"],[2,3,"K32"],[2,4,"K42"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K46"],[7,0,"K07"],[7,1,"K17"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[10,4,"K4A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,3,"K3C"],[12,4,"K4C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[13,4,"K4D"],[14,0,"K0E"],[14,1,"K1E"],[14,2,"K2E"],[14,3,"K3E"],[14,4,"K4E"]],"C6C6:6C6C":[],"C714:1010":[],"C81D:C868":[],"C88B:3388":[],"C88B:3988":[[0,0,"L01"],[0,1,"L06"],[0,2,"L11"],[0,3,"L16"],[0,4,"R01"],[0,5,"R06"],[0,6,"R11"],[0,7,"R16"],[1,0,"L02"],[1,1,"L07"],[1,2,"L12"],[1,3,"L17"],[1,4,"R02"],[1,5,"R07"],[1,6,"R12"],[1,7,"R17"],[2,0,"L03"],[2,1,"L08"],[2,2,"L13"],[2,4,"R03"],[2,5,"R08"],[2,6,"R13"],[3,0,"L04"],[3,1,"L09"],[3,2,"L14"],[3,4,"R04"],[3,5,"R09"],[3,6,"R14"],[4,0,"L05"],[4,1,"L10"],[4,2,"L15"],[4,4,"R05"],[4,5,"R10"],[4,6,"R15"]],"CA04:0001":[[0,0,"k11"],[0,1,"k21"],[0,2,"k31"],[0,3,"k41"],[0,4,"k51"],[1,0,"k12"],[1,1,"k22"],[1,2,"k32"],[1,3,"k42"],[1,4,"k52"],[2,0,"k13"],[2,1,"k23"],[2,2,"k33"],[2,3,"k43"],[3,0,"k14"],[3,1,"k24"],[3,2,"k34"],[3,3,"k44"],[4,0,"k15"],[4,1,"k25"],[4,2,"k35"],[4,3,"k45"],[5,0,"k16"],[5,1,"k26"],[5,2,"k36"],[5,3,"k46"],[6,0,"k17"],[6,1,"k27"],[6,2,"k37"],[6,3,"k47"],[6,4,"k57"],[7,0,"k18"],[7,3,"k48"],[7,4,"k58"],[7,6,"k78"],[7,7,"k88"],[8,5,"k69"],[8,6,"k79"],[8,7,"k89"],[8,8,"k99"],[8,9,"k109"],[9,5,"k610"],[9,6,"k710"],[9,7,"k810"],[9,8,"k910"],[9,9,"k1010"],[10,5,"k611"],[10,6,"k711"],[10,7,"k811"],[10,8,"k911"],[11,5,"k612"],[11,6,"k712"],[11,7,"k812"],[11,8,"k912"],[12,5,"k613"],[12,6,"k713"],[12,7,"k813"],[12,8,"k913"],[13,5,"k614"],[13,6,"k714"],[13,7,"k814"],[13,8,"k914"],[13,9,"k1014"],[14,5,"k615"],[14,6,"k715"],[14,7,"k815"],[14,8,"k915"],[14,9,"k1015"],[15,5,"k616"],[15,7,"k816"],[15,8,"k916"],[15,9,"k1016"]],"CA04:0002":[],"CA04:0003":[[0,0,"Play/Pause"],[0,1,"Mute"],[0,2,"Previous Track"],[0,3,"Next Track"],[1,0,"Esc"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"Shift"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"A"],[2,3,"\\"],[2,4,"GUI"],[3,0,"2"],[3,1,"W"],[3,2,"S"],[3,3,"Z"],[3,4,"Alt"],[4,0,"3"],[4,1,"E"],[4,2,"D"],[4,3,"X"],[5,0,"4"],[5,1,"R"],[5,2,"F"],[5,3,"C"],[6,0,"5"],[6,1,"T"],[6,2,"G"],[6,3,"V"],[6,4,"Space"],[7,0,"6"],[7,1,"Y"],[7,2,"H"],[7,3,"B"],[8,0,"7"],[8,1,"U"],[8,2,"J"],[8,3,"N"],[9,0,"8"],[9,1,"I"],[9,2,"K"],[9,3,"M"],[10,0,"9"],[10,1,"O"],[10,2,"L"],[10,3,","],[11,0,"0"],[11,1,"P"],[11,2,";"],[11,3,"."],[11,4,"Alt"],[12,0,"-"],[12,1,"["],[12,2,"'"],[12,3,"/"],[12,4,"Fn"],[13,0,"="],[13,1,"]"],[13,2,"#"],[13,3,"Shift"],[13,4,"GUI"],[14,0,"Backspace"],[15,0,"`"],[15,1,"\\"],[15,2,"Enter"],[15,3,"Fn"],[15,4,"Ctrl"],[16,0,"Insert"],[16,1,"Delete"],[16,4,"\u2190"],[17,0,"Home"],[17,1,"End"],[17,3,"\u2191"],[17,4,"\u2193"],[18,0,"Page Up"],[18,1,"Page Down"],[18,4,"\u2192"]],"CA04:0004":[],"CA04:0005":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"GUI"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Fn"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Space"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"Space"],[8,0,"I"],[8,1,"K"],[8,2,","],[8,3,"Alt"],[9,0,"O"],[9,1,"L"],[9,2,"."],[9,3,"GUI"],[10,0,"P"],[10,1,";"],[11,0,"["],[11,1,"'"],[11,2,"/"],[11,3,"Fn2"],[12,0,"]"],[12,2,"Shift"],[12,3,"\u2190"],[13,0,"Backspace"],[13,1,"Enter"],[13,2,"\u2191"],[13,3,"\u2193"],[14,0,"Page Up"],[14,1,"Page Down"],[14,2,"TG(3)"],[14,3,"\u2192"]],"CA04:0006":[[0,1,"Esc"],[0,2,"1"],[0,3,"`"],[0,4,"Q"],[0,5,"Tab"],[0,6,"A"],[0,7,"Caps Lock"],[0,8,"\\"],[0,9,"Shift"],[0,10,"GUI"],[0,11,"Ctrl"],[1,0,"F2"],[1,1,"F1"],[1,2,"3"],[1,3,"2"],[1,4,"E"],[1,5,"W"],[1,6,"D"],[1,7,"S"],[1,8,"X"],[1,9,"Z"],[1,11,"Alt"],[2,0,"F4"],[2,1,"F3"],[2,2,"5"],[2,3,"4"],[2,4,"T"],[2,5,"R"],[2,6,"G"],[2,7,"F"],[2,8,"V"],[2,9,"C"],[3,0,"F6"],[3,1,"F5"],[3,2,"7"],[3,3,"6"],[3,4,"U"],[3,5,"Y"],[3,6,"J"],[3,7,"H"],[3,8,"N"],[3,9,"B"],[3,11,"Space"],[4,0,"F8"],[4,1,"F7"],[4,2,"9"],[4,3,"8"],[4,4,"O"],[4,5,"I"],[4,6,"L"],[4,7,"K"],[4,8,","],[4,9,"M"],[5,0,"F10"],[5,1,"F9"],[5,2,"-"],[5,3,"0"],[5,4,"["],[5,5,"P"],[5,6,"'"],[5,7,";"],[5,8,"/"],[5,9,"."],[5,11,"Alt"],[6,0,"F12"],[6,1,"F11"],[6,2,"Backspace"],[6,3,"="],[6,4,"\\"],[6,5,"]"],[6,6,"Enter"],[6,7,"#"],[6,8,"Shift"],[6,10,"Ctrl"],[6,11,"GUI"],[7,0,"Scroll Lock"],[7,1,"Print Screen"],[7,2,"Home"],[7,3,"Insert"],[7,4,"End"],[7,5,"Delete"],[7,8,"\u2191"],[7,10,"\u2193"],[7,11,"\u2190"],[8,1,"Pause"],[8,3,"Page Up"],[8,5,"Page Down"],[8,11,"\u2192"]],"CA04:0007":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"#"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"GUI"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Play/Pause"],[14,1,"Delete"],[15,0,"Mute"],[15,1,"Insert"],[15,2,"Delete"],[15,3,"Page Up"],[15,4,"Page Down"],[15,5,"\u2192"]],"CA04:0008":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Fn"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"Delete"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"End"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"CA04:0009":[],"CA04:000A":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Alt"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"GUI"],[13,1,"Backspace"],[14,0,"Play/Pause"],[14,1,"Backspace"],[14,2,"\\"],[14,3,"Enter"],[14,4,"\u25bd"],[14,5,"Ctrl"],[15,0,"Print Screen"],[15,1,"Insert"],[15,2,"Delete"],[15,5,"\u2190"],[16,0,"Scroll Lock"],[16,1,"Home"],[16,2,"End"],[16,4,"\u2191"],[16,5,"\u2193"],[17,0,"Pause"],[17,1,"Page Up"],[17,2,"Page Down"],[17,5,"\u2192"]],"CA04:000B":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Alt"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,2,"Del"],[12,3,"Shift"],[12,4,"Fn"],[13,0,"Backspace"],[13,1,"|"],[13,2,"Enter"],[13,3,"Shift"],[13,4,"Ctrl"]],"CA04:000C":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Space"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"Backspace"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Ctrl"]],"CA04:000D":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"Backspace"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"Print Screen"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"\u2191"],[13,5,"\u2193"],[14,0,"Delete"],[14,1,"Num Lock"],[14,2,"7"],[14,3,"4"],[14,4,"1"],[14,5,"\u2192"],[15,0,"Insert"],[15,1,"/"],[15,2,"8"],[15,3,"5"],[15,4,"2"],[15,5,"0"],[16,0,"Page Up"],[16,1,"*"],[16,2,"9"],[16,3,"6"],[16,4,"3"],[16,5,"."],[17,0,"Page Down"],[17,1,"-"],[17,2,"+"],[17,3,"+"],[17,4,"Enter"],[17,5,"Enter"]],"CA04:000F":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Fn"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,2,"Delete"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Home"],[14,1,"End"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"CA04:0010":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Fn"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Ctrl"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"\u2190"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,3,"\u2191"],[13,4,"\u2193"],[14,0,"Insert"],[14,1,"Delete"],[14,2,"Page Up"],[14,3,"Page Down"],[14,4,"\u2192"]],"CA04:0011":[],"CA04:0012":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[14,0,"`"],[14,1,"\\"],[14,2,"Enter"],[14,3,"Fn"],[14,4,"Ctrl"],[15,0,"Insert"],[15,1,"Delete"],[15,4,"\u2190"],[16,0,"Home"],[16,1,"End"],[16,3,"\u2191"],[16,4,"\u2193"],[17,0,"Page Up"],[17,1,"Page Down"],[17,4,"\u2192"]],"CA04:0013":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Alt"],[12,0,"+"],[12,1,"}"],[12,3,"Shift"],[12,4,"Win"],[13,0,"Del"],[14,0,"Bksp"],[14,1,"|"],[14,2,"Enter"],[14,3,"Fn"],[14,4,"Menu"]],"CA04:0014":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[14,0,"Delete"],[14,1,"\\"],[14,2,"Enter"],[14,3,"Fn"],[14,4,"Ctrl"]],"CA04:0015":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"\\"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[14,0,"Delete"],[14,1,"\\"],[14,2,"Enter"],[14,3,"Fn"],[14,4,"Ctrl"]],"CA04:0016":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Alt"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[14,0,"Delete"],[14,1,"\\"],[14,2,"Enter"],[14,3,"Fn"],[14,4,"Ctrl"]],"CA04:0017":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"GUI"],[13,1,"Bksp"],[14,0,"F13"],[14,1,"Del"],[14,2,"\\"],[14,3,"Enter"],[14,4,"Fn"],[14,5,"Ctrl"],[15,0,"PrtSc"],[15,1,"Insert"],[15,2,"Delete"],[15,5,"\u2190"],[16,0,"Scroll Lock"],[16,1,"Home"],[16,2,"End"],[16,4,"\u2191"],[16,5,"\u2193"],[17,0,"Pause"],[17,1,"PgUp"],[17,2,"PgDn"],[17,5,"\u2192"]],"CA04:0018":[[0,0,"Tab"],[0,1,"Esc"],[0,2,"Shift"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Ctrl"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Super"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"⇓"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"⇑"],[8,0,"I"],[8,1,"K"],[8,2,","],[8,3,"←"],[9,0,"O"],[9,1,"L"],[9,2,"."],[9,3,"↓"],[10,0,"P"],[10,1,";"],[10,2,"/"],[10,3,"↑"],[11,0,"Back Space"],[11,1,"'"],[11,2,"Return"],[11,3,"→"]],"CA04:0019":[[0,0,"`"],[0,1,"Tab"],[0,2,"Esc"],[0,3,"Shift"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Ctrl"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Super"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Lower"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"N"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"M"],[7,4,"Raise"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,","],[8,4,"←"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"."],[9,4,"↓"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"/"],[10,4,"↑"],[11,0,"Del"],[11,1,"Back Space"],[11,2,"'"],[11,3,"Return"],[11,4,"→"]],"CA04:001B":[],"CA04:001C":[],"CA04:001D":[],"CA04:001E":[[0,0,"\u00ac"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"\""],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"\u00a3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"AltGr"],[11,0,"_"],[11,1,"{"],[11,2,"@"],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"}"],[12,2,"~"],[12,3,"Shift"],[12,4,"Menu"],[13,0,"Backspace"],[13,2,"Enter"],[13,4,"Ctrl"]],"CA04:001F":[[0,0,"\u00ac"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"|"],[1,4,"Win"],[2,0,"\""],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"\u00a3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"AltGr"],[11,0,"_"],[11,1,"{"],[11,2,"@"],[11,3,"?"],[11,4,"Ctrl"],[12,0,"+"],[12,1,"}"],[12,2,"~"],[12,3,"Shift"],[13,0,"Backspace"],[13,2,"Enter"],[14,0,"Home"],[14,1,"PgUp"],[14,2,"PgDn"],[14,3,"End"]],"CA04:0020":[],"CA04:0021":[],"CA04:0022":[],"CA04:0023":[],"CA04:0024":[],"CA04:0025":[],"CA04:0026":[],"CA04:0029":[],"CA04:0038":[],"CA04:0B75":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"#"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F5"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F6"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F7"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F8"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F9"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F10"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Ctrl"],[12,0,"F11"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"\u2190"],[13,0,"F12"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Enter"],[13,4,"\u2191"],[13,5,"\u2193"],[14,1,"Delete"],[15,0,"Delete"],[15,1,"Insert"],[15,2,"Delete"],[15,3,"Page Up"],[15,4,"Page Down"],[15,5,"\u2192"]],"CA04:1565":[],"CA04:1600":[],"CA04:2023":[],"CA04:2377":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"#"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Fn"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"\\"],[12,4,"Shift"],[12,5,"\u2190"],[13,1,"Backspace"],[14,0,"Print Screen"],[14,1,"Backspace"],[14,2,"\\"],[14,3,"Enter"],[14,4,"\u2191"],[14,5,"\u2193"],[15,0,"Delete"],[15,1,"Num Lock"],[15,2,"7"],[15,3,"4"],[15,4,"1"],[15,5,"\u2192"],[16,0,"Insert"],[16,1,"/"],[16,2,"8"],[16,3,"5"],[16,4,"2"],[16,5,"0"],[17,0,"Page Up"],[17,1,"*"],[17,2,"9"],[17,3,"6"],[17,4,"3"],[17,5,"."],[18,0,"Page Down"],[18,1,"-"],[18,2,"+"],[18,3,"+"],[18,4,"Enter"]],"CA04:4F48":[],"CA04:4F60":[],"CA04:5A65":[],"CA04:6060":[],"CA04:6565":[],"CA04:70F2":[],"CA04:A00C":[],"CA04:A7A5":[],"CA04:BA77":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,2,"#"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"\\"],[13,2,"Enter"],[13,4,"\u2190"],[14,0,"Delete"],[15,0,"Play/Pause"],[15,1,"Page Up"],[15,2,"Page Down"],[15,3,"\u2191"],[15,4,"\u2193"],[16,0,"Num Lock"],[16,1,"7"],[16,2,"4"],[16,3,"1"],[16,4,"\u2192"],[17,0,"/"],[17,1,"8"],[17,2,"5"],[17,3,"2"],[17,4,"0"],[18,0,"*"],[18,1,"9"],[18,2,"6"],[18,3,"3"],[18,4,"."],[19,0,"-"],[19,1,"+"],[19,2,"+"],[19,3,"Enter"],[19,4,"Enter"]],"CA04:C024":[],"CA04:DE57":[[0,0,"Esc"],[0,1,"`"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"1"],[1,2,"Q"],[1,3,"A"],[1,4,"\\"],[1,5,"GUI"],[2,0,"F2"],[2,1,"2"],[2,2,"W"],[2,3,"S"],[2,4,"Z"],[2,5,"Alt"],[3,0,"F3"],[3,1,"3"],[3,2,"E"],[3,3,"D"],[3,4,"X"],[4,0,"F4"],[4,1,"4"],[4,2,"R"],[4,3,"F"],[4,4,"C"],[5,0,"F5"],[5,1,"5"],[5,2,"T"],[5,3,"G"],[5,4,"V"],[6,0,"F6"],[6,1,"6"],[6,2,"Y"],[6,3,"H"],[6,4,"B"],[6,5,"Space"],[7,0,"F7"],[7,1,"7"],[7,2,"U"],[7,3,"J"],[7,4,"N"],[8,0,"F8"],[8,1,"8"],[8,2,"I"],[8,3,"K"],[8,4,"M"],[9,0,"F9"],[9,1,"9"],[9,2,"O"],[9,3,"L"],[9,4,","],[10,0,"F10"],[10,1,"0"],[10,2,"P"],[10,3,";"],[10,4,"."],[10,5,"Alt"],[11,0,"F11"],[11,1,"-"],[11,2,"["],[11,3,"'"],[11,4,"/"],[11,5,"Fn"],[12,0,"F12"],[12,1,"="],[12,2,"]"],[12,3,"#"],[12,4,"Shift"],[12,5,"GUI"],[13,1,"Backspace"],[14,0,"Play/Pause"],[14,1,"Backspace"],[14,2,"\\"],[14,3,"Enter"],[14,4,"\u25bd"],[14,5,"Ctrl"],[15,0,"Print Screen"],[15,1,"Insert"],[15,2,"Delete"],[15,5,"\u2190"],[16,0,"Scroll Lock"],[16,1,"Home"],[16,2,"End"],[16,4,"\u2191"],[16,5,"\u2193"],[17,0,"Pause"],[17,1,"Page Up"],[17,2,"Page Down"],[17,5,"\u2192"]],"CA17:CA39":[],"CAFE:0080":[],"CAFE:0FAD":[],"CB00:1337":[],"CB00:A455":[],"CB00:F09F":[],"CB10:0510":[],"CB10:1011":[],"CB10:1046":[],"CB10:1111":[],"CB10:1112":[],"CB10:1114":[],"CB10:111C":[],"CB10:1134":[],"CB10:113A":[],"CB10:1147":[],"CB10:1154":[],"CB10:1156":[],"CB10:1169":[],"CB10:1211":[],"CB10:1246":[],"CB10:1247":[],"CB10:1257":[],"CB10:125F":[],"CB10:1337":[],"CB10:1356":[],"CB10:136A":[],"CB10:144C":[],"CB10:1657":[[0,0,"F1"],[0,1,"F3"],[0,2,"F5"],[0,3,"F7"],[0,4,"F9"],[0,5,"7"],[0,6,"Y"],[0,7,"H"],[0,8,"N"],[1,0,"F2"],[1,1,"F4"],[1,2,"F6"],[1,3,"F8"],[1,4,"F10"],[1,5,"8"],[1,6,"U"],[1,7,"J"],[1,8,"M"],[1,9,"Space"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"Caps Lock"],[2,3,"Shift"],[2,4,"Ctrl"],[2,5,"9"],[2,6,"I"],[2,7,"K"],[2,8,","],[2,9,"Alt"],[3,0,"1"],[3,1,"Q"],[3,2,"A"],[3,4,"Win"],[3,5,"0"],[3,6,"O"],[3,7,"L"],[3,8,"."],[3,9,"Fn"],[4,0,"2"],[4,1,"W"],[4,2,"S"],[4,3,"Z"],[4,4,"Alt"],[4,5,"-"],[4,6,"P"],[4,7,":"],[4,8,"/"],[4,9,"Ctrl"],[5,0,"3"],[5,1,"E"],[5,2,"D"],[5,3,"X"],[5,4,"Fn"],[5,5,"="],[5,6,"{"],[5,7,"\""],[6,0,"4"],[6,1,"R"],[6,2,"F"],[6,3,"C"],[6,6,"}"],[6,8,"Shift"],[6,9,"Left"],[7,0,"5"],[7,1,"T"],[7,2,"G"],[7,3,"V"],[7,4,"Space"],[7,5,"Bksp"],[7,6,"|"],[7,7,"Enter"],[7,8,"Up"],[7,9,"Down"],[8,0,"6"],[8,3,"B"],[8,5,"Del"],[8,6,"Home"],[8,7,"PgUp"],[8,8,"PgDn"],[8,9,"Right"]],"CB10:2257":[],"CB10:3357":[],"CB10:4357":[],"CB10:5357":[],"CB10:6357":[],"CB3A:C12A":[],"CB3A:CC3A":[[0,0,"Mute"],[1,0,"Next"],[2,0,"Push"]],"CB3A:CC9A":[[0,0,"push_left"],[1,0,"push_right"],[2,0,"key_1"],[3,0,"key_2"],[4,0,"key_3"],[5,0,"key_4"],[6,0,"key_5"],[7,0,"key_6"]],"CBD0:C000":[],"CC3F:4705":[],"CCCD:BBBC":[],"CDCD:5337":[],"CDCD:5338":[],"CDCD:5339":[],"CEE2:0001":[],"CEE2:0002":[[0,0,"L00"],[0,1,"L10"],[0,2,"L20"],[0,3,"L30"],[0,4,"L40"],[0,5,"R00"],[0,6,"R10"],[0,7,"R20"],[0,8,"R30"],[0,9,"R40"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,3,"L31"],[1,5,"R01"],[1,6,"R11"],[1,7,"R21"],[1,8,"R31"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"L42"],[2,5,"R02"],[2,6,"R12"],[2,7,"R22"],[2,8,"R32"],[2,9,"R42"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,4,"L43"],[3,5,"R03"],[3,6,"R13"],[3,7,"R23"],[3,8,"R33"],[3,9,"R43"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,4,"L44"],[4,5,"R04"],[4,6,"R14"],[4,7,"R24"],[4,8,"R34"],[4,9,"R44"],[5,0,"L05"],[5,1,"L15"],[5,2,"L25"],[5,3,"L35"],[5,4,"L45"],[5,5,"R05"],[5,6,"R15"],[5,7,"R25"],[5,8,"R35"],[5,9,"R45"],[6,2,"L26"],[6,3,"L36"],[6,4,"L46"],[6,7,"R26"],[6,8,"R36"],[6,9,"R46"]],"CEE2:0003":[],"CEE2:0004":[],"CEE2:1001":[],"CEEB:0001":[],"CEEB:0007":[],"CEEB:0035":[],"CEEB:1256":[],"D00D:0020":[],"D00D:0021":[],"D00D:0022":[],"D00D:0031":[],"D010:0301":[[0,0,"1!"],[1,0,"2@"],[2,0,"3#"],[3,0,"Layers"],[4,0,"Encoder"]],"D010:0401":[[0,0,"1!"],[1,0,"2@"],[2,0,"3#"],[3,0,"4$"],[4,0,"Encoder"]],"D010:0901":[],"D010:1201":[],"D010:1601":[],"D010:1901":[],"D010:3001":[],"D010:3F01":[],"D143:0007":[],"D1F1:0100":[],"D5D0:992D":[],"D60D:3100":[],"D60D:3200":[],"D60D:4AD3":[],"D60D:4AD4":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"CapsLock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"K45"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"Fn1"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Fn2"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Ctrl"],[12,0,"+"],[12,1,"}"],[12,2,"#"],[12,3,"Shift"],[12,4,"Left"],[13,0,"Backspace"],[13,2,"Enter"],[13,3,"Up"],[13,4,"Down"],[14,0,"Delete"],[14,1,"Home"],[14,2,"PgUp"],[14,3,"PgDn"],[14,4,"Right"]],"D60D:6A1A":[],"D60D:7EC5":[],"D60D:7EC6":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"CapsLock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"Win"],[2,0,"@"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"$"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"%"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"K45"],[6,0,"^"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"&"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"*"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"("],[9,1,"O"],[9,2,"L"],[9,3,"<"],[9,4,"Alt"],[10,0,")"],[10,1,"P"],[10,2,":"],[10,3,">"],[10,4,"Fn1"],[11,0,"_"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[11,4,"Fn2"],[12,0,"+"],[12,1,"}"],[12,2,"#"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,2,"Enter"]],"D666:CAFE":[],"D772:000A":[],"D772:000B":[],"D772:000C":[],"D772:0012":[],"D772:0017":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Home"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Z"],[1,4,"Page Up"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"X"],[2,4,"Page Down"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"C"],[3,4,"Ctrl"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"V"],[4,4,"Alt"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"B"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Fn"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Alt"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"GUI"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Menu"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"Backspace"],[13,1,"\\"],[13,3,"Delete"],[13,4,"Delete"]],"D772:001A":[],"D812:0004":[],"D812:0007":[],"D812:0009":[],"D812:0010":[],"D812:0012":[],"D812:0013":[[0,0,"K00"],[0,1,"K10"],[0,2,"K20"],[1,0,"K01"],[1,1,"K11"],[1,2,"K21"],[1,3,"K31"],[1,4,"K41"],[2,0,"K02"],[2,1,"K12"],[3,0,"K03"],[3,1,"K13"],[3,2,"K23"],[3,3,"K33"],[4,0,"K04"],[4,1,"K14"],[4,2,"K24"],[4,3,"K34"],[4,4,"K44"],[5,0,"K05"],[5,1,"K15"],[5,2,"K25"],[5,3,"K35"],[5,4,"K45"],[6,0,"K06"],[6,1,"K16"],[6,2,"K26"],[6,3,"K36"],[6,4,"K46"],[7,0,"K07"],[7,2,"K27"],[7,3,"K37"],[8,0,"K08"],[8,1,"K18"],[8,2,"K28"],[8,3,"K38"],[8,4,"K48"],[9,0,"K09"],[9,1,"K19"],[9,2,"K29"],[9,3,"K39"],[10,0,"K0A"],[10,1,"K1A"],[10,2,"K2A"],[10,3,"K3A"],[11,0,"K0B"],[11,1,"K1B"],[11,2,"K2B"],[11,3,"K3B"],[11,4,"K4B"],[12,0,"K0C"],[12,1,"K1C"],[12,2,"K2C"],[12,3,"K3C"],[13,0,"K0D"],[13,1,"K1D"],[13,2,"K2D"],[13,3,"K3D"],[14,0,"K0E"],[14,1,"K1E"],[14,3,"K3E"],[14,4,"K4E"],[15,0,"K0F"],[15,1,"K1F"],[15,2,"K2F"],[15,3,"K3F"]],"D812:0014":[],"D812:0015":[],"D812:0024":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"GUI"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[3,4,"Alt"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Space"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[9,4,"Space"],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Menu"],[12,0,"="],[12,1,"]"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"GUI"],[13,0,"Backspace"],[13,1,"Backspace"],[13,2,"\\"],[13,3,"Shift"],[13,4,"Ctrl"]],"D812:0025":[],"DA12:6060":[],"DA74:7461":[],"DC9E:12ED":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[0,5,"5,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[1,5,"5,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[2,5,"5,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[3,5,"5,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[4,5,"5,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[5,5,"5,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[6,5,"5,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[7,5,"5,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[8,5,"5,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[9,5,"5,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[10,5,"5,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[11,5,"5,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[12,4,"4,12"],[12,5,"5,12"],[13,0,"0,13"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[13,5,"5,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"2,14"],[14,3,"3,14"],[14,4,"4,14"],[14,5,"5,14"]],"DC9E:177A":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,4,"4,0"],[0,5,"5,0"],[0,6,"6,0"],[1,0,"0,1"],[1,1,"1,1"],[1,2,"2,1"],[1,3,"3,1"],[1,4,"4,1"],[1,5,"5,1"],[1,6,"6,1"],[1,7,"7,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[2,5,"5,2"],[2,6,"6,2"],[2,7,"7,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[3,5,"5,3"],[3,6,"6,3"],[3,7,"7,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[4,5,"5,4"],[4,6,"6,4"],[4,7,"7,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,4,"4,5"],[5,5,"5,5"],[5,6,"6,5"]],"DE00:0F70":[],"DE17:0000":[],"DE17:60F0":[],"DE17:80F1":[],"DE29:7325":[],"DE29:7342":[],"DE43:1034":[[0,0,"`"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"!"],[1,3,"\\"],[1,4,"Win"],[2,0,"@"],[2,1,"Q"],[2,2,"A"],[2,3,"Z"],[2,4,"Alt"],[3,0,"#"],[3,1,"W"],[3,2,"S"],[3,3,"X"],[4,0,"$"],[4,1,"E"],[4,2,"D"],[4,3,"C"],[5,0,"%"],[5,1,"R"],[5,2,"F"],[5,3,"V"],[6,0,"^"],[6,1,"T"],[6,2,"G"],[6,3,"B"],[6,4,"Space"],[7,0,"&"],[7,1,"Y"],[7,2,"H"],[7,3,"N"],[8,0,"*"],[8,1,"U"],[8,2,"J"],[8,3,"M"],[9,0,"("],[9,1,"I"],[9,2,"K"],[9,3,"<"],[10,0,")"],[10,1,"O"],[10,2,"L"],[10,3,">"],[10,4,"AltGr"],[11,0,"_"],[11,1,"P"],[11,2,":"],[11,3,"?"],[11,4,"Win"],[12,0,"+"],[12,1,"{"],[12,2,"@"],[13,0,"Del"],[13,1,"}"],[13,2,"ISO"],[13,3,"Shift"],[13,4,"\u2190"],[14,0,"Bsp"],[14,1,"|"],[14,2,"Enter"],[14,3,"\u2191"],[14,4,"\u2193"],[15,4,"\u2192"],[16,1,"PgUp"],[16,2,"Home"],[16,3,"End"]],"DE43:1284":[],"DEAD:6585":[],"DEAF:0913":[],"DEB4:60EB":[],"DEED:0001":[],"E015:C386":[],"E015:C387":[],"E061:E66E":[],"E0E0:0030":[],"E117:6161":[],"E230:1337":[],"E230:2B74":[],"E5CA:0401":[],"E720:0001":[],"E739:A100":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[0,5,"5,0"],[1,1,"1,1"],[1,4,"4,1"],[1,5,"5,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[2,4,"4,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[3,5,"5,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[4,4,"4,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[5,4,"4,5"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[6,5,"5,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[7,4,"4,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[8,4,"4,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[9,4,"4,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[10,5,"5,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[11,5,"5,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[12,3,"3,12"],[13,0,"0,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[13,5,"5,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"3,14"],[14,5,"5,14"],[15,0,"0,15"],[15,1,"1,15"],[15,2,"2,15"],[15,5,"5,15"],[16,0,"0,16"],[16,1,"1,16"],[16,2,"2,16"],[16,4,"4,16"],[16,5,"5,16"],[17,0,"0,17"],[17,1,"1,17"],[17,2,"2,17"],[17,5,"5,17"]],"E739:A279":[],"E739:A300":[[0,0,"F13"],[0,1,"F17"],[0,2,"F21"],[1,0,"F14"],[1,1,"F18"],[1,2,"F22"],[2,0,"F15"],[2,1,"F19"],[2,2,"F23"],[3,0,"F16"],[3,1,"F20"],[3,2,"F24"]],"E739:A400":[[0,0,"0,0"],[0,1,"1,0"],[0,2,"2,0"],[0,3,"3,0"],[0,4,"4,0"],[1,0,"0,1"],[1,3,"3,1"],[1,4,"4,1"],[2,0,"0,2"],[2,1,"1,2"],[2,2,"2,2"],[2,3,"3,2"],[3,0,"0,3"],[3,1,"1,3"],[3,2,"2,3"],[3,3,"3,3"],[3,4,"4,3"],[4,0,"0,4"],[4,1,"1,4"],[4,2,"2,4"],[4,3,"3,4"],[5,0,"0,5"],[5,1,"1,5"],[5,2,"2,5"],[5,3,"3,5"],[6,0,"0,6"],[6,1,"1,6"],[6,2,"2,6"],[6,3,"3,6"],[6,4,"4,6"],[7,0,"0,7"],[7,1,"1,7"],[7,2,"2,7"],[7,3,"3,7"],[8,0,"0,8"],[8,1,"1,8"],[8,2,"2,8"],[8,3,"3,8"],[9,0,"0,9"],[9,1,"1,9"],[9,2,"2,9"],[9,3,"3,9"],[10,0,"0,10"],[10,1,"1,10"],[10,2,"2,10"],[10,3,"3,10"],[10,4,"4,10"],[11,0,"0,11"],[11,1,"1,11"],[11,2,"2,11"],[11,3,"3,11"],[11,4,"4,11"],[12,0,"0,12"],[12,1,"1,12"],[12,2,"2,12"],[13,1,"1,13"],[13,2,"2,13"],[13,3,"3,13"],[13,4,"4,13"],[14,0,"0,14"],[14,1,"1,14"],[14,2,"Enter"],[14,4,"4,14"]],"E739:A500":[[0,0,"Esc"],[0,1,"\u00ac"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,1,"!"],[1,4,"|"],[1,5,"Win"],[2,0,"F1"],[2,1,"\""],[2,2,"Q"],[2,3,"A"],[2,4,"Z"],[3,0,"F2"],[3,1,"\u00a3"],[3,2,"W"],[3,3,"S"],[3,4,"X"],[3,5,"Alt"],[4,0,"F3"],[4,1,"$"],[4,2,"E"],[4,3,"D"],[4,4,"C"],[5,0,"F4"],[5,1,"%"],[5,2,"R"],[5,3,"F"],[5,4,"V"],[6,1,"^"],[6,2,"T"],[6,3,"G"],[6,4,"B"],[6,5,"Space"],[7,0,"F5"],[7,1,"&"],[7,2,"Y"],[7,3,"H"],[7,4,"N"],[8,0,"F6"],[8,1,"*"],[8,2,"U"],[8,3,"J"],[8,4,"M"],[9,0,"F7"],[9,1,"("],[9,2,"I"],[9,3,"K"],[9,4,"<"],[10,0,"F8"],[10,1,")"],[10,2,"O"],[10,3,"L"],[10,4,">"],[10,5,"AltGr"],[11,0,"F9"],[11,1,"_"],[11,2,"P"],[11,3,":"],[11,4,"?"],[11,5,"Win"],[12,0,"F10"],[12,1,"+"],[12,2,"{"],[12,3,"@"],[13,0,"F11"],[13,2,"}"],[13,3,"~"],[13,4,"Shift"],[13,5,"Menu"],[14,0,"F12"],[14,1,"Backspace"],[14,2,"|"],[14,3,"Enter"],[14,5,"Ctrl"],[15,0,"PrtSc"],[15,1,"Insert"],[15,2,"Delete"],[15,5,"\u2190"],[16,0,"Scroll Lock"],[16,1,"Home"],[16,2,"End"],[16,4,"\u2191"],[16,5,"\u2193"],[17,0,"Pause"],[17,1,"PgUp"],[17,2,"PgDn"],[17,5,"\u2192"]],"EA0B:EA75":[],"EB50:EB52":[],"EB69:3700":[],"EB69:6001":[],"EB69:6003":[],"EB69:6005":[],"EB69:6006":[],"EB69:6008":[],"EB69:6009":[],"EB69:6501":[],"EB69:9001":[],"ECED:3663":[],"EDED:0065":[],"EDED:0068":[],"EDED:0080":[],"EDED:0081":[],"EDED:6060":[],"EDED:6063":[],"EDED:6064":[],"EDED:6570":[],"EDED:7075":[],"EDED:ED61":[],"EEEE:2019":[],"F00D:0000":[],"F048:F048":[[0,0,"ESC"],[0,1,"Q"],[0,2,"TAB"],[0,3,"A"],[0,4,"LSFT"],[0,5,"Z"],[0,6,"CAPS"],[0,7,"LCTL"],[1,0,"W"],[1,1,"E"],[1,2,"S"],[1,3,"D"],[1,4,"X"],[1,5,"C"],[1,6,"LGUI"],[1,7,"LALT"],[2,0,"R"],[2,1,"T"],[2,2,"Y"],[2,3,"F"],[2,4,"G"],[2,5,"V"],[2,6,"B"],[2,7,"SPC"],[3,0,"U"],[3,1,"I"],[3,2,"H"],[3,3,"J"],[3,4,"N"],[3,5,"M"],[3,6,"SPC"],[3,7,"DEL"],[4,0,"O"],[4,1,"P"],[4,2,"K"],[4,3,"L"],[4,4,"COMM"],[4,5,"DOT"],[4,6,"LEFT"],[4,7,"UP"],[5,0,"MINS"],[5,1,"BSPC"],[5,2,"SCLN"],[5,3,"ENT"],[5,4,"SLSH"],[5,5,"RSFT"],[5,6,"DOWN"],[5,7,"RGHT"]],"F100:7EEE":[],"F100:91CE":[],"F100:AD78":[],"F1F1:0025":[],"F1F1:0315":[],"F21E:6E6E":[],"F2E7:1226":[],"F35B:FAB0":[],"F35B:FAB1":[],"F35B:FAB5":[],"F35B:FAB6":[[0,0,"Esc"],[0,1,"Encoder"],[0,2,"F2"],[0,3,"F4"],[0,4,"F6"],[1,0,"\u2298"],[1,1,"Tab"],[1,2,"Caps Lock"],[1,3,"F3"],[1,4,"Ctrl"],[2,0,"1"],[2,1,"Q"],[2,2,"F1"],[2,3,"Shift"],[2,4,"GUI"],[3,0,"2"],[3,1,"W"],[3,2,"A"],[3,3,"Z"],[3,4,"F5"],[4,0,"3"],[4,1,"E"],[4,2,"S"],[4,3,"X"],[4,4,"Alt"],[5,0,"4"],[5,1,"R"],[5,2,"D"],[5,3,"C"],[6,0,"5"],[6,1,"T"],[6,2,"F"],[6,3,"V"],[7,0,"6"],[7,1,"Y"],[7,2,"G"],[7,3,"B"],[7,4,"Space"],[8,0,"7"],[8,1,"U"],[8,2,"H"],[8,3,"N"],[9,0,"8"],[9,1,"I"],[9,2,"J"],[9,3,"M"],[10,0,"9"],[10,1,"O"],[10,2,"K"],[10,3,","],[10,4,"Alt"],[11,0,"0"],[11,1,"P"],[11,2,"L"],[11,3,"."],[11,4,"Ctrl"],[12,0,"-"],[12,1,"["],[12,2,";"],[12,3,"/"],[13,0,"="],[13,1,"]"],[13,2,"'"],[13,3,"Shift"],[13,4,"Left"],[14,0,"Backspace"],[14,1,"\\"],[14,2,"Enter"],[14,3,"Up"],[14,4,"Down"],[15,0,"Delete"],[15,1,"PgUp"],[15,2,"PgDn"],[15,3,"End"],[15,4,"Right"]],"F35B:FAB8":[[0,0,"F9"],[0,1,"PrtScr"],[0,2,"F5"],[0,3,"Caps Lock"],[1,0,"7"],[1,1,"1"],[1,2,"Tab"],[1,3,"L Alt"],[1,4,"L Shift"],[1,5,"L Ctrl Duck"],[2,0,"8"],[2,1,"2"],[2,2,"Q"],[2,3,"A"],[2,4,"Z"],[3,0,"9"],[3,1,"3"],[3,2,"4"],[3,3,"W"],[3,4,"S"],[3,5,"X"],[4,0,"0"],[4,1,"5"],[4,2,"E"],[4,3,"D"],[5,0,"-"],[5,1,"6"],[5,2,"R"],[5,3,"F"],[5,4,"V"],[5,5,"C"],[6,0,"T"],[6,1,"G"],[6,2,"B"],[6,3,"P"],[6,4,"Space"],[6,5,"L Ctrl"]],"F35B:FAB9":[[0,0,"F9"],[0,1,"PrtScr"],[0,2,"F5"],[0,3,"Caps Lock"],[1,0,"7"],[1,1,"1"],[1,2,"Tab"],[1,3,"L Alt"],[1,4,"L Shift"],[1,5,"L Ctrl Duck"],[2,0,"8"],[2,1,"2"],[2,2,"Q"],[2,3,"A"],[2,4,"Z"],[3,0,"9"],[3,1,"3"],[3,2,"4"],[3,3,"W"],[3,4,"S"],[3,5,"X"],[4,0,"0"],[4,1,"5"],[4,2,"E"],[4,3,"D"],[5,0,"-"],[5,1,"6"],[5,2,"R"],[5,3,"F"],[5,4,"V"],[5,5,"C"],[6,0,"T"],[6,1,"G"],[6,2,"B"],[6,3,"P"],[6,4,"Space"],[6,5,"L Ctrl"]],"F35B:FABA":[],"F35B:FABB":[],"F7E0:0412":[],"F7E0:2401":[],"F7E0:2408":[],"F8E8:0002":[],"F8E8:0004":[],"F901:F902":[[0,0,"L00"],[0,1,"L10"],[0,2,"L20"],[0,3,"L30"],[0,4,"L40"],[0,5,"R06"],[0,6,"R16"],[0,7,"R26"],[0,8,"R36"],[0,9,"R46"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,3,"L31"],[1,4,"L41"],[1,5,"R05"],[1,6,"R15"],[1,7,"R25"],[1,8,"R35"],[1,9,"R45"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"L42"],[2,5,"R04"],[2,6,"R14"],[2,7,"R24"],[2,8,"R34"],[2,9,"R44"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,4,"L43"],[3,5,"R03"],[3,6,"R13"],[3,7,"R23"],[3,8,"R33"],[3,9,"R43"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,4,"L44"],[4,5,"R02"],[4,6,"R12"],[4,7,"R22"],[4,8,"R32"],[4,9,"R42"],[5,0,"L05"],[5,1,"L15"],[5,2,"L25"],[5,3,"L35"],[5,4,"L45"],[5,5,"R01"],[5,6,"R11"],[5,7,"R21"],[5,8,"R31"],[5,9,"R41"],[6,0,"L06"],[6,1,"L16"],[6,2,"L26"],[6,3,"L36"],[6,4,"L46"],[6,5,"R00"],[6,6,"R10"],[6,7,"R20"],[6,8,"R30"],[6,9,"R40"]],"F984:B5E8":[],"F984:B5E9":[],"FA7E:0000":[],"FA9D:5F10":[],"FAAD:422D":[],"FABE:0117":[],"FACE:000A":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"split"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"Shift"],[1,4,"Win"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Alt"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[7,4,"Win"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Ctrl"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,"<"],[10,0,"0"],[10,1,"P"],[10,2,":"],[10,3,">"],[11,0,"-"],[11,1,"{"],[11,2,"\""],[11,3,"?"],[12,0,"+"],[12,1,"}"],[12,2,"Enter"],[12,3,"Shift"],[12,4,"left"],[13,0,"backspace"],[13,1,"Bksp"],[13,2,"pgup"],[13,3,"Up"],[13,4,"down"],[14,0,"split"],[14,1,"pgup"],[14,2,"rotary"],[14,3,"pgup"],[14,4,"right"]],"FB30:26BE":[],"FB30:5F37":[],"FB9C:3F42":[],"FB9C:4D1B":[],"FB9C:6D8A":[],"FB9C:74B6":[],"FB9C:B260":[],"FB9C:B265":[],"FBFB:0050":[],"FC51:0059":[],"FEAE:8844":[],"FEAE:8846":[],"FEAE:8858":[],"FEAE:8870":[],"FEAE:8947":[],"FEDE:6942":[],"FEEB:6060":[],"FEED:0000":[],"FEED:0001":[],"FEED:0002":[],"FEED:0003":[],"FEED:0007":[],"FEED:0016":[],"FEED:0018":[],"FEED:001C":[],"FEED:0024":[],"FEED:002A":[],"FEED:002B":[],"FEED:0037":[[0,0,"k00"],[0,1,"k10"],[1,0,"k01"],[1,1,"k11"],[2,0,"k02"],[2,1,"k12"]],"FEED:0053":[],"FEED:0057":[],"FEED:005B":[],"FEED:0101":[[0,0,"Esc"],[0,1,"F10"],[0,2,"\u00ac"],[0,3,")"],[0,4,"Tab"],[0,5,"P"],[0,6,"Caps Lock"],[0,7,":"],[0,8,"Shift"],[0,9,">"],[0,10,"Ctrl"],[0,11,"AltGr "],[1,0,"F1"],[1,1,"F11"],[1,2,"!"],[1,3,"_"],[1,4,"Q"],[1,5,"{"],[1,6,"A"],[1,7,"@"],[1,8,"|"],[1,9,"?"],[1,10,"Win"],[1,11,"Win"],[2,0,"F2"],[2,1,"F12"],[2,2,"\""],[2,3,"+"],[2,4,"W"],[2,5,"}"],[2,6,"S"],[2,7,"~"],[2,8,"Z"],[2,9,"Shift"],[2,10,"Alt"],[2,11,"Menu"],[3,0,"F3"],[3,1,"PrtSc"],[3,2,"\u00a3"],[3,3,"Backspace"],[3,4,"E"],[3,5,"|"],[3,6,"D"],[3,7,"Enter"],[3,8,"X"],[3,9,"|"],[3,11,"Ctrl"],[4,0,"F4"],[4,1,"Scroll Lock"],[4,2,"$"],[4,3,"Insert"],[4,4,"R"],[4,5,"Delete"],[4,6,"F"],[4,8,"C"],[4,9,"\u2191"],[4,11,"\u2190"],[5,0,"F5"],[5,1,"Pause"],[5,2,"%"],[5,3,"Home"],[5,4,"T"],[5,5,"End"],[5,6,"G"],[5,8,"V"],[5,11,"\u2193"],[6,0,"F6"],[6,2,"^"],[6,3,"PgUp"],[6,4,"Y"],[6,5,"PgDn"],[6,6,"H"],[6,7,"4"],[6,8,"B"],[6,9,"1"],[6,11,"\u2192"],[7,0,"F7"],[7,2,"&"],[7,3,"Num Lock"],[7,4,"U"],[7,5,"7"],[7,6,"J"],[7,7,"5"],[7,8,"N"],[7,9,"2"],[7,11,"0"],[8,0,"F8"],[8,1,"+"],[8,2,"*"],[8,3,"/"],[8,4,"I"],[8,5,"8"],[8,6,"K"],[8,7,"6"],[8,8,"M"],[8,9,"3"],[8,11,"."],[9,0,"F9"],[9,1,"-"],[9,2,"("],[9,3,"*"],[9,4,"O"],[9,5,"9"],[9,6,"L"],[9,7,"="],[9,8,"<"],[9,9,"Enter"]],"FEED:0110":[],"FEED:0123":[],"FEED:0140":[],"FEED:0204":[],"FEED:0240":[[0,0,"Esc"],[0,1,"Caps"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Win"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Menu"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"Space"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Space"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[8,0,"I"],[8,1,"K"],[8,2,",<"],[8,3,"Left"],[9,0,"O"],[9,1,"L"],[9,2,".>"],[9,3,"Up"],[10,0,"P"],[10,1,";:"],[10,2,"/?"],[10,3,"Down"],[11,0,"BS"],[11,1,"Enter"],[11,2,"RShift"],[11,3,"Right"]],"FEED:0257":[],"FEED:02F7":[[0,0,"L01"],[0,1,"L07"],[0,2,"L13"],[0,3,"L27"],[0,5,"R01"],[0,6,"R07"],[0,7,"R13"],[0,8,"R27"],[1,0,"L02"],[1,1,"L08"],[1,2,"L14"],[1,5,"R02"],[1,6,"R08"],[1,7,"R14"],[2,0,"L03"],[2,1,"L09"],[2,2,"L15"],[2,3,"L19"],[2,4,"L23"],[2,5,"R03"],[2,6,"R09"],[2,7,"R15"],[2,8,"R19"],[2,9,"R23"],[3,0,"L04"],[3,1,"L10"],[3,2,"L16"],[3,3,"L20"],[3,4,"L24"],[3,5,"R04"],[3,6,"R10"],[3,7,"R16"],[3,8,"R20"],[3,9,"R24"],[4,0,"L05"],[4,1,"L11"],[4,2,"L17"],[4,3,"L21"],[4,4,"L25"],[4,5,"R05"],[4,6,"R11"],[4,7,"R17"],[4,8,"R21"],[4,9,"R25"],[5,0,"L06"],[5,1,"L12"],[5,2,"L18"],[5,3,"L22"],[5,4,"L26"],[5,5,"R06"],[5,6,"R12"],[5,7,"R18"],[5,8,"R22"],[5,9,"R26"]],"FEED:0302":[[0,0,"K63"],[0,1,"K64"],[0,2,"K65"],[0,3,"K42"],[0,4,"K56"],[1,0,"K00"],[1,1,"K15"],[1,2,"K29"],[1,3,"K43"],[2,0,"K01"],[2,1,"K16"],[2,2,"K30"],[2,3,"K44"],[2,4,"K57"],[3,0,"K02"],[3,1,"K17"],[3,2,"K31"],[3,3,"K45"],[3,4,"K58"],[4,0,"K03"],[4,1,"K18"],[4,2,"K32"],[4,3,"K46"],[4,4,"K59"],[5,0,"K04"],[5,1,"K19"],[5,2,"K33"],[5,3,"K47"],[6,0,"K05"],[6,1,"K20"],[6,2,"K34"],[7,0,"K06"],[7,1,"K21"],[7,2,"K35"],[7,3,"K48"],[7,4,"K60"],[8,0,"K07"],[8,1,"K22"],[8,2,"K36"],[8,3,"K49"],[9,0,"K08"],[9,1,"K23"],[9,2,"K37"],[9,3,"K50"],[10,0,"K09"],[10,1,"K24"],[10,2,"K38"],[10,3,"K51"],[10,4,"K61"],[11,0,"K10"],[11,1,"K25"],[11,2,"K39"],[11,3,"K52"],[12,0,"K11"],[12,1,"K26"],[12,2,"K40"],[12,3,"K53"],[13,0,"K12"],[13,1,"K27"],[13,3,"K54"],[14,0,"K13"],[14,1,"K28"],[14,2,"K41"],[14,3,"K55"],[14,4,"K62"],[15,0,"K14"]],"FEED:0348":[],"FEED:0495":[],"FEED:04EF":[],"FEED:0666":[],"FEED:0690":[],"FEED:0805":[],"FEED:0841":[],"FEED:0842":[],"FEED:0844":[],"FEED:09F5":[],"FEED:0A01":[],"FEED:0A0C":[],"FEED:0A64":[],"FEED:0ADB":[],"FEED:0B7F":[],"FEED:0B91":[],"FEED:0BEE":[],"FEED:0C60":[],"FEED:0C61":[],"FEED:0F34":[],"FEED:0F42":[],"FEED:1001":[],"FEED:1010":[],"FEED:112D":[],"FEED:1191":[],"FEED:1192":[],"FEED:1202":[],"FEED:1212":[],"FEED:1224":[],"FEED:1234":[],"FEED:1256":[],"FEED:1257":[],"FEED:1302":[],"FEED:1307":[],"FEED:1308":[],"FEED:1319":[],"FEED:1337":[],"FEED:13DE":[],"FEED:1475":[],"FEED:14BC":[],"FEED:1701":[],"FEED:17B9":[],"FEED:1800":[],"FEED:1805":[],"FEED:1895":[],"FEED:1960":[],"FEED:1A1B":[],"FEED:1A7C":[[0,0,"Q"],[0,1,"A"],[0,3,"Z"],[0,5,"Tab"],[1,0,"W"],[1,1,"S"],[1,3,"X"],[1,5,"Alt"],[2,0,"E"],[2,1,"D"],[2,3,"C"],[2,5,"Ctrl"],[3,0,"R"],[3,1,"F"],[3,3,"V"],[3,5,"Raise"],[4,0,"T"],[4,1,"G"],[4,3,"B"],[4,4,"GUI"],[5,0,"Y"],[5,2,"H"],[5,3,"Esc"],[5,4,"N"],[5,5,"Bksp"],[6,0,"U"],[6,2,"J"],[6,4,"M"],[6,5,"Shift"],[7,0,"I"],[7,2,"K"],[7,4,","],[7,5,"Lower"],[8,0,"O"],[8,2,"L"],[8,4,"."],[8,5,"Delete"],[9,0,"P"],[9,2,";"],[9,4,"/"],[9,5,"Enter"]],"FEED:1A7D":[[0,0,"Q"],[0,2,"A"],[0,3,"Z"],[1,0,"W"],[1,2,"S"],[1,3,"X"],[2,0,"E"],[2,2,"D"],[2,3,"C"],[2,4,"Ctrl"],[3,0,"R"],[3,2,"F"],[3,3,"V"],[3,4,"Lower"],[4,0,"T"],[4,2,"G"],[4,3,"B"],[5,1,"Y"],[5,2,"H"],[5,3,"N"],[5,4,"Bksp"],[6,1,"U"],[6,2,"J"],[6,3,"M"],[6,4,"Shift"],[7,1,"I"],[7,2,"K"],[7,3,","],[7,4,"Raise"],[8,1,"O"],[8,2,"L"],[8,3,"."],[9,1,"P"],[9,2,";"],[9,3,"Enter"]],"FEED:1A81":[],"FEED:1B1E":[],"FEED:2001":[],"FEED:2004":[],"FEED:2020":[],"FEED:2137":[],"FEED:2171":[],"FEED:2222":[],"FEED:2320":[[0,0,"D3"],[0,1,"D2"],[0,2,"D1"],[0,3,"D0"],[0,4,"D4"],[0,5,"C6"],[0,6,"D7"],[0,7,"E6"],[0,8,"B4"],[0,9,"B5"],[1,2,"F4"],[1,3,"F5"],[1,4,"F6"],[1,5,"F7"],[1,6,"B1"],[1,7,"B3"],[1,8,"B2"],[1,9,"B6"]],"FEED:2321":[[0,0,"A9"],[0,1,"A10"],[0,2,"B7"],[0,3,"B6"],[0,4,"B5"],[0,5,"B4"],[0,6,"B3"],[0,7,"B2"],[0,8,"B1"],[0,9,"B0"],[0,10,"A4"],[0,11,"A5"],[0,12,"A6"],[0,13,"A7"],[0,14,"A8"],[0,15,"A15"],[1,2,"A2"],[1,3,"A1"],[1,4,"A0"],[1,5,"B8"],[1,6,"B13"],[1,7,"B14"],[1,8,"B15"],[1,9,"B9"],[1,10,"B10"],[1,11,"B11"],[1,12,"B12"],[1,13,"A14"],[1,14,"A13"]],"FEED:2322":[[0,0,"B0"],[0,1,"B1"],[0,2,"B2"],[0,3,"B3"],[0,4,"B7"],[0,5,"D0"],[0,6,"D1"],[0,7,"D2"],[0,8,"D3"],[0,9,"C6"],[0,10,"C7"],[0,11,"D5"],[1,0,"F0"],[1,1,"F1"],[1,2,"F4"],[1,3,"F5"],[1,4,"F6"],[1,5,"F7"],[1,6,"B6"],[1,7,"B5"],[1,8,"B4"],[1,9,"D7"],[1,10,"D6"],[1,11,"D4"]],"FEED:2323":[[0,0,"B7"],[0,1,"D0"],[0,2,"D1"],[0,3,"D2"],[0,4,"D3"],[0,5,"D4"],[0,6,"D5"],[0,7,"D6"],[0,8,"D7"],[0,9,"E0"],[0,10,"E1"],[0,11,"C0"],[0,12,"C1"],[0,13,"C2"],[0,14,"C3"],[0,15,"C4"],[0,16,"C5"],[0,17,"C6"],[0,18,"C7"],[1,5,"E5"],[1,12,"A4"],[1,13,"A5"],[1,14,"A6"],[1,15,"A7"],[2,5,"E4"],[2,12,"A0"],[2,13,"A1"],[2,14,"A2"],[2,15,"A3"],[3,0,"B6"],[3,1,"B5"],[3,2,"B4"],[3,3,"B3"],[3,4,"B2"],[3,5,"B1"],[3,6,"B0"],[3,7,"E7"],[3,8,"E6"],[3,11,"F0"],[3,12,"F1"],[3,13,"F2"],[3,14,"F3"],[3,15,"F4"],[3,16,"F5"],[3,17,"F6"],[3,18,"F7"]],"FEED:2324":[[0,0,"0"],[0,1,"1"],[0,2,"2"],[0,3,"3"],[0,4,"4"],[0,5,"5"],[0,6,"6"],[0,7,"7"],[0,8,"8"],[0,9,"9"],[0,10,"10"],[0,11,"11"],[0,12,"12"],[1,3,"24"],[1,4,"25"],[1,12,"26"],[2,2,"23"],[2,3,"22"],[2,4,"21"],[2,5,"20"],[2,6,"19"],[2,7,"18"],[2,8,"17"],[2,9,"16"],[2,10,"15"],[2,11,"14"],[2,12,"13"]],"FEED:2325":[[0,0,"0"],[0,1,"1"],[0,2,"2"],[0,3,"3"],[0,4,"4"],[0,5,"5"],[0,6,"6"],[0,7,"7"],[0,8,"8"],[0,9,"9"],[0,10,"10"],[0,11,"11"],[0,12,"12"],[1,3,"24"],[1,4,"25"],[1,12,"26"],[2,2,"23"],[2,3,"22"],[2,4,"21"],[2,5,"20"],[2,6,"19"],[2,7,"18"],[2,8,"17"],[2,9,"16"],[2,10,"15"],[2,11,"14"],[2,12,"13"]],"FEED:2326":[],"FEED:23B0":[],"FEED:25E3":[],"FEED:2626":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"LAlt"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"LGui"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Space"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[5,3,"Space"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"Space"],[8,0,"I"],[8,1,"K"],[8,2,","],[8,3,"RGui"],[9,0,"O"],[9,1,"L"],[9,2,"."],[9,3,"RAlt"],[10,0,"P"],[10,1,";"],[10,2,"/"],[11,0,"-"],[11,1,"'"],[11,2,"Shift"],[11,3,"RCtrl"],[12,0,"Bksp"],[12,1,"Enter"]],"FEED:2718":[],"FEED:27DB":[[0,0,"k00"]],"FEED:2B29":[],"FEED:2B2B":[],"FEED:2BE5":[],"FEED:3000":[],"FEED:3060":[],"FEED:3061":[],"FEED:3070":[],"FEED:3333":[],"FEED:3404":[],"FEED:350C":[],"FEED:3521":[],"FEED:3708":[],"FEED:3939":[],"FEED:3941":[],"FEED:3942":[],"FEED:3B47":[],"FEED:3E01":[],"FEED:3EAE":[],"FEED:4024":[],"FEED:4040":[],"FEED:4084":[],"FEED:4096":[],"FEED:4140":[],"FEED:41CE":[],"FEED:4242":[],"FEED:4257":[],"FEED:4260":[],"FEED:4373":[],"FEED:4451":[],"FEED:4658":[],"FEED:4879":[],"FEED:4B4E":[],"FEED:4DD7":[],"FEED:5050":[],"FEED:5148":[],"FEED:516D":[],"FEED:524E":[],"FEED:5275":[],"FEED:542C":[],"FEED:552F":[],"FEED:558E":[],"FEED:56C2":[],"FEED:5959":[],"FEED:5967":[],"FEED:5B50":[],"FEED:5D5E":[],"FEED:5E14":[],"FEED:5F10":[],"FEED:6050":[],"FEED:6060":[],"FEED:6061":[],"FEED:6062":[],"FEED:6063":[],"FEED:6064":[],"FEED:6069":[],"FEED:6070":[],"FEED:6071":[],"FEED:6073":[],"FEED:6074":[],"FEED:6090":[],"FEED:6464":[],"FEED:6465":[],"FEED:6512":[],"FEED:6535":[],"FEED:6660":[],"FEED:6666":[],"FEED:672A":[],"FEED:6776":[],"FEED:67C0":[],"FEED:67F3":[],"FEED:6800":[[0,0,"Esc"],[0,1,"1"],[0,2,"Tab"],[0,3,"Q"],[0,4,"Keycaps"],[0,5,"A"],[0,6,"Shift"],[0,7,"Z"],[0,9,"Ctrl"],[1,0,"2"],[1,1,"3"],[1,2,"W"],[1,3,"E"],[1,4,"S"],[1,5,"D"],[1,6,"X"],[1,7,"C"],[1,8,"Alt"],[1,9,"GUI"],[2,0,"4"],[2,1,"5"],[2,2,"R"],[2,3,"T"],[2,4,"F"],[2,5,"G"],[2,6,"V"],[2,7,"B"],[2,8,"MO(2)"],[3,0,"6"],[3,1,"7"],[3,2,"Y"],[3,3,"U"],[3,4,"H"],[3,5,"J"],[3,6,"N"],[3,7,"M"],[3,9,"MO(1)"],[4,0,"8"],[4,1,"9"],[4,2,"I"],[4,3,"O"],[4,4,"K"],[4,5,"L"],[4,6,","],[4,7,"."],[4,8,"Left"],[4,9,"Down"],[5,0,"0"],[5,1,"Del"],[5,2,"P"],[5,3,"Backspace"],[5,4,";"],[5,5,"'"],[5,6,"/"],[5,7,"Enter"],[5,8,"Up"],[5,9,"Right"]],"FEED:6834":[],"FEED:6868":[],"FEED:68F1":[],"FEED:6955":[[0,0,"Esc"],[0,1,"Ctrl"],[0,2,"Shift"],[0,3,"GUI"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Alt"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"GUI"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"Backspace"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[5,3,"Esc"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Enter"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"Space"],[8,0,"I"],[8,1,"K"],[8,2,","],[8,3,"Alt"],[9,0,"O"],[9,1,"L"],[9,2,"."],[10,0,"P"],[10,1,"'"],[10,2,"/"],[11,0,"Delete"],[11,1,";"],[11,2,"Shift"],[11,3,"GUI"],[12,0,"Backspace"],[12,2,"MO(1)"],[12,3,"Ctrl"]],"FEED:6969":[],"FEED:6E55":[],"FEED:6FAA":[],"FEED:7051":[],"FEED:70EC":[],"FEED:72D4":[],"FEED:7421":[],"FEED:7539":[],"FEED:75B4":[],"FEED:7776":[],"FEED:7778":[],"FEED:7811":[],"FEED:7812":[],"FEED:7878":[],"FEED:79AE":[],"FEED:7C1A":[],"FEED:8686":[],"FEED:8687":[],"FEED:8688":[],"FEED:8888":[],"FEED:8889":[],"FEED:8DEF":[],"FEED:8E81":[[0,2,"Ctrl"],[0,6,"Ctrl"],[1,1,"Shift"],[1,6,"Shift"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"`"],[2,3,"1"],[2,4,"Q"],[2,5,"A"],[2,6,"Z"],[3,0,"\\"],[3,1,"Caps Lock"],[3,2,"F1"],[3,3,"2"],[3,4,"W"],[3,5,"S"],[3,6,"X"],[4,0,"F4"],[4,1,"F3"],[4,2,"F2"],[4,3,"3"],[4,4,"E"],[4,5,"D"],[4,6,"C"],[5,0,"G"],[5,1,"T"],[5,2,"5"],[5,3,"4"],[5,4,"R"],[5,5,"F"],[5,6,"V"],[5,7,"B"],[6,0,"F5"],[6,1,"Backspace"],[6,2,"F9"],[6,3,"F10"],[6,4,"\\"],[6,5,"\\"],[6,6,"Enter"],[6,7,"Space"],[7,0,"H"],[7,1,"Y"],[7,2,"6"],[7,3,"7"],[7,4,"U"],[7,5,"J"],[7,6,"M"],[7,7,"N"],[8,0,"F6"],[8,1,"]"],[8,2,"="],[8,3,"8"],[8,4,"I"],[8,5,"K"],[8,6,","],[8,7,"\\"],[9,1,"F7"],[9,2,"F8"],[9,3,"9"],[9,4,"O"],[9,5,"L"],[9,6,"."],[10,0,"'"],[10,1,"["],[10,2,"-"],[10,3,"0"],[10,4,"P"],[10,5,";"],[10,6,"#"],[10,7,"/"],[11,0,"0"],[11,1,"4"],[11,2,"Delete"],[11,3,"F11"],[11,4,"7"],[11,5,"1"],[11,6,"Num Lock"],[11,7,"\u2193"],[12,0,","],[12,1,"5"],[12,2,"Insert"],[12,3,"F12"],[12,4,"8"],[12,5,"2"],[12,6,"/"],[12,7,"\u2192"],[13,0,"."],[13,1,"6"],[13,2,"Page Up"],[13,3,"Page Down"],[13,4,"9"],[13,5,"3"],[13,6,"*"],[13,7,"-"],[14,0,"\u2191"],[14,1,"="],[14,2,"Home"],[14,3,"End"],[14,4,"+"],[14,5,"Enter"],[14,6,"Pause"],[14,7,"\u2190"],[15,0,"Alt"],[15,3,"Print Screen"],[15,4,"Scroll Lock"],[15,5,"GUI"],[15,7,"Alt Gr"]],"FEED:9090":[],"FEED:9372":[],"FEED:9692":[],"FEED:9696":[],"FEED:9789":[],"FEED:991D":[],"FEED:9A25":[],"FEED:9CE3":[],"FEED:9E8C":[],"FEED:A0A1":[],"FEED:AAAA":[],"FEED:AB3C":[],"FEED:ACC7":[],"FEED:ACC8":[],"FEED:ADD0":[],"FEED:AE12":[],"FEED:B077":[],"FEED:B07D":[],"FEED:B100":[],"FEED:B155":[[0,2,"Ctrl"],[0,6,"Ctrl"],[1,1,"Shift"],[1,6,"Shift"],[2,0,"Esc"],[2,1,"Tab"],[2,2,"`"],[2,3,"1"],[2,4,"Q"],[2,5,"A"],[2,6,"Z"],[3,0,"\\"],[3,1,"Caps Lock"],[3,2,"F1"],[3,3,"2"],[3,4,"W"],[3,5,"S"],[3,6,"X"],[4,0,"F4"],[4,1,"F3"],[4,2,"F2"],[4,3,"3"],[4,4,"E"],[4,5,"D"],[4,6,"C"],[5,0,"G"],[5,1,"T"],[5,2,"5"],[5,3,"4"],[5,4,"R"],[5,5,"F"],[5,6,"V"],[5,7,"B"],[6,0,"F5"],[6,1,"Backspace"],[6,2,"F9"],[6,3,"F10"],[6,5,"\\"],[6,6,"Enter"],[6,7,"Space"],[7,0,"H"],[7,1,"Y"],[7,2,"6"],[7,3,"7"],[7,4,"U"],[7,5,"J"],[7,6,"M"],[7,7,"N"],[8,0,"F6"],[8,1,"]"],[8,2,"="],[8,3,"8"],[8,4,"I"],[8,5,"K"],[8,6,","],[9,1,"F7"],[9,2,"F8"],[9,3,"9"],[9,4,"O"],[9,5,"L"],[9,6,"."],[10,0,"'"],[10,1,"["],[10,2,"-"],[10,3,"0"],[10,4,"P"],[10,5,";"],[10,6,"#"],[10,7,"/"],[11,1,"4"],[11,2,"Delete"],[11,3,"F11"],[11,4,"7"],[11,5,"1"],[11,6,"Num Lock"],[11,7,"\u2193"],[12,0,"0"],[12,1,"5"],[12,2,"Insert"],[12,3,"F12"],[12,4,"8"],[12,5,"2"],[12,6,"/"],[12,7,"\u2192"],[13,0,"."],[13,1,"6"],[13,2,"Page Up"],[13,3,"Page Down"],[13,4,"9"],[13,5,"3"],[13,6,"*"],[13,7,"-"],[14,0,"\u2191"],[14,2,"Home"],[14,3,"End"],[14,4,"+"],[14,5,"Enter"],[14,6,"Pause"],[14,7,"\u2190"],[15,0,"Alt"],[15,3,"Print Screen"],[15,4,"Scroll Lock"],[15,7,"Alt Gr"]],"FEED:B170":[],"FEED:B195":[],"FEED:B919":[],"FEED:B92B":[],"FEED:BD66":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Caps Lock"],[0,3,"Shift"],[0,4,"Ctrl"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[5,4,"Space"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[8,4,"Space"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"Fn"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"`"],[13,1,"\\"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"\u2190"],[14,0,"Backspace"],[14,3,"\u2191"],[14,4,"\u2193"],[15,0,"Insert"],[15,1,"Delete"],[15,4,"\u2192"]],"FEED:BEEF":[],"FEED:C010":[],"FEED:C18B":[],"FEED:C2F0":[],"FEED:C456":[],"FEED:C4B5":[],"FEED:CA22":[],"FEED:CA2C":[],"FEED:CA40":[],"FEED:CA42":[],"FEED:CA49":[],"FEED:CA60":[],"FEED:CA75":[],"FEED:CA96":[],"FEED:D070":[],"FEED:D465":[],"FEED:DA19":[],"FEED:DA20":[],"FEED:DAD3":[],"FEED:DB9F":[],"FEED:DE1D":[],"FEED:DFA1":[],"FEED:DFA3":[],"FEED:DFA5":[],"FEED:DFA8":[[0,0,"P"],[0,1,"Enter"],[0,2,"/"],[0,3,"Backspace"],[0,4,"T"],[0,5,"G"],[0,6,"B"],[1,0,"O"],[1,1,"L"],[1,2,"."],[1,3,"Ctrl"],[1,4,"R"],[1,5,"F"],[1,6,"V"],[2,0,"I"],[2,1,"K"],[2,2,","],[2,3,"Fn"],[2,4,"E"],[2,5,"D"],[2,6,"C"],[3,0,"U"],[3,1,"J"],[3,2,"M"],[3,3,"Space"],[3,4,"W"],[3,5,"S"],[3,6,"X"],[4,0,"Y"],[4,1,"H"],[4,2,"N"],[4,3,"Alt"],[4,4,"Q"],[4,5,"A"],[4,6,"Z"],[4,7,"Ctrl"]],"FEED:E401":[],"FEED:E80A":[],"FEED:E9B6":[],"FEED:EE11":[],"FEED:F22C":[[0,0,"L00"],[0,1,"L10"],[0,2,"L20"],[0,3,"L30"],[0,5,"R00"],[0,6,"R10"],[0,7,"R20"],[0,8,"R30"],[0,9,"RT1"],[1,0,"L01"],[1,1,"L11"],[1,2,"L21"],[1,3,"L31"],[1,5,"R01"],[1,6,"R11"],[1,7,"R21"],[1,8,"R31"],[1,9,"RT2"],[2,0,"L02"],[2,1,"L12"],[2,2,"L22"],[2,3,"L32"],[2,4,"LT1"],[2,5,"R02"],[2,6,"R12"],[2,7,"R22"],[2,8,"R32"],[2,9,"RT3"],[3,0,"L03"],[3,1,"L13"],[3,2,"L23"],[3,3,"L33"],[3,4,"LT2"],[3,5,"R03"],[3,6,"R13"],[3,7,"R23"],[3,8,"R33"],[4,0,"L04"],[4,1,"L14"],[4,2,"L24"],[4,3,"L34"],[4,4,"LT3"],[4,5,"R04"],[4,6,"R14"],[4,7,"R24"],[4,8,"R34"]],"FEED:F4B0":[],"FEED:F4B4":[],"FEED:F4B5":[[0,0,"l40"],[0,1,"l10"],[0,2,"l20"],[0,3,"l30"],[0,4,"l41"],[0,6,"r50"],[0,7,"r51"],[0,8,"r52"],[0,9,"r53"],[0,10,"r54"],[0,11,"r55"],[1,0,"l00"],[1,1,"l11"],[1,2,"l21"],[1,3,"l31"],[1,4,"l42"],[1,6,"r40"],[1,7,"r41"],[1,8,"r42"],[1,9,"r43"],[1,10,"r44"],[1,11,"r45"],[2,0,"l01"],[2,1,"l12"],[2,2,"l22"],[2,3,"l32"],[2,4,"l43"],[2,6,"r31"],[2,7,"r32"],[2,8,"r33"],[2,9,"r34"],[2,10,"r35"],[2,11,"r36"],[3,0,"l02"],[3,1,"l13"],[3,2,"l23"],[3,3,"l33"],[3,4,"l44"],[3,6,"r20"],[3,7,"r21"],[3,8,"r22"],[3,9,"r23"],[3,10,"r24"],[3,11,"r25"],[4,0,"l03"],[4,1,"l14"],[4,2,"l24"],[4,3,"l34"],[4,4,"l45"],[4,6,"r10"],[4,7,"r11"],[4,8,"r12"],[4,9,"r13"],[4,10,"r14"],[4,11,"r37"],[5,0,"l04"],[5,1,"l15"],[5,2,"l25"],[5,3,"l35"],[5,4,"l46"],[5,6,"r00"],[5,7,"r01"],[5,8,"r02"],[5,9,"r03"],[5,10,"r47"],[5,11,"r46"],[6,1,"l16"],[6,2,"l26"],[6,3,"l36"],[6,4,"l47"],[6,6,"r30"],[6,7,"oc"],[6,8,"fn"],[6,9,"r58"],[6,10,"r57"],[6,11,"r56"]],"FEED:F4E4":[],"FEED:FA9C":[],"FEED:FCB8":[],"FEFD:9460":[],"FEFE:0001":[[0,0,"Tab"],[0,1,"Esc"],[0,2,"Shift"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Ctrl"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Super"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"⇓"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[5,3,"Space"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Space"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"⇑"],[8,0,"I"],[8,1,"K"],[8,2,","],[8,3,"←"],[9,0,"O"],[9,1,"L"],[9,2,"."],[9,3,"↓"],[10,0,"P"],[10,1,";"],[10,2,"/"],[10,3,"↑"],[11,0,"BS"],[11,1,"'"],[11,2,"Return"]],"FEFE:3488":[],"FF21:AA03":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Ctrl"],[0,3,"Shift"],[0,4,"GUI"],[1,0,"1"],[1,1,"Q"],[1,2,"A"],[1,3,"\\"],[1,4,"GUI"],[2,0,"2"],[2,1,"W"],[2,2,"S"],[2,3,"Z"],[2,4,"Alt"],[3,0,"3"],[3,1,"E"],[3,2,"D"],[3,3,"X"],[4,0,"4"],[4,1,"R"],[4,2,"F"],[4,3,"C"],[5,0,"5"],[5,1,"T"],[5,2,"G"],[5,3,"V"],[6,0,"6"],[6,1,"Y"],[6,2,"H"],[6,3,"B"],[6,4,"Space"],[7,0,"7"],[7,1,"U"],[7,2,"J"],[7,3,"N"],[8,0,"8"],[8,1,"I"],[8,2,"K"],[8,3,"M"],[9,0,"9"],[9,1,"O"],[9,2,"L"],[9,3,","],[10,0,"0"],[10,1,"P"],[10,2,";"],[10,3,"."],[10,4,"Alt"],[11,0,"-"],[11,1,"["],[11,2,"'"],[11,3,"/"],[11,4,"GUI"],[12,0,"="],[12,1,"]"],[12,3,"Shift"],[12,4,"Ctrl"],[13,0,"`"],[13,1,"Backspace"],[13,2,"Enter"],[13,3,"Fn"],[13,4,"Delete"]],"FFFE:0001":[],"FFFE:0002":[[0,0,"Esc"],[0,1,"Tab"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Win"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[3,3,"Hyper"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"Lower"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[5,3,"Space"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[7,3,"Ralse"],[8,0,"I"],[8,1,"K"],[8,2,"<"],[8,3,"Fn"],[9,0,"O"],[9,1,"L"],[9,2,">"],[9,3,"Left"],[10,0,"P"],[10,1,":"],[10,2,"Up"],[10,3,"Down"],[11,0,"BackSpace"],[11,1,"Enter"],[11,2,"?"],[11,3,"Right"]],"FFFE:0005":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Fn"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"\""],[11,4,":"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[12,3,":"],[13,0,"Del"],[13,1,"Bksp"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Left"],[14,4,"Up"],[14,5,"Down"],[15,0,"Mute"],[15,1,"Home"],[15,2,"PageUp"],[15,3,"PageDn"],[15,4,"End"],[15,5,"Right"]],"FFFE:0007":[],"FFFE:0008":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Fn"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"'"],[11,5,"Left"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[13,0,"Delete"],[13,1,"Bksp"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[15,4,"Up"],[15,5,"Down"],[16,5,"Right"],[17,0,"PrtSc"],[17,1,"Numlock"],[17,2,"7"],[17,3,"4"],[17,4,"1"],[18,0,"Home"],[18,1,"/"],[18,2,"8"],[18,3,"5"],[18,4,"2"],[18,5,"0"],[19,0,"Pgup"],[19,1,"*"],[19,2,"9"],[19,3,"6"],[19,4,"3"],[19,5,"."],[20,0,"Pgdn"],[20,1,"-"],[20,2,"+"],[20,4,"Enter"]],"FFFE:0009":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Win"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"'"],[11,5,"Fn"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[13,1,"Backspace"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Ins"],[14,2,"Del"],[14,5,"Left"],[15,0,"ScrLk"],[15,1,"Home"],[15,2,"End"],[15,4,"Up"],[15,5,"Down"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"Right"]],"FFFE:000A":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Win"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"'"],[11,5,"Fn"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[13,1,"Backspace"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Ins"],[14,2,"Del"],[14,5,"Left"],[15,0,"ScrLk"],[15,1,"Home"],[15,2,"End"],[15,4,"Up"],[15,5,"Down"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"Right"],[17,0,"Cal"],[17,1,"Num"],[17,2,"7"],[17,3,"4"],[17,4,"1"],[18,0,"Mute"],[18,1,"/"],[18,2,"8"],[18,3,"5"],[18,4,"2"],[18,5,"0"],[19,0,"Vold"],[19,1,"*"],[19,2,"9"],[19,3,"6"],[19,4,"3"],[19,5,"."],[20,0,"Volu"],[20,1,"-"],[20,2,"+"],[20,4,"Enter"]],"FFFE:000C":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Win"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"'"],[11,5,"Fn"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[13,1,"Backspace"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Ins"],[14,2,"Del"],[14,5,"Left"],[15,0,"ScrLk"],[15,1,"Home"],[15,2,"End"],[15,4,"Up"],[15,5,"Down"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"Right"]],"FFFE:000D":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Win"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"'"],[11,5,"Fn"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[13,1,"Backspace"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Ins"],[14,2,"Del"],[14,5,"Left"],[15,0,"ScrLk"],[15,1,"Home"],[15,2,"End"],[15,4,"Up"],[15,5,"Down"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"Right"],[17,0,"Cal"],[17,1,"Num"],[17,2,"7"],[17,3,"4"],[17,4,"1"],[18,0,"Mute"],[18,1,"/"],[18,2,"8"],[18,3,"5"],[18,4,"2"],[18,5,"0"],[19,0,"Vold"],[19,1,"*"],[19,2,"9"],[19,3,"6"],[19,4,"3"],[19,5,"."],[20,0,"Volu"],[20,1,"-"],[20,2,"+"],[20,4,"Enter"]],"FFFE:000E":[[0,0,"Ese"],[0,1,"Tab"],[0,2,"Shift"],[0,3,"Ctrl"],[1,0,"Q"],[1,1,"A"],[1,2,"Z"],[1,3,"Win"],[2,0,"W"],[2,1,"S"],[2,2,"X"],[2,3,"Alt"],[3,0,"E"],[3,1,"D"],[3,2,"C"],[4,0,"R"],[4,1,"F"],[4,2,"V"],[4,3,"Space"],[5,0,"T"],[5,1,"G"],[5,2,"B"],[6,0,"Y"],[6,1,"H"],[6,2,"N"],[6,3,"Space"],[7,0,"U"],[7,1,"J"],[7,2,"M"],[8,0,"I"],[8,1,"K"],[8,2,"<"],[8,3,"Fn"],[9,0,"O"],[9,1,"L"],[9,2,">"],[9,3,"Left"],[10,0,"P"],[10,1,":"],[10,2,"Up"],[10,3,"Down"],[11,0,"BackSpace"],[11,1,"Enter"],[11,2,"Shift"],[11,3,"Right"]],"FFFE:0010":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Win"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"'"],[11,5,"Fn"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[13,1,"Backspace"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Ctrl"],[14,0,"PrtSc"],[14,1,"Ins"],[14,2,"Del"],[14,5,"Left"],[15,0,"ScrLk"],[15,1,"Home"],[15,2,"End"],[15,4,"Up"],[15,5,"Down"],[16,0,"Pause"],[16,1,"PgUp"],[16,2,"PgDn"],[16,5,"Right"]],"FFFE:0012":[[0,0,"Esc"],[0,1,"~"],[0,2,"Tab"],[0,3,"Caps Lock"],[0,4,"Shift"],[0,5,"Ctrl"],[1,0,"F1"],[1,1,"!"],[1,2,"Q"],[1,3,"A"],[1,4,"Z"],[1,5,"Win"],[2,0,"F2"],[2,1,"@"],[2,2,"W"],[2,3,"S"],[2,4,"X"],[2,5,"Alt"],[3,0,"F3"],[3,1,"#"],[3,2,"E"],[3,3,"D"],[3,4,"C"],[4,0,"F4"],[4,1,"$"],[4,2,"R"],[4,3,"F"],[4,4,"V"],[5,0,"F5"],[5,1,"%"],[5,2,"T"],[5,3,"G"],[5,4,"B"],[5,5,"Space"],[6,0,"F6"],[6,1,"^"],[6,2,"Y"],[6,3,"H"],[6,4,"N"],[7,0,"F7"],[7,1,"&"],[7,2,"U"],[7,3,"J"],[7,4,"M"],[8,0,"F8"],[8,1,"*"],[8,2,"I"],[8,3,"K"],[8,4,"<"],[9,0,"F9"],[9,1,"("],[9,2,"O"],[9,3,"L"],[9,4,">"],[9,5,"Alt"],[10,0,"F10"],[10,1,")"],[10,2,"P"],[10,3,":"],[10,4,"?"],[10,5,"Fn"],[11,0,"F11"],[11,1,"_"],[11,2,"{"],[11,3,"\""],[11,4,":"],[11,5,"Ctrl"],[12,0,"F12"],[12,1,"+"],[12,2,"}"],[12,3,":"],[13,0,"Del"],[13,1,"Bksp"],[13,2,"|"],[13,3,"Enter"],[13,4,"Shift"],[13,5,"Left"],[14,4,"Up"],[14,5,"Down"],[15,0,"Mute"],[15,1,"Home"],[15,2,"PageUp"],[15,3,"PageDn"],[15,5,"Right"]],"FFFE:001B":[],"FFFE:4155":[],"FFFF:0000":[]}} \ No newline at end of file diff --git a/Chromatics/ViewModels/CopyLayersDialogViewModel.cs b/Chromatics/ViewModels/CopyLayersDialogViewModel.cs new file mode 100644 index 00000000..ad42aa3c --- /dev/null +++ b/Chromatics/ViewModels/CopyLayersDialogViewModel.cs @@ -0,0 +1,316 @@ +using Chromatics.Enums; +using Chromatics.Helpers; +using Chromatics.Layers; +using Chromatics.Localization; +using CommunityToolkit.Mvvm.ComponentModel; +using RGB.NET.Core; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; + +namespace Chromatics.ViewModels +{ + // Per-layer copy model. The dialog shows one row per layer on + // the source device; the user ticks which layers to copy and + // (for Dynamic layers) tweaks the per-LedId mapping in an + // expandable section. + // + // Base and Effect layers don't get the per-LED expander — + // they're whole-device layers and the mapping is implicit + // (identity for keyboard pairs, positional fallback for + // anything else). What they do get is a "will replace existing" + // badge so the user knows the destination's existing Base / + // Effect layer is about to be evicted. + public partial class CopyLayersDialogViewModel : ViewModelBase + { + public CopyLayersDialogViewModel(IReadOnlyDictionary connectedDevices, Guid initialSourceGuid) + { + _connectedDevices = connectedDevices ?? new Dictionary(); + + foreach (var (guid, device) in _connectedDevices) + { + Devices.Add(new DeviceItem + { + DeviceId = guid, + Name = device.DeviceInfo?.DeviceName ?? "Device", + DeviceType = device.DeviceInfo?.DeviceType ?? RGBDeviceType.Unknown, + }); + } + + SelectedSource = Devices.FirstOrDefault(d => d.DeviceId == initialSourceGuid) + ?? Devices.FirstOrDefault(); + RebuildDestinationOptions(); + SelectedDestination = AvailableDestinations.FirstOrDefault(); + RebuildLayerRows(); + } + + private readonly IReadOnlyDictionary _connectedDevices; + + public ObservableCollection Devices { get; } = new(); + public ObservableCollection AvailableDestinations { get; } = new(); + public ObservableCollection LayerRows { get; } = new(); + + // Shared LedId pool for the per-row destination dropdowns. The + // list is the same for every row in the dialog (it's the dest + // device's full LedId set), so we hold it at the dialog VM + // level and the AXAML binds the per-row ComboBox to it via the + // window's DataContext. Avoids the per-row collection + // duplication and lets the AXAML binding path stay simple + // (no nested-type cast). + public ObservableCollection AvailableDestLedIds { get; } = new(); + + [ObservableProperty] private DeviceItem _selectedSource; + [ObservableProperty] private DeviceItem _selectedDestination; + [ObservableProperty] private string _summaryText; + [ObservableProperty] private bool _hasNoLayers; + [ObservableProperty] private bool _canCopy; + + public void SelectAll() + { + foreach (var row in LayerRows) row.IsSelected = true; + // UpdateSummary fires from each row's PropertyChanged handler, + // but recompute once at the end so the summary stays consistent + // even if a row was already selected and didn't trigger. + UpdateSummary(); + } + + public void ClearAll() + { + foreach (var row in LayerRows) row.IsSelected = false; + UpdateSummary(); + } + + partial void OnSelectedSourceChanged(DeviceItem value) + { + RebuildDestinationOptions(); + if (SelectedDestination == null + || !AvailableDestinations.Any(d => d.DeviceId == SelectedDestination.DeviceId)) + { + SelectedDestination = AvailableDestinations.FirstOrDefault(); + } + RebuildLayerRows(); + } + + partial void OnSelectedDestinationChanged(DeviceItem value) + { + RebuildLayerRows(); + } + + private void RebuildDestinationOptions() + { + AvailableDestinations.Clear(); + if (SelectedSource == null) return; + foreach (var d in Devices) + { + if (d.DeviceId == SelectedSource.DeviceId) continue; + if (!LayerCopier.IsCopyAllowed(SelectedSource.DeviceType, d.DeviceType)) continue; + AvailableDestinations.Add(d); + } + } + + private void RebuildLayerRows() + { + // Detach handlers from previous rows so deselected rows don't + // continue firing summary updates after a source switch. + foreach (var row in LayerRows) row.PropertyChanged -= OnRowChanged; + LayerRows.Clear(); + + HasNoLayers = false; + if (SelectedSource == null || SelectedDestination == null) { UpdateSummary(); return; } + if (!_connectedDevices.TryGetValue(SelectedSource.DeviceId, out var src)) { UpdateSummary(); return; } + if (!_connectedDevices.TryGetValue(SelectedDestination.DeviceId, out var dst)) { UpdateSummary(); return; } + + AvailableDestLedIds.Clear(); + foreach (var led in dst.OrderBy(l => (int)l.Id)) + AvailableDestLedIds.Add(led.Id); + + // Only Dynamic layers are copyable. Base and Effect layers + // are at-most-one per device by design and don't carry the + // per-LedId mapping data that makes copying meaningful; + // filtering them out here keeps the dialog focused on + // the layers users actually want to duplicate. + // + // Order matches the Mappings tab: descending zindex so the + // top-most layer in the Mappings list is the top row in + // the copy dialog. MappingViewModel.RefreshLayers uses + // `.OrderByDescending(l => l.zindex)`; mirror that here + // so the two views stay visually consistent. + var sourceLayers = MappingLayers.GetLayers().Values + .Where(l => l.deviceGuid == SelectedSource.DeviceId + && l.rootLayerType == LayerType.DynamicLayer) + .OrderByDescending(l => l.zindex) + .ToList(); + + if (sourceLayers.Count == 0) + { + HasNoLayers = true; + UpdateSummary(); + return; + } + + foreach (var layer in sourceLayers) + { + var usedSourceLedIds = layer.deviceLeds?.Values.Distinct().ToList() ?? new List(); + var defaultMap = LayerCopier.ComputeDefaultMappingForLayer(usedSourceLedIds, src, dst); + + var row = new LayerCopyRow + { + SourceLayer = layer, + IsSelected = true, + DisplayName = BuildLayerDisplayName(layer), + TypeBadge = BuildLayerTypeBadge(layer.rootLayerType), + RootLayerType = layer.rootLayerType, + WillReplaceExisting = LayerCopier.DestinationAlreadyHasLayerOfType( + SelectedDestination.DeviceId, layer.rootLayerType), + }; + + foreach (var ledId in usedSourceLedIds.OrderBy(id => (int)id)) + { + bool hasMapping = defaultMap.TryGetValue(ledId, out var destLedId); + row.KeyMappings.Add(new MappingRow + { + SourceLedId = ledId, + SourceLedIdLabel = ledId.ToString(), + DestinationLedId = hasMapping ? destLedId : default, + HasDestination = hasMapping, + }); + } + + row.PropertyChanged += OnRowChanged; + LayerRows.Add(row); + } + + UpdateSummary(); + } + + private void OnRowChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(LayerCopyRow.IsSelected)) UpdateSummary(); + } + + private void UpdateSummary() + { + int selected = LayerRows.Count(r => r.IsSelected); + CanCopy = selected > 0; + string template = LocalizationService.Instance["{0} layer(s) selected."]; + SummaryText = string.Format(template, selected); + } + + // Build the list of copy plans for LayerCopier.Apply. Walks + // the ticked LayerRows and snapshots their current + // mapping state into immutable plan entries. + public IReadOnlyList BuildPlans() + { + var plans = new List(); + foreach (var row in LayerRows) + { + if (!row.IsSelected) continue; + var mapping = new Dictionary(); + foreach (var m in row.KeyMappings) + { + if (!m.HasDestination) continue; + mapping[m.SourceLedId] = m.DestinationLedId; + } + plans.Add(new LayerCopier.LayerCopyPlan + { + SourceLayer = row.SourceLayer, + Mapping = mapping, + }); + } + return plans; + } + + // Friendly per-layer label. Only Dynamic layers reach this + // dialog (Base / Effect are filtered out in RebuildLayerRows), + // so the label is just the dynamic sub-type name — no need + // to prefix every row with "Dynamic:" when it's the only + // category in the list. + private static string BuildLayerDisplayName(Layer layer) + { + return layer.rootLayerType switch + { + LayerType.DynamicLayer => DynamicLayerTypeFromComboIndex(layer.layerTypeindex).ToString(), + LayerType.BaseLayer => ((BaseLayerType)layer.layerTypeindex).ToString(), + LayerType.EffectLayer => LocalizationService.Instance["Effect"], + _ => layer.rootLayerType.ToString(), + }; + } + + private static string BuildLayerTypeBadge(LayerType rootLayerType) => rootLayerType switch + { + LayerType.BaseLayer => LocalizationService.Instance["Base"], + LayerType.EffectLayer => LocalizationService.Instance["Effect"], + LayerType.DynamicLayer => LocalizationService.Instance["Dynamic"], + _ => rootLayerType.ToString(), + }; + + // CLAUDE.md note: `layer.layerTypeindex` for Dynamic layers is the + // ComboBox position in _dynamicLayerOrder, NOT the enum value. The + // first 10 positions coincide with the enum by accident; from + // position 10 onward they diverge. Use the official order array + // GameController consumes. + private static readonly DynamicLayerType[] _dynamicLayerOrder = + { + DynamicLayerType.None, + DynamicLayerType.Highlight, + DynamicLayerType.Keybinds, + DynamicLayerType.EnmityTracker, + DynamicLayerType.TargetHP, + DynamicLayerType.TargetCastbar, + DynamicLayerType.HPTracker, + DynamicLayerType.MPTracker, + DynamicLayerType.JobGaugeA, + DynamicLayerType.JobGaugeB, + DynamicLayerType.JobGaugeC, + DynamicLayerType.ExperienceTracker, + DynamicLayerType.BattleStance, + DynamicLayerType.Castbar, + DynamicLayerType.JobClassesHighlight, + DynamicLayerType.ReactiveWeatherHighlight, + }; + + private static DynamicLayerType DynamicLayerTypeFromComboIndex(int index) + { + if (index < 0 || index >= _dynamicLayerOrder.Length) return DynamicLayerType.None; + return _dynamicLayerOrder[index]; + } + + public sealed class DeviceItem + { + public Guid DeviceId { get; init; } + public string Name { get; init; } + public RGBDeviceType DeviceType { get; init; } + public override string ToString() => Name; + } + + public partial class LayerCopyRow : ObservableObject + { + [ObservableProperty] private bool _isSelected; + [ObservableProperty] private string _displayName; + [ObservableProperty] private string _typeBadge; + [ObservableProperty] private LayerType _rootLayerType; + [ObservableProperty] private bool _willReplaceExisting; + + public Layer SourceLayer { get; init; } + public ObservableCollection KeyMappings { get; } = new(); + + // Per-LED mapping is only meaningful for Dynamic layers — + // Base / Effect cover the whole device and we use identity / + // positional fallback under the hood. Hides the expander + // section on Base / Effect rows. + public bool ShowKeyMappings => RootLayerType == LayerType.DynamicLayer && KeyMappings.Count > 0; + + partial void OnRootLayerTypeChanged(LayerType value) => OnPropertyChanged(nameof(ShowKeyMappings)); + } + + public partial class MappingRow : ObservableObject + { + [ObservableProperty] private LedId _sourceLedId; + [ObservableProperty] private string _sourceLedIdLabel; + [ObservableProperty] private LedId _destinationLedId; + [ObservableProperty] private bool _hasDestination; + } + } +} diff --git a/Chromatics/ViewModels/HueAdoptionDialogViewModel.cs b/Chromatics/ViewModels/HueAdoptionDialogViewModel.cs index f813b70d..82774347 100644 --- a/Chromatics/ViewModels/HueAdoptionDialogViewModel.cs +++ b/Chromatics/ViewModels/HueAdoptionDialogViewModel.cs @@ -45,7 +45,7 @@ private void UpdateStatus() // Query the bridge for its lights, merging with the user's already- // adopted set so previously-adopted bulbs come back pre-checked. New // lights since the last adoption are unchecked by default. - public async Task LoadBulbsAsync(string bridgeIp, string bridgeKey, IReadOnlyDictionary alreadyAdopted, CancellationToken ct) + public async Task LoadBulbsAsync(string bridgeIp, string bridgeKey, IReadOnlyDictionary alreadyAdopted, CancellationToken ct) { IsLoading = true; UpdateStatus(); diff --git a/Chromatics/ViewModels/LifxAdoptionDialogViewModel.cs b/Chromatics/ViewModels/LifxAdoptionDialogViewModel.cs index 4c7ca788..db232149 100644 --- a/Chromatics/ViewModels/LifxAdoptionDialogViewModel.cs +++ b/Chromatics/ViewModels/LifxAdoptionDialogViewModel.cs @@ -50,7 +50,7 @@ private void UpdateStatus() // devices are unchecked; devices that were adopted but aren't on the // network show with a "(offline)" suffix and are pre-checked so the // user keeps them by default. - public async Task StartDiscoveryAsync(IReadOnlyDictionary alreadyAdopted, CancellationToken ct) + public async Task StartDiscoveryAsync(IReadOnlyDictionary alreadyAdopted, CancellationToken ct) { IsDiscovering = true; UpdateStatus(); diff --git a/Chromatics/ViewModels/SettingsViewModel.cs b/Chromatics/ViewModels/SettingsViewModel.cs index ae571dbb..a3b89ed6 100644 --- a/Chromatics/ViewModels/SettingsViewModel.cs +++ b/Chromatics/ViewModels/SettingsViewModel.cs @@ -7,9 +7,14 @@ using Chromatics.Extensions.RGB.NET.Devices.Hue; using Chromatics.Extensions.RGB.NET.Devices.LIFX; using Chromatics.Extensions.RGB.NET.Devices.PlayStation; +using Chromatics.Extensions.RGB.NET.Devices.Alienware; +using Chromatics.Extensions.RGB.NET.Devices.DynamicLighting; +using Chromatics.Extensions.RGB.NET.Devices.QmkRawHid; +using Chromatics.Extensions.RGB.NET.Devices.Yeelight; using Chromatics.Models; using Chromatics.Helpers; using Chromatics.Views; +using Chromatics.Views.Dialogs; using Microsoft.VisualBasic.FileIO; using Microsoft.Win32; using RGB.NET.Devices.Asus; @@ -23,6 +28,7 @@ using RGB.NET.Devices.SteelSeries; using RGB.NET.Devices.Wooting; using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; @@ -51,6 +57,7 @@ public SettingsViewModel() _betaChannel = s.betaChannel; _alwaysRunAsAdmin = s.alwaysRunAsAdmin; _enableCrashReports = s.enableCrashReports; + _dynamicLightingBypassConflictCheck = s.dynamicLightingBypassConflictCheck; _closeWithGame = s.closeWithGame; _globalBrightness = s.globalbrightness; @@ -131,7 +138,7 @@ private void BuildDeviceToggles(Models.SettingsModel s) () => RGBController.UnloadDeviceProvider(OpenRGBDeviceProvider.Instance), v => { var cur = AppSettings.GetSettings(); cur.deviceOpenRGBEnabled = v; AppSettings.SaveSettings(cur); })); - DeviceToggles.Add(MakeDeviceToggle("PlayStation (Beta)", "[BETA] Enable/disable PlayStation controller lighting (DualShock 4 / DualSense over USB or Bluetooth). Default: Disabled", + DeviceToggles.Add(MakeDeviceToggle("PlayStation", "Enable/disable PlayStation controller lighting (DualShock 4 / DualSense over USB or Bluetooth). Default: Disabled", s.devicePlayStationEnabled, () => RGBController.LoadDeviceProvider(PlayStationControllerRGBDeviceProvider.Instance), () => RGBController.UnloadDeviceProvider(PlayStationControllerRGBDeviceProvider.Instance), @@ -143,8 +150,8 @@ private void BuildDeviceToggles(Models.SettingsModel s) // stick. If either is cancelled, or the user adopts no bulbs, // the toggle reverts to off — same UX as the LIFX flow below. DeviceToggles.Add(new DeviceToggleItem( - "Hue (Beta)", - "[BETA] Enable/disable Philips HUE device library. Default: Disabled", + "Hue", + "Enable/disable Philips HUE device library. Default: Disabled", s.deviceHueEnabled, async () => { @@ -207,8 +214,8 @@ private void BuildDeviceToggles(Models.SettingsModel s) // Re-enabling re-prompts with existing adoptions pre-checked // (matches the user spec: see SettingsModel.deviceLifxAdoptedDevices). DeviceToggles.Add(new DeviceToggleItem( - "LIFX (Beta)", - "[BETA] Enable/disable LIFX device library (LAN protocol). Default: Disabled", + "LIFX", + "Enable/disable LIFX device library (LAN protocol). Default: Disabled", s.deviceLifxEnabled, async () => { @@ -271,6 +278,334 @@ private void BuildDeviceToggles(Models.SettingsModel s) cur.deviceLifxEnabled = false; AppSettings.SaveSettings(cur); })); + + // QMK Raw HID — auto-adopts every QMK-compatible board on first + // enable (no picker dialog yet; per-keyboard disable via the + // Mapping tab covers the "I don't want this one" case for v1 + // Beta). Covers NovelKeys, KBDFans, Drop, GMMK, Glorious and any + // other custom keyboard running QMK with Raw HID enabled. + DeviceToggles.Add(new DeviceToggleItem( + "QMK Keyboards (Beta)", + "[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled", + s.deviceQmkRawHidEnabled, + async () => + { + var cur = AppSettings.GetSettings(); + + Logger.WriteConsole(LoggerTypes.Devices, + "[QMK] Scanning for QMK-compatible keyboards on the USB bus..."); + + // Discovery + auto-adopt: run on a background thread to + // keep the Settings dialog responsive — per-device VIA + // handshakes can take 200-500ms each on a sluggish USB + // stack, and discovery + handshake of 5+ boards adds up. + bool result = await Task.Run(() => + { + var discovered = Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol.QmkRawHidDiscovery.Discover(); + if (discovered.Count == 0) + { + // No boards responded — leave the toggle off so + // the user sees the immediate "didn't take" UX + // rather than an empty-but-on provider. + return false; + } + + var adopted = new System.Collections.Generic.List(); + var seen = new System.Collections.Generic.HashSet(StringComparer.OrdinalIgnoreCase); + Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance.AdoptedDevices.Clear(); + foreach (var c in discovered) + { + string mfg = ""; string prod = ""; + try { mfg = c.Hid.GetManufacturer() ?? ""; } catch { } + try { prod = c.Hid.GetProductName() ?? ""; } catch { } + var key = $"{c.Hid.VendorID:X4}:{c.Hid.ProductID:X4}:{mfg}:{prod}"; + if (!seen.Add(key)) continue; + + adopted.Add(new QmkRawHidAdoptedDevice + { + VendorId = c.Hid.VendorID, + ProductId = c.Hid.ProductID, + Manufacturer = mfg, + Product = prod, + LedCount = c.LedCount, + Protocol = c.Protocol.ToString(), + ViaKeymapKey = string.Empty, + }); + Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance.AdoptedDevices.Add( + new Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidAdoptedDeviceFilter( + c.Hid.VendorID, c.Hid.ProductID, mfg, prod)); + } + + cur.deviceQmkRawHidAdoptedDevices = adopted; + cur.deviceQmkRawHidEnabled = true; + AppSettings.SaveSettings(cur); + + RGBController.LoadDeviceProvider( + Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance); + return true; + }); + + if (!result) + { + // The "no boards found" path. Logger.WriteConsole has + // already written the detailed enumeration breakdown + // (count of HID devices seen, candidates with the + // Raw HID interface, open-failures, etc.). Surface a + // short user-facing dialog too so it's obvious why + // the toggle didn't take — without this the toggle + // flashes on then back off with no visible feedback. + await DialogService.ShowAsync( + LocalizationService.Instance["No QMK Keyboards Found"], + LocalizationService.Instance["Chromatics didn't detect any QMK keyboards. Make sure your keyboard is plugged in over USB and that its firmware has Raw HID enabled (the default for any VIA-compatible build). If VIA, Vial, or OpenRGB is running, close it before enabling this provider - they hold the Raw HID interface exclusively. See the console for the full list of detected HID devices."]); + } + + return result; + }, + () => + { + var prov = Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance; + if (prov != null) + { + prov.AdoptedDevices.Clear(); + RGBController.UnloadDeviceProvider(prov); + prov.Dispose(); + } + var cur = AppSettings.GetSettings(); + cur.deviceQmkRawHidEnabled = false; + AppSettings.SaveSettings(cur); + })); + + // Yeelight — LAN-protocol bulbs, strips, lamps, ceiling lights. + // Mirrors the LIFX flow: enabling the toggle pops the + // YeelightAdoptionDialog which runs SSDP discovery and lets + // the user pick which bulbs Chromatics drives. Empty + // selection or no bulbs found leaves the toggle off. + DeviceToggles.Add(new DeviceToggleItem( + "Yeelight (Beta)", + "[BETA] Enable/disable Yeelight LAN device support. Discovers Yeelight bulbs, light strips, lamps, and ceiling lights on your LAN (requires LAN Control enabled in the Yeelight / Mi Home app). Default: Disabled", + s.deviceYeelightEnabled, + async () => + { + var cur = AppSettings.GetSettings(); + var owner = GetMainWindow(); + + var alreadyAdopted = (cur.deviceYeelightAdoptedDevices ?? new System.Collections.Generic.List()) + .ToDictionary(d => d.Id, d => d, StringComparer.OrdinalIgnoreCase); + + var dlg = new YeelightAdoptionDialog(alreadyAdopted); + if (owner != null) + await dlg.ShowDialog(owner); + else + dlg.Show(); + + if (!dlg.Saved) return false; + + // Empty selection or discovery returning nothing → leave + // the toggle off so the user sees the immediate "didn't + // take" UX rather than an empty-but-on provider. + if (dlg.SelectedDevices == null || dlg.SelectedDevices.Count == 0) + return false; + + cur.deviceYeelightAdoptedDevices = dlg.SelectedDevices; + cur.deviceYeelightEnabled = true; + AppSettings.SaveSettings(cur); + + Chromatics.Extensions.RGB.NET.Devices.Yeelight.YeelightRGBDeviceProvider.Instance.ClientDefinitions.Clear(); + foreach (var d in cur.deviceYeelightAdoptedDevices) + { + System.Net.IPEndPoint ep = null; + if (!string.IsNullOrEmpty(d.LastIp) && + System.Net.IPAddress.TryParse(d.LastIp, out var ip)) + { + ep = new System.Net.IPEndPoint(ip, d.LastPort > 0 ? d.LastPort : 55443); + } + Chromatics.Extensions.RGB.NET.Devices.Yeelight.YeelightRGBDeviceProvider.Instance.ClientDefinitions.Add( + new Chromatics.Extensions.RGB.NET.Devices.Yeelight.YeelightClientDefinition( + d.Id, d.Label, ep, d.Model, d.FirmwareVersion, d.Support)); + } + + // LoadDeviceProvider runs LoadDevices synchronously which + // for Yeelight includes a discovery sweep + per-bulb TCP + // connect + Music Mode handshake (~1.5s per bulb on a + // healthy LAN). Push to a background thread so the + // toggle returns immediately and the UI stays responsive + // while bulbs come online. + _ = Task.Run(() => RGBController.LoadDeviceProvider( + Chromatics.Extensions.RGB.NET.Devices.Yeelight.YeelightRGBDeviceProvider.Instance)); + return true; + }, + () => + { + var prov = Chromatics.Extensions.RGB.NET.Devices.Yeelight.YeelightRGBDeviceProvider.Instance; + if (prov != null) + { + prov.ClientDefinitions.Clear(); + RGBController.UnloadDeviceProvider(prov); + prov.Dispose(); + } + var cur = AppSettings.GetSettings(); + cur.deviceYeelightEnabled = false; + AppSettings.SaveSettings(cur); + })); + + // Alienware AlienFX — pure managed HID via HidSharp, no native + // DLL or Dell driver. Three HID dialects (V4 zone chassis, V5 + // notebook per-key, V8 external per-key) dispatched from one + // provider; auto-adopt every AlienFX device discovered on + // first enable. Mapping tab handles per-device disable. + DeviceToggles.Add(new DeviceToggleItem( + "Alienware (Beta)", + "[BETA] Enable/disable Alienware AlienFX device support. Auto-adopts any AlienFX-capable Alienware or Dell G-series chassis, notebook keyboard, or external keyboard discovered on the HID bus. Default: Disabled", + s.deviceAlienwareEnabled, + async () => + { + var cur = AppSettings.GetSettings(); + Logger.WriteConsole(LoggerTypes.Devices, + "[Alienware] Scanning for AlienFX devices on the HID bus..."); + + bool result = await Task.Run(() => + { + var discovered = Chromatics.Extensions.RGB.NET.Devices.Alienware.Protocol.AlienwareDiscovery.Discover(); + if (discovered.Count == 0) return false; + + var adopted = new System.Collections.Generic.List(); + var seen = new System.Collections.Generic.HashSet(StringComparer.OrdinalIgnoreCase); + Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareRGBDeviceProvider.Instance.ClientDefinitions.Clear(); + + foreach (var c in discovered) + { + string key = $"{c.Hid.VendorID:X4}:{c.Hid.ProductID:X4}:{c.Hid.DevicePath}"; + if (!seen.Add(key)) continue; + + adopted.Add(new AlienwareAdoptedDevice + { + VendorId = c.Hid.VendorID, + ProductId = c.Hid.ProductID, + Manufacturer = c.Manufacturer, + Product = c.Product, + DevicePath = c.Hid.DevicePath, + ApiVersion = c.ApiVersion.ToString(), + LightCount = c.LightCount, + ReportLength = c.ReportLength, + }); + + Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareRGBDeviceProvider.Instance.ClientDefinitions.Add( + new Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareClientDefinition( + c.Hid.VendorID, c.Hid.ProductID, c.Manufacturer, c.Product, + c.ApiVersion, c.LightCount, c.ReportLength, c.Hid.DevicePath)); + } + + cur.deviceAlienwareAdoptedDevices = adopted; + cur.deviceAlienwareEnabled = true; + AppSettings.SaveSettings(cur); + + RGBController.LoadDeviceProvider( + Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareRGBDeviceProvider.Instance); + return true; + }); + + if (!result) + { + await DialogService.ShowAsync( + LocalizationService.Instance["No Alienware Devices Found"], + LocalizationService.Instance["Chromatics didn't detect any AlienFX hardware on this PC. Make sure you're on an Alienware (or Dell G-series) machine with AlienFX lighting. If Alienware Command Center or another AlienFX tool is running, close it before enabling this provider - they hold the HID interface exclusively."]); + } + return result; + }, + () => + { + var prov = Chromatics.Extensions.RGB.NET.Devices.Alienware.AlienwareRGBDeviceProvider.Instance; + if (prov != null) + { + prov.ClientDefinitions.Clear(); + RGBController.UnloadDeviceProvider(prov); + prov.Dispose(); + } + var cur = AppSettings.GetSettings(); + cur.deviceAlienwareEnabled = false; + AppSettings.SaveSettings(cur); + })); + + // Windows Dynamic Lighting (LampArray). Discovery is handled + // by the Windows DeviceWatcher inside the provider so there's + // no per-device adoption picker — every Dynamic-Lighting- + // capable device the OS exposes shows up automatically. + // Background lighting (during FFXIV gameplay) is gated by the + // sparse package registered via SparsePackageRegistrar — we + // register on enable and deregister on disable so Chromatics + // only appears in Settings → Personalization → Dynamic Lighting + // → Background light control when the user actually wants it on. + DeviceToggles.Add(new DeviceToggleItem( + "Dynamic Lighting (Beta)", + "[BETA] Enable/disable the Windows Dynamic Lighting provider. Picks up any device Windows lists in Settings -> Personalization -> Dynamic Lighting (Razer, Logitech G LIGHTSYNC, ASUS ROG, HyperX, MSI, SteelSeries, HP/Omen). Default: Disabled", + s.deviceDynamicLightingEnabled, + async () => + { + // Conflict popup (vendor providers already enabled). + await ShowDynamicLightingOverlapPopupIfNeededAsync("Dynamic Lighting (Beta)").ConfigureAwait(true); + + // First-time hint dialog walking the user through the + // Settings → Personalization → Dynamic Lighting steps, + // including dragging Chromatics to the top of the + // Background light control list for gameplay-time writes. + var cur = AppSettings.GetSettings(); + if (!cur.dynamicLightingHintShown) + { + try + { + var owner = GetMainWindow(); + var hintDlg = new DynamicLightingHintDialog(); + if (owner != null) await hintDlg.ShowDialog(owner).ConfigureAwait(true); + else hintDlg.Show(); + } + catch { /* dialog failure shouldn't block enable */ } + } + + RGBController.LoadDeviceProvider(DynamicLightingRGBDeviceProvider.Instance); + + // Empty-result handling: if Windows enumerated zero + // compatible devices, unload the provider and leave the + // toggle off rather than ship an enabled-but-empty + // provider. Mirrors the LIFX / Yeelight pattern. + if (DynamicLightingRGBDeviceProvider.Instance.AdoptedDeviceCount == 0) + { + RGBController.UnloadDeviceProvider(DynamicLightingRGBDeviceProvider.Instance); + var cc = AppSettings.GetSettings(); + cc.deviceDynamicLightingEnabled = false; + AppSettings.SaveSettings(cc); + // Auto-disable path also deregisters the sparse package + // so a failed enable doesn't leave Chromatics in the + // Windows DL list with no devices to control. + if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)) + await SparsePackageRegistrar.DeregisterAsync().ConfigureAwait(true); + await DialogService.ShowAsync( + LocalizationService.Instance["No Dynamic Lighting devices found"], + LocalizationService.Instance["Chromatics didn't detect any Dynamic Lighting devices on this PC. Open Settings -> Personalization -> Dynamic Lighting in Windows and check that at least one compatible device is listed there. If your hardware is listed but Chromatics still doesn't see it, it may be hidden by an enabled vendor provider conflict; Settings -> Advanced has a toggle to control that."]); + return false; + } + + var c = AppSettings.GetSettings(); + c.deviceDynamicLightingEnabled = true; + AppSettings.SaveSettings(c); + // Register the sparse package so Chromatics gets package + // identity for AmbientLightingServer (Background light + // control list). Idempotent. Requires Win10 2004+. + if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)) + await SparsePackageRegistrar.EnsureRegisteredAsync().ConfigureAwait(true); + return true; + }, + () => + { + RGBController.UnloadDeviceProvider(DynamicLightingRGBDeviceProvider.Instance); + var c = AppSettings.GetSettings(); + c.deviceDynamicLightingEnabled = false; + AppSettings.SaveSettings(c); + // Fire-and-forget deregister: don't block the UI on the + // ~1s RemovePackageAsync call. DeregisterAsync swallows + // its own errors into the verbose log. Requires Win10 2004+. + if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)) + _ = SparsePackageRegistrar.DeregisterAsync(); + })); } private static Avalonia.Controls.Window GetMainWindow() @@ -289,11 +624,22 @@ private static DeviceToggleItem MakeDeviceToggle( Action saveFlag) { return new DeviceToggleItem(label, tooltip, initial, - () => + async () => { + // Surface the Dynamic Lighting overlap popup before + // we kick off the load. Either side (vendor → DL or + // DL → vendor) gets a one-shot warning naming the + // other provider so the user knows what to expect. + // The auto-dedup in DynamicLightingRGBDeviceProvider + // makes the actual conflict harmless (vendor SDK + // wins on overlapping devices), but we still tell + // the user up-front rather than make them figure it + // out from the device list. + await ShowDynamicLightingOverlapPopupIfNeededAsync(label).ConfigureAwait(true); + load(); saveFlag(true); - return Task.FromResult(true); + return true; }, () => { @@ -302,6 +648,42 @@ private static DeviceToggleItem MakeDeviceToggle( }); } + // Shows a one-shot popup naming the other half of an overlap + // (DL → enabled vendor providers, or vendor → DL when DL is + // enabled). Returns immediately for any provider that doesn't + // overlap with Dynamic Lighting (Corsair, Wooting, Coolermaster, + // Novation, OpenRGB, etc.) so the helper is safe to call + // unconditionally from MakeDeviceToggle. + private static async Task ShowDynamicLightingOverlapPopupIfNeededAsync(string enablingProviderLabel) + { + try + { + var settings = AppSettings.GetSettings(); + + bool isDl = enablingProviderLabel.StartsWith("Dynamic Lighting", StringComparison.OrdinalIgnoreCase); + IReadOnlyList conflicts; + if (isDl) + { + conflicts = Chromatics.Extensions.RGB.NET.Devices.DynamicLighting.DynamicLightingVendorOverlap + .GetEnabledOverlappingVendorNames(settings); + if (conflicts.Count == 0) return; + } + else + { + if (!Chromatics.Extensions.RGB.NET.Devices.DynamicLighting.DynamicLightingVendorOverlap + .IsOverlappingVendorName(enablingProviderLabel)) return; + if (!settings.deviceDynamicLightingEnabled) return; + conflicts = new[] { "Dynamic Lighting" }; + } + + string title = LocalizationService.Instance["Provider conflict"]; + string template = LocalizationService.Instance["{0} overlaps with {1}. Both providers may try to control the same physical devices on this PC. To prevent flickering, the existing vendor SDK takes priority on overlapping devices and Dynamic Lighting silently skips them; you can override per device from the Mappings tab."]; + string body = string.Format(template, enablingProviderLabel, string.Join(", ", conflicts)); + await DialogService.ShowAsync(title, body).ConfigureAwait(true); + } + catch { /* popup is advisory; never block toggle on failure */ } + } + private bool _winStart; public bool WinStart { @@ -421,6 +803,21 @@ public bool EnableCrashReports } } + private bool _dynamicLightingBypassConflictCheck; + public bool DynamicLightingBypassConflictCheck + { + get => _dynamicLightingBypassConflictCheck; + set + { + if (SetProperty(ref _dynamicLightingBypassConflictCheck, value)) + { + var s = AppSettings.GetSettings(); + s.dynamicLightingBypassConflictCheck = value; + AppSettings.SaveSettings(s); + } + } + } + private bool _closeWithGame; public bool CloseWithGame { diff --git a/Chromatics/ViewModels/YeelightAdoptionDialogViewModel.cs b/Chromatics/ViewModels/YeelightAdoptionDialogViewModel.cs new file mode 100644 index 00000000..9627181e --- /dev/null +++ b/Chromatics/ViewModels/YeelightAdoptionDialogViewModel.cs @@ -0,0 +1,151 @@ +using Chromatics.Extensions.RGB.NET.Devices.Yeelight; +using Chromatics.Extensions.RGB.NET.Devices.Yeelight.Protocol; +using Chromatics.Localization; +using CommunityToolkit.Mvvm.ComponentModel; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Threading; +using System.Threading.Tasks; + +namespace Chromatics.ViewModels +{ + public partial class YeelightAdoptionDialogViewModel : ViewModelBase + { + // Discovered + already-adopted bulbs are merged into a single list, + // pre-checked for any Id that's already adopted. The dialog reads + // back the IsSelected state on Save to compute the new adoption set. + public ObservableCollection Bulbs { get; } = new(); + + [ObservableProperty] + private string _statusText; + + [ObservableProperty] + private bool _isDiscovering; + + public YeelightAdoptionDialogViewModel() + { + LocalizationService.Instance.PropertyChanged += OnLocaleChanged; + UpdateStatus(); + } + + private void OnLocaleChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(LocalizationService.Version)) + UpdateStatus(); + } + + private void UpdateStatus() + { + if (IsDiscovering) + StatusText = LocalizationService.Instance["Searching for Yeelight devices on your network..."]; + else if (Bulbs.Count == 0) + StatusText = LocalizationService.Instance["No Yeelight devices found. Make sure each bulb has LAN Control enabled in the Yeelight or Mi Home app."]; + else + StatusText = string.Format(LocalizationService.Instance["{0} Yeelight device(s) found."], Bulbs.Count); + } + + public async Task StartDiscoveryAsync(IReadOnlyDictionary alreadyAdopted, CancellationToken ct) + { + IsDiscovering = true; + UpdateStatus(); + Bulbs.Clear(); + + // Seed with offline-but-adopted devices so the user can see them + // even if they don't respond to discovery this run. + foreach (var (id, dev) in alreadyAdopted) + { + var item = new YeelightBulbItem + { + Id = id, + Label = dev.Label, + IpDisplay = LocalizationService.Instance["(offline)"], + LastPort = dev.LastPort > 0 ? dev.LastPort : 55443, + Model = YeelightModelCatalog.GetOrDefault(dev.Model).DisplayName, + FirmwareVersion = dev.FirmwareVersion, + Support = dev.Support?.ToArray() ?? Array.Empty(), + IsSelected = true, + IsOnline = false, + }; + Bulbs.Add(item); + } + + var byId = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var item in Bulbs) byId[item.Id] = item; + + try + { + var results = await YeelightDiscovery.DiscoverAsync(TimeSpan.FromSeconds(3), ct); + + foreach (var dev in results) + { + if (string.IsNullOrEmpty(dev.Id) || dev.Endpoint == null) continue; + + if (byId.TryGetValue(dev.Id, out var existing)) + { + existing.IpDisplay = dev.Endpoint.Address.ToString(); + existing.LastPort = dev.Endpoint.Port; + existing.IsOnline = true; + if (!string.IsNullOrEmpty(dev.DisplayLabel)) existing.Label = dev.DisplayLabel; + if (!string.IsNullOrEmpty(dev.Model)) + existing.Model = YeelightModelCatalog.GetOrDefault(dev.Model).DisplayName; + if (!string.IsNullOrEmpty(dev.FirmwareVersion)) existing.FirmwareVersion = dev.FirmwareVersion; + if (dev.Support != null) + { + var arr = new string[dev.Support.Count]; + for (int i = 0; i < dev.Support.Count; i++) arr[i] = dev.Support[i]; + existing.Support = arr; + } + } + else + { + var arr = Array.Empty(); + if (dev.Support != null) + { + arr = new string[dev.Support.Count]; + for (int i = 0; i < dev.Support.Count; i++) arr[i] = dev.Support[i]; + } + var item = new YeelightBulbItem + { + Id = dev.Id, + Label = string.IsNullOrEmpty(dev.DisplayLabel) ? dev.Id : dev.DisplayLabel, + IpDisplay = dev.Endpoint.Address.ToString(), + LastPort = dev.Endpoint.Port, + Model = YeelightModelCatalog.GetOrDefault(dev.Model).DisplayName, + FirmwareVersion = dev.FirmwareVersion, + Support = arr, + IsSelected = false, + IsOnline = true, + }; + Bulbs.Add(item); + byId[item.Id] = item; + } + } + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + StatusText = string.Format(LocalizationService.Instance["Discovery failed: {0}"], ex.Message); + IsDiscovering = false; + return; + } + + IsDiscovering = false; + UpdateStatus(); + } + } + + public partial class YeelightBulbItem : ObservableObject + { + [ObservableProperty] private string _id; + [ObservableProperty] private string _label; + [ObservableProperty] private string _ipDisplay; + [ObservableProperty] private int _lastPort = 55443; + [ObservableProperty] private string _model; + [ObservableProperty] private string _firmwareVersion; + [ObservableProperty] private string[] _support = System.Array.Empty(); + [ObservableProperty] private bool _isSelected; + [ObservableProperty] private bool _isOnline; + } +} diff --git a/Chromatics/Views/Dialogs/CopyLayersDialog.axaml b/Chromatics/Views/Dialogs/CopyLayersDialog.axaml new file mode 100644 index 00000000..21251d33 --- /dev/null +++ b/Chromatics/Views/Dialogs/CopyLayersDialog.axaml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Chromatics/Views/Mapping/VirtualDeviceView.axaml.cs b/Chromatics/Views/Mapping/VirtualDeviceView.axaml.cs index 28f7a8ef..86513de7 100644 --- a/Chromatics/Views/Mapping/VirtualDeviceView.axaml.cs +++ b/Chromatics/Views/Mapping/VirtualDeviceView.axaml.cs @@ -193,6 +193,33 @@ private void OnResetBrightnessClick(object sender, RoutedEventArgs e) DeviceVm?.ResetBrightness(); } + private async void OnCopyLayersClick(object sender, RoutedEventArgs e) + { + var device = DeviceVm; + if (device == null) return; + var owner = this.FindAncestorOfType(); + if (owner == null) return; + + // Live device dictionary from the RGB surface — the dialog + // filters its destination list against this so newly-attached + // devices appear without needing a Mappings-tab refresh. + var connected = Chromatics.Core.RGBController.GetLiveDevices(); + + var dlg = new Chromatics.Views.Dialogs.CopyLayersDialog(connected, device.DeviceId); + await dlg.ShowDialog(owner); + + if (dlg.Applied) + { + // Let the Mappings tab pick up the freshly-created layers + // on the destination device. The layer list view binds + // off MappingLayers.GetLayers and rebuilds on RefreshLayers. + if (owner.DataContext is Chromatics.ViewModels.Mapping.MappingViewModel mvm) + { + try { mvm.RefreshLayers(); } catch { /* best-effort */ } + } + } + } + private async void OnResetLayoutClick(object sender, RoutedEventArgs e) { var device = DeviceVm; diff --git a/Chromatics/Views/SettingsView.axaml b/Chromatics/Views/SettingsView.axaml index 1f57cedf..dee52f89 100644 --- a/Chromatics/Views/SettingsView.axaml +++ b/Chromatics/Views/SettingsView.axaml @@ -109,6 +109,9 @@ +