A .NET client library for controlling ZSA keyboards through the Keymapp application's gRPC API.
Keymapp.NET provides a comprehensive C# wrapper around the Keymapp gRPC service, allowing you to programmatically control ZSA keyboards (like the Moonlander, Planck EZ, and Ergodox EZ) from your .NET applications.
- Keyboard Management: Connect to and manage multiple ZSA keyboards
- Layer Control: Set and unset keyboard layers programmatically
- RGB LED Control: Control individual LEDs or all LEDs with custom colors
- Status LED Control: Manage status LEDs on supported keyboards
- Brightness Control: Adjust keyboard brightness levels
- Async/Await Support: Full async support with cancellation tokens
- Dependency Injection: Built-in support for Microsoft.Extensions.DependencyInjection
- Extension Methods: Convenient extension methods for common operations
Add the project reference to your application:
<ProjectReference Include="path/to/Keymapp.NET/Keymapp.NET.csproj"/>
- Keymapp application must be running with gRPC API enabled (typically on
http://127.0.0.1:50051
) - A compatible ZSA keyboard connected to your system
using Keymapp.NET;
using Microsoft.Extensions.DependencyInjection;
using Grpc.Net.Client;
var services = new ServiceCollection()
.AddKeymappServices(GrpcChannel.ForAddress("http://127.0.0.1:50051"))
.BuildServiceProvider();
using var scope = services.CreateScope();
var keymappApi = scope.ServiceProvider.GetRequiredService<IKeymappApi>();
using Grpc.Net.Client;
using Keymapp.NET;
using var channel = GrpcChannel.ForAddress("http://127.0.0.1:50051");
await using var api = new KeymappApi(channel);
var status = await keymappApi.GetStatusAsync();
Console.WriteLine($"Keymapp Version: {status.KeymappVersion}");
if (status.ConnectedKeyboard != null)
{
Console.WriteLine($"Connected: {status.ConnectedKeyboard.FriendlyName}");
}
// Connect to any available keyboard
var connectResult = await keymappApi.ConnectAnyKeyboardAsync();
// Or connect to a specific keyboard
var keyboards = await keymappApi.GetKeyboardsAsync();
if (keyboards.Length > 0)
{
var request = new ConnectKeyboardRequest { Id = keyboards[0].Id };
var result = await keymappApi.ConnectKeyboardAsync(request);
}
// Set a specific LED to red
var redColor = Color.FromArgb(255, 0, 0);
await keymappApi.SetRGBLedAsync(0, redColor, 1000); // LED 0, red, 1 second
// Set all LEDs to blue
var blueColor = Color.FromArgb(0, 0, 255);
await keymappApi.SetRGBAllAsync(blueColor, 2000); // All LEDs, blue, 2 seconds
// Restore original colors
await keymappApi.RestoreKeyboardColorsAsync();
// Activate layer 1
await keymappApi.SetLayerAsync(1);
// Deactivate layer 1
await keymappApi.UnsetLayerAsync(1);
// Increase brightness
await keymappApi.IncreaseBrightnessAsync();
// Decrease brightness
await keymappApi.DecreaseBrightnessAsync();
// Bulk brightness update (extension method)
await keymappApi.UpdateBrightnessAsync(increase: true, steps: 3);
ConnectAsync(GrpcChannel channel, CancellationToken ct = default)
- Initialize connectionConnectKeyboardAsync(ConnectKeyboardRequest request, CancellationToken ct = default)
- Connect specific keyboardConnectAnyKeyboardAsync(CancellationToken ct = default)
- Connect any available keyboardDisconnectKeyboardAsync(CancellationToken ct = default)
- Disconnect current keyboard
GetStatusAsync(CancellationToken ct = default)
- Get Keymapp status and connected keyboard infoGetKeyboardsAsync(CancellationToken ct = default)
- List all available keyboards
SetLayerAsync(int layer, CancellationToken ct = default)
- Activate a keyboard layerUnsetLayerAsync(int layer, CancellationToken ct = default)
- Deactivate a keyboard layer
SetRGBLedAsync(int led, Color color, int sustain = 0, CancellationToken ct = default)
- Control individual RGB LEDSetRGBAllAsync(Color color, int sustain = 0, CancellationToken ct = default)
- Control all RGB LEDsSetStatusLedAsync(int led, bool on, int sustain = 0, CancellationToken ct = default)
- Control status LEDs
IncreaseBrightnessAsync(CancellationToken ct = default)
- Increase brightness by one stepDecreaseBrightnessAsync(CancellationToken ct = default)
- Decrease brightness by one step
The library includes helpful extension methods in KeymappExtensions
:
RestoreKeyboardColorsAsync()
- Restore all RGB LEDs to defaultRestoreStatusLedAsync()
- Restore status LED to defaultUpdateBrightnessAsync(bool increase, int steps)
- Bulk brightness adjustment
All API methods properly handle gRPC exceptions and cancellation tokens. Wrap calls in try-catch blocks to handle network issues:
try
{
var status = await keymappApi.GetStatusAsync();
// Handle success
}
catch (RpcException ex)
{
// Handle gRPC communication errors
Console.WriteLine($"gRPC Error: {ex.Message}");
}
catch (OperationCanceledException)
{
// Handle cancellation
Console.WriteLine("Operation was cancelled");
}
- Google.Protobuf
- Grpc.Net.Client
- Microsoft.Extensions.DependencyInjection.Abstractions
- Microsoft.Extensions.Logging.Abstractions
- Microsoft.Extensions.Options.ConfigurationExtensions
This project integrates with ZSA's Keymapp ecosystem. The protobuf definitions are sourced from the official ZSA Kontroll repository.
- Sample - Comprehensive example application demonstrating all API features
- Integration Tests - Test suite for API functionality