Let's start with a quick demo:

The exchange protocol is very simple yet efficient; it uses on-off keying (OOK): a binary 1 is represented by the presence of a signal, whereas a 0 corresponds to silence.

I designed a minimalist, scalable transmission protocol. Each word has a variable length: it can be 8 bits for a character or a type field. The type field lets the device determine the message length. The last bit of each word is the inverse of the preceding bit, ensuring a transition that triggers flushing the message to memory (see code). The type field and a transmission sequence allow the device to verify the link’s consistency and state. The message length is also variable, and the frame ends with a CRC for integrity checking.

The Emission Web Page

https://cdn.hackaday.io/files/2021968650753664/keypad.html.zip

also available here : https://oktoapp.com/keypad/

The protocol is extensible, enabling control of additional devices such as :

 a mouse,  an infrared transmitter, and more. 

The proposed web page requires no app installation; it runs in the browser and stores messages in localStorage,

so the data stays under the user’s control. 
The page is a static asset and can be hosted anywhere.
Other applications can be implemented:
a keyboard macro, a mouse macro, an infrared command, and a key vault for password management;
optional encryption can be added during transmission and decrypted by the device using the Web Cryptography API.
If other possibilities come to mind, feel free to mention them in the comments.

Arduino Code

https://cdn.hackaday.io/files/2021968650753664/keypad.ino

The code on this page is downloadable. It consists of two main parts:

  • First, the receiver detects a ‘1’ from the presence of oscillation and a ‘0’ from silence, then buffers the result.

  • Second, it decodes the buffered bits.

The device uses the digital input, which is much faster to process than the analog input on typical microcontrollers. An analog path was evaluated to push higher data rates by analyzing frequencies (FM/QAM/FFT), but decode times were never better than the current pulse-based approach: 2 ms/bit (≈ 500 bit/s ≈ 62.5 bytes/s).

If you believe you can achieve a higher throughput, feel free to share your code, it would be a pleasure to test it.