08-21-2025, 10:01 PM
Hi,
Here is a new program under Linux that retrieves the keycode of the pressed key and translates it into keysym and Unicode.
Here is a new program under Linux that retrieves the keycode of the pressed key and translates it into keysym and Unicode.
Code: (Select All)
' ========================================================================================
' This program is designed to manage the X11 keymap and interpret keyboard input,
' specifically focusing on printing the Unicode characters of pressed keys.
'
' It retrieves the current keymap using the xmodmap command, parses keycodes and
' their corresponding keysyms, and stores this information in structured data types.
'
' By tracking modifier states, the program accurately maps key events to their Unicode
' representations, allowing it to output the correct characters and their names to the
' console when keys are pressed.
'
' You can test this program after changing the keyboard language with setxkbmap.
'
' This program read raw keyboard events directly from a Linux input device file, typically
' located at `/dev/input/event0`. Modify keyboardFileName$ to change input device file.
'
' It is a low-level approach that bypasses standard input methods to capture every key
' press, release, and repeat event.
' ========================================================================================
' Structure to hold the current X11 keymap
type keymapType
keycode as _unsigned _byte ' xmodmap keycode adjusted (stored as keycode - 8)
keysym2 as string ' keysym for level 1 (no modifier)
name2 as string ' human-readable name for keysym2
keysym3 as string ' keysym for level 2 (Shift)
name3 as string ' human-readable name for keysym3
keysym4 as string ' keysym for level 3 (AltGr / Mode_switch)
name4 as string ' human-readable name for keysym4
keysym5 as string ' keysym for level 4 (Shift + AltGr)
name5 as string ' human-readable name for keysym5
end type
' Structure to hold a keysym definition parsed from keysymdef.h
type keysymdefType
symname as string ' The keysym name (e.g. "XK_A" without the "XK_" prefix in this code)
symcode as string ' The keysym constant value as found in the header (e.g. "0xff41")
unicode as string ' Optional Unicode mapping token (e.g. "U+0061") if present
end type
$console
_dest _console
' Execute the system command "xmodmap -pk" to get the current X11 keymap
' and extract keycodes, keysyms or names
shell "xmodmap -pk > ./keyboardWithXmodmap.tmp"
content$ = _readfile$("./keyboardWithXmodmap.tmp")
kill "./keyboardWithXmodmap.tmp"
redim xmodmap$(0)
split content$, _STR_NAT_EOL, xmodmap$()
clean xmodmap$()
dim keymap(8 to 255) as keymapType
for i%=3 to ubound(xmodmap$)
replace xmodmap$(i%), chr$(9), chr$(32)
redim keyCodeAndSym$(0)
split xmodmap$(i%), " ", keyCodeAndSym$()
k% = val(keyCodeAndSym$(0))
keymap(k%).keycode = k% - 8
if ubound(keyCodeAndSym$)>5 then
keymap(k%).keysym2 = keyCodeAndSym$(5)
keymap(k%).name2 = keyCodeAndSym$(6)
end if
if ubound(keyCodeAndSym$)>7 then
keymap(k%).keysym3 = keyCodeAndSym$(7)
keymap(k%).name3 = keyCodeAndSym$(8)
end if
if ubound(keyCodeAndSym$)>9 then
keymap(k%).keysym4 = keyCodeAndSym$(9)
keymap(k%).name4 = keyCodeAndSym$(10)
end if
if ubound(keyCodeAndSym$)>11 then
keymap(k%).keysym5 = keyCodeAndSym$(11)
keymap(k%).name5 = keyCodeAndSym$(12)
end if
next i%
' Get X11 keysym definitions from /usr/include/X11/keysymdef.h into ks() array
dim ks(2200) as keysymdefType
l% = 1
open "/usr/include/X11/keysymdef.h" for input as #1
do while not eof(1)
line input #1, content$
redim r$(0)
split content$, " ", r$()
if ubound(r$) = 0 then _continue
if left$(r$(lbound(r$)),7) <> "#define" then _continue
ks(l%).symname = mid$(r$(lbound(r$)+1),4)
ks(l%).symcode = r$(lbound(r$)+2)
for i% = lbound(r$)+3 to ubound(r$)
if left$(r$(i%),2) = "U+" then ks(l%).unicode = r$(i%)
next i%
l% = l% + 1
loop
close #1
screen _NewImage(1024,768,32)
' load the first monospace font
shell "fc-list
pacing=100
tyle=bold:lang=fr | head -n 1 | cut -d: -f1 > ./keyboardWithXmodmap.tmp"
open "./keyboardWithXmodmap.tmp" for input as #1
line input #1, fontFile$
close #1
kill "./keyboardWithXmodmap.tmp"
DIM fh AS LONG:
fh = _loadfont(fontFile$,24)
IF fh <= 0 THEN
$console
_dest _console
PRINT "Failed to load font file!"
_dest 0
END
END IF
_FONT fh
' Reads 24-byte event structures from the specified device file.
'
' It filters for key-related events and then determines if the event is a key press (DOWN_DETECTED),
' a key release (UP_DETECTED), or an auto-repeat (REPEAT_DETECTED).
'
' It specifically tracks the state of modifier keys (Left Shift, Right Shift, and Right Alt)
' to correctly interpret the character generated by other key presses.
'
' When a non-modifier key is pressed, it uses the key's scancode combined with the current state
' of the modifiers to look up the appropriate keysym and character name from a `keymap` array (not defined in this snippet).
'
' The resulting information is then printed to the window.
const KEY_EVENT = &h01
const UP_DETECTED = 0
const DOWN_DETECTED = 1
const REPEAT_DETECTED = 2
const KEY_LEFTSHIFT = 42
const KEY_RIGHTSHIFT = 54
const KEY_RIGHTALT = 100
dim aByte(24) as _unsigned _byte
keyboardFileName$ = "/dev/input/event0"
open keyboardFileName$ for binary as #1
print "keycode", "keysym", "unicode", "char.", "name"
p% = 1
do
get #1, , aByte(p%)
if (p% MOD 24) = 0 then
if aByte(17) = KEY_EVENT then
select case aByte(21)
case UP_DETECTED
select case aByte(19)
case KEY_LEFTSHIFT :
modifiers = modifiers and not 1
case KEY_RIGHTSHIFT :
modifiers = modifiers and not 1
case KEY_RIGHTALT :
modifiers = modifiers and not 2
end select
case DOWN_DETECTED
if aByte(19) = 1 then exit do ' Exit on ESC key down
select case aByte(19)
case KEY_LEFTSHIFT :
modifiers = modifiers or 1
case KEY_RIGHTSHIFT :
modifiers = modifiers or 1
case KEY_RIGHTALT :
modifiers = modifiers or 2
case else:
k% = aByte(19)+8
select case modifiers
case 0 :
printData keymap(k%).keycode, keymap(k%).keysym2, keymap(k%).name2, ks()
case 1 :
printData keymap(k%).keycode, keymap(k%).keysym3, keymap(k%).name3, ks()
case 2 :
printData keymap(k%).keycode, keymap(k%).keysym4, keymap(k%).name4, ks()
case 3 :
printData keymap(k%).keycode, keymap(k%).keysym5, keymap(k%).name5, ks()
end select
end select
case REPEAT_DETECTED
if SHOW_ME_REPETITION then
print " REPEAT ", aByte(19)
end if
end select
end if
p% = 0
end if
p% = p% + 1
loop
system
' print keycode, keysym, unicode, character, character name
sub printData (keycode, keysym as string, keyname as string, ks() as keysymdefType)
if keysym = "" then
print keycode, space$(8), space$(8), space$(8), keyname
end if
uc$ = _trim$(searchKeysym(ks(),keysym))
unicode = val("&H"+mid$(uc$,3))
if unicode > 0 then
_mapunicode unicode to &HFF
print keycode, keysym, uc$, chr$(&HFF), keyname
else
print keycode, keysym, space$(8), space$(8), keyname
end if
end sub
' search keysym to get the unicode equivalent
function searchKeysym$ (ks() as keysymdefType, keysym as string)
res$ = ""
for i% = lbound(ks) to ubound(ks)
if ks(i%).symcode = keysym then
res$ = ks(i%).unicode
exit for
end if
next i%
searchKeysym = res$
end function
' split string using a delimiter
Sub split (in$, delimiter$, result$())
ReDim result$(-1)
dim start, finish
start = 1
Do
While Mid$(in$, start, 1) = delimiter$
start = start + 1
If start > Len(in$) Then Exit Sub
Wend
finish = InStr(start, in$, delimiter$)
If finish = 0 Then finish = Len(in$) + 1
ReDim _Preserve result$(0 To UBound(result$) + 1)
result$(UBound(result$)) = Mid$(in$, start, finish - start)
start = finish + 1
Loop While start <= Len(in$)
End Sub
' clean array of string
sub clean (result$())
dim i%
for i% = lbound(result$) to ubound(result$)
if right$(result$(i%),1) = chr$(13) then
result$(i%) = left$(result$(i%),len(result$(i%))-1)
end if
next i%
end sub
' replace findString with replaceString into myString
sub replace (myString$, findString$, replaceString$)
start% = 1
do
position% = INSTR(start%, myString$, findString$)
IF position% THEN
MID$(myString$, position%, len(findString$)) = replaceString$
start% = position% + 1
END IF
loop until position% = 0
end sub

