InputEventSensor and polling

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

InputEventSensor and polling

Eric Clack
Hi all, 
I've been working on Phratch, a port of MIT Scratch to Pharo, mostly to learn Smalltalk and also because Scratch is a great learning environment and I can't bear to see it end up in Flash.

So I've been digging about in the old code to fix bugs and I'm getting a sense that there's some conflict between the way the Scratch team got things working in Squeak, and the way the Pharo team things want things done. 

I must say I think the Pharo team have things right in their drive for a cleaner, simpler system, however that means I'm a bit stuck.

See the attached image of my Scratch script.

Here's where I am...
1. Keyboard events for 'When <key> pressed' HatBlockMorph (with then pen commands) work fine as these follow the regular Morphic event model
2. But 'if <key> pressed' operation (with the stamp command inside) doesn't work because it relies on polling the InputEventSensor, and I think this bit of this class doesn't work as I expect.

My view right now is that for 2, I need to use some kind of polling, and InputEventSensor has methods such as keyboardPeek and peekKeyboardEvent that imply you can poll, but looking at the implementation, which uses WaitfreeQueue I can see that calling these methods results in events being consumed, hence my post to Stack Overflow...

I've hacked around to come up with something that sort of works, outlined in this post:
...but I get the feeling I'm doing the wrong thing here, and that I should come up with a solution that better fits the 'Pharo way'.

So, let me know what you think. I'm happy to provide more info and to research better solutions, let me know...

Finally, apologies for the long post! 

Best regards, 
-Eric.

--
Eric Clack
[hidden email]
East Sussex, England.

keypress.gif (8K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

stephane ducasse
Hi eric


Hi all, 
I've been working on Phratch, a port of MIT Scratch to Pharo, mostly to learn Smalltalk and also because Scratch is a great learning environment and I can't bear to see it end up in Flash.

So I've been digging about in the old code to fix bugs and I'm getting a sense that there's some conflict between the way the Scratch team got things working in Squeak, and the way the Pharo team things want things done. 

I must say I think the Pharo team have things right in their drive for a cleaner, simpler system, however that means I'm a bit stuck.

See the attached image of my Scratch script.

Here's where I am...
1. Keyboard events for 'When <key> pressed' HatBlockMorph (with then pen commands) work fine as these follow the regular Morphic event model
2. But 'if <key> pressed' operation (with the stamp command inside) doesn't work because it relies on polling the InputEventSensor, and I think this bit of this class doesn't work as I expect.

My view right now is that for 2, I need to use some kind of polling, and InputEventSensor has methods such as keyboardPeek and peekKeyboardEvent that imply you can poll,

Why do you need to poll for event? 
In Pharo 30 we should integrate a fix and normally you can just register to get notified when a new event is happening.

May be have a look at the EventModel package 

I hope it gets the latest version of the code. Fernando used it in gaucho so soon it will be in Pharo3.0 but we should do another serious pass on it.


but looking at the implementation, which uses WaitfreeQueue I can see that calling these methods results in events being consumed, hence my post to Stack Overflow...

I've hacked around to come up with something that sort of works, outlined in this post:
...but I get the feeling I'm doing the wrong thing here, and that I should come up with a solution that better fits the 'Pharo way'.

So, let me know what you think. I'm happy to provide more info and to research better solutions, let me know...

Finally, apologies for the long post! 

Best regards, 
-Eric.

--
Eric Clack
[hidden email]
East Sussex, England.
<keypress.gif>

Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

Eric Clack
Hi Stephane, 

On 15 May 2013 18:35, stephane ducasse <[hidden email]> wrote:
Hi eric
Why do you need to poll for event? 

I'd rather not poll as it seems inefficient, but the logic and ordering of the Scratch commands seems to dictate that it is necessary.

Here's my example pseudo code from that picture of the Scratch script in my original email...

    When flag clicked [
       Loop forever [
          move 5 steps
          turn 5 degrees
          if key <space> pressed? [
             Stamp the sprite on the screen
          ]
       ]
     ]

So "When flag clicked" is clearly event driven, and that's fine, that's how it works already.

But as far as I can see, that "if key <space> pressed?" cannot be event driven, because we don't want to start execution at that block if the space key is pressed, rather we want that to evaluate to true if the space key has been pressed recently ("recently" seems a problematic term to use here but that's another issue!).

Here's the code I started throwing together to make this work -- see the bit following this line:
    type = EventTypeKeyboard

InputEventSensor>>processEvent: evt 
"Process a single event. This method is run at high priority.
The event record is:
<type><timestamp><character code><updown><modifier keys>...
where updown is:
 0 - keystroke
 1 - key down
 2 - key up
NOTE: You must ensure that there is an instance variable keyPressed."
| type updown |
type := evt at: 1.

"Treat menu events first"
type = EventTypeMenu
ifTrue: [
self processMenuEvent: evt.
^nil].

"Tackle mouse events first"
type = EventTypeMouse
ifTrue: [
"Transmogrify the button state according to the platform's button map definition"
evt at: 5 put: (ButtonDecodeTable at: (evt at: 5) + 1).
"Map the mouse buttons depending on modifiers"
evt at: 5 put: (self mapButtons: (evt at: 5) modifiers: (evt at: 6)).

"Update state for polling calls"
mousePosition := (evt at: 3) @ (evt at: 4).
modifiers := evt at: 6.
mouseButtons := evt at: 5.

^evt].
"Finally keyboard"
type = EventTypeKeyboard
ifTrue: [
"Update state for polling calls"
modifiers := evt at: 5.
updown := evt at: 4.
(updown = 2) ifTrue: [ 
keyPressed := nil
] ifFalse: [  
keyPressed := evt at: 3 ].
^evt].
"Handle all events other than Keyborad or Mouse."
^evt.
Then I use this:

InputEventSensor>>keyPressed: asciiValue
"Is this key being pressed?"
self nextEvent.
^keyPressed = asciiValue

So should I be doing this? Should I test out these changes and suggest a patch to Pharo? I'm happy that the answer might be "no", but what can I try instead?

Thanks for your help.
-Eric.


--
Eric Clack
[hidden email]
East Sussex, England.
Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

stephane ducasse


I hate this code :)
I remember that in the EventModel we had to store the previous event somehow but this was one year ago.
I should go back to the code one of these days.
So for now I say make Phrath working we will check the kernel later.

Stef

But as far as I can see, that "if key <space> pressed?" cannot be event driven, because we don't want to start execution at that block if the space key is pressed, rather we want that to evaluate to true if the space key has been pressed recently ("recently" seems a problematic term to use here but that's another issue!).

Here's the code I started throwing together to make this work -- see the bit following this line:
    type = EventTypeKeyboard

InputEventSensor>>processEvent: evt 
"Process a single event. This method is run at high priority.
The event record is:
<type><timestamp><character code><updown><modifier keys>...
where updown is:
 0 - keystroke
 1 - key down
 2 - key up
NOTE: You must ensure that there is an instance variable keyPressed."
| type updown |
type := evt at: 1.

"Treat menu events first"
type = EventTypeMenu
ifTrue: [
self processMenuEvent: evt.
^nil].

"Tackle mouse events first"
type = EventTypeMouse
ifTrue: [
"Transmogrify the button state according to the platform's button map definition"
evt at: 5 put: (ButtonDecodeTable at: (evt at: 5) + 1).
"Map the mouse buttons depending on modifiers"
evt at: 5 put: (self mapButtons: (evt at: 5) modifiers: (evt at: 6)).

"Update state for polling calls"
mousePosition := (evt at: 3) @ (evt at: 4).
modifiers := evt at: 6.
mouseButtons := evt at: 5.

^evt].
"Finally keyboard"
type = EventTypeKeyboard
ifTrue: [
"Update state for polling calls"
modifiers := evt at: 5.
updown := evt at: 4.
(updown = 2) ifTrue: [ 
keyPressed := nil
] ifFalse: [  
keyPressed := evt at: 3 ].
^evt].
"Handle all events other than Keyborad or Mouse."
^evt.
Then I use this:

InputEventSensor>>keyPressed: asciiValue
"Is this key being pressed?"
self nextEvent.
^keyPressed = asciiValue

So should I be doing this? Should I test out these changes and suggest a patch to Pharo? I'm happy that the answer might be "no", but what can I try instead?

Thanks for your help.
-Eric.


--
Eric Clack
[hidden email]
East Sussex, England.

Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

jannik laval
Thank you Stef.

What I understand is that we should make Phratch works, modifying InputEventSensor.
Then we will modify Phratch when Pharo3.0 will be enough stable to port it.

Cheers,
Jannik

On May 15, 2013, at 9:15 PM, stephane ducasse <[hidden email]> wrote:



I hate this code :)
I remember that in the EventModel we had to store the previous event somehow but this was one year ago.
I should go back to the code one of these days.
So for now I say make Phrath working we will check the kernel later.

Stef

But as far as I can see, that "if key <space> pressed?" cannot be event driven, because we don't want to start execution at that block if the space key is pressed, rather we want that to evaluate to true if the space key has been pressed recently ("recently" seems a problematic term to use here but that's another issue!).

Here's the code I started throwing together to make this work -- see the bit following this line:
    type = EventTypeKeyboard

InputEventSensor>>processEvent: evt 
"Process a single event. This method is run at high priority.
The event record is:
<type><timestamp><character code><updown><modifier keys>...
where updown is:
 0 - keystroke
 1 - key down
 2 - key up
NOTE: You must ensure that there is an instance variable keyPressed."
| type updown |
type := evt at: 1.

"Treat menu events first"
type = EventTypeMenu
ifTrue: [
self processMenuEvent: evt.
^nil].

"Tackle mouse events first"
type = EventTypeMouse
ifTrue: [
"Transmogrify the button state according to the platform's button map definition"
evt at: 5 put: (ButtonDecodeTable at: (evt at: 5) + 1).
"Map the mouse buttons depending on modifiers"
evt at: 5 put: (self mapButtons: (evt at: 5) modifiers: (evt at: 6)).

"Update state for polling calls"
mousePosition := (evt at: 3) @ (evt at: 4).
modifiers := evt at: 6.
mouseButtons := evt at: 5.

^evt].
"Finally keyboard"
type = EventTypeKeyboard
ifTrue: [
"Update state for polling calls"
modifiers := evt at: 5.
updown := evt at: 4.
(updown = 2) ifTrue: [ 
keyPressed := nil
] ifFalse: [  
keyPressed := evt at: 3 ].
^evt].
"Handle all events other than Keyborad or Mouse."
^evt.
Then I use this:

InputEventSensor>>keyPressed: asciiValue
"Is this key being pressed?"
self nextEvent.
^keyPressed = asciiValue

So should I be doing this? Should I test out these changes and suggest a patch to Pharo? I'm happy that the answer might be "no", but what can I try instead?

Thanks for your help.
-Eric.


--
Eric Clack
[hidden email]
East Sussex, England.


Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

Eric Clack
Hi Stephane and Jannik, 
Well I don't hate the code (yet ;-) So perhaps I'll have a play with it a bit more and see if I can get something that works well, and fits with plans for Pharo3.0.

Cheers, 
-Eric.


On 15 May 2013 21:16, jannik.laval <[hidden email]> wrote:
Thank you Stef.

What I understand is that we should make Phratch works, modifying InputEventSensor.
Then we will modify Phratch when Pharo3.0 will be enough stable to port it.

Cheers,
Jannik

On May 15, 2013, at 9:15 PM, stephane ducasse <[hidden email]> wrote:



I hate this code :)
I remember that in the EventModel we had to store the previous event somehow but this was one year ago.
I should go back to the code one of these days.
So for now I say make Phrath working we will check the kernel later.

Stef

But as far as I can see, that "if key <space> pressed?" cannot be event driven, because we don't want to start execution at that block if the space key is pressed, rather we want that to evaluate to true if the space key has been pressed recently ("recently" seems a problematic term to use here but that's another issue!).

Here's the code I started throwing together to make this work -- see the bit following this line:
    type = EventTypeKeyboard

InputEventSensor>>processEvent: evt 
"Process a single event. This method is run at high priority.
The event record is:
<type><timestamp><character code><updown><modifier keys>...
where updown is:
 0 - keystroke
 1 - key down
 2 - key up
NOTE: You must ensure that there is an instance variable keyPressed."
| type updown |
type := evt at: 1.

"Treat menu events first"
type = EventTypeMenu
ifTrue: [
self processMenuEvent: evt.
^nil].

"Tackle mouse events first"
type = EventTypeMouse
ifTrue: [
"Transmogrify the button state according to the platform's button map definition"
evt at: 5 put: (ButtonDecodeTable at: (evt at: 5) + 1).
"Map the mouse buttons depending on modifiers"
evt at: 5 put: (self mapButtons: (evt at: 5) modifiers: (evt at: 6)).

"Update state for polling calls"
mousePosition := (evt at: 3) @ (evt at: 4).
modifiers := evt at: 6.
mouseButtons := evt at: 5.

^evt].
"Finally keyboard"
type = EventTypeKeyboard
ifTrue: [
"Update state for polling calls"
modifiers := evt at: 5.
updown := evt at: 4.
(updown = 2) ifTrue: [ 
keyPressed := nil
] ifFalse: [  
keyPressed := evt at: 3 ].
^evt].
"Handle all events other than Keyborad or Mouse."
^evt.
Then I use this:

InputEventSensor>>keyPressed: asciiValue
"Is this key being pressed?"
self nextEvent.
^keyPressed = asciiValue

So should I be doing this? Should I test out these changes and suggest a patch to Pharo? I'm happy that the answer might be "no", but what can I try instead?

Thanks for your help.
-Eric.


--
Eric Clack
[hidden email]
East Sussex, England.





--
Eric Clack
[hidden email]
East Sussex, England.
Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

Henrik Sperre Johansen

On May 15, 2013, at 10:34 PM, Eric Clack wrote:

> Hi Stephane and Jannik,
> Well I don't hate the code (yet ;-) So perhaps I'll have a play with it a bit more and see if I can get something that works well, and fits with plans for Pharo3.0.
>
> Cheers,
> -Eric.

Would it be possible to translate it to something like
alias spaceHandler
When space pressed [
        set t1 true]

When flag clicked [
        set t1 false
        install spaceHandler
       Loop forever [
          move 5 steps
          turn 5 degrees
          if t1 [
             Stamp the sprite on the screen
             set t1 false
          ]
       ]
        uninstall spaceHandler
     ]

In general, it should be possible to rewrite polling code to event-driven with some use of temporaries.

Cheers,
Henry
Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

Sean P. DeNigris
Administrator
In reply to this post by Eric Clack
Eric Clack wrote
I've been working on Phratch, a port of MIT Scratch to Pharo...I can't bear to see it end up in Flash.
Amen! What a great, important project. Please ask whatever you need to get this done. We will support you as much as we can :)
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

jannik laval
Hi Sean,

Thank you for your support.
You can help us by trying it and give us issues: https://code.google.com/p/phratch/

Cheers,
Jannik


2013/5/16 Sean P. DeNigris <[hidden email]>
Eric Clack wrote
> I've been working on Phratch, a port of MIT Scratch to Pharo...I can't
> bear to see it end up in Flash.

Amen! What a great, important project. Please ask whatever you need to get
this done. We will support you as much as we can :)



-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/InputEventSensor-and-polling-tp4687830p4688039.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




--

~~Dr. Jannik Laval~~
École des Mines de Douai
Enseignant-chercheur
http://www.jannik-laval.eu

Reply | Threaded
Open this post in threaded view
|

Re: InputEventSensor and polling

Igor Stasenko
In reply to this post by Henrik Sperre Johansen
On 16 May 2013 10:32, Henrik Johansen <[hidden email]> wrote:

>
> On May 15, 2013, at 10:34 PM, Eric Clack wrote:
>
>> Hi Stephane and Jannik,
>> Well I don't hate the code (yet ;-) So perhaps I'll have a play with it a bit more and see if I can get something that works well, and fits with plans for Pharo3.0.
>>
>> Cheers,
>> -Eric.
>
> Would it be possible to translate it to something like
> alias spaceHandler
> When space pressed [
>         set t1 true]
>
> When flag clicked [
>         set t1 false
>         install spaceHandler
>        Loop forever [
>           move 5 steps
>           turn 5 degrees
>           if t1 [
>              Stamp the sprite on the screen
>              set t1 false
>           ]
>        ]
>         uninstall spaceHandler
>      ]
>
> In general, it should be possible to rewrite polling code to event-driven with some use of temporaries.
>
+1

you can simply turn polling into non-polling by recording the events
(as they come
i.e. key-down , then key-up) in some "keyboard map"
then your test "if space down" is actually asking keyboard map whether
space key
is held down or not, and you don't need polling event sensor.

For "key pressed" events the story is a bit more complicated, because there's a
lot of mess how to translate "key-down /up" pair of physical events
(separated by time)
into one or series of synthesized "key pressed" events.
Operating systems handling them differently, VM (hardcoded) code tries
to unify this
but IMO is only makes things worse, because it introducing common
"worst" denominator.

From VM side, i would really leave only raw event handling (e.g.
physical key down/up events)
and let image side decide how to synthesize "key pressed" events.

However, with devices like touchpads things even worse, because they
actually generating only
key press events (while actually user still touching screen and then
releases after some time,
so it is still key down/up physically).
(maybe implementing own virtual keyboard in image would be a good
solution to that problem)

> Cheers,
> Henry



--
Best regards,
Igor Stasenko.