2024-05-03 23:34:10 +02:00
# include "IKeyboard.hpp"
# include "../defines.hpp"
2024-06-11 17:17:45 +02:00
# include "../helpers/varlist/VarList.hpp"
2024-05-03 23:34:10 +02:00
# include "../managers/input/InputManager.hpp"
2024-07-21 13:09:54 +02:00
# include "../managers/SeatManager.hpp"
# include "../config/ConfigManager.hpp"
# include <sys/mman.h>
# include <aquamarine/input/Input.hpp>
# include <cstring>
2024-05-03 23:34:10 +02:00
2024-07-21 13:09:54 +02:00
# define LED_COUNT 3
constexpr static std : : array < const char * , 8 > MODNAMES = {
XKB_MOD_NAME_SHIFT , XKB_MOD_NAME_CAPS , XKB_MOD_NAME_CTRL , XKB_MOD_NAME_ALT , XKB_MOD_NAME_NUM , " Mod3 " , XKB_MOD_NAME_LOGO , " Mod5 " ,
} ;
constexpr static std : : array < const char * , 3 > LEDNAMES = { XKB_LED_NAME_NUM , XKB_LED_NAME_CAPS , XKB_LED_NAME_SCROLL } ;
//
2024-05-03 23:34:10 +02:00
uint32_t IKeyboard : : getCapabilities ( ) {
return HID_INPUT_CAPABILITY_KEYBOARD ;
}
2024-05-05 23:18:10 +02:00
eHIDType IKeyboard : : getType ( ) {
return HID_TYPE_KEYBOARD ;
}
2024-05-03 23:34:10 +02:00
IKeyboard : : ~ IKeyboard ( ) {
events . destroy . emit ( ) ;
2024-07-21 13:09:54 +02:00
clearManuallyAllocd ( ) ;
}
void IKeyboard : : clearManuallyAllocd ( ) {
if ( xkbStaticState )
xkb_state_unref ( xkbStaticState ) ;
if ( xkbState )
xkb_state_unref ( xkbState ) ;
if ( xkbKeymap )
xkb_keymap_unref ( xkbKeymap ) ;
if ( xkbKeymapFD > = 0 )
close ( xkbKeymapFD ) ;
xkbKeymap = nullptr ;
xkbState = nullptr ;
xkbStaticState = nullptr ;
xkbKeymapFD = - 1 ;
}
void IKeyboard : : setKeymap ( const SStringRuleNames & rules ) {
2024-07-25 13:02:05 +02:00
if ( keymapOverridden ) {
Debug : : log ( LOG , " Ignoring setKeymap: keymap is overridden " ) ;
return ;
}
2024-07-21 13:09:54 +02:00
currentRules = rules ;
xkb_rule_names XKBRULES = {
. rules = rules . rules . c_str ( ) ,
. model = rules . model . c_str ( ) ,
. layout = rules . layout . c_str ( ) ,
. variant = rules . variant . c_str ( ) ,
. options = rules . options . c_str ( ) ,
} ;
const auto CONTEXT = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ) ;
if ( ! CONTEXT ) {
Debug : : log ( ERR , " setKeymap: CONTEXT null?? " ) ;
2024-05-03 23:34:10 +02:00
return ;
2024-07-21 13:09:54 +02:00
}
clearManuallyAllocd ( ) ;
Debug : : log ( LOG , " Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {}) " , rules . layout , rules . variant , rules . rules , rules . model ,
rules . options ) ;
if ( ! xkbFilePath . empty ( ) ) {
auto path = absolutePath ( xkbFilePath , g_pConfigManager - > configCurrentPath ) ;
if ( FILE * const KEYMAPFILE = fopen ( path . c_str ( ) , " r " ) ; ! KEYMAPFILE )
Debug : : log ( ERR , " Cannot open input:kb_file= file for reading " ) ;
else {
xkbKeymap = xkb_keymap_new_from_file ( CONTEXT , KEYMAPFILE , XKB_KEYMAP_FORMAT_TEXT_V1 , XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
fclose ( KEYMAPFILE ) ;
}
}
if ( ! xkbKeymap )
xkbKeymap = xkb_keymap_new_from_names ( CONTEXT , & XKBRULES , XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
if ( ! xkbKeymap ) {
g_pConfigManager - > addParseError ( " Invalid keyboard layout passed. ( rules: " + rules . rules + " , model: " + rules . model + " , variant: " + rules . variant +
" , options: " + rules . options + " , layout: " + rules . layout + " ) " ) ;
Debug : : log ( ERR , " Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded. " , rules . layout , rules . variant , rules . rules , rules . model ,
rules . options ) ;
memset ( & XKBRULES , 0 , sizeof ( XKBRULES ) ) ;
currentRules . rules = " " ;
currentRules . model = " " ;
currentRules . variant = " " ;
currentRules . options = " " ;
currentRules . layout = " us " ;
xkbKeymap = xkb_keymap_new_from_names ( CONTEXT , & XKBRULES , XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
}
updateXKBTranslationState ( xkbKeymap ) ;
const auto NUMLOCKON = g_pConfigManager - > getDeviceInt ( hlName , " numlock_by_default " , " input:numlock_by_default " ) ;
if ( NUMLOCKON = = 1 ) {
// lock numlock
const auto IDX = xkb_map_mod_get_index ( xkbKeymap , XKB_MOD_NAME_NUM ) ;
if ( IDX ! = XKB_MOD_INVALID )
modifiersState . locked | = ( uint32_t ) 1 < < IDX ;
2024-08-23 21:35:52 +02:00
// 0 to avoid mods getting stuck if depressed during reload
updateModifiers ( 0 , 0 , modifiersState . locked , modifiersState . group ) ;
2024-07-21 13:09:54 +02:00
}
for ( size_t i = 0 ; i < LEDNAMES . size ( ) ; + + i ) {
ledIndexes . at ( i ) = xkb_map_led_get_index ( xkbKeymap , LEDNAMES . at ( i ) ) ;
Debug : : log ( LOG , " xkb: LED index {} (name {}) got index {} " , i , LEDNAMES . at ( i ) , ledIndexes . at ( i ) ) ;
}
for ( size_t i = 0 ; i < MODNAMES . size ( ) ; + + i ) {
modIndexes . at ( i ) = xkb_map_mod_get_index ( xkbKeymap , MODNAMES . at ( i ) ) ;
Debug : : log ( LOG , " xkb: Mod index {} (name {}) got index {} " , i , MODNAMES . at ( i ) , modIndexes . at ( i ) ) ;
}
2024-05-03 23:34:10 +02:00
2024-07-25 13:02:05 +02:00
updateKeymapFD ( ) ;
xkb_context_unref ( CONTEXT ) ;
g_pSeatManager - > updateActiveKeyboardData ( ) ;
}
void IKeyboard : : updateKeymapFD ( ) {
Debug : : log ( LOG , " Updating keymap fd for keyboard {} " , deviceName ) ;
if ( xkbKeymapFD > = 0 )
close ( xkbKeymapFD ) ;
xkbKeymapFD = - 1 ;
2024-07-21 13:09:54 +02:00
auto cKeymapStr = xkb_keymap_get_as_string ( xkbKeymap , XKB_KEYMAP_FORMAT_TEXT_V1 ) ;
xkbKeymapString = cKeymapStr ;
free ( cKeymapStr ) ;
int rw , ro ;
if ( ! allocateSHMFilePair ( xkbKeymapString . length ( ) + 1 , & rw , & ro ) )
Debug : : log ( ERR , " IKeyboard: failed to allocate shm pair for the keymap " ) ;
else {
auto keymapFDDest = mmap ( nullptr , xkbKeymapString . length ( ) + 1 , PROT_READ | PROT_WRITE , MAP_SHARED , rw , 0 ) ;
close ( rw ) ;
if ( keymapFDDest = = MAP_FAILED ) {
Debug : : log ( ERR , " IKeyboard: failed to mmap a shm pair for the keymap " ) ;
close ( ro ) ;
} else {
memcpy ( keymapFDDest , xkbKeymapString . c_str ( ) , xkbKeymapString . length ( ) ) ;
munmap ( keymapFDDest , xkbKeymapString . length ( ) + 1 ) ;
xkbKeymapFD = ro ;
}
}
2024-07-25 13:02:05 +02:00
Debug : : log ( LOG , " Updated keymap fd to {} " , xkbKeymapFD ) ;
2024-05-03 23:34:10 +02:00
}
void IKeyboard : : updateXKBTranslationState ( xkb_keymap * const keymap ) {
2024-07-25 13:02:05 +02:00
if ( xkbStaticState )
xkb_state_unref ( xkbStaticState ) ;
2024-07-21 13:09:54 +02:00
if ( xkbState )
xkb_state_unref ( xkbState ) ;
2024-10-08 14:15:53 +02:00
if ( xkbSymState )
xkb_state_unref ( xkbSymState ) ;
2024-07-25 13:02:05 +02:00
xkbState = nullptr ;
xkbStaticState = nullptr ;
2024-10-08 14:15:53 +02:00
xkbSymState = nullptr ;
2024-05-03 23:34:10 +02:00
if ( keymap ) {
Debug : : log ( LOG , " Updating keyboard {:x}'s translation state from a provided keymap " , ( uintptr_t ) this ) ;
2024-07-25 13:02:05 +02:00
xkbStaticState = xkb_state_new ( keymap ) ;
xkbState = xkb_state_new ( keymap ) ;
2024-10-08 14:15:53 +02:00
xkbSymState = xkb_state_new ( keymap ) ;
2024-05-03 23:34:10 +02:00
return ;
}
2024-07-21 13:09:54 +02:00
const auto KEYMAP = xkbKeymap ;
const auto STATE = xkbState ;
2024-05-03 23:34:10 +02:00
const auto LAYOUTSNUM = xkb_keymap_num_layouts ( KEYMAP ) ;
const auto PCONTEXT = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ) ;
for ( uint32_t i = 0 ; i < LAYOUTSNUM ; + + i ) {
2024-05-07 17:07:50 +02:00
if ( xkb_state_layout_index_is_active ( STATE , i , XKB_STATE_LAYOUT_EFFECTIVE ) = = 1 ) {
2024-05-03 23:34:10 +02:00
Debug : : log ( LOG , " Updating keyboard {:x}'s translation state from an active index {} " , ( uintptr_t ) this , i ) ;
CVarList keyboardLayouts ( currentRules . layout , 0 , ' , ' ) ;
CVarList keyboardModels ( currentRules . model , 0 , ' , ' ) ;
CVarList keyboardVariants ( currentRules . variant , 0 , ' , ' ) ;
xkb_rule_names rules = { . rules = " " , . model = " " , . layout = " " , . variant = " " , . options = " " } ;
std : : string layout , model , variant ;
layout = keyboardLayouts [ i % keyboardLayouts . size ( ) ] ;
model = keyboardModels [ i % keyboardModels . size ( ) ] ;
variant = keyboardVariants [ i % keyboardVariants . size ( ) ] ;
rules . layout = layout . c_str ( ) ;
rules . model = model . c_str ( ) ;
rules . variant = variant . c_str ( ) ;
auto KEYMAP = xkb_keymap_new_from_names ( PCONTEXT , & rules , XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
if ( ! KEYMAP ) {
Debug : : log ( ERR , " updateXKBTranslationState: keymap failed 1, fallback without model/variant " ) ;
rules . model = " " ;
rules . variant = " " ;
KEYMAP = xkb_keymap_new_from_names ( PCONTEXT , & rules , XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
}
if ( ! KEYMAP ) {
Debug : : log ( ERR , " updateXKBTranslationState: keymap failed 2, fallback to us " ) ;
rules . layout = " us " ;
KEYMAP = xkb_keymap_new_from_names ( PCONTEXT , & rules , XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
}
2024-07-25 13:02:05 +02:00
xkbState = xkb_state_new ( KEYMAP ) ;
xkbStaticState = xkb_state_new ( KEYMAP ) ;
2024-10-08 14:15:53 +02:00
xkbSymState = xkb_state_new ( KEYMAP ) ;
2024-05-03 23:34:10 +02:00
xkb_keymap_unref ( KEYMAP ) ;
xkb_context_unref ( PCONTEXT ) ;
return ;
}
}
Debug : : log ( LOG , " Updating keyboard {:x}'s translation state from an unknown index " , ( uintptr_t ) this ) ;
xkb_rule_names rules = {
. rules = currentRules . rules . c_str ( ) ,
. model = currentRules . model . c_str ( ) ,
. layout = currentRules . layout . c_str ( ) ,
. variant = currentRules . variant . c_str ( ) ,
. options = currentRules . options . c_str ( ) ,
} ;
const auto NEWKEYMAP = xkb_keymap_new_from_names ( PCONTEXT , & rules , XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
2024-07-25 13:02:05 +02:00
xkbState = xkb_state_new ( NEWKEYMAP ) ;
xkbStaticState = xkb_state_new ( NEWKEYMAP ) ;
2024-10-08 14:15:53 +02:00
xkbSymState = xkb_state_new ( NEWKEYMAP ) ;
2024-05-03 23:34:10 +02:00
xkb_keymap_unref ( NEWKEYMAP ) ;
xkb_context_unref ( PCONTEXT ) ;
}
std : : string IKeyboard : : getActiveLayout ( ) {
2024-07-21 13:09:54 +02:00
const auto KEYMAP = xkbKeymap ;
const auto STATE = xkbState ;
2024-05-03 23:34:10 +02:00
const auto LAYOUTSNUM = xkb_keymap_num_layouts ( KEYMAP ) ;
for ( uint32_t i = 0 ; i < LAYOUTSNUM ; + + i ) {
2024-05-07 17:07:50 +02:00
if ( xkb_state_layout_index_is_active ( STATE , i , XKB_STATE_LAYOUT_EFFECTIVE ) = = 1 ) {
2024-05-03 23:34:10 +02:00
const auto LAYOUTNAME = xkb_keymap_layout_get_name ( KEYMAP , i ) ;
if ( LAYOUTNAME )
return std : : string ( LAYOUTNAME ) ;
return " error " ;
}
}
return " none " ;
}
2024-07-28 12:46:38 +02:00
std : : optional < uint32_t > IKeyboard : : getLEDs ( ) {
2024-07-21 13:09:54 +02:00
if ( xkbState = = nullptr )
2024-07-28 12:46:38 +02:00
return { } ;
2024-05-03 23:34:10 +02:00
uint32_t leds = 0 ;
2024-07-21 13:09:54 +02:00
for ( uint32_t i = 0 ; i < LED_COUNT ; + + i ) {
if ( xkb_state_led_index_is_active ( xkbState , ledIndexes . at ( i ) ) )
2024-05-03 23:34:10 +02:00
leds | = ( 1 < < i ) ;
}
2024-07-28 12:46:38 +02:00
return leds ;
}
void IKeyboard : : updateLEDs ( ) {
std : : optional < uint32_t > leds = getLEDs ( ) ;
if ( ! leds . has_value ( ) )
return ;
updateLEDs ( leds . value ( ) ) ;
2024-05-14 17:14:43 +02:00
}
void IKeyboard : : updateLEDs ( uint32_t leds ) {
2024-07-21 13:09:54 +02:00
if ( ! xkbState )
2024-05-14 17:14:43 +02:00
return ;
2024-05-03 23:34:10 +02:00
if ( isVirtual ( ) & & g_pInputManager - > shouldIgnoreVirtualKeyboard ( self . lock ( ) ) )
return ;
2024-07-21 13:09:54 +02:00
if ( ! aq ( ) )
return ;
aq ( ) - > updateLEDs ( leds ) ;
}
uint32_t IKeyboard : : getModifiers ( ) {
uint32_t modMask = modifiersState . depressed | modifiersState . latched ;
uint32_t mods = 0 ;
for ( size_t i = 0 ; i < modIndexes . size ( ) ; + + i ) {
if ( modIndexes . at ( i ) = = XKB_MOD_INVALID )
continue ;
if ( ! ( modMask & ( 1 < < modIndexes . at ( i ) ) ) )
continue ;
mods | = ( 1 < < i ) ;
}
return mods ;
}
void IKeyboard : : updateModifiers ( uint32_t depressed , uint32_t latched , uint32_t locked , uint32_t group ) {
if ( ! xkbState )
return ;
xkb_state_update_mask ( xkbState , depressed , latched , locked , 0 , 0 , group ) ;
2024-10-08 14:15:53 +02:00
if ( xkbSymState )
xkb_state_update_mask ( xkbSymState , 0 , 0 , 0 , 0 , 0 , group ) ;
2024-07-21 13:09:54 +02:00
if ( ! updateModifiersState ( ) )
return ;
2024-07-27 17:43:45 +02:00
keyboardEvents . modifiers . emit ( SModifiersEvent {
. depressed = modifiersState . depressed ,
. latched = modifiersState . latched ,
. locked = modifiersState . locked ,
. group = modifiersState . group ,
} ) ;
2024-07-21 13:09:54 +02:00
updateLEDs ( ) ;
}
bool IKeyboard : : updateModifiersState ( ) {
if ( ! xkbState )
return false ;
auto depressed = xkb_state_serialize_mods ( xkbState , XKB_STATE_MODS_DEPRESSED ) ;
auto latched = xkb_state_serialize_mods ( xkbState , XKB_STATE_MODS_LATCHED ) ;
auto locked = xkb_state_serialize_mods ( xkbState , XKB_STATE_MODS_LOCKED ) ;
auto group = xkb_state_serialize_layout ( xkbState , XKB_STATE_LAYOUT_EFFECTIVE ) ;
if ( depressed = = modifiersState . depressed & & latched = = modifiersState . latched & & locked = = modifiersState . locked & & group = = modifiersState . group )
return false ;
modifiersState . depressed = depressed ;
modifiersState . latched = latched ;
modifiersState . locked = locked ;
modifiersState . group = group ;
return true ;
}
void IKeyboard : : updateXkbStateWithKey ( uint32_t xkbKey , bool pressed ) {
const auto contains = std : : find ( pressedXKB . begin ( ) , pressedXKB . end ( ) , xkbKey ) ! = pressedXKB . end ( ) ;
if ( contains & & pressed )
return ;
if ( ! contains & & ! pressed )
return ;
if ( contains )
std : : erase ( pressedXKB , xkbKey ) ;
else
pressedXKB . emplace_back ( xkbKey ) ;
xkb_state_update_key ( xkbState , xkbKey , pressed ? XKB_KEY_DOWN : XKB_KEY_UP ) ;
if ( updateModifiersState ( ) ) {
2024-10-09 00:33:10 +02:00
if ( xkbSymState )
xkb_state_update_mask ( xkbSymState , 0 , 0 , 0 , 0 , 0 , modifiersState . group ) ;
2024-07-21 13:09:54 +02:00
keyboardEvents . modifiers . emit ( SModifiersEvent {
. depressed = modifiersState . depressed ,
. latched = modifiersState . latched ,
. locked = modifiersState . locked ,
. group = modifiersState . group ,
} ) ;
}
2024-05-03 23:34:10 +02:00
}