Author Topic: Mouse Routines  (Read 3303 times)

0 Members and 1 Guest are viewing this topic.

Offline Ophelius

  • Newbie
  • Posts: 15
    • View Profile
Mouse Routines
« on: February 26, 2020, 12:19:28 am »
Hi,
I just recently discovered QB64, and as a huge user of QB45 in the 90's and early 2000's, QB64 is just an amazing upgrade!
That being said, I've been toying around with the built-in mouse routines and omg are they inefficient! I don't see the logic in having it only update when it changes, it makes you need all these awkward loops to do simple things. Is there an advantage I'm not understanding?

Here's some routines I modified from online examples that use assembly to read the values at any time, not just when they change:

Code: QB64: [Select]
  1. FUNCTION MouseX% ()
  2.  
  3.     STATIC AsmMouseX%(), InitDone%
  4.  
  5.     IF InitDone% = 0 THEN
  6.         Asm$ = "B80300CD33891EAA0A890EBB0B8916CC0CCB"
  7.         Bytes% = LEN(Asm$) \ 2
  8.         REDIM AsmMouseX%(Bytes%)
  9.  
  10.         DEF SEG = VARSEG(AsmMouseX%(0))
  11.         FOR i% = 0 TO Bytes% - 1
  12.             POKE VARPTR(AsmMouseX%(0)) + i%, VAL("&H" + MID$(Asm$, (i% * 2) + 1, 2))
  13.         NEXT i%
  14.         DEF SEG
  15.         InitDone% = 1
  16.  
  17.     END IF
  18.  
  19.     DEF SEG = VARSEG(AsmMouseX%(0))
  20.     CALL ABSOLUTE(VARPTR(AsmMouseX%(0)))
  21.     DEF SEG
  22.  
  23.     MouseX% = (PEEK(&HBBB) + PEEK(&HBBC) * 256)
  24.  
  25.  
  26. FUNCTION MouseY% ()
  27.     STATIC AsmMouseY%(), InitDone%
  28.  
  29.     IF InitDone% = 0 THEN
  30.         Asm$ = "B80300CD33891EAA0A890EBB0B8916CC0CCB"
  31.         Bytes% = LEN(Asm$) \ 2
  32.         REDIM AsmMouseY%(Bytes%)
  33.  
  34.         DEF SEG = VARSEG(AsmMouseY%(0))
  35.         FOR i% = 0 TO Bytes% - 1
  36.             POKE VARPTR(AsmMouseY%(0)) + i%, VAL("&H" + MID$(Asm$, (i% * 2) + 1, 2))
  37.         NEXT i%
  38.         DEF SEG
  39.         InitDone% = 1
  40.  
  41.     END IF
  42.  
  43.     DEF SEG = VARSEG(AsmMouseY%(0))
  44.     CALL ABSOLUTE(VARPTR(AsmMouseY%(0)))
  45.     DEF SEG
  46.  
  47.     MouseY% = (PEEK(&HCCC) + PEEK(&HCCD) * 256)
  48.  
  49.  
  50. FUNCTION MouseB% ()
  51.     '0 = none, 1 = left, 2=right, 3=both
  52.     STATIC AsmMouseB%(), InitDone%
  53.  
  54.     IF InitDone% = 0 THEN
  55.         Asm$ = "B80300CD33891EAA0A890EBB0B8916CC0CCB"
  56.         Bytes% = LEN(Asm$) \ 2
  57.         REDIM AsmMouseB%(Bytes%)
  58.  
  59.         DEF SEG = VARSEG(AsmMouseB%(0))
  60.         FOR i% = 0 TO Bytes% - 1
  61.             POKE VARPTR(AsmMouseB%(0)) + i%, VAL("&H" + MID$(Asm$, (i% * 2) + 1, 2))
  62.         NEXT i%
  63.         DEF SEG
  64.         InitDone% = 1
  65.  
  66.     END IF
  67.  
  68.     DEF SEG = VARSEG(AsmMouseB%(0))
  69.     CALL ABSOLUTE(VARPTR(AsmMouseB%(0)))
  70.     DEF SEG
  71.  
  72.     MouseB% = PEEK(&HAAA)
  73.  
  74.  
  75. SUB MouseOn ()
  76.     STATIC AsmMouseOn%(), InitDone%
  77.  
  78.     IF InitDone% = 0 THEN
  79.         Asm$ = "B80100CD33891EAA0A890EBB0B8916CC0CCB"
  80.         Bytes% = LEN(Asm$) \ 2
  81.         REDIM AsmMouseOn%(Bytes%)
  82.  
  83.         DEF SEG = VARSEG(AsmMouseOn%(0))
  84.         FOR i% = 0 TO Bytes% - 1
  85.             POKE VARPTR(AsmMouseOn%(0)) + i%, VAL("&H" + MID$(Asm$, (i% * 2) + 1, 2))
  86.         NEXT i%
  87.         DEF SEG
  88.         InitDone% = 1
  89.     END IF
  90.  
  91.     DEF SEG = VARSEG(AsmMouseOn%(0))
  92.     CALL ABSOLUTE(VARPTR(AsmMouseOn%(0)))
  93.     DEF SEG
  94.  
  95.  
  96. SUB MouseOff ()
  97.     STATIC AsmMouseOff%(), InitDone%
  98.  
  99.     IF InitDone% = 0 THEN
  100.         Asm$ = "B80200CD33891EAA0A890EBB0B8916CC0CCB"
  101.         Bytes% = LEN(Asm$) \ 2
  102.         REDIM AsmMouseOff%(Bytes%)
  103.  
  104.         DEF SEG = VARSEG(AsmMouseOff%(0))
  105.         FOR i% = 0 TO Bytes% - 1
  106.             POKE VARPTR(AsmMouseOff%(0)) + i%, VAL("&H" + MID$(Asm$, (i% * 2) + 1, 2))
  107.         NEXT i%
  108.         DEF SEG
  109.         InitDone% = 1
  110.     END IF
  111.  
  112.     DEF SEG = VARSEG(AsmMouseOff%(0))
  113.     CALL ABSOLUTE(VARPTR(AsmMouseOff%(0)))
  114.     DEF SEG
  115.  
  116.  


To me this is way better, whenever you need the current mouse values you just use these functions:
Code: QB64: [Select]
  1. MouseOn
  2.    locate 1,1: Print MouseX, MouseY, MouseB
  3.  

What are your thoughts?
« Last Edit: February 26, 2020, 02:48:15 pm by Ophelius »

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Mouse Routines
« Reply #1 on: February 26, 2020, 12:24:49 am »
First, Welcome to the Forum :-)

Which "built-in" mouse routines are you referring to? These..

_MOUSEX, _MOUSEY, _MOUSEBUTTON(), _MOUSEINPUT, _MOUSEWHEEL, etc..?

These commands are a god-send compared to what was available back in the QB45 days. Could you provide some code examples of what you are referring to?
« Last Edit: February 26, 2020, 12:27:55 am by TerryRitchie »
In order to understand recursion, one must first understand recursion.

FellippeHeitor

  • Guest
Re: Mouse Routines
« Reply #2 on: February 26, 2020, 12:33:22 am »
It's really just a matter of getting used to the new approach. You replace a call to MouseOn with a single line of WHILE _MOUSEINPUT: WEND in your main program loop and you're good to go. All mouse functions will contain the current data.

Code: QB64: [Select]

Welcome to the forum.
« Last Edit: February 26, 2020, 12:35:17 am by FellippeHeitor »

Offline Ophelius

  • Newbie
  • Posts: 15
    • View Profile
Re: Mouse Routines
« Reply #3 on: February 26, 2020, 12:39:40 am »
First, Welcome to the Forum :-)

Which "built-in" mouse routines are you referring to? These..

_MOUSEX, _MOUSEY, _MOUSEBUTTON(), _MOUSEINPUT, _MOUSEWHEEL, etc..?

These commands are a god-send compared to what was available back in the QB45 days. Could you provide some code examples of what you are referring to?

Yes, all of those. Maybe I just didn't put too much thought into it. Like this for example:

Code: QB64: [Select]
  1.   DO WHILE _MOUSEINPUT '      Check the mouse status
  2.   LOOP
  3.  

This will only get you the values when they change, and you can't just print _MouseX etc without using _Mouseinput first.
All the examples in the help for _MouseInput, _MouseButton, etc have all these Do:Loops where it can be a lot simpler. I've used a lot of libraries in the past and none managed mouse inputs this way, they all have simple functions that return the current values when called. Maybe I'm just not used to it. So what's the advantage?

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Mouse Routines
« Reply #4 on: February 26, 2020, 12:49:39 am »
FellippeHeitor's example is the best approach.

_MOUSEINPUT polls the mouse for status. QB64 keeps track of all mouse events even when using something like the INPUT command. As long as _MOUSEINPUT is true (-1) there is data to be collected. If you want the latest mouse information you need to clear _MOUSEINPUT using a loop until it is false (0) like so:

WHILE _MOUSEINPUT: WEND

Now that all the previous mouse information has been cleared the next call to any mouse command will be the most recent.
« Last Edit: February 26, 2020, 12:50:47 am by TerryRitchie »
In order to understand recursion, one must first understand recursion.

Offline Ophelius

  • Newbie
  • Posts: 15
    • View Profile
Re: Mouse Routines
« Reply #5 on: February 26, 2020, 12:59:02 am »
Ah, I see, thanks guys. I guess it's just about wrapping my head around a new approach, I'm used to the old way which works for my coding styles. Either way, I was just curious, and the routines I posted are there and works fine if someone want's to use them.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Mouse Routines
« Reply #6 on: February 26, 2020, 01:06:59 am »
You're welcome :-)  The new mouse commands were a bit strange for me as well when I first discovered QB64 but over the years have found them incredibly easy to use and manipulate.
In order to understand recursion, one must first understand recursion.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Mouse Routines
« Reply #7 on: February 26, 2020, 01:17:47 am »
Here's a little demo to show how the _MOUSEINPUT command can be used to your advantage:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2. INPUT "Click around on the screen a few times then press ENTER", a$
  3.         LINE -(_MOUSEX, _MOUSEY), _RGB32(255, 255, 255)
  4.         clicks = clicks + 1
  5.     END IF
  6. PRINT "You clicked"; clicks; " times"

Even when the INPUT command has taken over QB64 is monitoring the mouse.
In order to understand recursion, one must first understand recursion.

Offline Ophelius

  • Newbie
  • Posts: 15
    • View Profile
Re: Mouse Routines
« Reply #8 on: February 26, 2020, 12:29:45 pm »
Here's a little demo to show how the _MOUSEINPUT command can be used to your advantage:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2. INPUT "Click around on the screen a few times then press ENTER", a$
  3.         LINE -(_MOUSEX, _MOUSEY), _RGB32(255, 255, 255)
  4.         clicks = clicks + 1
  5.     END IF
  6. PRINT "You clicked"; clicks; " times"

Even when the INPUT command has taken over QB64 is monitoring the mouse.

Ok, I understand the advantage now, that is much better.
Edit: Although this does seem strange to me since the program is both in the Input loop and While:Wend loop at the same time? How is this possible? If it's in the documentation please point me to it so I can understand. Thanks
« Last Edit: February 26, 2020, 12:32:46 pm by Ophelius »

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Mouse Routines
« Reply #9 on: February 26, 2020, 01:57:38 pm »
I'm not sure what you mean by the program being in two loops.

QB64 buffers the mouse input. You can check if there is information in the buffer by verifying that _MOUSEINPUT is true (-1). If it is you can use any of the mouse commands to grab that instance in time. _MOUSEINPUT has been placed in a WHILE:WEND loop to keep reporting about the status of the buffer. When _MOUSEINPUT is finally false (0) the buffer has been cleared.

You see this happen in Windows when you start clicking on things and Windows can't keep up, but it still remembers where and what your mouse did, even when it was busy beforehand, and catches up with you.
In order to understand recursion, one must first understand recursion.

Offline Ophelius

  • Newbie
  • Posts: 15
    • View Profile
Re: Mouse Routines
« Reply #10 on: February 26, 2020, 02:45:23 pm »
I'm not sure what you mean by the program being in two loops.

QB64 buffers the mouse input. You can check if there is information in the buffer by verifying that _MOUSEINPUT is true (-1). If it is you can use any of the mouse commands to grab that instance in time. _MOUSEINPUT has been placed in a WHILE:WEND loop to keep reporting about the status of the buffer. When _MOUSEINPUT is finally false (0) the buffer has been cleared.

You see this happen in Windows when you start clicking on things and Windows can't keep up, but it still remembers where and what your mouse did, even when it was busy beforehand, and catches up with you.

What I mean is that in QB45, you were stuck on the Input line until the user pressed enter(caught in the input loop, program halts until enter is pressed). The example given shows an input, but somehow it's also checking the while:wend at the same time? Is this not procedural programming anymore?

FellippeHeitor

  • Guest
Re: Mouse Routines
« Reply #11 on: February 26, 2020, 03:09:50 pm »
You are still stuck in the INPUT call until enter is pressed, the difference with the QB64 approach is that there is a buffer, which stores mouse data generated while the program was stuck in the INPUT call. After enter is pressed, you can keep reading the buffer, as in Terry's example, or flush it, as in my example, so that you always have the current mouse data, instead of buffer history. Both approaches have their advantages.

Quote
The example given shows an input, but somehow it's also checking the while:wend at the same time?

The while: wend block won't be checked again until INPUT is done with.
« Last Edit: February 26, 2020, 03:10:53 pm by FellippeHeitor »

Offline Ophelius

  • Newbie
  • Posts: 15
    • View Profile
Re: Mouse Routines
« Reply #12 on: February 26, 2020, 03:25:04 pm »
Ooh ok I see, there's a buffer. Makes sense now. Thanks