MouseUp and TouchUp

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
It would be nice to have a MouseUp and TouchUp command. It can be use for example; clicking a button only execute once. MouseDown on the other hand always true on click, making it execute many times. So I added this on modules\mojo\input.csx
Code:
Global __MouseDown:Bool
Function MouseUp( button=MOUSE_LEFT )
	If device.KeyDown( KEY_LMB+button ) 
		__MouseDown=True
	Else
		If __MouseDown
			__MouseDown=False
			Return True
		endif
	Endif
	Return False
End
Global __TouchDown:Bool
Function TouchUp( index=0 )
	If device.KeyDown( KEY_TOUCH0+index )
		__TouchDown=True
	Else
		If __TouchDown
			__TouchDown=False
			Return True
		endif
	Endif
	Return False
End

Example use in Cerberus would be..
Code:
If MouseUp() 
	Print ("Do something Once")
Endif
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
I am not very sure how MouseHit() works. I try but it not fire-up OnRender. According to doc it returns the number of times the specified mouse button has been pressed since the last OnUpdate. So maybe that is why it is silence in OnRender()

I check, MouseHit() also trigger at the moment mousedown event occurs. The difference from mousedown is it triggers only once. And it did not tell about the mouse button being released. But I like to know about that state.

The mouseup event occurs when the mouse button is released after being pressed. This method is often used for confirming something is clicked.
The mouseup info can be helpful in many tasks like drag and drop object. But, you can probably do the drag and drop any other way.

Example scenario; if you press any button in the window, it does not consider click until you release the button. It actually monitors MouseUp on that button. If you click but drag away from that button and then release, the button didn't do the job, assuming you cancel the click. It's like playing chess:D and only confirm if you let go of your hand.

Also, back from Blitzbasic and BlitzPlus time, They have this MouseUp() command.
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
681
Here are my two cents regarding this function. Besides functionality I am pretty sure MouseUp() is not the proper name for this. MouseDown describes the state of the button being held down, so MouseUp would be nothing more than "Not MouseDown".
Your functionality is something like MouseReleased() that only returns true, if the Mousebutton is not held down after it was held down on last check.
Besides that I am not sure if you gain a lot with a separate function like that. In all your use cases you would have to track some other condition to verify the release action that cannot be ommited with a MouseRelease() function. For example if you want to have a button to be clicked the moment you release it you would still have to have a flag like wasMousePressedOnButton which makes the MousRelease() function redundant.
Maybe I missed something here and there is a greater advantage of your functionality, so let me know.
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
All those input comands with the word "hit" in them needs to be done inside OnUpdate, they won't work in OnRender.

They have some clever inner-working so you can get information what happens in-between the individual readings, and I think that's why they need to be inside Onupdate becuase you can't have longlasting actions like this in the graphics-thread.

e.g. MouseHit does not just read mousedown or mouseup, it reacts on both down-events and up-events as a group. TouchHit is even more interesting in the information ig gives I can't remember right now.
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
@Phil7, I like MouseUp than MouseReleased because it's short :p
But I guess, as you said, MouseReleased makes more sense(y)

Btw.. I see many languages like JS,.NET,C#,Objective-C use MouseUp, not as "NOT MouseDown" but as releasing a mouse button over something.

About the user case..
I can't think of something that really relies on MouseUp. People can always go around and do stuff their way. But there is a time when I like to know a button is released from a press, and it's nice if I can get it in one command.🙏
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Btw.. I see many languages like JS,.NET,C#,Objective-C use MouseUp, not as "NOT MouseDown" but as releasing a mouse button over something.
Usually with JS and other languages you do something that's similar to MouseHit. Because you don't just go by the MouseUp event you really want a MouseDown event first when it's on the button or area.

Otherwise you would be able to press the mouse away from the button, and then float over it and release. You don't want that to trigger a press. Of course you can do that but its not common and most of the time it's not the user experience that you'd want.
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
Otherwise you would be able to press the mouse away from the button, and then float over it and release. You don't want that to trigger a press. Of course you can do that but its not common and most of the time it's not the user experience that you'd want.
The way I see is different. Try to click the close button in your browser, and then move away from it and release. You see it cancels the command. This is a common practice in many objects. I guess by mousedown we cannot proceed yet, the user might want to drag or long-press to pop a small menu etc
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Good point, but think about it these two properties are not exclusive. Almost all the time these two are actually combined.

Lemme see if I can remember all of the combinations that I know of on top of my head :

Release anywhere = this always cancels, anyting at any time.

Click anywhere and then release inside-button = nothing (typically not not in apps and the browser, but some places use this, it feels very easy to accidentally do something you don't want to do). I could agree to call this a "game click" if you will.

Click-inside-button and release outside = cancel.

Click-inside-button and relase-inside-button = this I would call the most "proffesional" click. It's hard to do anything by acciden.
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
681
Click-inside-button and relase-inside-button = this I would call the most "proffesional" click. It's hard to do anything by acciden.
This has one special case in it where you press inside the button, then leave the button while pressing, then entering the button again and then releasing. This does execute the command in common apps.
And these three types of behaviours show how it needs to be implemented to work intuitively for most people:
Check for xy-coords when pressing. Check for xy-coords when releasing. Only execute command if both xy-coords are on the button when releasing - and don't check in between.
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
True, there's a lot of things to think about here.

You could also update variables every frame to keep things like mouseup, doubleclick, holding status and pretty much everything else that you need.

I just have a touchpad and never use middle mouse button anymore.

Code:
Strict
Import mojo2

Function Main:Int()
    New MYGame
    Return 0
End

Class MYGame Extends App
  
    Field canvas:Canvas
    Field clicktime:Int = 300            ' Max time between doubleclick (ms)
    Field lclick:Int , rclick:Int            ' Mousehit
    Field ldown:Int , rdown:Int            ' Mousedown
    Field ldouble:Int , rdouble:Int        ' Doubleclicked
    Field lhold:Int , rhold:Int             ' Mousedown that is not true when click = true
    Field lrel : Int,rrel:Int                 ' True when hold is released
    Field ltime:Int , rtime:Int            ' Internal
  
    Method OnCreate:Int()
        canvas=New Canvas() ; SetSwapInterval 1 ; SetUpdateRate 0
        Return 0
    End

    Method OnRender:Int()
        canvas.Clear
  
        mouse()
        canvas.DrawText "Left Button",10,0
        canvas.DrawText "Click   "+String(lclick),10,20
        canvas.DrawText "Down    "+String(ldown),10,40
        canvas.DrawText "Hold    "+String(lhold),10,60
        canvas.DrawText "Release "+String(lrel), 10,80
        canvas.DrawText "Double  "+String(ldouble),10,100

        canvas.DrawText "Right Button",10,200
        canvas.DrawText "Click   "+String(rclick),10,220
        canvas.DrawText "Down    "+String(rdown),10,240
        canvas.DrawText "Hold    "+String(rhold),10,260
        canvas.DrawText "Relase "+String(rrel),10,280
        canvas.DrawText "Double  "+String(rdouble),10,300
      
        If rdouble Or ldouble Then Print "Double click"
        If lrel Or rrel Then Print "Released"

        canvas.Flush
        Return 0
    End

   Method mouse:Void()
 
        lclick = False ; ldouble = False
        If MouseDown(0) ' MouseDown(0 or MOUSE_LEFT), MouseDown(1 or MOUSE_RIGHT), MouseDown(MOUSE_MIDDLE)
            If ldown = True
                lhold = True
            Else
                lclick=True
                If (ltime + clicktime) > Millisecs() Then ldouble = True
                If ldouble = False Then ltime = Millisecs()
            End If
            ldown=True
        Else
            lrel = False
            If lhold = True Then lrel = True
            ldown = False ; lhold = False
        End If
      
        rclick = False ; rdouble = False
        If MouseDown(1)
            If rdown = True
                rhold = True
            Else
                rclick = True
                If rtime + clicktime > Millisecs() Then rdouble = True
                If rdouble = False Then rtime = Millisecs()
            End If
            rdown = True
        Else
            rrel = False
            If rhold = True Then rrel = True
            rdown = False ; rhold = False
        End If
      
    End
  
 End
 
Last edited:

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
And these three types of behaviours show how it needs to be implemented to work intuitively for most people:
I agreed. People need to implement themself according to what they want and what is necessary for their game. Their requirement could be complex. So let them decide how and what to add.(y)

And to implement those they can use basic commands like MouseDown, MouseHit, Not MouseDown, etc. I tough it was nice to have another basic command MouseUp that gave the after-click signal. Just a simple signal similar to MouseHit, except its triggers once during release.
🏃🏽💨💨
 

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
3,281
Hi @magic . I saw you made a PR. I think your implementation is to simple. It needs to react on specific mouse/touch IDs separately, means it should store its state independently. Even more so for touch ids. And when should the state reset? Mouse/TouchDown and Mouse/TouchHit return values for each frame.

I got the notion that @Phil7 doesn't need to see this implemented, correct?

A function like this has no connection to any UI functionality which you have discussed in between. Also someone here said it should report (fire) when the button, touch is released. "fire" imho means it should call a handler aka callback (OnMouseUp for an example). But then we should also implement handlers/callbacks for the Down and Hit functions as well, or?
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
Hi @magic . I saw you made a PR. I think your implementation is to simple. It needs to react on specific mouse/touch IDs separately, means it should store its state independently. Even more so for touch ids. And when should the state reset? Mouse/TouchDown and Mouse/TouchHit return values for each frame.
Hi @MikeHart , I use the same style with MouseHit implementation in PR version. The PR version is better than the code I post above.

The state is reset every onRender. Compared to MouseHit where it reset every OnUpdate. I wonder why MouseHit does that, and it makes MouseHit cannot be used inside OnRender.

I'm not sure exactly should we add it to Cerberus, but I like it and use it, so I PR. It's ok if the Team didn't add it. I'm pretty new to GitHub and trying to learn about open source project contributions. Hope my PR didn't annoy you.
 

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
3,281
No it doesn't annoy me at all. The only thing I am looking out for is if it makes sense, doesn't break existing functionality and has no negative performance impact. Regarding OnUpdate and OnRender, well that is the logic of CX. Input in OnUpdate, Output in OnRender. You can always set a flag from the input and render accordingly.
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
681
It doesn't annoy me either. I really like the discussion around this. Similar to @MikeHart, the only thing why I am hesitating to put it in is that I want to make sure that the basic command set stays lean and each command is either necessary or really adds convenience for common use cases.
So, if you could come up with some code where it makes sense (shortens the code or helps readability substancially), I would put it in input, but if it is more of a nice to have item I would prefer to have it in some separate module (if possible).
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
I often set up Cerberus's OnRender to take consideration for Vertical blanking. this can be a problem sometimes for input speed.

Also, some platforms like Android, forces this anyway, you don't have a choice. The speed of OnUpdate will be as low as OnRender regardless in those cases. Which might sound good, 60 samples per second but I don't think that's the case what is happening, it's more like 30 by some reason.

I also discovered that this also means that Android devices with 120hz displays will give you amazing inputs. Because they OnUpdate and OnRender WILL have the same speed. It's like having a real d-pad

maybe I should mention that I found that HTML5 is actually much better than Desktop at input. At least this is true for macOS and Linux, I don't have Windows. But I think it is no differente. You have one frame lag on HTML5 verus two frame lags on Desktop. It sounds like nothing but 16ms vs 32ms makes a huge difference for some things.

OnUpdate is used by MouseHit as some platforms allows OnUpdate to run at really high speeds while OnRender runs at the speed it does best.
Both Desktop and HTLM5 allows different speeds of OnUpdate and OnRender I think. You can use the relevant commands to set everything up as you wish. Android does not allow that. It's the same speed.

A range of non-scientific tests showed me these results:
* Android devices with 60 fps or thereabout often has the worst input speed (Still really good for most things)
* Desktop platforms comes next
* Then comes HTML5 which is significantly better than desktop (this might come as a surprise, I don't know the details, but I guess there's system buffers in the way)
* The best speeds will come from the iOS and Android using 120Hz, those are amazing.
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
I would love callbacks because as you know; if want to set a really low OnUpdate speed to save battery let's say..
.. how would you then be able to read input decently?
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
Our input device code (inputdevice.cxs) already tracks the KeyUp Event.
Code:
    Method KeyEvent:Void( event:Int,data:Int )
        Select event
        Case BBGameEvent.KeyDown
            If Not _keyDown[data]
                _keyDown[data]=True
                PutKeyHit data
                If data=KEY_LMB
                    _keyDown[KEY_TOUCH0]=True
                    PutKeyHit KEY_TOUCH0
                Else If data=KEY_TOUCH0
                    _keyDown[KEY_LMB]=True
                    PutKeyHit KEY_LMB
                Endif
            Endif
        Case BBGameEvent.KeyUp
            If _keyDown[data]
                <<<<<I ADDED THE CODE HERE>>>>>
                _keyDown[data]=False
                If data=KEY_LMB
                    _keyDown[KEY_TOUCH0]=False
                Else If data=KEY_TOUCH0
                    _keyDown[KEY_LMB]=False
                Endif
            Endif
        Case BBGameEvent.KeyChar
            If _charPut<_charQueue.Length
                _charQueue[_charPut]=data
                _charPut+=1
            Endif
        End
    End
In my PR version, I basically only add the below code to reach that signal, and I don't think it takes a lot of performance impact.
Code:
                If Not _keyUp[data]
                    _keyUp[data]=True
                    If data=KEY_LMB
                        _keyUp[KEY_TOUCH0]=True
                    Else If data=KEY_TOUCH0
                        _keyUp[KEY_LMB]=True
                    Endif
                endif
Some other file I edit is minor (var and func for tracking that). And if you wish, we can make it only track inside onUpdate like KeyHit.

Just to let you know.. but never mind.(y):)
 
Top Bottom