In PBCC 4.03 and previous versions of PBCC 4, you could subclass the graphic window and capture these messages, there was a change in PBCC 4.04, where you must subclass the static control on the graphic window to capture these messages. A graphic window is a dialog box with one static control on it, the static control is what you actually do the drawing on. All you need to do is get the handle of this static control with hStatic = GetWindow(hGraphicWindow, %GW_CHILD) and subclass hStatic instead of hGraphicWindow. I posted an example of how to do this at http://www.powerbasic.com/support/pb...ad.php?t=35336.
Announcement
Collapse
No announcement yet.
Capturing mouse and keyboard messages from a graphic Window in PBCC 4.04
Collapse
X
-
A simplified version of the example program is given below. The keyboard gets detected only after you click the window. If the first thing you do is press keys they will not be detected.
This morning I asked PB support about this. Here’s their reply to the first – I assume it’s OK to quote support email:
The static control on the graphic window must have the keyboard focus before it can receive a key board message. The easiest solution would be to subclass the dialog of the graphic window and catch a WM_SETFOCUS message and set the focus to the static control, this way the dialog will never receive the keyboard focus, only the static control will.Code:%WM_NCHITTEST = &H084 %GW_CHILD = 5 %GWL_WNDPROC = -4 %WM_MOUSEMOVE = &H200 %WM_LBUTTONDOWN = &H201 %WM_RBUTTONDOWN = &H204 %WM_KEYDOWN = &H100 Type POINTAPI x As Long y As Long End Type Declare Function GetWindow Lib "USER32.DLL" Alias "GetWindow" (ByVal hWnd As Dword, ByVal wCmd As Dword) As Long Declare Function SetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" (ByVal hWnd As Dword, ByVal nIndex As Long, ByVal lNewLong As Long) As Long Declare Function CallWindowProc Lib "USER32.DLL" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Dword, ByVal hWnd As Dword, ByVal uMsg As Dword, ByVal wParam As Dword, ByVal lParam As Long) As Long '================================================================ Global GraphicWindowChildOldProc As Long Global finished As Long '---------------------------------------------------------------- ' Called whenever keyboard or mouse activity is detected in the graphics window. Function GraphicWindowChildNewProc(ByVal hWnd As Dword, ByVal wMsg As Dword, ByVal wParam As Dword, ByVal lParam As Long) As Long Local p As POINTAPI Select Case wMsg Case %WM_NCHITTEST Case %WM_MOUSEMOVE p.x = Lo(Word, lParam) ' Current mouse X Position in the graphic window. p.y = Hi(Word, lParam) ' Current mouse Y Position in the graphic window. Print "Mouse at " + Format$(Lo(Word, lParam)) + "," + Format$(Hi(Word, lParam)) Case %WM_LBUTTONDOWN Print "Left -click at " + Format$(Lo(Word,lParam)) + "," + Format$(Hi(Word,lParam)) Case %WM_RBUTTONDOWN Print "Right-click at " + Format$(Lo(Word,lParam)) + "," + Format$(Hi(Word,lParam)) Case %WM_KEYDOWN If Chr$(WPARAM) = $Esc Then finished = 1 Else Print Chr$(wparam) End If End Select Function = CallWindowProc(GraphicWindowChildOldProc, hWnd, wMsg, wParam, lParam) End Function '---------------------------------------------------------------- Function PBMain Local hGraphicWindow As Dword Local hStatic As Dword Local w As Long Graphic Window "Graphic Window SubClassing Example", 0, 0, 320, 240 To hGraphicWindow ' Retrieve handle to static control (the graphic) on the graphic window (dialog box). hStatic = GetWindow(hGraphicWindow, %GW_CHILD) ' Subclass the graphic window; any keyboard or mouse activity in the window ' will cause the GraphicWindowChildNewProc function to be called. GraphicWindowChildOldProc = SetWindowLong(hStatic, %GWL_WNDPROC, CodePtr(GraphicWindowChildNewProc)) Console Set Loc 320,0 Graphic Attach hGraphicWindow, 0, ReDraw Graphic Font "Times New Roman", 14, 0 Graphic Print "Move mouse, click, type." Graphic Print "Press Esc to quit" Graphic ReDraw ' Loop until Esc is pressed on the graphic window. While finished = 0 Incr w ' Every third iteration give back one time slice ' to Windows to prevent 100% CPU utilization. If w Mod 3 = 0 Then Sleep 0 End If Wend End Function
Algorithms - interesting mathematical techniques with program code included.
-
Mark--
For a particular window (any window) to receive keyboard input, it must have the focus. That window can receive the focus programatically, or by physically "clicking" on it. That choice is entirely up to you, but it is a prerequisite. This isn't likely to change in the future.
Regards,
Bob Zale
PowerBASIC Inc.
Comment
-
1. I do not believe the question was about anticipated changes to Windows; rather, it was a question if there are any anticipated changes to the compiler to not require the use of subclassing to capture mouse/keyboard notifications.
Of course this would get into "vaporware" so no answer should be anticipated.
2. Since I don't have CC "dot=oh-four" I can't test Steve's examples, but the SDK doc says pretty clearly...
. Although static controls are child windows, they cannot be selected. Therefore, they cannot receive the keyboard focus and cannot have a keyboard interface..
2. (Speculation, but good speculation ) ....if you DO need a 'real' keyboard interface on a graphic window, I can't see anything to stop you from adding a child window to that graphic window of any class... 'edit' comes to mind to take in keystrokes and get input from the user. CreateWindowEx works just fine with PB/CC.
I don't see a "window procedure interface" in the GRAPHIC WINDOW but if subclassing works for the static control no reason it shouldn't work for an explicitly-added edit control.
Then again, when you start gettng into controls and such, the PB/Windows compiler might be a better choice of tool. The GRAPHICS commands appear identical, so that part of the program would be pretty much the same.
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
[beginning text deleted]
If you kept the console I suppose you could use some sort of set focus command.
Note that you can’t use Graphic Print within the "callback" function, you need to set a variable to what you want to print, then print it later (say in PBMain), within a loop that checks that variable.Algorithms - interesting mathematical techniques with program code included.
Comment
-
More on the 4.03/4.04 difference ...
Say you have several graphic windows on the screen at once. And each window has “buttons” on it – really just areas that are checked for mouse-click’s – and each button has a shortcut key.
Naturally you want all these keys to work in all the windows, regardless which has the focus.
In both 4.03 and 4.04 if you process the mouse and keyboard in the a subclassing procedure for a window, the window must have the focus (from clicking) before the keys will work.
However, in 4.03 you could subclass a window twice, once for the mouse and once for the keyboard, in different ways. In what follows win1 and win2 are PB handles for two graphic windows.GW1 = GetWindow(win1, %GW_CHILD)where GWnew1 and GWnew2 process mouse-clicks, GWnew_k processes the keyboard.
GWold1 = SetWindowLong(GW1, %GWL_WNDPROC, CodePtr(GWnew1))
GW2 = GetWindow(win2, %GW_CHILD)
GWold2 = SetWindowLong(GW2, %GWL_WNDPROC, CodePtr(GWnew2))
GWold1k = SetWindowLong(win1, %GWL_WNDPROC, CodePtr(GWnew_k))
GWold2k = SetWindowLong(win2, %GWL_WNDPROC, CodePtr(GWnew_k))
This works in 4.03 (when it probably shouldn't) and not in 4.04.Last edited by Mark Hunter; 8 Nov 2007, 06:13 PM.Algorithms - interesting mathematical techniques with program code included.
Comment
-
The following code displays two graphic windows side by side, sans console. When you click on either window you will see printed where, and which mouse button. When you type letters they will be displayed in that window.
It works as it ought to, in 4.04.
It doesn’t work in the earlier version, 4.03, though something like it can be made to work with some extra code.Code:#Console Off '---------------------------------------------------------------- ' From WinAPI32 ... %WM_NCHITTEST = &H084 %HTTRANSPARENT = -1 %HTCLIENT = 1 %GW_CHILD = 5 %GWL_WNDPROC = -4 %WM_LBUTTONDOWN = &H201 %WM_RBUTTONDOWN = &H204 %WM_KEYDOWN = &H100 Declare Function GetWindow Lib "USER32.DLL" Alias "GetWindow" (ByVal hWnd As Dword, ByVal wCmd As Dword) As Long Declare Function SetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" (ByVal hWnd As Dword, ByVal nIndex As Long, ByVal lNewLong As Long) As Long Declare Function CallWindowProc Lib "USER32.DLL" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Dword, ByVal hWnd As Dword, ByVal uMsg As Dword, ByVal wParam As Dword, ByVal lParam As Long) As Long '================================= =========================== Global GraphicWindowChildOldProc1 As Dword Global GraphicWindowChildOldProc2 As Dword Global GWold1k As Dword Global GWold2k As Dword Global whichWindow As Long 'in window 1 or 2 Global ky As Long 'keycode Global whichButton As Long 'button left or right (1 or 2) Global xmouse, ymouse As Long 'mouse-click position ' Zero/Non-zero ky and whichButton are also used as flags for ' keyboard and mouse activity, respectively. '---------------------------------------------------------------- ' Called whenever keyboard or mouse activity is detected in the FIRST window. Function GraphicWindowChildNewProc1(ByVal hWnd As Dword, ByVal wMsg As Dword, ByVal wParam As Dword, ByVal lParam As Long) As Long Local result As Dword result = CallWindowProc(GraphicWindowChildOldProc1, hWnd, wMsg, wParam, lParam) Select Case wMsg Case %WM_NCHITTEST If result = %HTTRANSPARENT Then result = %HTCLIENT Case %WM_LBUTTONDOWN xmouse = Lo(Word, lParam) :ymouse = Hi(Word, lParam) whichWindow = 1 whichButton = 1 Case %WM_RBUTTONDOWN xmouse = Lo(Word, lParam) :ymouse = Hi(Word, lParam) whichWindow = 1 whichButton = 2 Case %WM_KEYDOWN ky = wParam whichWindow = 1 End Select Function = result End Function '---------------------------------------------------------------- ' Called whenever keyboard or mouse activity is detected in the SECOND window. Function GraphicWindowChildNewProc2(ByVal hWnd As Dword, ByVal wMsg As Dword, ByVal wParam As Dword, ByVal lParam As Long) As Long Local result As Dword result = CallWindowProc(GraphicWindowChildOldProc2, hWnd, wMsg, wParam, lParam) Select Case wMsg Case %WM_NCHITTEST If result = %HTTRANSPARENT Then result = %HTCLIENT Case %WM_LBUTTONDOWN xmouse = Lo(Word, lParam) :ymouse = Hi(Word, lParam) whichWindow = 2 whichButton = 1 Case %WM_RBUTTONDOWN xmouse = Lo(Word, lParam) :ymouse = Hi(Word, lParam) whichWindow = 2 whichButton = 2 Case %WM_KEYDOWN ky = wParam whichWindow = 2 End Select Function = result End Function '---------------------------------------------------------------- Function PBMain Local hGraphicWindow1 As Dword Local hGraphicWindow2 As Dword Local hStatic As Dword Local w As Long ' Create two graphic windows side by side Graphic Window "", 0, 0, 398, 400 To hGraphicWindow1 Graphic Window "", 400, 0, 398, 400 To hGraphicWindow2 ' Subclass hStatic = GetWindow(hGraphicWindow1, %GW_CHILD) GraphicWindowChildOldProc1 = SetWindowLong(hStatic, %GWL_WNDPROC, CodePtr(GraphicWindowChildNewProc1)) hStatic = GetWindow(hGraphicWindow2, %GW_CHILD) GraphicWindowChildOldProc2 = SetWindowLong(hStatic, %GWL_WNDPROC, CodePtr(GraphicWindowChildNewProc2)) ' Print instructions on the windows Graphic Attach hGraphicWindow1, 0, ReDraw Graphic Font "Times New Roman", 12, 0 Graphic Print " Click or type, press Esc to quit." Graphic ReDraw Graphic Attach hGraphicWindow2, 0, ReDraw Graphic Font "Times New Roman", 12, 0 Graphic Print " Click or type, press Esc to quit." Graphic ReDraw ' Start with the second window having the focus Graphic Set Focus ' Continually check ky for keyboard activity and ' whichwindow for mouse activity. Print on the ' window that was last clicked. (Or Do Incr w If w Mod 3 = 0 Then Sleep 0 ' give time slice to Windows End If If ky Then If whichWindow = 1 Then Graphic Attach hGraphicWindow1, 0, ReDraw Else Graphic Attach hGraphicWindow2, 0, ReDraw End If If ky = Asc($Esc) Then Exit Do ElseIf ky = Asc($Cr) Then Graphic Print "[CR]" ElseIf ky = Asc($Spc) Then Graphic Print "[space]"; Else Graphic Print Chr$(ky); End If Graphic ReDraw ky = 0 'reset for next time End If If whichButton Then If whichWindow = 1 Then Graphic Attach hGraphicWindow1, 0, ReDraw Else Graphic Attach hGraphicWindow2, 0, ReDraw End If Graphic Print " - Button"; Str$(whichbutton); Graphic Print " at "; Str$(xmouse); ","; Str$(ymouse) Graphic ReDraw whichButton = 0 'reset for next time End If Loop End Function
Algorithms - interesting mathematical techniques with program code included.
Comment
Comment