Author Topic: [SOLVED] Linux: problem with key-codes like CTRL-PgUp and CTRL-PgDn in a console  (Read 2265 times)


  • Sr. Member
  • ****
  • Posts: 465
Versions: FPC 3.2.0 beta rev 43824, Linux Ubuntu 18.04 64-bit with KDE-Plasma-Desktop, Windows 7 32-bit.

I please need a Linux expert for reading special key-codes in FPC console programs (and maybe for "Konsole" terminal from KDE-Desktop).

I'm adapting a bunch of FPC console programs from Windows to Linux. Since about 35 years I used these 2 functions to read from the keyboard in my console programs:
Code: Pascal  [Select][+][-]
  1. program Test1; // read Keyboard via Unit CRT
  3. {$mode objfpc}{$H+}
  5. uses crt;
  7. type Taste = 0..511; // Scan-Code for a key
  9. function checkTaste: Taste;
  10.    {checks for a key, but does not wait. Result: 0 = no key pressed /
  11.     1..255 = normal ASCII-Code / 257..511 = extended Scan-Code}
  12.    var b: byte;
  13.    begin
  14.    if not KeyPressed then exit(0);
  15.    b:=byte(ReadKey); if b <> 0 then exit(b);
  16.    b:=byte(ReadKey); exit(b+256);
  17.    end;
  19. function readTaste: Taste;
  20.    {waits for a key, until one has been pressed. Result is as checkTaste()}
  21.    var t: Taste;
  22.    begin
  23.    repeat t:=checkTaste;
  24.    until  t <> 0;
  25.    readTaste:=t;
  26.    end;
  28. var t: Taste;
  30. begin
  31. writeln('FPC-Version: ', {$I %FPCVERSION%}, ' / To exit press "x"');
  33. repeat t:=readTaste;
  34.        if t < 256 then
  35.           begin
  36.           write(HexStr(t,2)); // show Hex-Code of ASCII-char
  37.           if t > 32 then write('=', chr(t), ' ') else write(' ');
  38.           end
  39.        else write('*', HexStr(t and $FF,2), ' '); // show extended Scan-Code
  40. until  t = ord('x');
  41. writeln;
  42. end.

They worked perfect on all Windows versions I ever had (at last Windows 7) including every special key-codes with SHIFT/CTRL/ALT and including our 7 German special characters (Ä Ö Ü ä ö ü ß) which send a 1-Byte-Code in CP850 (which was perfect for German Windows consoles) and so all programs were "designed" simple to handle all printable chars in vars of type "char".

But on Linux - as often - there are problems: most keys work, but I found 5 keys, which do not work:
 - END-key: sends 3 keys = "F" and "[" and <ESC>
 - CTRL-PgUp and CTRL-PgDn: send nothing (on Windows they work perfect)
 - CTRL-LeftArrow and CTRL-RightArrow: send wrong Scancodes *44 and *43 (which belong to <F10> and <F9>)
After some research I found unit "keyboard" as an alternative and created a little demo program:
Code: Pascal  [Select][+][-]
  1. program Test2; // read Keyboard via Unit keyboard
  3. {$mode objfpc}{$H+}
  5. uses keyboard;
  7. var k,t: TKeyEvent;
  8.     RK: TKeyRecord absolute k;
  9.     RT: TKeyRecord absolute t;
  11. begin
  12. InitKeyBoard;
  13. writeln('FPC-Version: ' + {$I %FPCVERSION%});
  14. writeln('"scan"=Scancode, "code"=ASCII-Code of printable chars / To exit press "x"');
  16. repeat
  17.    k:=GetKeyEvent; {waits for a key}
  18.    write('scan=', HexStr(hi(RK.KeyCode),2),  ' code=', HexStr(lo(RK.KeyCode),2),
  19.          ' shift=', HexStr(RK.ShiftState,2), ' flags=', HexStr(RK.Flags,2), '':2);
  20.    t:=TranslateKeyEvent(k);
  21.    write('scan=', HexStr(hi(RT.KeyCode),2),  ' code=', HexStr(lo(RT.KeyCode),2),
  22.          ' shift=', HexStr(RT.ShiftState,2), ' flags=', HexStr(RT.Flags,2), '':2);
  23.    write('"', KeyEventToString(t), '"  ');
  25.    case GetKeyEventFlags(t) of
  26.       kbASCII:    write('ASCII');
  27.       kbUniCode:  write('Unicode');
  28.       kbFnKey:    write('Function');
  29.       kbPhys:     write('Physical');
  30.       kbReleased: write('Released');
  31.    end; {case}
  32.    writeln;
  33. until GetKeyEventChar(t) = 'x';
  35. DoneKeyBoard;
  36. end.

But unfortunately that caused as many new problems as it solved:
 - END-key and CTRL-LeftArrow / CTRL-RightArrow: now work correct
 - CTRL-PgUp and CTRL-PgDn: again send nothing
 - 7 German special characters: now send 2 "keys" with it's UTF8-Code, e.g. "Ä"=C384 (requires additional effort to "catch" and convert them to 1-Byte-Codes in CP850, without danger to "hang" if an expected 2nd Code does not come)
 - ESC-key: must always pressed twice! (which is "unusable" in my eyes)
Above tests I made with the "Konsole" terminal from KDE-Desktop. I tried another "Virtual Console", which can be evoked via CTRL-ALT-F2 .. CTRL-ALT-F6. "Test1" shows 4 wrong key codes, but in "Test2" all 5 problem-keys work correctly! So it's proof, that CTRL-PgUp and CTRL-PgDn can generally work on Linux.

But those "Virtual Consoles" have so big and many disadvantages, that they are "unusable" for most purposes:
 - a "Virtual Console" covers a complete screen. They are not resizeable. Even if you have 2 screens, both show always the same. So it's impossible, to see any other window from other applications at the same time, e.g. to read something from there and to operate the console at the same time - and vice versa.
 - there is no mouse possible in a "Virtual Console" e.g. to mark/select/copy something into the clipboard or to have a convenient context menu
 - and uncountable more disadvantages
 - and above noted problems with 7 German special characters and the ESC-key (to press twice) exist also.

I spent more time and found out, that "Konsole" terminal from KDE-Desktop has configurable "Key bindings" (see screenshot1). Default is "Standard (XFree 4)". I tried the 2 others ("Linux console" and "Solaris console"), which made some difference, but:
 - CTRL-PgUp and CTRL-PgDn: again send nothing (in both Tests)
 - CTRL-LeftArrow and CTRL-RightArrow: now send completely wrong codes (in both tests)

So the "Key binding" had an influence and so I tried to "Edit" a newly created one (see screenshot2, it shows the "definition" of CTRL-PgDn). But I did not understand how this should work, and all what I tried, made either no difference or "killed" the changed key totally.
Question: is there someone who knows how to operate this dialog? And do you think, it can make CTRL-PgUp and CTRL-PgDn working? If yes, please what must I do?
Because my keyboard is old (via PS/2) I organized a new one (via USB) but the results were the same.
In the "System Settings" of KDE-Plasma / Hardware / Input Devices / Hardware / you can select 1 of "hundreds" of different keyboard models (see screenshot3). I tried another one but the results were the same.

I spent more time and in I found:
The terminal emulation of the Linux kernel is ... configurable. On the Linux console, the Free Pascal keyboard unit tries to implement full functionality.

Users of applications using the keyboard unit should expect the following:
 - Full functionality on the Linux console. It must be the bare console, SSH into another machine will kill the full functionality.
 - Limited functionality otherwise.

Notes about Linux full functionality:
 - ... Unlike what you're used to with other Unix software, escape works as you intuitively expect, it generates the keycode for an escape key without a delay.

The limited functionality does include these quirks:
 - Escape must be pressed two times before it has effect
 - <a long list of more quirks>

I don't really understand, in which cases "full functionality" applies and when "limited functionality" applies. From my understanding, I should have "full functionality", because I don't use SSH into another machine. But obviously I have "limited functionality", because ESC has to be pressed twice. Can somebody please explain this? Is it anyhow possible, to "switch" from "limited functionality" to "full functionality", so that ESC must only pressed once?

At that point I decided to stop for now and ask you for help. I'm a beginner on Linux.
I attached above 2 Test-programs, so that you can easy experiment with them, if you want.
Sorry that this post got so long. But I wanted to give you as many infos as I have.
Thanks a lot in advance for your attention.
« Last Edit: February 14, 2020, 02:39:43 pm by Hartmut »


  • Hero Member
  • *****
  • Posts: 10704
It may be that some key combinations are in use by your terminal window itself (as per its menubar) but you can often hide the terminal menu and then it is supposed to work.
The reason I think that is the case is that fp (the textmode IDE) exposes the same behavior unless I hide the terminal menu.
« Last Edit: February 02, 2020, 05:43:40 pm by Thaddy »


  • Global Moderator
  • Hero Member
  • *****
  • Posts: 9085
  • FPC developer.
Fullscreen and other forms of "full control"  console sucks under Linux.


  • Hero Member
  • *****
  • Posts: 10704
Fullscreen and other forms of "full control"  console sucks under Linux.
That is many times the case, but e.g. lxterminal behaves pretty decent when its menu is hidden through edit|preferences and not without hiding the menu.


  • Sr. Member
  • ****
  • Posts: 465
It may be that some key combinations are in use by your terminal window itself (as per its menubar) but you can often hide the terminal menu and then it is supposed to work.
Fullscreen and other forms of "full control"  console sucks under Linux.

Thank you both for your answers. I tried in my "Konsole" terminal (from KDE-Desktop):
 - menu Settings / Show Menubar => off
 - menu Settings / Full Screen Mode => on
 - and both together
but unfortunately all 3 modes made no difference (with both of my Test programs).

... but e.g. lxterminal behaves pretty decent when its menu is hidden through edit|preferences and not without hiding the menu.
Thank you for that suggestion. I found lxterminal in and in my Synaptic package manager, so I can install it easily. I will do it tomorrow and then report the results.


  • Sr. Member
  • ****
  • Posts: 465
I tested LXTerminal with it's menu visible and with it's menu hidden.
Unfortunately this made no difference for my 5 problem-keys (with both of my Test programs).

Are there any more ideas to solve (or explore) this problem?


  • Hero Member
  • *****
  • Posts: 2190

Linux basics: Every physical scancode is mapped to a logical keycode to put special local keys (french, spanish, german .....) on dedicated keys. This is done via linux utility


A small manual is at

So you can map every code to every logical key. Or disable them: On my keyboard I disabled the nonsense key Shift Lock.

If you want to know which logical key is mapped to which keycap use

showkey --scancodes

And then hit in the next 10 seconds a key.

So finaly: You can never be shure which distro maps the scancodes to which logical keys.

And further : it depends on the configuration of your system:

I tested your 35 year old test1 and it worked without a problem. But due to my configuration all results were utf8.

My configuration: Suse Tumbleweed, KDE, the test in  KDE konsole.


PS The forum is nearly unusable slow.


  • Sr. Member
  • ****
  • Posts: 465
Thanks a lot @winni for your reply. That sounds very promising.

At first I had to fight a little with command "showkey --scancodes", because it showed me an error message "file descriptor, who points to console, could not be found" (translated from German). But with "sudo" it worked.

So I tried to find out the scancode e.g. of keys PgUp and CTRL-PgUp in my "Konsole" Terminal (from KDE-Plasma desktop):
 - PgUp => ^[[5~0xe0 0x49 0xe0 0xc9
 - CTRL-PgUp => 0xe0 0x49 0xe0 0xc9

Because your documentation link recommended to use a Virtual Console, I tried it too and got:
 - PgUp => 0xe0 0x49 0xe0 0xc9
 - CTRL-PgUp => 0xe0 0x49 0xe0 0xc9

If I interpret those numbers correctly, the scancode of key "PgUp" is 0x49, independent of CTRL or not, because a "scancode" is a code for a physical key, independent of modifiers like SHIFT/CTRL/ALT. And there comes my problem:
   setkeycodes <scancode> <keycode>
assigns a <keycode> to a <scancode> independent of a modifier, but I need different results for PgUp and CTRL-PgUP, to be able to distinguish them.

Please, how can that be solved?


  • Hero Member
  • *****
  • Posts: 2190

If you hit Ctrl-PageUp then you hit two keys and will get two scancode

Hit just Ctrl. You get:

Left Ctrl down:  0x1d
Left Ctrl up:      0x9d
Right Ctrl down: 0xe0 0x1d
Right Ctrl up: 0xe0 0x9d

PageUp gives

^[[5~0xe0 0x49 0xe0 0xc9

The scancodes are sent one after another as the keys are pressed. It is up to the mapping to set them together to logical codes.

As every distro makes it's own stuff especialy with keyboard configuration I refer to an unbuntu page which shows how to change keycaps:



  • Sr. Member
  • ****
  • Posts: 465
Thank you for that infos and the link. I scanned it and it looks very interesting. I will test it tomorrow and report then.


  • Sr. Member
  • ****
  • Posts: 465
I worked through the link from Winni. Then at first I wanted to make key CTRL-PgUp work, which until now sends nothing in both of my Test-programs.

The 1st part I got managed: via "xev" I got infos about PgUp and CTRL-PgUp:
 - PgUp => state 0x0, keycode 112 (keysym 0xff55, Prior), same_screen YES,
 - CTRL-PgUp => state 0x4, keycode 112 (keysym 0xff55, Prior), same_screen YES,

For the 2nd part was said, that "xmodmap" is depricated and "xkb" should be used. But "xkb" was not installed on my Ubuntu, while "xmodmap" was, so I wanted to use "xmodmap". But I face 2 problems:
(a) I want to change the behaviour of CTRL-PgUp, not of PgUP
(b) I want to assign to CTRL-PgUp not one of the many predefined "keysym" names (like BackSpace/Escape/Home etc.), but assign the same "code", which my 2 Test-programs expect for key CTRL-PgUp, which on Windows has Scancode *84 (hex).

For "xmodmap" I found this documentation. For problem (a) the only thing I found there is:
... The first keysym is used when no modifier key is pressed in conjunction with this key, the second with Shift, the third when the Mode_switch key is used with this key and the fourth when both the Mode_switch and Shift keys are used.

As a small test, to see what happens, I tried
   xmodmap -e "keycode 112 = Prior a b c"
After this, PgUp worked as before, SHIFT-PgUp sended "a", but CTRL-PgUp again sended nothing. So how can I change the behaviour of CTRL-PgUp?

For problem (b) I found nothing in above documentatin link. How must I declare the correct code?
Thanks for any help.


  • Sr. Member
  • ****
  • Posts: 465
After spending more time I found out, that you can define one of the CTRL-keys as above named "Mode_switch key":
   xmodmap -e "keycode 37 = Mode_switch NoSymbol Mode_switch" # use left CTRL-key
   xmodmap -e "keycode 105 = Mode_switch NoSymbol Mode_switch" # use right CTRL-key

But if you define the left CTRL-key this way, CTRL-C / CTRL-V doesn't work any longer in a text editor, so it's completely unusable. If you define the right CTRL-key this way, it works, but then you always have to remember, that CTRL-PgUp / CTRL-PgDn need the right CTRL-key, while for all other keys I am used the left CTRL-key - very uncomfortable and annoying.

After spending more time I found "xkb". That means, that in /usr/share/X11/xkb/symbols/ you have plenty of files with key-definitions, which include each others deeply nested. Although I read a lot of documentation, here too I found no way, to assign keys with a normal CTRL-behavior.

Again I'm a little disappointed from Linux. For something primitive like a keyboard they use an unbelievable complex system to handle it, but seem not to be able to assign keys with a normal CTRL-behavior.

After spending more time I found tool AutoKey. It allows you to assign a code to a Hotkey and can handle Hotkeys like CTRL-PgUp / CTRL-PgDn in the normal way.
I could install it via my packet manager on Ubuntu 18.04.
Short tutorial =
Homepage =
Definitions for all function keys =


TinyPortal © 2005-2018