Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: TextEntered generates multiple events  (Read 4514 times)

0 Members and 1 Guest are viewing this topic.

Quit

  • Newbie
  • *
  • Posts: 6
    • View Profile
TextEntered generates multiple events
« on: March 09, 2016, 12:02:15 am »
Hi there. I'm trying to make a notepad-like app, and i'm stuck at the core function -entering text. What happens is that whenever i press a "text" key on my keyboard, instead of one letter, at least 10 are added to the output string (immediately, without any delay). I tried disabling key repeat, i tried some weird bool flags to check if a key was 'unpressed' before you could press it again. The function for text capture goes as follows
if (mEvent->type == sf::Event::EventType::TextEntered)
        {
               
                if (mEvent->text.unicode < 256)
                {
                        if (mEvent->text.unicode ==  8)
                        {
                                size_t i = std::distance(mBuffer.begin(), mIt);

                                if (i == 0 || i > mBuffer.size())
                                {
                                }
                                else
                                        mIt = mBuffer.erase(mBuffer.begin() + (i - 1));
                        }
                        else if (mEvent->text.unicode == 13)
                        {
                                mIt = mBuffer.insert(mIt, '\n') + 1;
                        }
                        else
                        {
                                mIt = mBuffer.insert(mIt, static_cast<char>(mEvent->text.unicode)) + 1;
                                printf("%s\n", mBuffer.c_str());
                        }
                }
        }
 
mBuffer is an std::string, mIt is an std::string::iterator

G.

  • Hero Member
  • *****
  • Posts: 1593
    • View Profile
Re: TextEntered generates multiple events
« Reply #1 on: March 09, 2016, 12:56:05 am »
Is your code inside your event loop? (If not, it should)

Quit

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: TextEntered generates multiple events
« Reply #2 on: March 09, 2016, 02:52:36 pm »
Yup, obviously it is. I don't think there is smth wrong with the loop itself. For one, other functionalities that are already implemented and that are based on input work just fine (clicking on buttons, turning pages with arrow keys). Moreover, the code that i pasted actually comes straight from my small prototype where i was checking how i would go about text edition and back then it worked as expected (one button press = one 'type' event). The only difference is that in the prototype the unicode characters were being pushed into a vector of char's when you were typing. The vector was then fed to a stringstream via for loop and turned into a string that was used to update sf::Text object. In this version, the unicode chars are pushed directly into the string that is the source for an sf::Text object. I'm no expert but i don't think this should have any influence on how the input is 'gathered'. As if that weren't enough, in prototype version i didn't even disable the key repeat in the window object. The only difference i believe may have ANY impact is that in the prototype i was polling events directly on a renderwindow object, while in this version it's a pointer and window is created via "new" tag

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: TextEntered generates multiple events
« Reply #3 on: March 09, 2016, 09:03:28 pm »
Does:
if (mEvent->type == sf::Event::EventType::TextEntered)
    {
        if (mEvent->text.unicode < 256)
        {
            std::cout << text.unicode << std::endl;

            // commented out the rest of your code here
        }
    }
also output multiple times when you press a key?

Is your code inside your event loop? (If not, it should)
Yup, obviously it is.
It's not at all obvious as you didn't show it.

The only difference i believe may have ANY impact is that in the prototype i was polling events directly on a renderwindow object, while in this version it's a pointer and window is created via "new" tag
Are you polling the events in a different thread?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Quit

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: TextEntered generates multiple events
« Reply #4 on: March 10, 2016, 07:26:27 pm »
Quote
also output multiple times when you press a key?

unfortunately yes. just tapped 'a' and the console is full of output (23 messages to be exact)

Quote
It's not at all obvious as you didn't show it.

sorry, didn't mean it like that. I meant that if it wasn't in a loop, the app would freeze right after a startup, not produce an excessive amount of input.

Quote
Are you polling the events in a different thread?

No, everything runs in one main thread. It is organized more/less in the following way

Quote
int main()
{
     Program program;  //this object contains the sf::Event mEvent and sf::RenderWindow* mWindow object, which is then shared with all other subsystems

     program.run();
}

Quote
program.run()
{
                while (mRunning)
                {
                                mWindow->pollEvent(mEvent);
                                if (mEvent.type == sf::Event::Closed)
                                                mRunning = false;

                                mLoadedSoftware->fillPages();
                                mLoadedSoftware->updatePages();
                                mLoadedSoftware->drawPages();
                }
}

and then in Software object, to which the pointer to mEvent is passed, we have updatePages()

Quote
void Software::updatePages()
{
   mActiveState->updatePages();
}

which for each state calls it's own input handling. Maybe also worth noting is that all the input, regardless of the state, behaves in the same way: i.e. one mouse click generates tens of click events. But all of this was easy to work around with bool triggers. For typing it's no good as using the bool trigger 'pressed/unpressed' makes the program miss half of the letters typed

edit: also, right after creating a new sf::RenderWindow object i put
   mWindow->setKeyRepeatEnabled(false);
but it doesn't change a thing in the program's behavior
« Last Edit: March 10, 2016, 07:34:27 pm by Quit »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: TextEntered generates multiple events
« Reply #5 on: March 10, 2016, 07:44:43 pm »
while (mRunning)
{
    mWindow->pollEvent(mEvent);
    if (mEvent.type == sf::Event::Closed)
        mRunning = false;

    mLoadedSoftware->fillPages();
    mLoadedSoftware->updatePages();
    mLoadedSoftware->drawPages();
}
There is no event loop here.
You are polling once, then processing the entire frame using that one event. This isn't technically incorrect but it's not taking into account if pollEvent() fails. The event is no longer valid as it's still the same event as it was before and you're still processing it as if it's just received a new one. This is why all event processing usually goes within a specific event loop that only processes the event if polling was successful.

This would explain why you're getting multiple "hits". The event is the same until it receives a different event.

Also, you might consider creating (or resetting) the event each frame, just before the event polling. That way, the event is - at least - in its default state, rather than its previous state.
(click to show/hide)

However, since an event can't hold "no event has occurred" (and why would it?), you would be processing the event as if the default event has occurred (which, I think would be Closed so if this closes your window immediately, you can see why)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Quit

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: TextEntered generates multiple events
« Reply #6 on: March 10, 2016, 10:01:48 pm »
Quote
There is no event loop here.
You are polling once, then processing the entire frame using that one event. This isn't technically incorrect but it's not taking into account if pollEvent() fails. The event is no longer valid as it's still the same event as it was before and you're still processing it as if it's just received a new one. This is why all event processing usually goes within a specific event loop that only processes the event if polling was successful.

Another lesson in humility, another lesson in careful analysis. Naturally, in my prototype I had
Code: [Select]
sf::Event event;
while (window.pollEvent(event))
hence it worked like a charm. Added a while loop within while(mRunning) and bingo. You, Sir, are a kind genius and a scholar.

Quote
Also, you might consider creating (or resetting) the event each frame, just before the event polling. That way, the event is - at least - in its default state, rather than its previous state.

However, since an event can't hold "no event has occurred" (and why would it?), you would be processing the event as if the default event has occurred (which, I think would be Closed so if this closes your window immediately, you can see why)

I'm not sure if I follow here. I tried both versions now and they behaved in a same way. Could you explain the potential benefits of resetting the event object prior to each poll operation?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: TextEntered generates multiple events
« Reply #7 on: March 11, 2016, 09:04:40 am »
Resetting a sf::Event instance doesn't make sense, because there's no point storing and reusing it outside the event loop. The typical usage is to declare a fresh sf::Event on the stack just before starting the event loop.

sf::Event event;
while (window.pollEvent(event))
{
    ...
}

And yes, if you write the event loop correctly, you don't care anyway ;)
Laurent Gomila - SFML developer

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: TextEntered generates multiple events
« Reply #8 on: March 11, 2016, 05:30:56 pm »
My "resetting" idea was, as I pointed out, majorly flawed.
It could be used by "resetting" (setting) to an event that you don't process. That way, it would be as if the event was a non-event.

Still, that is really hacky and having the usual/standard/typical event loop - as Laurent pointed out and it is present in almost all SFML code - is the most reliable solution.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*