Posts: 2,180
Threads: 222
Joined: Apr 2022
Reputation:
104
This is a mix of WIN32 API and QB64 code. I would have posted it all in Win API, but I haven't looked into controlling the mouse cursor, only locating it. So what it does is produce a borderless window with a fake blank top strip you can drag around the screen. The limits placed on the cursor, to keep it from racing away from the window, are a bit choppy. Maybe that could be improved with a different approach. If anyone has a pure Win API example to compare it to, that would be nice.
Code: (Select All) DIM WinMse AS POINTAPI
TYPE POINTAPI
X_Pos AS LONG
Y_Pos AS LONG
END TYPE
DECLARE DYNAMIC LIBRARY "User32"
FUNCTION GetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG)
FUNCTION SetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG, BYVAL dwNewLong AS LONG)
FUNCTION SetWindowPos& (BYVAL hwnd AS LONG, BYVAL hWndInsertAfter AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL cx AS LONG, BYVAL cy AS LONG, BYVAL wFlags AS LONG)
FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
FUNCTION GetCursorPos (lpPoint AS POINTAPI)
END DECLARE
WIDTH 50, 25
DO: LOOP UNTIL _SCREENEXISTS
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
_TITLE "No Border"
hwnd& = _WINDOWHANDLE
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
_DELAY .25
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& AND WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)
LOCATE 1, 1
COLOR 0, 7
PRINT SPACE$(_WIDTH);
fw = _FONTWIDTH
fh = _FONTHEIGHT
x = _SCREENX: y = _SCREENY
DO
_LIMIT 60
IF GetAsyncKeyState(1) < 0 THEN
IF lb = 0 THEN lb = 1
ELSE
IF lb THEN lb = 0: dragpt = 0
END IF
z = GetCursorPos(WinMse)
IF lb THEN
IF dragpt THEN
IF WinMse.X_Pos <> oldxpos THEN
j = SGN(WinMse.X_Pos - oldxpos) ' This will be multiplied in statements to speed things up.
DO
x = x + j * 8
_SCREENMOVE x, y
_MOUSEMOVE dragpt, 1
IF j > 0 THEN
IF x + dragpt * fw >= WinMse.X_Pos THEN EXIT DO
ELSE
IF x + dragpt * fw <= WinMse.X_Pos THEN EXIT DO
END IF
LOOP
END IF
IF WinMse.Y_Pos <> oldypos THEN
j = SGN(WinMse.Y_Pos - oldypos)
DO
IF j > 0 THEN
y = y + j * 3
_SCREENMOVE x, y
_MOUSEMOVE dragpt, 1
IF y >= WinMse.Y_Pos THEN EXIT DO
ELSE
y = y + j * 8
_SCREENMOVE x, y
_MOUSEMOVE dragpt, 1
IF y <= WinMse.Y_Pos THEN EXIT DO
END IF
LOOP
END IF
z = GetCursorPos(WinMse)
ELSE
IF WinMse.Y_Pos >= _SCREENY AND WinMse.Y_Pos <= _SCREENY + fh THEN
x = _SCREENX: y = _SCREENY
dragpt = (WinMse.X_Pos - x) \ fw
END IF
END IF
END IF
IF LEN(INKEY$) THEN SYSTEM
oldypos = WinMse.Y_Pos
oldxpos = WinMse.X_Pos
LOOP
Pete
Posts: 2,698
Threads: 327
Joined: Apr 2022
Reputation:
217
A different approach:
Code: (Select All) Declare Dynamic Library "User32"
Function GetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long)
Function SetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long, Byval dwNewLong As Long)
Function SetWindowPos& (ByVal hwnd As Long, Byval hWndInsertAfter As Long, Byval x As Long, Byval y As Long, Byval cx As Long, Byval cy As Long, Byval wFlags As Long)
End Declare
Width 50, 25
Do: Loop Until _ScreenExists
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
_Title "No Border"
hwnd& = _WindowHandle
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& And WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)
Do
k = _KeyHit
x = _ScreenX: y = _ScreenY
Select Case k
Case 19200: _ScreenMove x - 10, y
Case 19712: _ScreenMove x + 10, y
Case 18432: _ScreenMove x, y - 10
Case 20480: _ScreenMove x, y + 10
End Select
_Limit 30
Print "Much";
Print " easier";
Print " than";
Print " Pete's";
Print " method!";
_Display
Loop Until k = 27
Just use the arrow keys to move your screen.
For your mouse, you'd probably want to set it up so it works with either one distinct area of the screen ("click HERE to drag this window!"), or in combo with a control-key. (CTRL + mouse drag, for instance.)
Posts: 2,180
Threads: 222
Joined: Apr 2022
Reputation:
104
Investing in a CHEESE factory, Steve?
ROFL at use the arrow keys.
Pete
Posts: 2,698
Threads: 327
Joined: Apr 2022
Reputation:
217
(11-25-2022, 07:45 PM)Pete Wrote: Investing in a CHEESE factory, Steve?
ROFL at use the arrow keys.
Pete
For mouse movement of your borderless window, use my patented MBS function. It works for all these type need!
Code: (Select All) Screen _NewImage(800, 600, 32)
Declare Dynamic Library "User32"
Function GetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long)
Function SetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long, Byval dwNewLong As Long)
Function SetWindowPos& (ByVal hwnd As Long, Byval hWndInsertAfter As Long, Byval x As Long, Byval y As Long, Byval cx As Long, Byval cy As Long, Byval wFlags As Long)
End Declare
Do: Loop Until _ScreenExists
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
_Title "No Border"
hwnd& = _WindowHandle
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& And WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)
Do
x = _ScreenX: y = _ScreenY
result = MBS
If (result And 64) And (_KeyDown(100306) Or _KeyDown(100305)) Then _ScreenMove x + MMX, y + MMY 'ctrl-hold event
_Limit 60
Loop Until _KeyDown(27)
Function MBS% 'Mouse Button Status
Static StartTimer As _Float
Static ButtonDown As Integer
Static ClickCount As Integer
Const ClickLimit## = 0.2 'Less than 1/4th of a second to down, up a key to count as a CLICK.
' Down longer counts as a HOLD event.
Shared Mouse_StartX, Mouse_StartY, Mouse_EndX, Mouse_EndY, MMX, MMY
MMX = 0: MMY = 0
While _MouseInput 'Remark out this block, if mouse main input/clear is going to be handled manually in main program.
Select Case Sgn(_MouseWheel)
Case 1: tempMBS = tempMBS Or 512
Case -1: tempMBS = tempMBS Or 1024
End Select
MMX = MMX + _MouseMovementX
MMY = MMY + _MouseMovementY
Wend
If _MouseButton(1) Then tempMBS = tempMBS Or 1
If _MouseButton(2) Then tempMBS = tempMBS Or 2
If _MouseButton(3) Then tempMBS = tempMBS Or 4
If StartTimer = 0 Then
If _MouseButton(1) Then 'If a button is pressed, start the timer to see what it does (click or hold)
ButtonDown = 1: StartTimer = Timer(0.01)
Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
ElseIf _MouseButton(2) Then
ButtonDown = 2: StartTimer = Timer(0.01)
Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
ElseIf _MouseButton(3) Then
ButtonDown = 3: StartTimer = Timer(0.01)
Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
End If
Else
BD = ButtonDown Mod 3
If BD = 0 Then BD = 3
If Timer(0.01) - StartTimer <= ClickLimit Then 'Button was down, then up, within time limit. It's a click
If _MouseButton(BD) = 0 Then tempMBS = 4 * 2 ^ ButtonDown: ButtonDown = 0: StartTimer = 0
Else
If _MouseButton(BD) = 0 Then 'hold event has now ended
tempMBS = 0: ButtonDown = 0: StartTimer = 0
Mouse_EndX = _MouseX: Mouse_EndY = _MouseY
Else 'We've now started the hold event
tempMBS = tempMBS Or 32 * 2 ^ ButtonDown
End If
End If
End If
MBS = tempMBS
End Function
Now, I don't want any old mouse click and drag to move my screen, so I've set this up to require a CTRL + DRAG event to work.
Press CTRL on the keyboard and hold it. Press the left mouse button. Move the mouse, move the window.
It really is that easy. No API calls required, except for the ones to hide the title bar and all to begin with.
Code: (Select All) Do
x = _ScreenX: y = _ScreenY
result = MBS
If (result And 64) And (_KeyDown(100306) Or _KeyDown(100305)) Then _ScreenMove x + MMX, y + MMY 'ctrl-hold event
_Limit 60
Loop Until _KeyDown(27)
^ There's my whole program, if you exclude the MBS routine and use it as a library routine, and don't count the code to hide the titlebar.
Posts: 1,002
Threads: 50
Joined: May 2022
Reputation:
27
11-25-2022, 09:05 PM
(This post was last modified: 11-25-2022, 09:07 PM by Kernelpanic.)
(11-25-2022, 07:10 PM)Pete Wrote: This is a mix of WIN32 API and QB64 code. I would have posted it all in Win API, but I haven't looked into controlling the mouse cursor, only locating it. So what it does is produce a borderless window with a fake blank top strip you can drag around the screen. The limits placed on the cursor, to keep it from racing away from the window, are a bit choppy. Maybe that could be improved with a different approach. If anyone has a pure Win API example to compare it to, that would be nice. @Pete - skillfully again from programming, but where's the practical use?
Can precision play a role with integer numbers? That's only interesting for floating point numbers, isn't it?
Posts: 1,586
Threads: 59
Joined: Jul 2022
Reputation:
52
(11-25-2022, 09:05 PM)Kernelpanic Wrote: Can precision play a role with integer numbers? That's only interesting for floating point numbers, isn't it? "Precision" is just another way of saying bit-width, such as 64-bit having the greatest "precision" you could have out of a whole number in QB64. It seems to be clouded by "SINGLE", "DOUBLE" and "_FLOAT" but the source is the same, how it's interpreted is vastly different from integer. It comes from the size of registers of the CPU.
Posts: 2,180
Threads: 222
Joined: Apr 2022
Reputation:
104
(11-25-2022, 09:05 PM)Kernelpanic Wrote: (11-25-2022, 07:10 PM)Pete Wrote: This is a mix of WIN32 API and QB64 code. I would have posted it all in Win API, but I haven't looked into controlling the mouse cursor, only locating it. So what it does is produce a borderless window with a fake blank top strip you can drag around the screen. The limits placed on the cursor, to keep it from racing away from the window, are a bit choppy. Maybe that could be improved with a different approach. If anyone has a pure Win API example to compare it to, that would be nice. @Pete - skillfully again from programming, but where's the practical use?
Can precision play a role with integer numbers? That's only interesting for floating point numbers, isn't it?
Great question. Say you want to have a custom title bar instead of the Windows title bar wit its predetermined functions like close, restore, minimize, etc. This allows a user to make their custom title bar do whatever they want, while maintaining the best Windows feature, the ability to drag the window around with the mouse.
Pete
Posts: 2,698
Threads: 327
Joined: Apr 2022
Reputation:
217
And here's a demo of dragging the window from my custom title bar:
Code: (Select All) Screen _NewImage(800, 600, 32)
$Color:32
Declare Dynamic Library "User32"
Function GetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long)
Function SetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long, Byval dwNewLong As Long)
Function SetWindowPos& (ByVal hwnd As Long, Byval hWndInsertAfter As Long, Byval x As Long, Byval y As Long, Byval cx As Long, Byval cy As Long, Byval wFlags As Long)
End Declare
Do: Loop Until _ScreenExists
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
hwnd& = _WindowHandle
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& And WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)
Line (0, 0)-(_Width, 30), SkyBlue, BF 'My custom titlebar
pw = _PrintWidth("ð Steve's Tripple Line Title ð")
_PrintString ((_Width - pw) \ 2, 2), "ð Steve's Tripple Line Tittle ð"
Do
x = _ScreenX: y = _ScreenY
result = MBS
If (result And 64) And (_MouseY <= 30) Then startdrag = -1 ' we're in the title bar and triggered a hold event.
If startdrag Then
_ScreenMove x + MMX, y + MMY ' drag the window from the title bar
_MouseMove Mouse_StartX, Mouse_StartY ' keep the mouse in its original position
End If
If (result And 1) = 0 Then startdrag = 0 ' hold event is over, quit dragging
_Limit 60
Loop Until _KeyDown(27)
Function MBS% 'Mouse Button Status
Static StartTimer As _Float
Static ButtonDown As Integer
Static ClickCount As Integer
Const ClickLimit## = 0.2 'Less than 1/4th of a second to down, up a key to count as a CLICK.
' Down longer counts as a HOLD event.
Shared Mouse_StartX, Mouse_StartY, Mouse_EndX, Mouse_EndY, MMX, MMY
MMX = 0: MMY = 0
While _MouseInput 'Remark out this block, if mouse main input/clear is going to be handled manually in main program.
Select Case Sgn(_MouseWheel)
Case 1: tempMBS = tempMBS Or 512
Case -1: tempMBS = tempMBS Or 1024
End Select
MMX = MMX + _MouseMovementX
MMY = MMY + _MouseMovementY
Wend
If _MouseButton(1) Then tempMBS = tempMBS Or 1
If _MouseButton(2) Then tempMBS = tempMBS Or 2
If _MouseButton(3) Then tempMBS = tempMBS Or 4
If StartTimer = 0 Then
If _MouseButton(1) Then 'If a button is pressed, start the timer to see what it does (click or hold)
ButtonDown = 1: StartTimer = Timer(0.01)
Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
ElseIf _MouseButton(2) Then
ButtonDown = 2: StartTimer = Timer(0.01)
Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
ElseIf _MouseButton(3) Then
ButtonDown = 3: StartTimer = Timer(0.01)
Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
End If
Else
BD = ButtonDown Mod 3
If BD = 0 Then BD = 3
If Timer(0.01) - StartTimer <= ClickLimit Then 'Button was down, then up, within time limit. It's a click
If _MouseButton(BD) = 0 Then tempMBS = 4 * 2 ^ ButtonDown: ButtonDown = 0: StartTimer = 0
Else
If _MouseButton(BD) = 0 Then 'hold event has now ended
tempMBS = 0: ButtonDown = 0: StartTimer = 0
Mouse_EndX = _MouseX: Mouse_EndY = _MouseY
Else 'We've now started the hold event
tempMBS = tempMBS Or 32 * 2 ^ ButtonDown
End If
End If
End If
MBS = tempMBS
End Function
Posts: 2,180
Threads: 222
Joined: Apr 2022
Reputation:
104
And the Bud Tugly award goes to...
Getting better.
While the pointer doesn't stay affixed as well, the window movement is smoother when it moves the distance of the difference in the last cursor position.
Code: (Select All) DIM WinMse AS POINTAPI
TYPE POINTAPI
X_Pos AS LONG
Y_Pos AS LONG
END TYPE
DECLARE DYNAMIC LIBRARY "User32"
FUNCTION GetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG)
FUNCTION SetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG, BYVAL dwNewLong AS LONG)
FUNCTION SetWindowPos& (BYVAL hwnd AS LONG, BYVAL hWndInsertAfter AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL cx AS LONG, BYVAL cy AS LONG, BYVAL wFlags AS LONG)
FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
FUNCTION GetCursorPos (lpPoint AS POINTAPI)
END DECLARE
WIDTH 50, 25
DO: LOOP UNTIL _SCREENEXISTS
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
_TITLE "No Border"
hwnd& = _WINDOWHANDLE
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
_DELAY .25
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& AND WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)
LOCATE 1, 1
COLOR 0, 7
PRINT SPACE$(_WIDTH);
fw = _FONTWIDTH
fh = _FONTHEIGHT
x = _SCREENX: y = _SCREENY
DO
_LIMIT 60
IF GetAsyncKeyState(1) < 0 THEN
IF lb = 0 THEN lb = 1
ELSE
IF lb THEN lb = 0: dragpt = 0
END IF
z = GetCursorPos(WinMse)
IF lb THEN
IF dragpt THEN
IF WinMse.X_Pos <> oldxpos OR WinMse.Y_Pos <> oldypos THEN
j1 = (WinMse.X_Pos - oldxpos)
j2 = (WinMse.Y_Pos - oldypos)
x = x + j1: y = y + j2
_SCREENMOVE x, y
_MOUSEMOVE dragpt, 1
END IF
z = GetCursorPos(WinMse)
ELSE
IF WinMse.Y_Pos >= _SCREENY AND WinMse.Y_Pos <= _SCREENY + fh THEN
x = _SCREENX: y = _SCREENY
dragpt = (WinMse.X_Pos - x) \ fw
END IF
END IF
END IF
IF LEN(INKEY$) THEN SYSTEM
oldypos = WinMse.Y_Pos
oldxpos = WinMse.X_Pos
LOOP
Pete
Shoot first and shoot people who ask questions, later.
Posts: 2,180
Threads: 222
Joined: Apr 2022
Reputation:
104
Okay, just for the hell of it, I figured out how to do a Win32 set mouse cursor event. It really doesn't make any difference.
Code: (Select All) DIM WinMse AS POINTAPI
TYPE POINTAPI
X_Pos AS LONG
Y_Pos AS LONG
END TYPE
DECLARE DYNAMIC LIBRARY "User32"
FUNCTION GetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG)
FUNCTION SetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG, BYVAL dwNewLong AS LONG)
FUNCTION SetWindowPos& (BYVAL hwnd AS LONG, BYVAL hWndInsertAfter AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL cx AS LONG, BYVAL cy AS LONG, BYVAL wFlags AS LONG)
FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
FUNCTION GetCursorPos (lpPoint AS POINTAPI)
FUNCTION SetCursorPos& (BYVAL x AS INTEGER, BYVAL y AS INTEGER)
END DECLARE
DIM AS INTEGER setxy
WIDTH 50, 25
DO: LOOP UNTIL _SCREENEXISTS
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
_TITLE "No Border"
hwnd& = _WINDOWHANDLE
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
_DELAY .25
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& AND WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)
LOCATE 1, 1
COLOR 0, 7
PRINT SPACE$(_WIDTH);
fw = _FONTWIDTH
fh = _FONTHEIGHT
x = _SCREENX: y = _SCREENY
DO
_LIMIT 60
IF GetAsyncKeyState(1) < 0 THEN
IF lb = 0 THEN lb = 1
ELSE
IF lb THEN lb = 0: dragpt = 0
END IF
z = GetCursorPos(WinMse)
IF lb THEN
IF dragpt THEN
IF WinMse.X_Pos <> oldxpos OR WinMse.Y_Pos <> oldypos THEN
j1 = (WinMse.X_Pos - oldxpos)
j2 = (WinMse.Y_Pos - oldypos)
x = x + j1: y = y + j2
_SCREENMOVE x, y
setxy = SetCursorPos(x + dragpt, y)
END IF
z = GetCursorPos(WinMse)
ELSE
IF WinMse.Y_Pos >= _SCREENY AND WinMse.Y_Pos <= _SCREENY + fh THEN
x = _SCREENX: y = _SCREENY
dragpt = (WinMse.X_Pos - x)
END IF
END IF
END IF
IF LEN(INKEY$) THEN SYSTEM
oldypos = WinMse.Y_Pos
oldxpos = WinMse.X_Pos
LOOP
It still beat the heck out of me how we can move a window on the window's desktop with the mouse cursor "fixed" to a drag position but when you try to program that event the mouse cursor isn't fixed, but always trying to readjust.
Pete
|