Unbuffered reading of keystrokes for better latency
This commit is contained in:
parent
3102fa6e59
commit
925f106846
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -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) )
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -401,7 +401,7 @@ class FWidget : public FVTerm, public FObject
|
|||
|
||||
private:
|
||||
// Methods
|
||||
void init();
|
||||
void initRootWidget();
|
||||
void finish();
|
||||
void insufficientSpaceAdjust();
|
||||
void KeyPressEvent (FKeyEvent*);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue