So, as promised, here is an solution, that at least works for my needs:
All credits goes to Thanasis Georgiou!
He posted an pseudo-code that exactly describes, what needed.
https://thgeorgiou.com/posts/2016-02-23-Communicating-using-keyboard-status-LEDs/
An commandline c++ exe sends test to the arduino by toggling the keyboard leds (capslock, numlock, scrollock).
Yes, it is an slow way of communication, and yes, there could (or schould) be added an ACK message, BUT it works!
I had to tweak with GetKeyState(0) a lot, to enshure, i'm always getting the updated key values (this is an windows issue, and calling GetKeyState(0) is forcing the system to refresh the keystates)
PC (Dev-C++):
#include <iostream>
#include <string>
#include <bitset>
#include <Windows.h>
const int ClockSpeed = 10;
const int Delay = 1000 / ClockSpeed;
void SetCapsLock(BOOL bState)
{
GetKeyState(0);
Sleep(8);
GetKeyState(0);
Sleep(8);
BYTE keyState[256];
GetKeyboardState((LPBYTE)&keyState);
if((bState&&!(keyState[VK_CAPITAL]&1)) || (!bState && (keyState[VK_CAPITAL]&1)))
{
keybd_event(VK_CAPITAL,
0,
KEYEVENTF_EXTENDEDKEY | 0,
0);
keybd_event(VK_CAPITAL,
0,
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
0);
}
}
void SetNumLock(BOOL bState)
{
GetKeyState(0);
Sleep(8);
GetKeyState(0);
Sleep(8);
BYTE keyState[256];
GetKeyboardState((LPBYTE)&keyState);
if((bState&&!(keyState[VK_NUMLOCK]&1)) || (!bState && (keyState[VK_NUMLOCK]&1)))
{
keybd_event(VK_NUMLOCK,
0,
KEYEVENTF_EXTENDEDKEY | 0,
0);
keybd_event(VK_NUMLOCK,
0,
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
0);
}
}
void SetScrollLock(BOOL bState)
{
GetKeyState(0);
Sleep(8);
GetKeyState(0);
Sleep(8);
BYTE keyState[256];
GetKeyboardState((LPBYTE)&keyState);
if((bState&&!(keyState[VK_SCROLL]&1)) || (!bState && (keyState[VK_SCROLL]&1)))
{
keybd_event(VK_SCROLL,
0,
KEYEVENTF_EXTENDEDKEY | 0,
0);
keybd_event(VK_SCROLL,
0,
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
0);
}
}
std::bitset<8> ToBits(unsigned char byte)
{
return std::bitset<8>(byte);
}
int main(int argc, char** argv)
{
bool loopflag = true;
while(loopflag) {
SetCapsLock(false);
SetNumLock(false);
SetScrollLock(false);
std::cout << "Enter string:";
std::string s;
std::getline(std::cin, s);
s = s + '\n';
if (s=="-q") {
loopflag=false;
break;
}
for (std::size_t i=0; i< s.size(); i++)
{
std::bitset<8> v8 = std::bitset<8>(s.c_str()[i]);
for (int j=0; j<8; j+= 2)
{
//Set data lines
SetNumLock(v8[j]);
SetCapsLock(v8[j+1]);
//Cycle Clock
Sleep(Delay/3);
SetScrollLock(true);
Sleep(Delay/3);
SetScrollLock(false);
Sleep(Delay/3);
//std::cout << v8[j];
//std::cout << v8[j+1];
}
//std::cout << std::bitset<8>(s.c_str()[i]) << std::endl;
}
//std::cout << "" << std::endl;
SetCapsLock(false);
SetNumLock(false);
SetScrollLock(false);
}
}
Arduino (this code shoud be used with Nicehood's HID library (e.g. BootKeyboard):
(GitHub - NicoHood/HID: Bring enhanced HID functions to your Arduino!)
//#################################################
// Read from Status-HID-Keyboard-Leds
// call this function each time a new Led-State has receives, or - as i do - in your main loop as often as possible
//#################################################
char yourIncommingChar;
// which byte are we receiving
unsigned char byteIndex = 0;
// which bit of the byte above we are receiving right now
unsigned char bitIndex = 0;
// was the last cycle a clock?
unsigned char lastClock = 0;
uint8_t myLeds;
void ReadKeyboardLedCommunication(void) {
if(BootKeyboard.getLeds() == myLeds) {
return;
} else {
myLeds = BootKeyboard.getLeds();
}
if ((myLeds & LED_SCROLL_LOCK)!=0) { // if numlock is enabled HIGH
if (lastClock == 0) {
lastClock = 1;
//store numlock
if((myLeds & LED_NUM_LOCK) != 0) {
yourIncommingChar |= 1 << (bitIndex);
}
// advance the bit index since we stored one bit
bitIndex++;
//store capslock
if((myLeds & LED_CAPS_LOCK) != 0) {
yourIncommingChar |= 1 << (bitIndex);
}
bitIndex++; // another bit
//if this byte is received, move to next one
if (bitIndex == 8) {
byteIndex++;
bitIndex = 0;
}
}
} else if ((myLeds & LED_SCROLL_LOCK)==0) { // scroll lock off
// clock cycle finished
if (lastClock == 1) {
lastClock = 0;
if (byteIndex == 1) {
Serial.print(yourIncommingChar);
yourIncommingChar = 0;
bitIndex = 0;
byteIndex = 0;
}
}
}
}
For my needs, i modded the dynamic serial command parser, so it can read the yourIncommingChar, too (this way i don't waste programm space, and as i'll use this whenever serial is not available, i don't need to care about it).
There's a lot to do, an maybe someone would like to participate and help to improve the communication.
I'm an simple hobby programmer, so there will be a lot that could be done better.
However, this is wat works for me.
I'd be happy for ANY advice to do things better!!!!