/*********************************************************************** * ftermlinux.cpp - Contains the Linux terminal functions * * * * This file is part of the FINAL CUT widget toolkit * * * * Copyright 2018-2021 Markus Gans * * * * FINAL CUT is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * FINAL CUT is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program. If not, see * * . * ***********************************************************************/ #include #include #include "final/fapplication.h" #include "final/fc.h" #include "final/fcharmap.h" #include "final/flog.h" #include "final/fsystem.h" #include "final/fterm.h" #include "final/ftermcap.h" #include "final/ftermdetection.h" #include "final/ftermlinux.h" #include "final/ftypes.h" #if defined(__linux__) #include // need keyboard modifiers #include "../fonts/newfont.h" #include "../fonts/unicodemap.h" #include "../fonts/vgafont.h" namespace finalcut { //---------------------------------------------------------------------- // class FTermLinux //---------------------------------------------------------------------- // constructors and destructor //---------------------------------------------------------------------- FTermLinux::~FTermLinux() // destructor { if ( screen_font.data ) delete[] screen_font.data; if ( screen_unicode_map.entries ) delete[] screen_unicode_map.entries; } // public methods of FTermLinux //---------------------------------------------------------------------- FTermLinux::CursorStyle FTermLinux::getCursorStyle() const { // Get the current set cursor style return linux_console_cursor_style; } //---------------------------------------------------------------------- char* FTermLinux::getCursorStyleString() { // Gets the current cursor style string of the Linux console static std::array buf{}; std::fill (std::begin(buf), std::end(buf), '\0'); std::snprintf (buf.data(), buf.size(), CSI "?%dc", int(getCursorStyle())); return buf.data(); } //---------------------------------------------------------------------- bool FTermLinux::setCursorStyle (CursorStyle style) { // Set cursor style in linux console const auto& fterm_data = FTerm::getFTermData(); if ( ! FTerm::isLinuxTerm() ) return false; linux_console_cursor_style = style; if ( fterm_data->isCursorHidden() ) return false; setLinuxCursorStyle(style); return true; } //---------------------------------------------------------------------- void FTermLinux::setUTF8 (bool enable) const { if ( ! FTerm::isLinuxTerm() ) return; if ( enable ) FTerm::putstring (ESC "%G"); else FTerm::putstring (ESC "%@"); std::fflush(stdout); } //---------------------------------------------------------------------- #if defined(ISA_SYSCTL_SUPPORT) bool FTermLinux::setPalette (FColor index, int r, int g, int b) { if ( ! FTerm::isLinuxTerm() ) return false; return setVGAPalette (index, r, g, b); } #else bool FTermLinux::setPalette (FColor, int, int, int) { return false; } #endif //---------------------------------------------------------------------- bool FTermLinux::isLinuxConsole() { // Check if it's a Linux console char arg{0}; int fd_tty = FTerm::getTTYFileDescriptor(); const auto& fsystem = FTerm::getFSystem(); if ( fd_tty < 0 ) // Undefined tty file descriptor fd_tty = 0; // Get keyboard type an compare return ( fsystem->isTTY(fd_tty) && fsystem->ioctl(fd_tty, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84)) ); } //---------------------------------------------------------------------- void FTermLinux::init() { // Initialize Linux console const auto& fterm_data = FTerm::getFTermData(); const auto& term_detection = FTerm::getFTermDetection(); screen_unicode_map.entries = nullptr; screen_font.data = nullptr; fterm_data->supportShadowCharacter (true); fterm_data->supportHalfBlockCharacter (true); initKeyMap(); #if defined(ISA_SYSCTL_SUPPORT) getVGAPalette(); #endif if ( FTerm::openConsole() == 0 ) { term_detection->setLinuxTerm (isLinuxConsole()); if ( FTerm::isLinuxTerm() ) { getUnicodeMap(); getScreenFont(); #if defined(ISA_SYSCTL_SUPPORT) // Enable 16 background colors if ( setBlinkAsIntensity(true) == 0 ) FTermcap::max_color = 16; else FTermcap::max_color = 8; #endif // Underline cursor setCursorStyle (LinuxConsoleCursorStyle::Underscore); // Framebuffer color depth in bits per pixel framebuffer_bpp = getFramebuffer_bpp(); // More than 4 bits per pixel and the font uses the blink-bit if ( framebuffer_bpp >= 4 && screen_font.charcount <= 256 ) FTermcap::max_color = 16; } FTerm::detectTermSize(); FTerm::closeConsole(); } else { std::clog << FLog::LogLevel::Error << "Can not open the console." << std::endl; std::abort(); } } //---------------------------------------------------------------------- void FTermLinux::initCharMap() const { constexpr sInt16 NOT_FOUND = -1; if ( new_font || vga_font ) return; if ( screen_unicode_map.entry_ct > 0 && screen_unicode_map.entries ) { for (auto&& entry : fc::character) { const auto ucs = entry.unicode; const sInt16 fontpos = getFontPos(ucs); // Fix for a non-cp437 Linux console with PC charset encoding if ( fontpos > 255 || fontpos == NOT_FOUND ) entry.pc = entry.ascii; // Character substitutions for missing characters if ( fontpos == NOT_FOUND ) { characterFallback (ucs, { L'▲', L'↑', L'^' }); characterFallback (ucs, { L'▼', L'↓', L'v' }); characterFallback (ucs, { L'►', L'▶', L'→', L'>' }); characterFallback (ucs, { L'◄', L'◀', L'←', L'<' }); characterFallback (ucs, { L'●', L'◆', L'⬤', L'*' }); characterFallback (ucs, { L'•', L'●', L'◆', L'⬤', L'*' }); characterFallback (ucs, { L'×', L'❌', L'x' }); characterFallback (ucs, { L'÷', L'➗', L'/' }); characterFallback (ucs, { L'√', L'✓', L'x' }); characterFallback (ucs, { L'ˣ', L'ⁿ', L'ˆ', L'`' }); } } } initSpecialCharacter(); } //---------------------------------------------------------------------- void FTermLinux::finish() const { if ( FTerm::isLinuxTerm() ) { #if defined(ISA_SYSCTL_SUPPORT) setBlinkAsIntensity (false); #endif setLinuxCursorStyle (LinuxConsoleCursorStyle::Default); } } //---------------------------------------------------------------------- bool FTermLinux::loadVGAFont() { vga_font = true; new_font = false; if ( FTerm::openConsole() == 0 ) { if ( isLinuxConsole() ) { // Set the standard vga font 8x16 const int ret = setScreenFont(fc::__8x16std, 256, 8, 16); if ( ret != 0 ) vga_font = false; // Unicode character mapping struct unimapdesc unimap; unimap.entry_ct = uInt16(fc::unicode_cp437_pairs.size()); unimap.entries = const_cast(fc::unicode_cp437_pairs.data()); setUnicodeMap(&unimap); } else vga_font = false; FTerm::detectTermSize(); FTerm::closeConsole(); } else vga_font = false; if ( vga_font ) { const auto& fterm_data = FTerm::getFTermData(); fterm_data->supportShadowCharacter (true); fterm_data->supportHalfBlockCharacter (true); } return vga_font; } //---------------------------------------------------------------------- bool FTermLinux::loadNewFont() { new_font = true; vga_font = false; if ( FTerm::openConsole() == 0 ) { if ( isLinuxConsole() ) { // Set the graphical font int ret; #if defined(ISA_SYSCTL_SUPPORT) if ( has9BitCharacters() ) ret = setScreenFont(fc::__9x16graph, 256, 8, 16); // set 9×16 else #endif ret = setScreenFont(fc::__8x16graph, 256, 8, 16); // set 8×16 if ( ret != 0 ) new_font = false; // Unicode character mapping struct unimapdesc unimap; unimap.entry_ct = uInt16(fc::unicode_newfont_pairs.size()); unimap.entries = const_cast(fc::unicode_newfont_pairs.data()); setUnicodeMap(&unimap); } else new_font = false; FTerm::detectTermSize(); FTerm::closeConsole(); } else new_font = false; if ( new_font ) { const auto& fterm_data = FTerm::getFTermData(); fterm_data->supportShadowCharacter (true); fterm_data->supportHalfBlockCharacter (true); } return new_font; } //---------------------------------------------------------------------- bool FTermLinux::loadOldFont() { bool retval{false}; if ( FTerm::openConsole() == 0 ) { if ( isLinuxConsole() ) { if ( screen_font.data ) { const int ret = setScreenFont ( screen_font.data , screen_font.charcount , screen_font.width , screen_font.height , true ); delete[] screen_font.data; screen_font.data = nullptr; if ( ret == 0 ) retval = true; } if ( screen_unicode_map.entries ) { setUnicodeMap (&screen_unicode_map); initCharMap(); delete[] screen_unicode_map.entries; screen_unicode_map.entries = nullptr; } } FTerm::detectTermSize(); FTerm::closeConsole(); } if ( retval ) vga_font = new_font = false; return retval; } //---------------------------------------------------------------------- bool FTermLinux::saveColorMap() { if ( ! FTerm::isLinuxTerm() ) return false; #if defined(ISA_SYSCTL_SUPPORT) return saveVGAPalette(); #else return false; #endif } //---------------------------------------------------------------------- bool FTermLinux::resetColorMap() { if ( ! FTerm::isLinuxTerm() ) return false; #if defined(ISA_SYSCTL_SUPPORT) return resetVGAPalette(); #else return false; #endif } //---------------------------------------------------------------------- void FTermLinux::setBeep (int Hz, int ms) const { if ( ! FTerm::isLinuxTerm() ) return; // Range for frequency: 21-32766 if ( Hz < 21 || Hz > 32766 ) return; // Range for duration: 0-1999 if ( ms < 0 || ms > 1999 ) return; FTerm::putstringf ( CSI "10;%d]" CSI "11;%d]" , Hz, ms ); std::fflush(stdout); } //---------------------------------------------------------------------- void FTermLinux::resetBeep() const { if ( ! FTerm::isLinuxTerm() ) return; // Default frequency: 750 Hz // Default duration: 125 ms FTerm::putstring ( CSI "10;750]" CSI "11;125]" ); std::fflush(stdout); } //---------------------------------------------------------------------- FKey FTermLinux::modifierKeyCorrection (const FKey& key_id) { // Get the current modifier key state const Pair pair{getModifierKey(), key_id}; const auto& key = key_map[pair]; if ( key == FKey(0) ) // Not found return key_id; else // Found return key_map[pair]; } // private methods of FTermLinux //---------------------------------------------------------------------- int FTermLinux::getFramebuffer_bpp() const { int fd{-1}; const char* fb = "/dev/fb/0"; struct fb_var_screeninfo fb_var{}; struct fb_fix_screeninfo fb_fix{}; const auto& fsystem = FTerm::getFSystem(); if ( (fd = fsystem->open(fb, O_RDWR)) < 0 ) { if ( errno != ENOENT && errno != ENOTDIR ) return -1; fb = "/dev/fb0"; if ( (fd = fsystem->open(fb, O_RDWR)) < 0 ) return -1; } if ( fsystem->ioctl(fd, FBIOGET_VSCREENINFO, &fb_var) == 0 && fsystem->ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix) == 0 ) { fsystem->close(fd); return static_cast(fb_var.bits_per_pixel); } else { fsystem->close(fd); } return -1; } //---------------------------------------------------------------------- bool FTermLinux::getScreenFont() { struct console_font_op font{}; const int fd_tty = FTerm::getTTYFileDescriptor(); int ret{-1}; if ( fd_tty < 0 ) return false; // Initialize unused padding bytes in struct std::memset (&font, 0, sizeof(console_font_op)); font.op = KD_FONT_OP_GET; font.flags = 0; font.width = 32; font.height = 32; font.charcount = 512; // Initialize with 0 try { static constexpr std::size_t data_size = 4 * 32 * 512; font.data = new uChar[data_size](); } catch (const std::bad_alloc&) { badAllocOutput ("FString"); return false; } // Font operation const auto& fsystem = FTerm::getFSystem(); ret = fsystem->ioctl (fd_tty, KDFONTOP, &font); if ( ret != 0 ) { if ( font.data ) delete[] font.data; return false; } screen_font.width = font.width; screen_font.height = font.height; screen_font.charcount = font.charcount; screen_font.data = font.data; return true; } //---------------------------------------------------------------------- bool FTermLinux::getUnicodeMap() { const int fd_tty = FTerm::getTTYFileDescriptor(); int ret{-1}; if ( fd_tty < 0 ) return false; screen_unicode_map.entry_ct = 0; screen_unicode_map.entries = nullptr; // Get count const auto& fsystem = FTerm::getFSystem(); ret = fsystem->ioctl (fd_tty, GIO_UNIMAP, &screen_unicode_map); if ( ret != 0 ) { const std::size_t count = screen_unicode_map.entry_ct; if ( errno != ENOMEM || count == 0 ) return false; try { screen_unicode_map.entries = new struct unipair[count](); } catch (const std::bad_alloc&) { badAllocOutput ("unipair[count]"); return false; } // Get unicode-to-font mapping from kernel ret = fsystem->ioctl (fd_tty, GIO_UNIMAP, &screen_unicode_map); if ( ret != 0 ) return false; } return true; } //---------------------------------------------------------------------- FTermLinux::ModifierKey& FTermLinux::getModifierKey() { // Get Linux console shift state char subcode{6}; // Shift state command + return value // Fill bit field with 0 std::memset (&mod_key, 0x00, sizeof(mod_key)); const auto& fsystem = FTerm::getFSystem(); // TIOCLINUX, subcode = 6 (TIOCL_GETSHIFTSTATE) if ( fsystem->ioctl(0, TIOCLINUX, &subcode) >= 0 ) { if ( subcode & (1 << KG_SHIFT) ) mod_key.shift = true; if ( subcode & (1 << KG_ALTGR) ) mod_key.alt_gr = true; if ( subcode & (1 << KG_CTRL) ) mod_key.ctrl = true; if ( subcode & (1 << KG_ALT) ) mod_key.alt = true; } return mod_key; } //---------------------------------------------------------------------- int FTermLinux::setScreenFont ( const uChar fontdata[], uInt count , uInt fontwidth, uInt fontheight , bool direct) { struct console_font_op font{}; const int fd_tty = FTerm::getTTYFileDescriptor(); int ret{-1}; if ( fd_tty < 0 ) return -1; // Initialize unused padding bytes in struct std::memset (&font, 0x00, sizeof(console_font_op)); font.op = KD_FONT_OP_SET; font.flags = 0; font.width = fontwidth; font.height = fontheight; font.charcount = count; if ( direct ) font.data = const_cast(fontdata); else { const std::size_t bytes_per_line = font.width / 8; const std::size_t data_size = bytes_per_line * 32 * font.charcount; try { font.data = new uChar[data_size](); // Initialize with 0 } catch (const std::bad_alloc&) { badAllocOutput ("uChar[data_size]"); return -1; } for (std::size_t i{0}; i < count; i++) std::memcpy ( font.data + bytes_per_line * 32 * i , &fontdata[i * font.height] , font.height ); } // Font operation const auto& fsystem = FTerm::getFSystem(); ret = fsystem->ioctl (fd_tty, KDFONTOP, &font); if ( ret != 0 && errno != ENOSYS && errno != EINVAL ) { if ( ! direct ) delete[] font.data; return -1; } if ( ! direct ) delete[] font.data; if ( ret == 0 ) return 0; else return -1; } //---------------------------------------------------------------------- int FTermLinux::setUnicodeMap (struct unimapdesc* unimap) const { struct unimapinit advice; const int fd_tty = FTerm::getTTYFileDescriptor(); int ret{-1}; if ( fd_tty < 0 ) return -1; advice.advised_hashsize = 0; advice.advised_hashstep = 0; advice.advised_hashlevel = 0; do { // Clear the unicode-to-font table const auto& fsystem = FTerm::getFSystem(); ret = fsystem->ioctl (fd_tty, PIO_UNIMAPCLR, &advice); if ( ret != 0 ) return -1; // Put the new unicode-to-font mapping in kernel ret = fsystem->ioctl (fd_tty, PIO_UNIMAP, unimap); if ( ret != 0 ) advice.advised_hashlevel++; } while ( ret != 0 && errno == ENOMEM && advice.advised_hashlevel < 100); if ( ret == 0 ) return 0; else return -1; } //---------------------------------------------------------------------- void FTermLinux::setLinuxCursorStyle (CursorStyle style) const { FTerm::putstringf (CSI "?%dc", style); } #if defined(ISA_SYSCTL_SUPPORT) //---------------------------------------------------------------------- inline uInt16 FTermLinux::getInputStatusRegisterOne() const { // Gets the VGA input-status-register-1 const auto& fsystem = FTerm::getFSystem(); // Miscellaneous output (read port) static constexpr uInt16 misc_read = 0x3cc; const uChar misc_value = fsystem->inPortByte(misc_read); const uInt16 io_base = ( misc_value & 0x01 ) ? 0x3d0 : 0x3b0; // 0x3ba : Input status 1 mono/MDA (read port) // 0x3da : Input status 1 color/CGA (read port) return io_base + 0x0a; } //---------------------------------------------------------------------- uChar FTermLinux::readAttributeController (uChar index) const { // Reads a byte from the attribute controller from a given index const auto& fsystem = FTerm::getFSystem(); // Attribute controller (write port) static constexpr uInt16 attrib_cntlr_write = 0x3c0; // Attribute controller (read port) static constexpr uInt16 attrib_cntlr_read = 0x3c1; const uInt16 input_status_1 = getInputStatusRegisterOne(); fsystem->inPortByte (input_status_1); // switch to index mode fsystem->outPortByte (index & 0x1f, attrib_cntlr_write); // selects address register const uChar res = fsystem->inPortByte (attrib_cntlr_read); // read from data register // Disable access to the palette and unblank the display fsystem->inPortByte (input_status_1); // switch to index mode index = (index & 0x1f) | 0x20; // set bit 5 (enable display) fsystem->outPortByte (index, attrib_cntlr_write); fsystem->inPortByte (attrib_cntlr_read); return res; } //---------------------------------------------------------------------- void FTermLinux::writeAttributeController (uChar index, uChar data) const { // Writes a byte from the attribute controller from a given index const auto& fsystem = FTerm::getFSystem(); // Attribute controller (write port) static constexpr uInt16 attrib_cntlr_write = 0x3c0; const uInt16 input_status_1 = getInputStatusRegisterOne(); fsystem->inPortByte (input_status_1); // switch to index mode fsystem->outPortByte (index & 0x1f, attrib_cntlr_write); // selects address register fsystem->outPortByte (data, attrib_cntlr_write); // write to data register // Disable access to the palette and unblank the display fsystem->inPortByte (input_status_1); // switch to index mode index = (index & 0x1f) | 0x20; // set bit 5 (enable display) fsystem->outPortByte (index, attrib_cntlr_write); fsystem->outPortByte (data, attrib_cntlr_write); } //---------------------------------------------------------------------- inline uChar FTermLinux::getAttributeMode() const { // Gets the attribute mode value from the vga attribute controller static constexpr uChar attrib_mode = 0x10; return readAttributeController(attrib_mode); } //---------------------------------------------------------------------- inline void FTermLinux::setAttributeMode (uChar data) const { // Sets the attribute mode value from the vga attribute controller static constexpr uChar attrib_mode = 0x10; writeAttributeController (attrib_mode, data); } //---------------------------------------------------------------------- int FTermLinux::setBlinkAsIntensity (bool enable) const { // Uses blink-bit as background intensity. // That permits 16 colors for background const auto& fsystem = FTerm::getFSystem(); const int fd_tty = FTerm::getTTYFileDescriptor(); // Test if the blink-bit is used by the screen font (512 characters) if ( screen_font.charcount > 256 ) return -1; if ( fsystem->getuid() != 0 ) // Direct hardware access requires root privileges return -2; if ( fd_tty < 0 ) return -1; // Enable access to VGA I/O ports (from 0x3B4 with num = 0x2C) if ( fsystem->ioctl(fd_tty, KDENABIO, 0) < 0 ) return -1; // error on KDENABIO if ( enable ) setAttributeMode (getAttributeMode() & 0xF7); // clear bit 3 else setAttributeMode (getAttributeMode() | 0x08); // set bit 3 // Disable access to VGA I/O ports if ( fsystem->ioctl(fd_tty, KDDISABIO, 0) < 0 ) return -1; // error on KDDISABIO return 0; } //---------------------------------------------------------------------- bool FTermLinux::has9BitCharacters() const { // Are 9-bit wide characters used? // 9-bit character: // 0xc0...0xdf - copying the eighth pixel into the ninth pixel // The rest - the ninth pixel has the background color const auto& fsystem = FTerm::getFSystem(); const int fd_tty = FTerm::getTTYFileDescriptor(); if ( fsystem->getuid() != 0 ) // Direct hardware access requires root privileges return false; if ( fd_tty < 0 ) return false; // Enable access to VGA I/O ports (from 0x3B4 with num = 0x2C) if ( fsystem->ioctl(fd_tty, KDENABIO, 0) < 0 ) return false; // error on KDENABIO const bool nine_bit_char( getAttributeMode() & 0x04 ); // Disable access to VGA I/O ports if ( fsystem->ioctl(fd_tty, KDDISABIO, 0) < 0 ) return false; // error on KDDISABIO return nine_bit_char; } //---------------------------------------------------------------------- void FTermLinux::getVGAPalette() { const auto& fsystem = FTerm::getFSystem(); if ( fsystem->ioctl(0, GIO_CMAP, cmap.color.data()) != 0 ) setVGADefaultPalette(); // Fallback, if GIO_CMAP does not work } //---------------------------------------------------------------------- void FTermLinux::setVGADefaultPalette() { constexpr std::array defaultColor = {{ {0x00, 0x00, 0x00}, {0xaa, 0x00, 0x00}, {0x00, 0xaa, 0x00}, {0xaa, 0x55, 0x00}, {0x00, 0x00, 0xaa}, {0xaa, 0x00, 0xaa}, {0x00, 0xaa, 0xaa}, {0xaa, 0xaa, 0xaa}, {0x55, 0x55, 0x55}, {0xff, 0x55, 0x55}, {0x55, 0xff, 0x55}, {0xff, 0xff, 0x55}, {0x55, 0x55, 0xff}, {0xff, 0x55, 0xff}, {0x55, 0xff, 0xff}, {0xff, 0xff, 0xff} }}; std::transform ( defaultColor.begin() , defaultColor.end() , cmap.color.begin() , [] (const RGB& rgb) { return rgb; } ); } //---------------------------------------------------------------------- bool FTermLinux::setVGAPalette (FColor index, int r, int g, int b) { // Set the vga color map if ( r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256 ) { cmap.color[uInt16(index)].red = uChar(r); cmap.color[uInt16(index)].green = uChar(g); cmap.color[uInt16(index)].blue = uChar(b); } const auto& fsystem = FTerm::getFSystem(); if ( fsystem->ioctl(0, PIO_CMAP, cmap.color.data()) == 0 ) return true; else return false; } //---------------------------------------------------------------------- bool FTermLinux::saveVGAPalette() { // Save the current vga color map const auto& fsystem = FTerm::getFSystem(); if ( fsystem->ioctl(0, GIO_CMAP, saved_color_map.color.data()) == 0 ) has_saved_palette = true; else has_saved_palette = false; return has_saved_palette; } //---------------------------------------------------------------------- bool FTermLinux::resetVGAPalette() { // Reset the vga color map const auto& fsystem = FTerm::getFSystem(); if ( has_saved_palette ) { if ( fsystem->ioctl (0, PIO_CMAP, saved_color_map.color.data()) ) return false; } else { setVGADefaultPalette(); if ( fsystem->ioctl(0, PIO_CMAP, cmap.color.data()) != 0 ) return false; } return true; } #endif // defined(ISA_SYSCTL_SUPPORT) //---------------------------------------------------------------------- void FTermLinux::initKeyMap() { keyCorrection(); shiftKeyCorrection(); ctrlKeyCorrection(); altKeyCorrection(); shiftCtrlKeyCorrection(); shiftAltKeyCorrection(); ctrlAltKeyCorrection(); shiftCtrlAltKeyCorrection(); } //---------------------------------------------------------------------- inline void FTermLinux::keyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); key_map[{m, FKey::Up}] = FKey::Up; // Up key_map[{m, FKey::Down}] = FKey::Down; // Down key_map[{m, FKey::Left}] = FKey::Left; // Left key_map[{m, FKey::Right}] = FKey::Right; // Right key_map[{m, FKey::Insert}] = FKey::Insert; // Ins key_map[{m, FKey::Del_char}] = FKey::Del_char; // Del key_map[{m, FKey::Home}] = FKey::Home; // Home key_map[{m, FKey::End}] = FKey::End; // End key_map[{m, FKey::Page_up}] = FKey::Page_up; // PgUp key_map[{m, FKey::Page_down}] = FKey::Page_down; // PgDn } //---------------------------------------------------------------------- inline void FTermLinux::shiftKeyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); m.shift = 1; key_map[{m, FKey::Up}] = FKey::Shift_up; // Shift+Up key_map[{m, FKey::Down}] = FKey::Shift_down; // Shift+Down key_map[{m, FKey::Left}] = FKey::Shift_left; // Shift+Left key_map[{m, FKey::Right}] = FKey::Shift_right; // Shift+Right key_map[{m, FKey::Insert}] = FKey::Shift_insert; // Shift+Ins key_map[{m, FKey::Del_char}] = FKey::Shift_del_char; // Shift+Del key_map[{m, FKey::Home}] = FKey::Shift_home; // Shift+Home key_map[{m, FKey::End}] = FKey::Shift_end; // Shift+End key_map[{m, FKey::Page_up}] = FKey::Shift_page_up; // Shift+PgUp key_map[{m, FKey::Page_down}] = FKey::Shift_page_down; // Shift+PgDn } //---------------------------------------------------------------------- inline void FTermLinux::ctrlKeyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); m.ctrl = 1; key_map[{m, FKey::Up}] = FKey::Ctrl_up; // Ctrl+Up key_map[{m, FKey::Down}] = FKey::Ctrl_down; // Ctrl+Down key_map[{m, FKey::Left}] = FKey::Ctrl_left; // Ctrl+Left key_map[{m, FKey::Right}] = FKey::Ctrl_right; // Ctrl+Right key_map[{m, FKey::Insert}] = FKey::Ctrl_insert; // Ctrl+Ins key_map[{m, FKey::Del_char}] = FKey::Ctrl_del_char; // Ctrl+Del key_map[{m, FKey::Home}] = FKey::Ctrl_home; // Ctrl+Home key_map[{m, FKey::End}] = FKey::Ctrl_end; // Ctrl+End key_map[{m, FKey::Page_up}] = FKey::Ctrl_page_up; // Ctrl+PgUp key_map[{m, FKey::Page_down}] = FKey::Ctrl_page_down; // Ctrl+PgDn } //---------------------------------------------------------------------- inline void FTermLinux::altKeyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); m.alt = 1; key_map[{m, FKey::Up}] = FKey::Meta_up; // Meta+Up key_map[{m, FKey::Down}] = FKey::Meta_down; // Meta+Down key_map[{m, FKey::Left}] = FKey::Meta_left; // Meta+Left key_map[{m, FKey::Right}] = FKey::Meta_right; // Meta+Right key_map[{m, FKey::Insert}] = FKey::Meta_insert; // Meta+Ins key_map[{m, FKey::Del_char}] = FKey::Meta_del_char; // Meta+Del key_map[{m, FKey::Home}] = FKey::Meta_home; // Meta+Home key_map[{m, FKey::End}] = FKey::Meta_end; // Meta+End key_map[{m, FKey::Page_up}] = FKey::Meta_page_up; // Meta+PgUp key_map[{m, FKey::Page_down}] = FKey::Meta_page_down; // Meta+PgDn } //---------------------------------------------------------------------- inline void FTermLinux::shiftCtrlKeyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); m.shift = 1; m.ctrl = 1; key_map[{m, FKey::Up}] = FKey::Shift_Ctrl_up; // Shift+Ctrl+Up key_map[{m, FKey::Down}] = FKey::Shift_Ctrl_down; // Shift+Ctrl+Down key_map[{m, FKey::Left}] = FKey::Shift_Ctrl_left; // Shift+Ctrl+Left key_map[{m, FKey::Right}] = FKey::Shift_Ctrl_right; // Shift+Ctrl+Right key_map[{m, FKey::Insert}] = FKey::Shift_Ctrl_insert; // Shift+Ctrl+Ins key_map[{m, FKey::Del_char}] = FKey::Shift_Ctrl_del_char; // Shift+Ctrl+Del key_map[{m, FKey::Home}] = FKey::Shift_Ctrl_home; // Shift+Ctrl+Home key_map[{m, FKey::End}] = FKey::Shift_Ctrl_end; // Shift+Ctrl+End key_map[{m, FKey::Page_up}] = FKey::Shift_Ctrl_page_up; // Shift+Ctrl+PgUp key_map[{m, FKey::Page_down}] = FKey::Shift_Ctrl_page_down; // Shift+Ctrl+PgDn } //---------------------------------------------------------------------- inline void FTermLinux::shiftAltKeyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); m.shift = 1; m.alt = 1; key_map[{m, FKey::Up}] = FKey::Shift_Meta_up; // Shift+Meta+Up key_map[{m, FKey::Down}] = FKey::Shift_Meta_down; // Shift+Meta+Down key_map[{m, FKey::Left}] = FKey::Shift_Meta_left; // Shift+Meta+Left key_map[{m, FKey::Right}] = FKey::Shift_Meta_right; // Shift+Meta+Right key_map[{m, FKey::Insert}] = FKey::Shift_Meta_insert; // Shift+Meta+Ins key_map[{m, FKey::Del_char}] = FKey::Shift_Meta_del_char; // Shift+Meta+Del key_map[{m, FKey::Home}] = FKey::Shift_Meta_home; // Shift+Meta+Home key_map[{m, FKey::End}] = FKey::Shift_Meta_end; // Shift+Meta+End key_map[{m, FKey::Page_up}] = FKey::Shift_Meta_page_up; // Shift+Meta+PgUp key_map[{m, FKey::Page_down}] = FKey::Shift_Meta_page_down; // Shift+Meta+PgDn } //---------------------------------------------------------------------- inline void FTermLinux::ctrlAltKeyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); m.ctrl = 1; m.alt = 1; key_map[{m, FKey::Up}] = FKey::Ctrl_Meta_up; // Ctrl+Meta+Up key_map[{m, FKey::Down}] = FKey::Ctrl_Meta_down; // Ctrl+Meta+Down key_map[{m, FKey::Left}] = FKey::Ctrl_Meta_left; // Ctrl+Meta+Left key_map[{m, FKey::Right}] = FKey::Ctrl_Meta_right; // Ctrl+Meta+Right key_map[{m, FKey::Insert}] = FKey::Ctrl_Meta_insert; // Ctrl+Meta+Ins key_map[{m, FKey::Del_char}] = FKey::Ctrl_Meta_del_char; // Ctrl+Meta+Del key_map[{m, FKey::Home}] = FKey::Ctrl_Meta_home; // Ctrl+Meta+Home key_map[{m, FKey::End}] = FKey::Ctrl_Meta_end; // Ctrl+Meta+End key_map[{m, FKey::Page_up}] = FKey::Ctrl_Meta_page_up; // Ctrl+Meta+PgUp key_map[{m, FKey::Page_down}] = FKey::Ctrl_Meta_page_down; // Ctrl+Meta+PgDn } //---------------------------------------------------------------------- inline void FTermLinux::shiftCtrlAltKeyCorrection() { ModifierKey m{}; std::memset (&m, 0x00, sizeof(m)); m.shift = 1; m.ctrl = 1; m.alt = 1; key_map[{m, FKey::Up}] = FKey::Shift_Ctrl_Meta_up; // Shift+Ctrl+Meta+Up key_map[{m, FKey::Down}] = FKey::Shift_Ctrl_Meta_down; // Shift+Ctrl+Meta+Down key_map[{m, FKey::Left}] = FKey::Shift_Ctrl_Meta_left; // Shift+Ctrl+Meta+Left key_map[{m, FKey::Right}] = FKey::Shift_Ctrl_Meta_right; // Shift+Ctrl+Meta+Right key_map[{m, FKey::Insert}] = FKey::Shift_Ctrl_Meta_insert; // Shift+Ctrl+Meta+Ins key_map[{m, FKey::Del_char}] = FKey::Shift_Ctrl_Meta_del_char; // Shift+Ctrl+Meta+Del key_map[{m, FKey::Home}] = FKey::Shift_Ctrl_Meta_home; // Shift+Ctrl+Meta+Home key_map[{m, FKey::End}] = FKey::Shift_Ctrl_Meta_end; // Shift+Ctrl+Meta+End key_map[{m, FKey::Page_up}] = FKey::Shift_Ctrl_Meta_page_up; // Shift+Ctrl+Meta+PgUp key_map[{m, FKey::Page_down}] = FKey::Shift_Ctrl_Meta_page_down; // Shift+Ctrl+Meta+PgDn } //---------------------------------------------------------------------- inline void FTermLinux::initSpecialCharacter() const { const auto& fterm_data = FTerm::getFTermData(); const auto c1 = wchar_t(UniChar::UpperHalfBlock); const auto c2 = wchar_t(UniChar::LowerHalfBlock); const auto c3 = wchar_t(UniChar::FullBlock); if ( FTerm::charEncode(c1, Encoding::PC) == FTerm::charEncode(c1, Encoding::ASCII) || FTerm::charEncode(c2, Encoding::PC) == FTerm::charEncode(c2, Encoding::ASCII) || FTerm::charEncode(c3, Encoding::PC) == FTerm::charEncode(c3, Encoding::ASCII) ) { fterm_data->supportShadowCharacter (false); } const auto c4 = wchar_t(UniChar::RightHalfBlock); const auto c5 = wchar_t(UniChar::LeftHalfBlock); if ( FTerm::charEncode(c4, Encoding::PC) == FTerm::charEncode(c4, Encoding::ASCII) || FTerm::charEncode(c5, Encoding::PC) == FTerm::charEncode(c5, Encoding::ASCII) ) { fterm_data->supportHalfBlockCharacter (false); } } //---------------------------------------------------------------------- sInt16 FTermLinux::getFontPos (wchar_t ucs) const { constexpr sInt16 NOT_FOUND = -1; for (std::size_t n{0}; n < screen_unicode_map.entry_ct; n++) { if ( screen_unicode_map.entries[n].unicode == ucs ) return static_cast(screen_unicode_map.entries[n].fontpos); } return NOT_FOUND; } //---------------------------------------------------------------------- void FTermLinux::characterFallback ( wchar_t ucs , std::vector fallback ) const { constexpr sInt16 NOT_FOUND = -1; const auto& fterm_data = FTerm::getFTermData(); charSubstitution& sub_map = fterm_data->getCharSubstitutionMap(); if ( fallback.size() < 2 || ucs != fallback[0] ) return; for (auto iter = fallback.begin() + 1; iter != fallback.end(); iter++) { sInt16 pos = getFontPos(*iter); if ( pos != NOT_FOUND ) { sub_map[ucs] = *iter; return; } } } } // namespace finalcut #endif // defined(__linux__)