#698885 mc: invalid <Shift>+<F(i)> hotkeys behavior in text console

Package:
mc
Source:
mc
Description:
Midnight Commander - a powerful file manager
Submitter:
Bob Bib
Date:
2026-03-05 12:51:01 UTC
Severity:
normal
Tags:
#698885#5
Date:
2013-01-24 22:00:26 UTC
From:
To:
Dear Maintainer,

in text console, <Shift>+<F(i)> hotkeys behave in a wrong way,
as if they were <Shift>+<F(i+2)>.

Single <F(i)> pressed keys function as they should.

In x-terminal-emulator those hotkeys work correctly.

#698885#10
Date:
2013-01-30 23:58:58 UTC
From:
To:
The following explanation by from Egmont Koblinger [1] seems relevant:

	This seems to be a problem with the console-data or kbd or whichever
	similar package of Linux distros... They offer multiple keymaps, and define
	function keys differently in them.

	E.g. type "loadkeys us" -> with the U.S. keymap pressing Shift+F4 will do
	what you'd expect from Shift-F6.
	But type "loadkeys ru" -> with the Russian keymap Shift+F6 works as
	expected.

	Seems that the kernel's builtin keymap makes the Shift key offset the
	function keys by 10 (drivers/tty/vt/defkeymap.map says «keycode 64 = F6
	F16» and later «string F16 = "\033[29~"»), and this is what mc expects too
	(mc.lib: «f16=\\e[29~»).  Unfortunately, many keymaps, including the
	probably most widely used "us" wants to be able to assign separate action
	to F11 and Shift+F1, so they shift by 12 and define «keycode 64 = F6 F18».

	There's nothing mc could do about this right now, first all the keymaps
	should be made consistent.

[1]: https://mail.gnome.org/archives/mc-devel/2013-January/msg00028.html
--- Much of humankind's intellectual and emotional struggle has been not for truth, but against truth. The advance of science has been sporadically fought against for thousands of years. -- C. W. Dalton, "The Right Brain and Religion"
#698885#13
Date:
2013-01-30 23:58:58 UTC
From:
To:
The following explanation by from Egmont Koblinger [1] seems relevant:

	This seems to be a problem with the console-data or kbd or whichever
	similar package of Linux distros... They offer multiple keymaps, and define
	function keys differently in them.

	E.g. type "loadkeys us" -> with the U.S. keymap pressing Shift+F4 will do
	what you'd expect from Shift-F6.
	But type "loadkeys ru" -> with the Russian keymap Shift+F6 works as
	expected.

	Seems that the kernel's builtin keymap makes the Shift key offset the
	function keys by 10 (drivers/tty/vt/defkeymap.map says «keycode 64 = F6
	F16» and later «string F16 = "\033[29~"»), and this is what mc expects too
	(mc.lib: «f16=\\e[29~»).  Unfortunately, many keymaps, including the
	probably most widely used "us" wants to be able to assign separate action
	to F11 and Shift+F1, so they shift by 12 and define «keycode 64 = F6 F18».

	There's nothing mc could do about this right now, first all the keymaps
	should be made consistent.

[1]: https://mail.gnome.org/archives/mc-devel/2013-January/msg00028.html
--- Much of humankind's intellectual and emotional struggle has been not for truth, but against truth. The advance of science has been sporadically fought against for thousands of years. -- C. W. Dalton, "The Right Brain and Religion"
#698885#16
Date:
2013-03-10 14:33:06 UTC
From:
To:
Hi,

I have the same problem with mc 4.7.0.9,
and I've solved it via "Learn Keys" option
( Menu -> Options -> Learn Keys ).

#698885#25
Date:
2015-12-20 01:36:55 UTC
From:
To:
698885-submitter@debian.org
Cc:
Bcc:
Subject:
Reply-To:

tags 698885 fixed
thanks

for your bug report.
See this workaround please:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=698885#16

best regards

Denis Briand

#698885#36
Date:
2025-01-12 10:05:47 UTC
From:
To:
See upstream in https://midnight-commander.org/ticket/3254 :

```
on the console it's the kbd package that's broken because half of the keymaps are shifted by 2 compared to the other half. To make it worse, the kernel's builtin table just doesn't match the standard "us" layout shipped by kbd or console-tools or whatever that's called nowadays.

…

Until that one is solved (i.e. the kbd/console-tools package ships keymaps that are consistent with each other and with the kernel's default) there's nothing mc could do.
```

#698885#41
Date:
2026-03-03 08:58:04 UTC
From:
To:
Here's an update. I'm describing what I see on Ubuntu 25.10.


The kernel's built-in keymap (drivers/tty/vt/defkeymap.map) hasn't
changed.  It defines 20 different escape sequences, and has a strong
off-by-10 vibe (e.g. Shift+F3 produces the 13th of these sequences).
Shift+F1, F11 and Shift+F11 all generate the same sequence, and so do
Shift+F2, F12 and Shift+F12.

kbd / console-setup has slightly changed.  It no longer ships its own
keymaps, but rather "loadkeys" launches "ckbcomp" which converts X11's xkb
definition files to the console's format.

It's a nice move and I do appreciate that the console now uses the
better-maintained xkb maps.  It hopefully also provides more consistency.
The "us" and "ru" keymap no longer differ in the handling of function keys,
and I assume all the keymaps are unified now in this regard.

(I have no information on other distros, I don't know if others might use a
different loadkeys / keyboard data implementation.)

The maps loaded by my loadkeys (via ckbcomp), however, do not agree with
the kernel's built-in map.  They do whatever the "us" layout did for me 13
years ago.

There are still only 20 different escape sequences, the same ones as in the
bulit-in map.  They are laid out off-by-12, to the keys F1..F12 and
Shift+F1..Shift+F8.  Shift+F9..Shift+F12 do nothing.

Terminfo also describes the very same 20 different escape sequences for
kf1..kf20, whereas there's no kf21 and above capability.
--- So, there are two different possible layouts. The kernel's built-in, presumably used by minimal or embedded Linux systems, ones where the console is not set up with "loadkeys", is fully functional for mc's purposes. However, we'd need to have an exception in the code to know that terminfo's kf13 etc. entries are off by 10, rather than by 12 as for graphical terminals. If we have to have such hacks on top of terminfo then what's the purpose? We could just hardcode the keys and be done with it (as we currently do). The ones loaded by "loadkeys" (at least on Ubuntu 25.10; again: not sure about other distros) could be handled by mc out of the box without any special hack / exception, since the same offset of 12 is used as for any other terminal. However, Shift+F9 (pulldown menu at its previous state) and Shift+F10 (quit without updating the working directory) are unavailable.
--- What should be done to fix the situation: Agree on 24 different escape sequences, and their unique assignment to the F1..F12 and Shift+F1..Shift+F12 keys. Then make sure that the kernel's hardcoded table, the tables loaded by loadkeys (generated via ckbcomp, or loaded from its own data files, or whatever), and terminfo (up to kf24) all define these. For the best compatibility, I think the right choice is to keep what's already defined in terminfo, and with the usual off-by-12 mapping, the keys loaded by loadkeys. Add four new entries for the current gaps of Shift+F9..Shift+F12 (terminfo: kf21..kf24). The only component receiving a backwards incompatible change would be the kernel's hardwired table; for downstream distros that do run "loadkeys" this doesn't even matter. e.
#698885#46
Date:
2026-03-03 13:12:23 UTC
From:
To:
ckbcomp is a perl script, its copyright line stating the years 2005-2006,
so it's not new at all.  It has existed even back then when I made my first
observations here.

As for the "keycode" lines it generates, it properly generates up to F24
(and beyond for other modifiers), with off-by-12 semantics as we've already
established.  That is, physical keypresses Shift+F9..Shift+F12 are mapped
to the logical symbols F21..F24.  So far this is what I'm looking for.

The problem is that the corresponding "string" lines are missing, which
would define the escape sequence belonging to F21..F24.

They can be installed with a script like

sudo loadkeys <<EOF
string F21 = "\033[35~"
string F22 = "\033[36~"
string F23 = "\033[37~"
string F24 = "\033[38~"
EOF

and then taught to mc using its "Learn keys" dialog.  This way even
Shift+F9 and Shift+10 will work as intended.

Note that I'm not certain what are the "best" escape sequences to choose,
it's always been a mistery to me why and where some numbers are skipped.
But as for someone's local fix, it doesn't matter.

ckbcomp doesn't emit such individual "string" commands, but emits a magical
"strings as usual" line to be processed with loadkeys.  This command
reverts F1..F20 to their defaults, but luckily leaves the unset-by-default
F21..F24 at the values we've set manually.  So, subsequent "loadkeys xx"
commands won't override them.

#698885#51
Date:
2026-03-05 12:49:15 UTC
From:
To:
Contrary to my previous posts, there might be a strong reason to keep the
kernel's current built-in table, and adjust loadkeys+ckbcomp to match that.

The kernel's bulit-in table matches the behavior of at least two popular
terminals: pterm (putty) and urxvt.  Shift-F1 generates \e[23~ etc. (unlike
after a loadkeys+ckbcomp when Shift-F1 becomes \e[25~).

With these terminals (Linux's hardwired default, putty and urxvt), combined
with the corresponding TERM value of linux, putty* or rxvt-unicode*,
terminfo's 'kf13' etc. keys are defined with off-by-10 semantics; whereas
for most of the xterm-like terminals terminfo defines them with off-by-12
semantics.  Notice that the problem already exists with putty and urxvt,
independently from the confusion in the Linux kernel vs. loadkeys+ckbcomp.

Honestly I have no idea how someone is expected to handle the shifted
function keys using terminfo, having no information whether the keys
describing them are indexed from 10 or 12.  And apparently I'm not the only
confused developer.

To which the short-term solution is to avoid terminfo and hardwire a
handful of potential escape sequences.

Which approach, if the console is off-by-2 compared to putty and urxvt (as
it is after loadkeys), it is super prone to the shited function keys being
interpreted off-by-2 in one or the other.  The developer would have to
check the TERM value and based on that choose one of two conflicting lookup
tables.

It would be definitely safer, more reliable if at least these terminals
agreed on the sequences they sent.  Which would mean to keep the kernel's
built-in table as-is, and adjust loadkeys+ckbcomp.  Resulting in folks
getting angry because then they _again_ cannot tell F11 apart from Shift+F1.

I think the only true way out of this mess is to switch to some completely
different escape sequences (maybe \e[1;2P ..., \e[15;2~ ... as used by
xterm).