Unbuffered reading of keystrokes for better latency

This commit is contained in:
Markus Gans 2020-03-05 21:30:54 +01:00
parent 3102fa6e59
commit 925f106846
13 changed files with 107 additions and 40 deletions

View File

@ -1,3 +1,7 @@
2020-03-05 Markus Gans <guru.mail@muenster.de>
* Unbuffered reading of keystrokes for better latency
* Mouse adjustments when resizing an rxvt terminal
2020-02-25 Markus Gans <guru.mail@muenster.de>
* New command line switch "--no-terminal-data-request" to disable
font and title determination

View File

@ -274,6 +274,7 @@ int main (int argc, char* argv[])
{
// Create the application object
finalcut::FApplication app (argc, argv);
app.setNonBlockingRead();
// Create main dialog object
MainWindow main_dlg (&app);

View File

@ -1004,6 +1004,7 @@ int main (int argc, char* argv[])
// Create the application object app
finalcut::FApplication app(argc, argv);
app.setNonBlockingRead();
app.redefineDefaultColors(true);
app.setTermTitle (title);

View File

@ -684,13 +684,11 @@ void FApplication::processKeyboardEvent()
findKeyboardWidget();
flush();
keyboard->escapeKeyHandling(); // special case: Esc key
keyboard->clearKeyBufferOnTimeout();
if ( isKeyPressed() )
keyboard->fetchKeyCode();
// special case: Esc key
keyboard->escapeKeyHandling();
}
//----------------------------------------------------------------------
@ -1121,6 +1119,12 @@ void FApplication::processResizeEvent()
if ( ! hasChangedTermSize() )
return;
if ( mouse )
{
mouse->setMaxWidth (uInt16(getDesktopWidth()));
mouse->setMaxHeight (uInt16(getDesktopHeight()));
}
FResizeEvent r_ev(fc::Resize_Event);
sendEvent(app_object, &r_ev);

View File

@ -42,7 +42,8 @@ namespace finalcut
{
// static class attributes
uInt64 FKeyboard::key_timeout{100000}; // 100 ms (default timeout for keypress)
uInt64 FKeyboard::read_blocking_time{100000}; // preset to 100 ms
uInt64 FKeyboard::key_timeout{100000}; // preset to 100 ms
struct timeval FKeyboard::time_keypressed{};
#if defined(__linux__)
@ -123,7 +124,7 @@ bool FKeyboard::isKeyPressed()
FD_ZERO(&ifds);
FD_SET(stdin_no, &ifds);
tv.tv_sec = 0;
tv.tv_usec = 100000; // 100 ms
tv.tv_usec = FKeyboard::read_blocking_time; // preset to 100 ms
const int result = select (stdin_no + 1, &ifds, nullptr, nullptr, &tv);
if ( result > 0 && FD_ISSET(stdin_no, &ifds) )
@ -290,6 +291,7 @@ inline FKey FKeyboard::getSingleKey()
if ( utf8_input && (firstchar & 0xc0) == 0xc0 )
{
char utf8char[5]{}; // Init array with '\0'
const std::size_t buf_len = std::strlen(fifo_buf);
if ( (firstchar & 0xe0) == 0xc0 )
len = 2;
@ -298,6 +300,9 @@ inline FKey FKeyboard::getSingleKey()
else if ( (firstchar & 0xf8) == 0xf0 )
len = 4;
if ( buf_len < len && ! isKeypressTimeout() )
return fc::need_more_data;
for (std::size_t i{0}; i < len ; i++)
utf8char[i] = char(fifo_buf[i] & 0xff);
@ -403,7 +408,7 @@ FKey FKeyboard::UTF8decode (const char utf8[])
inline ssize_t FKeyboard::readKey()
{
setNonBlockingInput();
const ssize_t bytes = read(FTermios::getStdIn(), &read_buf, READ_BUF_SIZE - 1);
const ssize_t bytes = read(FTermios::getStdIn(), &read_character, 1);
unsetNonBlockingInput();
return bytes;
}
@ -418,12 +423,8 @@ void FKeyboard::parseKeyBuffer()
{
if ( bytesread + fifo_offset <= int(FIFO_BUF_SIZE) )
{
for (std::size_t i{0}; i < std::size_t(bytesread); i++)
{
fifo_buf[fifo_offset] = read_buf[i];
fifo_offset++;
}
fifo_buf[fifo_offset] = char(read_character);
fifo_offset++;
fifo_in_use = true;
}
@ -453,7 +454,7 @@ void FKeyboard::parseKeyBuffer()
key = 0;
}
std::fill_n (read_buf, READ_BUF_SIZE, '\0');
read_character = 0;
}
//----------------------------------------------------------------------

View File

@ -527,7 +527,7 @@ int FMouseGPM::gpmEvent (bool clear)
FD_SET(stdin_no, &ifds);
FD_SET(gpm_fd, &ifds);
tv.tv_sec = 0;
tv.tv_usec = 100000; // 100 ms
tv.tv_usec = FKeyboard::getReadBlockingTime(); // preset to 100 ms
const int result = select (max + 1, &ifds, nullptr, nullptr, &tv);
if ( result > 0 && FD_ISSET(stdin_no, &ifds) )

View File

@ -182,6 +182,13 @@ FColor FVTerm::rgb2ColorIndex (uInt8 r, uInt8 g, uInt8 b)
return 16 + ri + gi + bi;
}
//----------------------------------------------------------------------
void FVTerm::setNonBlockingRead (bool enable)
{
uInt64 blocking_time = (enable) ? 0 : 100000; // 0 or 100 ms
FKeyboard::setReadBlockingTime (blocking_time);
}
//----------------------------------------------------------------------
void FVTerm::clearArea (int fillchar)
{

View File

@ -36,7 +36,7 @@ namespace finalcut
{
// global FWidget object
static FWidget* rootObject{nullptr};
static FWidget* root_widget{nullptr};
// static class attributes
FStatusBar* FWidget::statusbar{nullptr};
@ -59,7 +59,7 @@ uInt FWidget::modal_dialog_counter{};
// constructors and destructor
//----------------------------------------------------------------------
FWidget::FWidget (FWidget* parent, bool disable_alt_screen)
: FVTerm( ! (bool(parent) || rootObject), disable_alt_screen)
: FVTerm( ! (bool(parent) || root_widget), disable_alt_screen)
, FObject(parent)
{
// init bit field with 0
@ -73,7 +73,7 @@ FWidget::FWidget (FWidget* parent, bool disable_alt_screen)
if ( ! parent )
{
if ( rootObject )
if ( root_widget )
{
auto ftermdata = getFTerm().getFTermData();
ftermdata->setExitMessage("FWidget: No parent defined! "
@ -82,12 +82,12 @@ FWidget::FWidget (FWidget* parent, bool disable_alt_screen)
return;
}
rootObject = this;
root_widget = this;
show_root_widget = nullptr;
redraw_root_widget = nullptr;
modal_dialog_counter = 0;
statusbar = nullptr;
init();
initRootWidget();
}
else
{
@ -133,7 +133,7 @@ FWidget::~FWidget() // destructor
accelerator_list.clear();
// finish the program
if ( rootObject == this )
if ( root_widget == this )
finish();
}
@ -454,7 +454,7 @@ void FWidget::setTopPadding (int top, bool adjust)
{
if ( isRootWidget() )
{
auto r = rootObject;
auto r = root_widget;
r->wclient_offset.setY1 (r->padding.top);
adjustSizeGlobal();
}
@ -475,7 +475,7 @@ void FWidget::setLeftPadding (int left, bool adjust)
{
if ( isRootWidget() )
{
auto r = rootObject;
auto r = root_widget;
r->wclient_offset.setX1 (r->padding.left);
adjustSizeGlobal();
}
@ -496,7 +496,7 @@ void FWidget::setBottomPadding (int bottom, bool adjust)
{
if ( isRootWidget() )
{
auto r = rootObject;
auto r = root_widget;
r->wclient_offset.setY2 (int(r->getHeight()) - 1 - r->padding.bottom);
adjustSizeGlobal();
}
@ -517,7 +517,7 @@ void FWidget::setRightPadding (int right, bool adjust)
{
if ( isRootWidget() )
{
auto r = rootObject;
auto r = root_widget;
r->wclient_offset.setX2 (int(r->getWidth()) - 1 - r->padding.right);
adjustSizeGlobal();
}
@ -533,8 +533,8 @@ void FWidget::setTermSize (const FSize& size)
if ( isXTerminal() )
{
rootObject->wsize.setRect(FPoint(1, 1), size);
rootObject->adjust_wsize = rootObject->wsize;
root_widget->wsize.setRect(FPoint(1, 1), size);
root_widget->adjust_wsize = root_widget->wsize;
FTerm::setTermSize(size); // width = columns / height = lines
detectTermSize();
}
@ -995,7 +995,7 @@ void FWidget::show()
{
// Sets the initial screen settings
initScreenSettings();
// Draw the vdesktop
// Initializing vdesktop
const auto& r = getRootWidget();
setColor(r->getForegroundColor(), r->getBackgroundColor());
clearArea (getVirtualDesktop());
@ -1292,7 +1292,7 @@ void FWidget::adjustSize()
if ( ignore_padding && ! isDialogWidget() )
setTermOffset();
else
woffset = rootObject->wclient_offset;
woffset = root_widget->wclient_offset;
}
else if ( ignore_padding && p )
{
@ -1654,8 +1654,8 @@ void FWidget::onAccel (FAccelEvent*)
void FWidget::onResize (FResizeEvent* ev)
{
// The terminal was resized
rootObject->resize();
rootObject->redraw();
root_widget->resize();
root_widget->redraw();
ev->accept();
}
@ -1676,7 +1676,7 @@ void FWidget::onClose (FCloseEvent* ev)
// private methods of FWidget
//----------------------------------------------------------------------
void FWidget::init()
void FWidget::initRootWidget()
{
try
{
@ -2012,7 +2012,7 @@ void FWidget::setStatusbarText (bool enable)
//----------------------------------------------------------------------
void detectTermSize()
{
const auto& r = rootObject;
const auto& r = root_widget;
FTerm::detectTermSize();
r->adjust_wsize.setRect (1, 1, r->getDesktopWidth(), r->getDesktopHeight());
r->woffset.setRect (0, 0, r->getDesktopWidth(), r->getDesktopHeight());

View File

@ -166,7 +166,7 @@ void drawTransparentShadow (FWidget* w)
w->print() << FPoint(int(width) + 1, int(y) + 1) << " ";
}
w->print() << FStyle (fc::Transparent)
w->print() << FStyle (fc::Reset) << FStyle (fc::Transparent)
<< FPoint (1, int(height) + 1)
<< " "
<< FStyle (fc::Reset)

View File

@ -104,10 +104,13 @@ class FKeyboard final
const FString getKeyName (const FKey);
keybuffer& getKeyBuffer();
timeval* getKeyPressedTime();
static uInt64 getKeypressTimeout();
static uInt64 getReadBlockingTime();
// Mutators
void setTermcapMap (fc::FKeyMap*);
void setKeypressTimeout (const uInt64);
static void setKeypressTimeout (const uInt64);
static void setReadBlockingTime (const uInt64);
void enableUTF8();
void disableUTF8();
void enableMouseSequences();
@ -130,7 +133,6 @@ class FKeyboard final
private:
// Constants
static constexpr std::size_t READ_BUF_SIZE{1024};
static constexpr FKey NOT_SET = static_cast<FKey>(-1);
// Accessors
@ -169,10 +171,11 @@ class FKeyboard final
#endif
static timeval time_keypressed;
static uInt64 read_blocking_time;
static uInt64 key_timeout;
fc::FKeyMap* key_map{nullptr};
FKey key{0};
char read_buf[READ_BUF_SIZE]{'\0'};
uChar read_character{};
char fifo_buf[FIFO_BUF_SIZE]{'\0'};
int fifo_offset{0};
int stdin_status_flags{0};
@ -200,10 +203,22 @@ inline FKeyboard::keybuffer& FKeyboard::getKeyBuffer()
inline timeval* FKeyboard::getKeyPressedTime()
{ return &time_keypressed; }
//----------------------------------------------------------------------
inline uInt64 FKeyboard::getKeypressTimeout()
{ return key_timeout; }
//----------------------------------------------------------------------
inline uInt64 FKeyboard::getReadBlockingTime()
{ return read_blocking_time; }
//----------------------------------------------------------------------
inline void FKeyboard::setKeypressTimeout (const uInt64 timeout)
{ key_timeout = timeout; }
//----------------------------------------------------------------------
inline void FKeyboard::setReadBlockingTime (const uInt64 blocking_time)
{ read_blocking_time = blocking_time; }
//----------------------------------------------------------------------
inline void FKeyboard::enableUTF8()
{ utf8_input = true; }

View File

@ -236,6 +236,10 @@ class FVTerm
static bool setInheritBackground();
static bool unsetInheritBackground();
static void setNonBlockingRead (bool);
static void setNonBlockingRead();
static void unsetNonBlockingRead();
static void setTermTitle (const FString&);
static void setEncoding (fc::encoding);
static bool setVGAFont();
@ -871,6 +875,14 @@ inline bool FVTerm::setInheritBackground()
inline bool FVTerm::unsetInheritBackground()
{ return setInheritBackground(false); }
//----------------------------------------------------------------------
inline void FVTerm::setNonBlockingRead()
{ setNonBlockingRead(true); }
//----------------------------------------------------------------------
inline void FVTerm::unsetNonBlockingRead()
{ setNonBlockingRead(false); }
//----------------------------------------------------------------------
inline void FVTerm::setTermTitle (const FString& title)
{ FTerm::setTermTitle(title); }

View File

@ -401,7 +401,7 @@ class FWidget : public FVTerm, public FObject
private:
// Methods
void init();
void initRootWidget();
void finish();
void insufficientSpaceAdjust();
void KeyPressEvent (FKeyEvent*);

View File

@ -330,6 +330,30 @@ void FKeyboardTest::noArgumentTest()
keyboard->escapeKeyHandling();
CPPUNIT_ASSERT ( keyboard->getKey() == 0 );
// Keypress timeout
CPPUNIT_ASSERT ( keyboard->getKeypressTimeout() == 100 * 1000 );
keyboard->setKeypressTimeout(0); // 0 ms
CPPUNIT_ASSERT ( keyboard->getKeypressTimeout() == 0 );
keyboard->setKeypressTimeout(100000); // 100 ms
CPPUNIT_ASSERT ( keyboard->getKeypressTimeout() == 100 * 1000 );
// Read blocking time
CPPUNIT_ASSERT ( keyboard->getReadBlockingTime() == 100 * 1000 );
keyboard->setReadBlockingTime(1000000); // 1000 ms
CPPUNIT_ASSERT ( keyboard->getReadBlockingTime() == 1000 * 1000 );
keyboard->setReadBlockingTime(0); // 0 ms
CPPUNIT_ASSERT ( keyboard->getReadBlockingTime() == 0 );
keyboard->setReadBlockingTime(50000); // 50 ms
CPPUNIT_ASSERT ( keyboard->getReadBlockingTime() == 50 * 1000 );
keyboard->setReadBlockingTime(100000); // 100 ms
CPPUNIT_ASSERT ( keyboard->getReadBlockingTime() == 100 * 1000 );
}
//----------------------------------------------------------------------
@ -2823,13 +2847,11 @@ void FKeyboardTest::input (std::string s)
//----------------------------------------------------------------------
void FKeyboardTest::processInput()
{
keyboard->escapeKeyHandling(); // special case: Esc key
keyboard->clearKeyBufferOnTimeout();
if ( keyboard->isKeyPressed() )
keyboard->fetchKeyCode();
// special case: Esc key
keyboard->escapeKeyHandling();
}
//----------------------------------------------------------------------