Companion App

A project log for Keybon – Adaptive Macro Keyboard

Customizable OLED keyboard that adapts to the apps you use

Max.KMax.K 12/09/2020 at 20:3211 Comments

Without the appropriate desktop software, Keybon is just a programmable keyboard. The goal was to add the ability to configure the device from windows and change keyboard layouts on the go. I decided to create a windows forms application in C#. 

The application works like this: You connect to the keyboard via a COM port. Then you configure the icons that are displayed on the OLED screens and the macro functions for each button. This can be done via drag&drop for the images. The button commands need to be entered in a way the “sendkeys” method can interpret them. For example, +{h}{e}{l}{l}{o} prints “Hello” when pressing the corresponding button. You can create up to 8 layouts, but there is really no hardware limitation to this. As the layouts are only saved on the computer, the STM32’s memory is not the limiting factor. When a layout is activated, the application sends a command to the keyboard that disables its HID function. After that, the nine images are transferred via the COM port as a stream of bytes. This takes only a few milliseconds, so the change on the actual OLEDs is instant. To each layout a set of windows processes can be added. The software constantly checks what application is running in the foreground. If for example Google Chrome is opened, the software instantly switches to the matching layout.
As this was is my first C# project, making the app took some time and effort. By splitting the functionality into small parts, each problem became solvable. Detecting foreground apps has fortunately been well documented. Writing images to the keyboard was just a matter of efficiently splitting bitmaps into bytes. One of the most complicated part was saving and loading settings. I decided to use the feature built into Visual Studio, that saves a single .xml file to “users/appdata/…”. This way the .exe works without an install or a visible settings folder. As .xml files are text based the bitmap information needs to be serialized first and reassembled into an image later. After all I am quite happy with the companion software. There are of course plenty of usability features that could be added, but the basic functionality is sufficient to use the keyboard productively.


4gordi wrote 05/17/2022 at 13:13 point

Hi. How i can add more then 8 templates? And how we can change tamplate with shortcut key?

  Are you sure? yes | no

Max.K wrote 05/17/2022 at 15:29 point

This line defines how many layouts are available:
public ScreenLayout[] Layouts = new ScreenLayout[8];

When you press a button portDataReceived() is executed. You have to change the content of this function to open a layout instead of emulating a key press.

The app could select a new layout with switchToLayout(...)

  Are you sure? yes | no

4gordi wrote 05/17/2022 at 16:36 point

Thanx for feedback) Where i can find string: “public ScreenLayout[] Layouts = new ScreenLayout[8]”? Which document?

And where enter a command: switchToLayout(…)? Sorry, for noob’s question(

  Are you sure? yes | no

Max.K wrote 05/17/2022 at 17:59 point

You need to set up the C# project in Visual Studio:

Just to clarify, you need to need to change the code in some places. It's doable but a little more work than just running commands.

  Are you sure? yes | no

4gordi wrote 05/17/2022 at 18:19 point

I understood. If i change “portDataRecieved()” function to “switchToLayout()” it means this button will do change layout and will no longer be responsible for shortcut? For example, i may pass the function to “1” number of button, on all templates first oled-button will lead to other layout?

  Are you sure? yes | no

Max.K wrote 05/17/2022 at 20:55 point

portDataReceived is executed whenever a char from the Keybon is received. The line 

SendKeys.SendWait(Layouts[currentLayout].keyCommand[keyReceived - 49]);

is what does the emulated button pressing. It presses the key that is mapped to the current layout. Instead of this line you should do this:

if(keyReceived == '1') switchToLayout(2) 

else SendKeys.SendWait...

But your function needs to be aware if we are already in a sub-menu. Then e.g. key '1' has a different effect. But that is up to you.

  Are you sure? yes | no

4gordi wrote 05/18/2022 at 08:50 point

i can do it via button click flag?

For example:

flagPressed = 0

if(keyReceived == '1' and flagPressed == 0)


flagPressed = 1

elif(keyRecived == ‘1’ and flagPressed != 0)

switchToLayout(1) // how i can come back to -1 layout?

else SendKeys.SendWait...

sorry, for my perseverance, i’m bad in C#, but I'm a fast learner) and good at python)

  Are you sure? yes | no

Max.K wrote 05/18/2022 at 16:11 point

You'd have to translate that to C# but yes, that should work. Have you tried running the app from Visual Studio already? 

  Are you sure? yes | no

4gordi wrote 05/18/2022 at 18:12 point

Yes, i ran app from visual studio, and i correct number of layers to 15) Add some features, like a minimize to tray and other cosmetic improvements, it works good)

btn_pressed = true; 

if (keyReceived == '1' & btn_pressed == false)
                    btn_pressed = true;

                else if (keyReceived == '1' & btn_pressed == true)
                    btn_pressed = false;
                    SendKeys.SendWait(Layouts[currentLayout].keyCommand[keyReceived - 49]);


It's right? Maybe insert this code in handler picturebox_click?

I create fork on github with my version of keybon companion

  Are you sure? yes | no

Max.K wrote 05/20/2022 at 18:52 point

Yes, that seems like it should work. Have you tried it already?

  Are you sure? yes | no

4gordi wrote 05/21/2022 at 11:34 point

Temporarily unable to check, not all components are in stock( They sent me defective screens(

  Are you sure? yes | no