Author Topic: _DEVICEINPUT vs _MOUSEINPUT  (Read 3830 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
_DEVICEINPUT vs _MOUSEINPUT
« on: February 20, 2019, 12:20:30 pm »
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. devices = _DEVICES
  4. FOR i = 1 TO devices
  5.     IF INSTR(_DEVICE$(i), "[KEYBOARD]") THEN Keyboard = i
  6.     IF INSTR(_DEVICE$(i), "[MOUSE]") THEN Mouse = i
  7.     IF INSTR(_DEVICE$(i), "[CONTROLLER]") THEN JoyStick = i
  8.  
  9.     _LIMIT 60
  10.     x = _DEVICEINPUT
  11.     IF x = Mouse THEN PRINT INT(_AXIS(1) * 320 + 320), INT(_AXIS(2) * 240 + 240), _MOUSEX, _MOUSEY
  12.  
  13.  
  14. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit

Some very simple code to show 2 different ways to get our Mouse X/Y information. 

_DEVICEINPUT returns values of -1 to +1, with 0 being the center of our screen, so we need to translate that into screen coordinates with the simple math functions: INT(_AXIS(1) * 320 + 320) and INT(_AXIS(2) * 240 + 240).

If you run the little demo and scroll the mouse a few times, you'll quickly see my query:  Why do the numbers sometimes not match?  Is this something off with my math, as simple as it is, or is this just an instance of the 2 routines polling the mouse at various different times as it moves and generating slightly different results?  Whenever I stop moving the mouse, the end results always seem to match (within a single pixel which could be the result of rounding differences), but the steps in the middle seem completely different from each other from time to time.  (Sometimes by a change of dozens of pixels.)

Is this right?  Wrong?  Any ideas?
« Last Edit: February 20, 2019, 12:32:19 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: _DEVICEINPUT vs _MOUSEINPUT
« Reply #1 on: February 20, 2019, 12:38:36 pm »
I'm thinking this is a case of _DEVICEINPUT taking forever to clear the buffer and keep up with current events.  Trr this code for a demo:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. devices = _DEVICES
  4. FOR i = 1 TO devices
  5.     IF INSTR(_DEVICE$(i), "[KEYBOARD]") THEN Keyboard = i
  6.     IF INSTR(_DEVICE$(i), "[MOUSE]") THEN Mouse = i
  7.     IF INSTR(_DEVICE$(i), "[CONTROLLER]") THEN JoyStick = i
  8.  
  9.  
  10.  
  11.  
  12.     _LIMIT 60
  13.     x = _DEVICEINPUT
  14.     IF x = Mouse THEN
  15.         LOCATE 1, 1
  16.         PRINT INT(_AXIS(1) * 320 + 320), INT(_AXIS(2) * 240 + 240), _MOUSEX, _MOUSEY
  17.         PRINT _WHEEL(1), _WHEEL(2), _WHEEL(3)
  18.         PRINT _BUTTON(1), _BUTTON(2), _BUTTON(3)
  19.     END IF
  20. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit
  21.  
  22.  

Scroll the mouse repeatedly across the screen for several seconds and then stop.  Watch how _MOUSEX/_MOUSEY give you the current location instantly, and then notice how it takes several seconds after you stop moving the mouse so the AXIS commands will catch up to your position. 

Unless I'm doing something wrong here, I really don't see how the DEVICE commands could be used reliably to handle mouse input.  Is there something obvious I'm missing to make this work as intended? 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: _DEVICEINPUT vs _MOUSEINPUT
« Reply #2 on: February 20, 2019, 02:12:06 pm »
Once you've figured the mouse's _DEVICE number, call _DEVICEINPUT with that index, much like you do with _MOUSEINPUT. Look at the critical bit below:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. devices = _DEVICES
  4. FOR i = 1 TO devices
  5.     IF INSTR(_DEVICE$(i), "[KEYBOARD]") THEN Keyboard = i
  6.     IF INSTR(_DEVICE$(i), "[MOUSE]") THEN Mouse = i
  7.     IF INSTR(_DEVICE$(i), "[CONTROLLER]") THEN JoyStick = i
  8.  
  9.     DO WHILE _DEVICEINPUT(Mouse): LOOP 'this is the critical bit
  10.     CLS
  11.     PRINT INT(_AXIS(1) * 320 + 320), INT(_AXIS(2) * 240 + 240), _MOUSEX, _MOUSEY
  12.     _DISPLAY
  13.     _LIMIT 60
  14. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit
  15.  
« Last Edit: February 20, 2019, 02:13:49 pm by FellippeHeitor »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: _DEVICEINPUT vs _MOUSEINPUT
« Reply #3 on: February 20, 2019, 03:40:45 pm »
Steve, FellippeHeitor,  thank you very much for this program. This is exactly what I was thinking about when using the mouse and the MAPTRIANGLE 3D command, which is based on OpenGL just like _DEVICEINPUT, because in the OpenGL space that generates MAPTRIANGLE 3D with MOUSEINPUT, I have to recalculate it. I needed to get mouse coordinates in the OpenGL coordinate system. I'll try to implant it tomorrow. For information on Dungeon - I already have a program that translates the map from the map image (from PNG) to OpenGL (for MAPTRIANGLE 3D), and the display in the space is correct, but I will still solve the collision scheme. The easiest way will be a 2D field that solves a collision when converting a map from PNG to an OpenGL coordinate system. The big problem I'm addressing today is a way of calculating visibility in a space that limits the number of elements to display in the array. It will take a while. But I'm a lot out of theme of this thread.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: _DEVICEINPUT vs _MOUSEINPUT
« Reply #4 on: February 21, 2019, 05:25:59 am »
Once you've figured the mouse's _DEVICE number, call _DEVICEINPUT with that index, much like you do with _MOUSEINPUT. Look at the critical bit below:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. devices = _DEVICES
  4. FOR i = 1 TO devices
  5.     IF INSTR(_DEVICE$(i), "[KEYBOARD]") THEN Keyboard = i
  6.     IF INSTR(_DEVICE$(i), "[MOUSE]") THEN Mouse = i
  7.     IF INSTR(_DEVICE$(i), "[CONTROLLER]") THEN JoyStick = i
  8.  
  9.     DO WHILE _DEVICEINPUT(Mouse): LOOP 'this is the critical bit
  10.     CLS
  11.     PRINT INT(_AXIS(1) * 320 + 320), INT(_AXIS(2) * 240 + 240), _MOUSEX, _MOUSEY
  12.     _DISPLAY
  13.     _LIMIT 60
  14. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit
  15.  

One point of interest here:  You have to either put the mousewheel information inside the WHILE:WEND loop, or else clear the buffer afterwards.  So far, I've found 2 different methods which work:

Method 1: Scroll wheel inside the WHILE

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3.     _LIMIT 60
  4.     WHILE _DEVICEINPUT(2): Scroll = Scroll + _WHEEL(3): WEND 'clear and update the mouse buffer
  5.  
  6.     LOCATE 1, 1
  7.     PRINT INT(_AXIS(1) * 320 + 320), INT(_AXIS(2) * 240 + 240) 'convert to screen coordinates
  8.     PRINT _WHEEL(1), _WHEEL(2), _WHEEL(3), Scroll 'mouse wheel status
  9.     PRINT _BUTTON(1), _BUTTON(2), _BUTTON(3) 'mouse button status
  10.  
  11. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit


Method 2: Clear the buffer after processing mouse information

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3.     _LIMIT 60
  4.     x = _DEVICEINPUT(2) 'update mouse information
  5.  
  6.     LOCATE 1, 1
  7.     PRINT INT(_AXIS(1) * 320 + 320), INT(_AXIS(2) * 240 + 240)
  8.     Scroll = Scroll + _WHEEL(3)
  9.     PRINT _WHEEL(1), _WHEEL(2), _WHEEL(3), Scroll
  10.     PRINT _BUTTON(1), _BUTTON(2), _BUTTON(3)
  11.     WHILE _DEVICEINPUT(2): WEND 'clear the mouse buffer
  12. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit
  13.  

In many ways, I think I personally prefer method 2 as it allows us a means to completely skip the mouse processing routines if nothing is going on with them, as such:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3.     _LIMIT 60
  4.     x = _DEVICEINPUT(2) 'update mouse information
  5.  
  6.     IF x THEN
  7.         LOCATE 1, 1
  8.         PRINT INT(_AXIS(1) * 320 + 320), INT(_AXIS(2) * 240 + 240)
  9.         Scroll = Scroll + _WHEEL(3)
  10.         PRINT _WHEEL(1), _WHEEL(2), _WHEEL(3), Scroll
  11.         PRINT _BUTTON(1), _BUTTON(2), _BUTTON(3)
  12.     END IF
  13.  
  14.     WHILE _DEVICEINPUT(2): WEND 'clear the mouse buffer
  15. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit
  16.  

With programs which require a lot of CPU power, method 2 might be preferable as it skips the whole mouse handling routines unless the values have changed and require processing.

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: _DEVICEINPUT vs _MOUSEINPUT
« Reply #5 on: February 22, 2019, 10:06:17 am »
I wonder if keyboard and maybe even timer could be added such that you have a getEvent like routine st when called, it clears all previous mouse clicks or keypresses... and waits for next event to occur to report. Not sure that it could work with mouse wheel?
« Last Edit: February 22, 2019, 10:07:44 am by bplus »