Nicht Fershtein: teaching a penguin to understand multimedia keys. We simulate the work of the keyboard Scan codes of keyboard keys table

The key number sent by the keyboard processor is uniquely dependent on the layout of the keyboard matrix, but not on the designations printed on the surface of the keys. This number is called a Scan Code. The word "scan" refers to the fact that the keyboard computer scans the keyboard to find the key that has been pressed.

Ascii code of the pressed key

Usually, the program does not need the serial number of the pressed key, but the code corresponding to the designation on this key (ASCII code).

The ASCII code is not directly related to the scan code, since several ASCII code values ​​can correspond to the same key, depending on the state of other keys. For example, the key labeled "1" is also used to enter the character "!" (if it was pressed together with the key ).

Therefore, all conversions of the scan code to ASCII code are performed by software. Typically, in the MS-DOS operating system, these conversions are performed by BIOS modules. To use Cyrillic characters, these modules are extended by keyboard drivers, both included in the localized versions of MS-DOS, and created as separate programs.

Auto repeat mode

If you press the key and do not release it, the keyboard will go into auto-repeat mode. In this case, the code of the pressed key is automatically sent to the computer after a certain period of time, called the auto-repeat period. The auto-repeat mode makes it easier to enter a large number of identical characters from the keyboard.

It should be noted that the keyboard contains an internal 16-byte buffer through which it communicates with the computer.

Keyboard types

Until recently, there were three different types of keyboards. These are the keyboard for IBM PC/XT computers, the 84-key keyboard for IBM PC/AT, and the 101-key (extended) keyboard for IBMPC/AT. Some keyboards have an operation mode switch (XT/AT) located on the bottom cover. It must be installed in the correct position.

After the Microsoft Windows operating system became widespread, a new type of keyboard was created specifically for it. Two buttons were added to a conventional IBMPC / AT keyboard, the first of which duplicates the Start menu call, performed using the left mouse button, and the second - the call of the same menu using the right mouse button.

Keyboard ports

The assignment of ports for keyboard operation depends on the type of computer.

ComputerIbm pc/xt

To work with an IBM PC/XT keyboard, ports with addresses 60h and 61h are used.

Port 60h is read-only. After performing this operation, it contains the scan code of the last key pressed.

Port 61h is available for both reading and writing. It controls not only the keyboard, but also other computer devices, for example, the operation of the built-in speaker. If the high bit of port 61h is written to 1, the keyboard will be locked, if 0 - unlocked.

Since port 61h controls more than just the keyboard, changing the contents of the most significant bit must save the state of the remaining bits of this port. To do this, you can first read the contents of the port into the register, change the state of the high bit, then write the new value to the port.

Most modern keyboards are equipped with multimedia keys, and mice already have three to seven buttons. On the disk that comes with the kit, and on the manufacturer's website, drivers and various useful programs only for Windows. Everyone knows that Linux is famous for its ability to customize the system for itself, if, of course, you know where and what to configure. Our task is to teach the penguin to work with additional loaves.

Key Scan Code Definition

Whatever you press on your keyboard, the X server and the kernel, in general, do not care what is written or drawn on it. They are only interested in the scan code of the button, and first the Xs read the kernel key code table, and then the key code is tied to its own code table. If in Windows there is no problem of setting up multimedia keys in the console as such, then in Linux you have to separately configure the reaction to pressing buttons in the console and in the X-Window.

To find out the key code, you should use the xev utility that is included with the X server. After its launch, the Event Tester window appears, now we sequentially press the keys, remembering the issued code:

$xev
...
KeyRelease event, serial 31, synthetic NO, window 0x3e00001,
root 0x67, subw 0x0, time 279734676, (311,611), root:(1104,687),
state 0x2000, keycode 236 (keysym 0x1008ff19, XF86Mail), same_screen YES,

XFilterEvent returns: False
KeyRelease event, serial 31, synthetic NO, window 0x2600001,
root 0x67, subw 0x0, time 265877259, (883,334), root:(886,358),
state 0x0, keycode 161 (keysym 0x0, NoSymbol), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False

The output can be huge as every mouse move as you pass over the Event Tester window is tracked. The key is described by the KeyRelease block, in particular, the keycode value is exactly the scan code that we want to know. In the example shown, two keys are pressed. Keycode 236 corresponds to the keycode for the X server specified in keysym and the XF86Mail action, which in KDE launches the default mail client. For key number 161, the code and action are not defined.

It is possible that a key is pressed, but its scan code is not issued. This means that the kernel cannot find a matching value. The output of dmesg should look like this:

Use "setkeycodes 0xec to make it known.

That is, you are offered to set the scan code of the key yourself using setkeycodes, while choosing the keycode value is very simple. Convert the resulting digit to a decimal number (most calculators can do this) and add 128. In this example, 0xec=236, that is, we get scan code 364. If in doubt, a list of enabled and disabled scan codes can be viewed by running the getkeycodes utility in the console or dumpkeys. For example, if the output is "getkeycodes | grep<код клавиши>” gave nothing, so this code can be safely used.

The XKeycaps utility (www.jwz.org/xkeycaps), which is a graphical front-end to Xmodmap, can also help determine the scan code.

The xev program does not work in the console, of course. To find out the scan code issued by the kernel, use the showkey or getkeycodes utility:

$showkey
keyboard was in UNICODE mode
press any key (the program will end 10 seconds after the last key press)...
0xe0 0x6c 0xe0 0xec

The first two digits correspond to the pressed key, the second - to the absence of pressing.

Configuring scancode binding in X-Window

So, now we have scan codes, we need to tell the X server what it should actually do when this key is pressed, that is, give it a symbolic name. The list of symbol names is given in the XF86keysym.h header file. By default, X server header files are not installed on modern distributions. To see it in Ubuntu, you need to install the x11proto-core-dev package, after which this file will be in the /usr/include/X11 directory. Alternatively, you can contact the X.Org CVS server. We look:

$ cat /usr/include/X11/XF86keysym.h
/*
* Keys found on some "Internet" keyboards.
*/
#define XF86XK_Standby 0x1008FF10
#define XF86XK_AudioLowerVolume 0x1008FF11
#define XF86XK_AudioRaiseVolume 0x1008FF13
#define XF86XK_AudioPlay 0x1008FF14
#define XF86XK_AudioStop 0x1008FF15
#define XF86XK_Mail 0x1008FF19

If we compare the last line with the xev output, we see that the values ​​match the key with keycode 236 - keysym 0x1008ff19, XF86Mail (no XK_ suffix). You will find a list of all available values ​​in the form in which they should be used in /usr/share/X11/XKeysymDB.

There are two ways to create your own layout: create a description of your keyboard or use Xmodmap. The last method is the easiest, so we will talk about it further. In the user's home directory, create an .Xmodmap file, in which we enter the desired values:

$medit ~/. xmodmap

keycode 161 XF86Calculator
keycode 174 XF86AudioLowerVolume
keycode 176 XF86AudioRaiseVolume
keycode 162 XF86AudioPause

And so on, the principle, I think, is clear. Moreover, the key code can be entered both in decimal and hexadecimal form. According to my observations, the codes of most keys are standardized. Therefore, if you once set up a reaction to a keystroke and transfer the file to another computer, it is likely that on another keyboard the reaction to pressing a key that is also signed will be similar. Gnome desktop users with GDM can write all of these lines to the system-wide /etc/X11/Xmodmap.

In other cases, we still need to tell the X server to use the generated file. This is implemented differently in different distributions, the main idea is to run the /usr/bin/xmodmap $HOME/.Xmodmap command when the user logs in or starts X. Here everyone dances as he wants. The forums suggest using the $HOME/.xsession file (may be called .Xsession on some distributions), .xprofile, or the system's /etc/X11/Xsession. And I'm afraid that this is not all possible options. Let's see how it's done in KUbuntu:

$ sudo grep -iR xmodmap /etc

As a result, we find the most curious file /etc/X11/Xsession.d/80ubuntu-xmodmap with the following content:

$ cat /etc/X11/Xsession.d/80ubuntu-xmodmap

/usr/bin/xmodmap /usr/share/apps/kxkb/ubuntu.xmodmap || true

USRMODMAP="$HOME/.Xmodmap"

if [ -x /usr/bin/xmodmap ]; then
if [ -f "$USRMODMAP" ]; then
/usr/bin/xmodmap "$USRMODMAP" || true
fi
fi

That is, the contents of the ubuntu.xmodmap file and the custom.Xmodmap file, if it exists, are loaded. When you open ubuntu.xmodmap in an editor, you'll find a list of keycodes and mapped symbol names. From this we can conclude: if a developer reports that his distribution kit supports multimedia keyboards, then with a high degree of probability you can find a similar file. Other distributions have a similar system for running custom xmodmap files.

Now that the symbolic names have been assigned to the keys, you can assign the desired actions to them. Some windowing environments like KDE are able to process actions on symbolic names. So, when you press the XF86AudioPlay (QUESTION) button, the default player starts playing. To set the desired combination, just go to the "KDE Control Center -> Regional and Accessibility -> Keyboard Shortcuts" (in KUbuntu, look in "System Setting -> Keyboard & Mouse"). There is a similar menu item in Gnome (you can just call gnome-keyboard-bindings) and in XFce. Plus, some programs like Amarok, Konqueror, MPD also handle keystrokes. In other environments without
graphical configuration tools will most likely require manual intervention in the configuration files. For example, in order for IceWM to start the XMMS player by pressing a key with the symbolic name XF86AudioPlay, and then pause it when pressed again, add the following line to the ~/.icewm file that appears after the first launch:

$ mcedit ~/.icewm

key XF86AudioPlay xmms --play-pause

In Fluxbox, the string to launch the player would look like this:

$ mcedit ~/.fluxbox/keys

None XF86AudioPlay:ExecCommand xmms --play-pause

There are usually examples in configs, so I think you can easily figure out the rest of the window managers yourself.

Setting the reaction in the console

In the console, the procedure is somewhat different. As you remember, the dmesg output recommended assigning keycodes using the setkeycodes command. But there are differences here - there cannot be more than 128 keyboard commands in the console, you should choose values ​​from 0 to 127:

$setkeycodes 0xec 118

You can view free values ​​in the current keyboard layout file. On Ubuntu and all Debian based distributions this is usually /etc/console-setup/boottime.kmap.gz. If there are no problems with the keys after starting, we enter this line in one of the start scripts, for example, in /etc/init.d/rc.local.

Now it remains to set the correspondence of the key and the action performed. Here the scope for creativity is even greater than in X. In keymaps(5), the procedure for matching a keycode is as follows:

( plain | ) keycode keynumber = keysym

# Switching the console one back when pressing the key with code 105
keycode 105 = Decr_Console
# Switch the console one forward when you click on and a key with code 106
alt keycode 106 = Incr_Console

But you can create your own options by specifying the command in variables:

keycode 120 = F100
string F100 = "/sbin/shutdown -h now\n"

In other words, upon pressing the key with code 120, the action specified in the F100 variable will be performed; in our case, the computer is set to turn off. Instead of F100, of course, you can use any other name.

Now the equally important part is where to write it all down. The documentation and numerous tips suggest using the current console layout file (in my case, boottime.kmap.gz). By the way, this is the only layout description file available after installing KUbuntu; to see other options, install the console-data package. After that, in /usr/share/keymaps/i386/ you can find several subdirectories with files inside. But if you need to switch to a different layout (in Ubuntu and some other distributions, the /etc/default/console-setup or ~/.console-setup file is used for this purpose), all settings will need to be transferred to another file, which is somewhat
uncomfortable. If you still decide to take this step, use the existing entries as a template, without writing anything in the first position, and do not forget to leave an empty line at the end.

A little about the laptop

Until I came across a laptop, the scan codes of the keys of which could not be determined. Therefore, the settings here are no different from those described above. Although there is one technique that I would like to talk about. I find the hibernation mode very convenient to use, when you turn on the computer, you find everything in its place. Modern distributions generally support it, although the setup is generally simple - just install the hibernate package and override the necessary options in the configuration file. The only thing is that each time you need to run the /usr/sbin/hibernate script to switch to this mode, which is not always convenient. I just want to close the lid of the laptop, and turn it on again
food, discover everything in its place.

This is very easy to do using the acpid daemon, which is a kind of user interface that allows you to manage any ACPI events available through /proc/acpi/event. In doing so, acpid reads a set of configuration files from the /etc/acpi/events/ directory. If there is no package with the daemon in the distribution, install it from the repository; the latest version can be downloaded from phobos.fs.tum.de/acpi. After installation, you need to create two files in the /etc/acpi/events directory: lid and power. The first describes the response to closing the lid, the second - to pressing the power button.

$ sudo mcedit /etc/acpi/events/lid

event=button/lid.*
action=/usr/sbin/hibernate

$ sudo mcedit /etc/acpi/events/power

event=button/power.*
action=/sbin/shutdown -h now

These are somewhat simplified options, in KUbuntu you will find more complex scripts. After that, restarting the acpid daemon is required:

$ sudo /etc/init.d/acpid restart

Now, when you close the laptop lid, the system will hibernate with the power off, and when you press the power button, it will turn off. Simple and convenient.

Tuners

If you don't like fiddling with configuration files, here are a few programs that will help you customize how the multimedia keys work. For example, the original purpose of the Sven program (sven.linux.kiev.ua) was to set up additional keys on the multimedia keyboard, but starting from version 0.4, it can correct typing errors and change keyboard layout. Moreover, even if you have a regular keyboard, with its help you can emulate multimedia keys by using keyboard shortcuts instead. You can also assign actions to specific mouse buttons. She understands approximately 10,000 Russian words and 9,500 English. If the program did not switch
itself, then the layout can be changed manually, using a specially defined key (Break by default). With a separate key (Scroll Lock) you can change the case of words (upper, lower, the first letter is upper, the rest are lower). The keyboard layout switch indicator remembers its state for each window, so if you often switch between applications, you will no longer need to change the layout additionally. The program has great features, and I would advise you to take a look at it. All settings are made using graphics program, built on GTK+ libraries. Sven has been tested on Linux, but should in principle work on *BSD systems. Window manager to use
irrelevant.

Features of KeyTouch (keytouch.sf.net) are somewhat more modest, this utility is used exclusively for configuring multimedia keys. Although with its help you can assign your own action to any key, which differs from the default settings. On the program website, in addition to source codes and packages for some distributions, you can find ready-made settings for multimedia keyboards from most well-known manufacturers.

Another interesting solution - xbindkeys (hocwp.free.fr/xbindkeys/xbindkeys.html) - allows you to assign any command to any keyboard and mouse button, including shell commands. All settings are made in the configuration file, which has a simple and understandable format.

The next typical PC device, seemingly simple, but sometimes causing trouble for the researcher, is the keyboard.

In general, the device is simple. Especially none of the outdated models connected to the PS / 2 port. As numerous experimental data show, the Claudia control chip scans keystrokes and transmits them in serial code to the port. The clock frequency of this transmission is a multiple (in the vast majority of cases) of 6.3 or 10 kHz. Although the author came across a couple of copies in the most recent years, the clock frequency of which was in the region of 20 kHz.

All keyboards, when pressing and holding any key, begin (after a pause) to repeat the transmission of the key code “to infinity”. In normal mode, this usually causes the controller buffer to overflow and crash after a few seconds. There is a sound signal of the system "speaker" - "squeak". The essence of the test mode (the most common) is to block the buffer overflow command, which allows, when the key is pressed, to provide an endless transmission of the selected character over the “clave” cable.

As always, for the correct subsequent calculation of the result, it is necessary to create a constant alternation of pulses in the code packet. For keyboard codes, there can be two such combinations:

10101010 (55) “+” key; = »

01010101 (AA) in standard tables - not applicable

The general table of scan codes is shown in Table 14.1

Table 14.1- Keyboard scan codes

Key

Scan code

Key

Scan code

Key

Scan code

Key

Scan code

Thus, when implementing the test mode and, for example, a weight placed on the “+” key, an infinite sequence of pulse packets will be present in the “clave” cable. In this case, the pulse repetition period in the packet (that is, the clock frequency) will be equal to 6.10 or 20 kHz, and the packet repetition rate will be much lower. The data format is shown in figure 14.1

Two lines are used for data exchange in the keyboard cable - KBData and KBSync. When transmitting scan codes, the keyboard sets the next bit of data on the KBData line and confirms the transmission by transferring the signal from "1" to "0" on the KBSync line.

The controller can signal its unwillingness to transmit/receive data with a low level on the KBSync line. The rest of the time, when there is no data to transmit, both lines have a high signal level.



As follows from the above, in the PEMIN spectrum of the keyboard cable one should expect frequency components with a clock frequency of 1/76.04·10 -6 =13.15 kHz. Moreover, due to the presence of two phase-shifted signals with different (but multiple!) periods, even and odd frequency components will differ in amplitude.

As expected, the PEMIN sync data line is not informative in principle. But distinguishing one PAMIN from another is not at all easy. One cable, the signals are synchronous ...

Almost the only way is to pick up a scan code with a minimum number of logical "1" in the package. These are the keys "F3" and F9 "(03 and 01 in the hex code). Code "00" is not used.

The oscillogram of the scan code "F3" is shown below.


Strictly “in terms of energy”, if you measure all the frequency components of PEMIN with the code “=” and, for example, the code “F9”, then the difference in the readings of the receiver at EACH of the frequency components is the true information part of the PEMIN energy. And this is the maximum maximum. The work is rather complicated and tedious, if it is not possible to entrust it to the “machine”. The very components of PEMIN for such low frequencies are not easily identified. So also the differences to "catch" ...



In practice, SI, in the vast majority of cases, simply measure the levels of PEMIN (without subtracting anything) and calculate the security parameter. It is possible and so, "with a margin", but the specialist is obliged to know the true state of affairs.

In conclusion, the consideration is the "pinout" of the AT and PS / 2 keyboard connectors.


The “pictures” on the receiver look far from being so “classical”, however, it is quite recognizable. Here are examples



The spectrum clearly shows an increase in the amplitude of the components with decreasing frequency.

There are also features of the “clave” measurements in this frequency region (from tens of kHz and further). The fact is that the keyboard, in its usual location, is located not far from the system unit. And in the upper part of the SB there is a switching power supply - the most powerful source of PEMIN for both "E" and "H" components. In the "light" of such a theatrical spotlight, to see the dull "light" of the keyboard is a special art! Therefore, I propose the following approach. Move the “claudia” away from the SB as far as possible. Better - on a PS / 2 extension cable. Commercials 2-2.5 meters.

Place the antenna so that as little as possible is directed at it from the SB (the signal, with a receiver bandwidth of more than 10 kHz, is a continuous spectrum). And now, near the so oriented, fixed antenna, start twisting the "clave" and its cable (not vice versa!). Then you will have much more chances to detect the PEMIN signals of the keyboard, to see the PEMIN components on the analyzer screen with your own eyes.

All of the above referred to the keyboard with a PS / 2 interface. But now they are being massively replaced by USB keyboards.

In general, this interface was considered in sufficient detail together with printers. However, it would be useful to give some "target designation" regarding the keyboard.

Let's recall the construction of packages for the USB interface, given that the keyboard is connected strictly with low-speed (that is, in fact, via the USB 1.0 interface).

The maximum size of the DATA payload (payload) for low-speed devices is 8 bytes. That is, this is exactly what the keyboard scan code requires.

Seeing the signal (namely data) in the USB line was not such an easy task. Nevertheless, this is what was revealed exactly in the cable of a typical USB “clave” of the GENIUS KB-06XE model, specifically in the “data +” line (wire) (Figure 14.10)


These two oscillograms change each other with an unspecified (chaotic) frequency, and the "pictures" of the signals do not depend on the pressed key of the keyboard (or none pressed). No other changes in the "variable" part of the package (frame) could be identified.

The repetition frequency of these packets is rigidly stabilized (Fig. 14.11), and the duration of each is (seen on the oscillograms) about 34 ± 1 μs.


Packets follow every 4ms. However, it should be noted that the end of each packet “trembles” all the time, and it is noticeable, the classic “jitter”. Therefore, the spectral picture is somewhat blurred and becomes clear only after sufficiently long averaging.


In addition, it should be taken into account that, due to different pulse repetition periods and different pulse durations, the spectrum has the character of a mixture of a continuous and a line spectrum. Nevertheless, the lobed character of the spectrum, which is natural for an infinite sequence of packets and is a multiple of its "petals" of the average packet duration, is retained very clearly. Only the "zeros" of the function are smoothed by jitter and the non-repetitive period of the individual pulses. However, the picture itself is quite typical. With a finer frequency resolution, the spectrum begins to resolve on “lines” determined by the packet repetition rate (250 Hz) (Fig. 14.13) responsible for data transfer failed. Nevertheless, it can be argued that the PEMIN keyboard cable will still be like this and no other. It is clear at what frequencies to look for it, it is clear that it will be continuous (in any case, with a frequency resolution of the receiver of more than 0.3 kHz). And it is clear which value to substitute in the calculations as a clock value (the minimum period of pulses in a packet in the experiment was 1.322 μs). To measure this, with any SI, having an oscilloscope, at least with a 200 MHz band, is a trivial task. Test mode, in fact - any, you can press the keys (any), you can not press anything. Packets on the interface are transferred all the same. And, as a first approximation, we consider them informative (until proven otherwise).

The given oscillograms and spectra were obtained using an AKIP-4108/2 oscilloscope connected to the same computer on which measurements were performed (it should be noted that this is a very functional repetition of the development of PICO Technology by ours. No worse than the Chinese :)) .

The spectrum clearly goes far beyond 1 MHz (the oscilloscope no longer allowed, and there was little point in connecting the analyzer). The rest is already due to the cable, as a random antenna and the degree of its shielding.

For other modes of the USB interface, an oscilloscope with a bandwidth of many GHz is already needed.

How exactly to count the continuous spectrum and, at the same time, remain within the framework of the existing NMD is a separate conversation and not for open discussion, alas ... However, in subsequent publications we will have to return to it, there is nowhere to go. Trying to stay within limits...

Most likely on your phone already installed by default QR code scanner, you can easily scan the first QR code with it. It is very easy to do this. Just follow our instructions.

1. Open the QR code reader on your phone.

2. Hold the device over the QR code so that it is clearly visible on the screen of your smartphone.

If you correctly hold your smartphone over the QR code, then the following will happen:

  • The phone automatically scans the code.
  • In some apps, you have to click on an image to scan a code instead of a button like you would to take a photo on your smartphone.

3. Press the indicated button if required.

Super! Your smartphone reads the code and follows the given link, which does not always happen instantly. On most devices, this may take a few seconds.

You will start seeing QR codes everywhere. They are used for teaching, informing, explaining and for many other things. Find them and scan! QR codes will save you a lot of time and effort.

How to Scan QR Codes on Android

And now we will tell you how to use the QR code scanner app on Android.

Briefly:
1. Open Play Market .
2. Search QR code reader .
3. Select QR Code Reader(via Scan).
4. Click " Install".
5. Open the program QR code reading.
7. Point the camera at the QR code.
8. Click " OK".

Step 1. Open Play Store on Android. It's an icon in an app or home screen.

Step 2 Enter the QR code reader in the search engine. A list of applications for reading the QR code will appear.

  • This article explains how to use the QR Code Reader, but you can choose the application you like. Just be sure to read about the app before downloading.
  • The steps should be the same for all QR code reader apps.

Step 3Click QR Code Reader developed by Scan. The name of the developer is listed below each app. You may have to scroll down the page to find the app made by Scan.

Step 4Click Install. A pop-up window will appear asking you to grant permission to access information on your Android.

Step 5Click "Accept". QR Code Reader will now be installed on your Android device.

    • When the app is downloaded, the "Install" button will change to "Open" and you will have a new icon in the app.

Step 6Open QR Code Reader. It's an icon that looks like a QR code on the app. An app that looks like a standard camera screen will open.

Step 7Align the QR code in the camera frame. A bit like how you take photos, except you don't have to press any buttons. When the barcode scanner reads the code, a pop-up window will appear with the URL in the code.


Step 8Click OK to open the website. This launches your default web browser and navigates to the URL in the QR code.

I was motivated to work on a device of this kind by the fact that most of the easy-to-replicate Gamemort devices did not allow for a sufficient number of control buttons to be implemented. The PC game port was originally designed for a maximum of four buttons. All kinds of extensions also do not have the desired flexibility. For example, the CH Flightstick Pro extension, popular among do-it-yourselfers, allows you to implement up to 14 buttons, but you can’t use any two buttons at the same time - about flying on such devices in games in which you have to constantly “turn your head” - in the same birds, you can forget. Some extensions use exclusively a digital interface - the data on the pressed buttons and the deflection of the handle are transmitted over the digital lines of the gameport, which were originally intended to transmit data on the four "standard" buttons. I even consider such extensions somewhat redundant. Yes, and the conversion of analog data to digital complicates the design of the joystick. In addition, not every game will want to understand what kind of monster "attached" to it. And the clave - here it is, in all its 102-key beauty! In addition, RU.GAME.FLIGHT subscribers added fuel to the fire, from time to time asking “how can I tame Claudia and cross with Joy?” and leaving with nothing.

In short, the task of the device is to "sit" on the bus between the keyboard and the PC and simulate keystrokes on the keyboard, according to the buttons pressed on the device.

So, I sat down for development. Before that, I had experience with various microprocessors and microcontrollers. In general - fingers from ear to ear. And I naively thought that now I will take the docks, make RTFM and in a week I will be on a white horse. The whole snag turned out to be that I could not find documentation on the data transfer protocol between the keyboard and the controller either on the Internet or in the relevant Fido conferences. I had to take an oscilloscope and take several weeks to analyze temporary huts and try to repeat them. Therefore, most of the information below is the result of my conclusions and is not documented. If I'm wrong about something, I'll be glad to hear comments at rashpil at ukr dot net.

Basic principles of data transmission

All of the following is true for PS / 2 and AT keyboards, which differ only in the connector design (they can be connected via an adapter).

Between the keyboard and the controller located on the computer motherboard (hereinafter referred to as simply the “controller”), two-way data exchange is carried out. The controller transmits various commands (for example, changing the state of the LEDs or the auto-repeat speed). The keyboard transmits the scan codes of the keys pressed (scan code is a symbol of a key, not to be confused with ASCII codes).

Scan codes

Key Scan code Key Scan code Key Scan code Key Scan code
1 16 2 1E 3 26 4 25
5 2E 6 36 7 3D 8 3E
9 46 0 45 - 4E + 55
backspace 66 Tab 0D Q 15 W 1D
E 24 R 2D T 2C Y 35
U 3C I 43 O 44 P 4d
[ 54 ] 5B Enter 5A Ctrl(L) 14
A 1C S 1B D 23 F 2B
G 34 H 33 J 3B K 42
L 4B ; 4C " 52 ` 0E
Shift(L) 12 \ 61 Z 1A X 22
C 21 V 2A B 32 N 31
M 3A , 41 . 49 / 4A
Shift(R) 59 Alt(L) 11 Space 29 cap lock 58
Esc 76 F1 05 F2 06 F3 04
F4 0C F5 03 F6 0B F7 83
F8 0A F9 01 F10 09 F11 78
F12 07 scroll lock 7E * 7C Num Lock 77
7 6C 8 75 9 7D - 7B
4 6B 5 73 6 74 + 5A
1 69 2 72 3 7A 0 70
. 71 Alr(R) E0-11 Ctrl(R) E0-14 Print Screen E0-12-E0-7C
Insert E0-70 Delete E0-71 Left E0-6B Home E0-6C
end E0-69 Up E0-75 Down E0-72 PageUp E0-7D
PageDown E0-7A Right E0-74 Enter E0-5A / E0-4A

Note: The AT keyboard actually has three different sets of scancodes. I gave only the values ​​​​for set number 2 - the default one.

When a key is pressed, the keyboard sends the scan code of that key to the controller. When released - first the prefix 0F0h, and then the scan code of the released key.

Key combinations with Shift, Alt and Ctrl are transmitted as a sequence of two scan codes. From the point of view of the controller, these keys are no different from all the others. In the same way, Num Lock and Caps Lock modes do not differ at the hardware level - they differ at the software level by the program that serves the interrupts from the keyboard.

Briefly I want to dwell on the implementation of the auto-repeat mode. As a rule, the auto-repeat functions are assigned to the keyboard itself - after a certain time, if the key is not released, the keyboard sends another exactly the same scan code. If at this time one more key is pressed, then another scan code will “fly” to the controller and it will be considered that only one key has been pressed. In games, this problem is solved in an elementary way - the key is considered pressed until the corresponding scan code with the 0F0h prefix arrives. Therefore, I did not implement auto-repeat functions in principle.

In addition to the above scan codes, the keyboard may return some service commands. But these commands, as well as the commands issued by the controller, are of no practical value in this case. Therefore, I will not dwell on them.

Description of the exchange protocol

Data exchange between the keyboard and the controller is carried out asynchronously using a serial protocol. The essence of asynchronous transmission is that data is transmitted only when there is something to transmit - a key on the keyboard is pressed / released and the corresponding scan code needs to be issued or the controller needs to issue a command to the keyboard.

Two lines are used for data exchange - KBData and KBSync. When transmitting scan codes, the keyboard sets the next bit of data on the KBData line and confirms the transmission by transferring the signal from "1" to "0" on the KBSync line. When receiving data from the controller, the keyboard reads the data bit from the KBData line and issues a confirmation of receipt by transferring the signal from "1" to "0" on the KBSync line. The controller can signal its unwillingness to transmit/receive data with a low level on the KBSync line. The rest of the time, when there is no data to transmit, both lines have a high signal level. The pulse repetition rate of the KBSync line is about 10-25KHz.

Data is transmitted in the following order: one start bit - "0", eight data bits, parity bit (sum of all bits +1), one stop bit - "1". After receiving each byte of data, the controller sets a low level on the KBSync line, thereby signaling that it is busy processing the received data and is not ready to receive the next. This can be considered an acknowledgment of acceptance. The keyboard acknowledges each byte of the received command by issuing the code 0FAh. If an error occurs during transmission, the controller may require the transmission of the last byte to be repeated by issuing the 0FEh command. The keyboard behaves differently - it simply ignores errors. I do not see anything fatal in this - if your system gives frequent crashes, then it has no place on the desktop.

Most likely, my explanations were too confusing, so I will try to illustrate them with a few timing diagrams.

General view of data transmission from the keyboard (S1 - start bit; S2 - stop bit; D0-D7 - data; P - parity bit; W - processing of received data)

An example of transmitting byte 74h is the "6" key on the numpad. In this example, when the keyboard initiates a transmission, the controller signals that it is not ready to receive data and the keyboard waits for the KBSync line to be released.

Hardware implementation

Now I will go directly to the description of the implementation of the device in the hardware.

The device is included in the gap between the KBSync and KBData signals and passes signals from / to the keyboard through itself, polls the state of the four buttons and issues the corresponding scan codes, thereby simulating the operation of the keyboard.

The basis of the device is a single-chip microcontroller AT89C2051. The AT89C2051 microcontroller from Atmel belongs to the MCS-51 family (the domestic analogue is MK-51). The main difference between the AT89C2051 and the i8051 is lower power consumption, the number of I/O lines reduced to 15, and the inability to use external memory. More information on the AT89C2051 and i8051 can be found at www.atmel.com and www.intel.com. Instead of AT89C2051, you can use AT89C51, i8051 (KP1816BE51) or i8031 (KP1816BE31) with external ROM. But the last two options, due to their increased power consumption, can lead to the keyboard controller fuse blown.

On Atmel microcontrollers, after the main designation, the maximum frequency of the clock generator in megahertz is indicated. I advise you to install a microcontroller designed for a frequency of 24 MHz and quartz with a higher frequency - 16-20 MHz.

Schematic diagram. (R1-R4 - 47K; R5 - 10K; C1, C2 - 18pF; C3 - 1uF; D1 - AT89C2051; BQ1 - quartz 12-24MHz)

The P1.4 line is used as a button poll enable output. This is a reserve for future extensions - lines P1.4-P1.7 will be used to issue the address of the line for polling pressed buttons (up to 16 lines of 4 buttons each). "0" on the line P1.0-P1.3 means that the corresponding button is pressed.

Elements C3 and R5 implement a circuit for generating a reset signal when power is applied.

The KBData lines from the keyboard and controller are fed to inputs P3.2 (INT0) and P3.3 (INT1). Thus, an attempt to initiate a data transfer from the keyboard or controller causes the corresponding interrupt. The routines for servicing these interrupts simply broadcast the signals corresponding to the transfer of one byte through the microcontroller. At a time when the microcontroller is not busy transmitting data, the lines P1.0-P1.4 are polled, the received data is processed and the corresponding scan codes are issued to the controller. In this version, priority is given to data transmitted by the device itself. Therefore, data from the keyboard can sometimes be lost.

Concluding this section, I will give the pinout of the AT and PS / 2 keyboard connectors.

The -KBReset signal is an optional signal. Some controllers may use it to reset the keyboard.

Firmware text

I provide the source code for the firmware for the AT89C2051 microcontroller in the hope that an inquisitive reader can correct me or adapt the program to work with a different type of microcontroller.

org 0 sjmp start org 3 jmp from_keyboard ; INT0 org 13h jmp to_keyboard ; INT1 start mov a,#5 ; setting interrupt type mov tcon,a ; INT0 and INT1 on the front - mov a,#0 ; transition from "1" to "0" mov ip,a mov a,#85h mov ie,a mov a,#0ffh ; at address 06h the last mov 6,a is stored; processed code clr p1.4 ; enable polling loop mov a,p1 ; the state of the buttons is read anl a,#15 ; - junior four bits of port P1; D0 - up; D1 - right; D2 - down; D3 - left mov dptr,#hat_table ; read data about four buttons movc a,@a+dptr ; expanding to eight directions; D0 - up; D1 - right; D2 - down; D3 - left; D4 - right-up; D5 - right-down; D6 - left-down; D7 - left-up mov r2,a ; save data mov r0,a xrl a,6 ; if the new data is the same as jz loop ; received in the previous cycle - repeat the poll mov r1,#8 ; loop for eight bits loop3 jnb acc.7,loop2 ; "1" - there was a change push acc mov a,r1 mov dptr,#key_table-1 ; extract the corresponding scancode movc a,@a+dptr push acc mov a,r0 ; register R0 - a sign of pressing / releasing rlc a ; emulated key mov r0,a ; "1" - "key" was released pop acc mov acc.7,c ; if D7=1 - scancode will be preceded by 0f0h acall send_key ; output scan code pop acc sjmp loop2a loop2 push acc mov a,r0 rlc a mov r0,a pop acc loop2a rl a djnz 1,loop3 mov 6,r2 sjmp loop send_key mov ie,#80h ; interrupts disabled acall send2comp ; send scan code mov ie,#85h ; interrupts enabled ret send2comp jnb acc.7,send ; if necessary, 0f0h push acc mov a,#0f0h acall send pop acc clr acc.7 mov b,#200 l9 nop djnz b,l9 send push 1 push 0 clr p3.3 ; P3.3 - KBData mov b,#6 ; set start bit l10 nop djnz b,l10 clr p3.5 mov b,#15 l2 nop djnz b,l2 setb p3.5 mov b,#6 l3 nop djnz b,l3 mov r0,#8 ; mov r1,#1 byte_loop xrl 1h,a rrc a mov p3.3,c mov b,#6 l6 nop djnz b,l6 clr p3.5 mov b,#15 l4 nop djnz b, l4 setb p3.5 mov b,#6 l5 nop djnz b,l5 djnz r0,byte_loop mov a,r1 mov c,acc.0 mov p3.3,c ; parity output mov b,#6 l8 nop djnz b,l8 clr p3.5 mov b,#15 l12 nop djnz b,l12 setb p3.5 mov b,#6 l13 nop djnz b,l13 setb p3.3 ; output stop bit mov b,#6 l7 nop djnz b,l7 clr p3.5 mov b,#15 l11 nop djnz b,l11 setb p3.5 mov b,#200 l14 nop djnz b,l14 setb p3.5 pop 0 pop 1 ret from_keyboard ; send one byte to controller mov ie,#80h push psw push acc push b mov b,#2 in6 jnb p3. 4,in8 djnz b,in6 sjmp in7 in8 mov b,#10 in1 mov a,p3 rl a orl a,#11010111b mov p3,a jnb p3.4,in1 in2 mov a,p3 rl a orl a,#11010111b mov p3,a jb p3.4,in2 djnz b,in1 in3 mov a,p3 rl a orl a,#11010111b mov p3,a jnb p3.4,in3 mov p3,#0ffh in4 jb p3.5,in4 in5 jnb p3 .3,in7 clr p3.4 jnb p3.5,in5 in7 mov p3,#0ffh pop b pop acc pop psw mov tcon,#5 mov ie,#85h reti to_keyboard ; send one byte to keyboard mov ie,#80h push psw push acc push b mov b,#5 out61 jb p3.5,out7 djnz b,out61 setb p3.4 setb p3.2 out62 jnb p3.5,out62 out6 mov c ,p3.4 mov p3.5,c mov c,p3.3 mov p3.2,c jb p3.4,out6 out8 mov b,#10 out1 mov c,p3.4 mov p3.5,c mov c, p3.3 mov p3.2,c jnb p3.4,out1 out2 mov c,p3.4 mov p3.5,c mov c,p3.3 mov p3.2,c jb p3.4,out2 djnz b,out1 out3 mov c,p3.4 mov p3.5,c mov c,p3.2 mov p3.3,c jnb p3.2,out3 out7 mov p3,#0ffh pop b pop acc pop psw mov tcon,#5 mov ie ,#85h reti hat_table ; table for expanding data read from port P1 ; index in the table - four-digit binary code; data - state of eight emulated keys; "0" - key pressed db 0ffh ; left+right+up+down=illegal combination db 0ffh ; left+right+down=illegal combination db 0ffh ; left+up+down=illegal combination db 0bfh ; left+down=left-down db 0ffh ; left+right+up=illegal combination db 0ffh ; left+right=illegal combination db 07fh ; left+up=left-up db 0f7h ; left db 0ffh ; right+up+down=illegal combination db 0dfh ; down+right=down-right db 0ffh ; up+down=illegal combination db 0fbh ; down db 0efh ; right+up=right-up db 0fdh ; right db 0feh ; up db 0ffh ; no buttons pressed key_table ; scan code table db 75h ; numpad 8 db 74h ; numpad 6 db 72h ; numpad 2 db 6bh ; numpad 4 db 7dh ; numpad 9 db 7ah ; numpad 3 db 69h ; numpad 1 db 6ch ; numpad 7

In the tools.zip archive you will find two programs: a51.exe is an assembler, hex2bin is a converter of hex files that are obtained at the output of the assembler into a binary format suitable for flashing the ROM of the microcontroller with a programmer.

Assembly and troubleshooting

You can assemble the device according to the above scheme on a breadboard, a board etched at home or manufactured in an industrial way. Place a socket under the microcontroller. It is best to leave room on the board for 2-3 16-pin DIP packages - they will be added in future versions.

Further, after making the desired changes, the source code of the microprogram is assembled - by the a51.exe program. For flashing by the programmer, the received hex file is converted into a binary image by the hex2bin.exe program.

Having fully assembled the device, we connect it to the keyboard and computer. Three... Two... One... Let's go!.. A device properly assembled from known good components should work immediately. If not, check the correct installation, the presence of power on the microcontroller. Use an oscilloscope to check if the clock generator has started and if a high-level pulse comes to the RST input when the power is turned on. When pressing the keys on the keyboard, the pulses on the lines P3.3 and P3.5 should repeat, with some delay, the pulses on the lines P3.2 and P3.4, respectively. When pressing / releasing the device buttons, pulses should also appear on lines P3.3 and P3.5. If this does not help - write to me ( rashpil at aport dot en) bug report, specifying the model and type (AT, PS/2) of your keyboard, motherboard/multicard, used microcontroller and the frequency of the used quartz resonator. I tried to test the device with the maximum number of motherboards and keyboards - no problems were identified. In my case, 14.2 MHz quartz was used.

Known bugs

The current version of the firmware contains the following flaws:

  • Double-byte scan codes are not tracked. This leads to the fact that sometimes, when using the hat and the keyboard at the same time, the keyboard keys “freeze” in the pressed state or are perceived incorrectly;
  • Sometimes the data is transferred incorrectly from the controller to the keyboard. This can be expressed, for example, in the fact that the LEDs do not change their state when the Num Lock, Caps Lock, Scroll Lock keys are pressed;
  • Bounce of contacts of the buttons of the hut. So far, this has not become fatal for me in games.

Future plans

Here is a short list of what I would like to implement in future versions:

  • Minor bugfixes - more correct signal processing; tracking double-byte scan codes;
  • Connecting a 16x4 matrix - support for up to 64 buttons or two huts and up to 56 buttons;
  • Support for up to 16 different layouts of scan codes stored in the ROM of the microcontroller;
  • Connecting an NVRAM chip with the ability to save and reprogram "on the fly" up to 32 scan code layouts.

Conclusion

I tried to present all the data necessary to understand the principle of operation of my device. This description does not claim to be 100% technically accurate. If I'm wrong about something, please tell me your version of events. If you can make improvements and additions to my circuit and / or firmware, if you have ideas for further development of the circuit, also let me know. In addition, I am waiting for information from craftsmen who were able to repeat or adapt this device for other types of microcontrollers.

Vladimir "Rasp" Klimus (rashpil at ukr dot net)