SetBlitz3DEventCallback and SetBlitz3DHWND Bug

Archives Forums/Blitz3D SDK Bug Reports/SetBlitz3DEventCallback and SetBlitz3DHWND Bug

monotonic(Posted 2008) [#1]
When you call SetBlitz3DHWND and setup the render target, the SetBlitz3DEventCallback no longer registers keyboard events only mouse events are registered.

However, if you don't set the render target using the said function call, the callback event handler recieves keyboard and mouse events.


Rob Pearmain(Posted 2008) [#2]
I concur. I really need a fix for this.

Many thanks


skidracer(Posted 2008) [#3]
Try calling SetFocus on the appropriate hwnd when you get a mouse down event.


monotonic(Posted 2008) [#4]
Hi skidracer,

That doesn't seem to work.


skidracer(Posted 2008) [#5]
Any chance you could post some code. I added a SetFocus to the bmx 3DPanel example and keyboard events started firing just fine.


monotonic(Posted 2008) [#6]
Yeah sure, the code below shows the bug in action.


Edit: Obviously this code will not run on it's own, it's just an example.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;


using bb = Blitz3DSDK;


namespace TestApp
{
    public partial class Form1 : Form
    {

        // Windows messages
        const int WM_LBUTTONDOWN = 0x201;
        const int WM_LBUTTONUP = 0x202;
        const int WM_LBUTTONDBLCLK = 0x203;
        const int WM_RBUTTONDOWN = 0x204;
        const int WM_RBUTTONUP = 0x205;
        const int WM_RBUTTONDBLCLK = 0x206;
        const int WM_MBUTTONDOWN = 0x207;
        const int WM_MBUTTONUP = 0x208;
        const int WM_MBUTTONDBLCLK = 0x209;
        const int WM_KEYUP = 0x101;

        // The callback function pointer
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate int dBBEventHandler(int hWnd, int Msg, int wParam, int lParam);
        private dBBEventHandler BBEventHandler;

        // this is true when the application should exit
        private bool m_b_exitapp = false;

        // holds info about the last event
        private string m_s_lastevent = "None";

        public Form1()
        {
            InitializeComponent();
        }


        private void btnInitB3D_Click(object sender, EventArgs e)
        {
            // initialise b3d
            bb.SetBlitz3DHWND(RenderPanel.Handle.ToInt32());

            // assign the event handler
            BBEventHandler = new dBBEventHandler(Engine_BBEventHandler);
            bb.SetBlitz3DEventCallback(Marshal.GetFunctionPointerForDelegate(BBEventHandler).ToInt32());

            // setup graphics
            bb.BeginBlitz3D();
            bb.Graphics3D(RenderPanel.Width, RenderPanel.Height, 32);

            // begin the main loop
            MainLoop();
        }


        // the main loop
        private void MainLoop()
        {
            while (!m_b_exitapp)
            {
                Application.DoEvents();

                bb.Cls();
                bb.RenderWorld();
                bb.Text(10, 10, "Last event to occurr: " + m_s_lastevent);
                bb.Flip();
            }

            Application.Exit();
        }


        //The event handler for the callback event
        public int Engine_BBEventHandler(int hWnd, int Msg, int wParam, int lParam)
        {
            // process the event
            switch (Msg)
            {
                case WM_LBUTTONDOWN:
                    // left mouse button is down
                    m_s_lastevent = "Left mouse button down";
                    RenderPanel.Focus();
                    break;

                case WM_RBUTTONDOWN:
                    // right mouse button is down
                    m_s_lastevent = "Right mouse button down";
                    RenderPanel.Focus();
                    break;

                case WM_KEYUP:
                    // keyboard
                    m_s_lastevent = "Keyboard key released";
                    RenderPanel.Focus();
                    break;
            }

            return -1;

        }

        private void button1_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            m_b_exitapp = true;
        }
    }
}



Any suggestions on this would be great, because currently I'm not able to use the sdk for what I want to do with it. So, it's kind of a money pit at the moment.


augGa(Posted 2008) [#7]
Adding my voice... I too really need this fixed or I just wasted $100... The purpose is to use with other languages..but can not control the app without keyboard input... can not even close the app without aborting it.... hmmm...I have tested extensively .. no setfocus or anything else works. for me..
am putting development on hold until I see response / fix.. no sense letting my peeps waste time trying to get around such a basic bug... thanks


monotonic(Posted 2008) [#8]
Yeah, this is really annoying. Input is the most basic of requirements for a game or application, so not being able to capture input kinda sucks, huh!

I don't know what is causing it, but if setting focus to the render target works in BlitzMax then surely it shouldn't be that hard to track it down for .NET languages such as C#.


Rob Pearmain(Posted 2008) [#9]
Re-Adding my voice, I am in a similar predicament


augGa(Posted 2008) [#10]
adding to the knowledge (??)
one of my peeps (very bright young lady) stayed up late last night playing with the problem.. she REALLY WANTS TO USE BLITZ... or she needs to get a life...here is what she found:
using XP .. VB2008 .net .....Kanti's 2nd Example..using PicBox as canvas...Problems encountered with VB2008.net are as Monotonic and others stated above..
KeyHit in example always returns zero.. NO KEY or Mouse strokes are recognized by windows or Blitz.. i.e., app appears dead..
what she Did:
kanati's Code: b3d.PositionEntity(camera, 0, 0, -4, 1)
'while the escape key isn't hit, rotate the cube and update the world...
While b3d.KeyHit(KEY_ESCAPE) = 0
b3d.UpdateWorld(1)
...etc...
b3d.Flip(1)

End While
b3d.EndBlitz3D()

replaced with:
me.keypreview()
while KeepGoing
System.Windows.Forms.Application.DoEvents() ' let Vb events fire

b3d.updateworld.... etc
end while
b3d=nothing

assuming winform is FORM1
in the form1.KeyPress event
If AscW(e.KeyChar) = System.Windows.Forms.Keys.Escape Then
KeepGoing = False
End If

...
apparently here is what is happening...
the KeyPreview allows the FORMS KeyPressed event
to GET the keypressed BEFORE it is passed to Whatever other control has focus (i.e. Textbox)... testing here for escape and setting var to terminate the Blitz loop works...
after falling out of the loop Kanati's code had the ENDBLITZ3D statement.. if left here VB2008 aborts with
ATTEMPT TO ACCESS CORRUPT MEMORY error.. interesting in that it aborts in the KEYHIT code of the SDK ...Hmm...setting the created class to nothing and using the App closing to clean up seems to work...
Note: Setfocus (Focus) does not work in vb2008.net. i.e making sure focus is on a control (i.e. TextBox) and using that controls keypressed event DOES NOT WORK ...also insuring focus is on the target control DOES NOT WORK .... but this keypreview does... why ??? ... Not a clue.....


monotonic(Posted 2008) [#11]
I have tried the KeyPreview and it doesn't work here, strange. I believe that B3D SDK is consuming the events, at a higher level of priority than the form.

Anyhoo, using this method would require you to get mouse input from the B3D event callback and the keyboard input from the PreviewKeyDown event, not the nicest of methods.

Having the callback event fixed is definitely needed.


augGa(Posted 2008) [#12]
monotonic...
sorry .. my bad... right after the while KeepGoing she had..
System.Windows.Forms.Application.DoEvents() ' let Vb events fire
.... maybe why the vb works...
agree with u the bug needs to get fixed.. the young lady that works for me is going to try and implement your method in vb to see if we can get the Mouse input...although I won't let this go much past tomorrow.. other work to do ... oh well.. will wait on Mr. Sibley ... don't even know if they intend to fix.. may be one of those issues that will simply be ignored.. no response either way..


monotonic(Posted 2008) [#13]
I recieved an email from Simon H regarding an email I sent to BRL Support about this. He said that he has sent an email to Mark reminding him that the SDK needs an update desperately.

[*edit* Woohoo the word email used 3 times in two sentences, ok maybe not so good :) ]


I'm just in the process of implementing an IMessageFilter class to see if this does anything, will post back with the results.


monotonic(Posted 2008) [#14]
Ok, just created a UserControl and derived it from Panel and implemented IMessageFilter. This allows you to capture events i.e. Pre-filter them before dispatch.
I have pasted some example code below that shows how to implement this. This won't work out-of-the-box but it shows how to do it.


Code for the user control that implements the IMessageFilter, the PreFilterMessage function is called by the OS to filter the messages before dispatch.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;



namespace MyApplication
{

    public partial class RenderPanel : Panel, IMessageFilter
    {

        /// <summary>
        ///  Construction
        /// </summary>
        public RenderPanel()
        {
            InitializeComponent();
        }


        /// <summary>
        /// This is just a property to allow the parent control to see the last message that was filtered
        /// </summary>
        public string LastEvent
        {
            get { return m_s_last_event; }
        }private string m_s_last_event;


        /// <summary>
        /// The interface method, which is called to err.. pre filter messages :)
        /// </summary>
        /// <param name="m">reference to the message object</param>
        /// <returns>true to filter the message and stop it from being dispatched; 
        ///         false to allow the message to continue to the next filter or control.</returns>
        public bool PreFilterMessage(ref Message m)
        {
            // set the debug property to the message id
            m_s_last_event = m.Msg.ToString();

            return false;
        }
    }
}



This code shows how to actually register the object with the application message filters, if this is not done it will not work. You need to add a RenderPanel control to the main form in the normal way. Next, you need to add the following code somewhere in an initialisation function such as Form.Load to register the message filter.
Application.AddMessageFilter( My_RenderControl );



marksibly(Posted 2008) [#15]
Hi,

I'm not sure what's happening, but it looks like the Blitz3D window isn't receiving input focus.

The apps above are in control of the event loop (Application.DoEvents()?) so b3d is the last one to see any events - ie: it's not 'higher up' or anything, and the internal b3d event handler just passes on events to the SetBlitz3DEventCallback handler - and if that's not receiving any keyboard events, then the b3d window probably doesn't have input focus.


Try calling SetFocus on the appropriate hwnd when you get a mouse down event.


Has someone tried this with the HWND passed to the event handler - ie: NOT the HWND passed to SetBlitz3DHWND?


Moraldi(Posted 2008) [#16]
I have not such problems using Blitz3DSDK with Dev-C++.
You can download this sample:

http://www.moraldigames.com/Temp/UDrop%20Pro.zip

Everything works fine with mouse and keyboard input inside my 3D canvas as well as the menu short cuts
You can rotate the camera using the left mouse button holding the ALT key, move it holding the CONTROL key or pan using the right mouse button holding the CONTROL key.
If you press F5 you can hide or show right side panels.
I don't think that there is a problem in SDK...


augGa(Posted 2008) [#17]
Monotonic..
You guys are a lot brighter than I... soooooo...
These discussions are getting me confused...
have you tried to use sdk with a standard windows control (Pic box or PANEL) WITHOUT a Callback routine of your own.. and if so does it work...
WE / I am assuming to render to a Pic Box simply need to use SETBLITZ3dHWND giving it the handle to the pic box and all further Blitz comands will work.. i.e. when mouse is clicked within the Pic Box bbMouseX .. etc... works as if it is the 'built in' blitz canvas....
NO CALLBACK IS NEEDED ???
Is this correct ??
if This IS CORRECT:
then there IS A PROBLEM with the SDK and setfocus does not work... (at least in Vb.net)
If you agree then perhaps your above example Should not include the callback... just confusing the issues...and would allow Mark to find the problem.....

If this is NOT CORRECT:
oops... where do I find doc on how to handle..
Html doc=Specifies a parent window for the Blitz3DSDK to use with the windowed modes of the bbGraphics3D command.


for info..
using the std Blitz Canvas that is 'Built In' (not using SetBlitz3dHwnd) works Fine with vb.net....

Moraldi..
Thanks ..but need to know WHAT 3d Canvas are you using??? ie. is it a standard windows control ?


augGa(Posted 2008) [#18]
Kanati...
Guess I should have asked.. used your example rendering to a pic box.... DOES IT WORK FOR YOU ????
we tried it with vb.20005 and vb.2008 when we click on GO and blitz renders to pic box... render is OK .. we no longer have any MOUSE commands or Keyboard input ( KEYHIT etc) .. we can not even close the windows form or minimize/maximize.. NOTA... Display is fine... just can not "Interact' with the Picbox.. we went from there to trying many other tests.. insuring focus is on pic box etc.. KEY TO ME is that we can not use the Mouse to CLOSE THE WINDOWS FORM.. Nothing to do with pic box...


monotonic(Posted 2008) [#19]
Kurtz,

no the events are not fired from the picturebox or panel, that is the standard .NET events such as OnClick etc.. It is when you set the HWND that causes the problem, when using the standard window like you said all is good.


Mark,

Hi, no I haven't tried doing that yet good idea. I have been setting focus to the render control like the example code I posted earlier. I will try this an post back with the results.


monotonic(Posted 2008) [#20]
Mark

You are genius! That works like a dream, all you need to do is add the following import somewhere in your class.
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr SetFocus(int hWnd);


Then in your Blitz3DEventCallback function just do the following:
SetFocus( hWnd );


[*EDIT*] You need to keep track of the focus for the render target because setting focus to the render target every time the callback is fired will result in your other controls not being able to recieve keyboard focus i.e. a textbox

e.g.
if( m_b_b3d_has_focus )
      SetFocus( hWnd );

[*END EDIT*]

Now all events are recieved including keyboard.

Thanks Mark.


Moraldi,

It was a problem with .NET (C#, VB.NET etc) taking control of the message loop like Mark said.


augGa(Posted 2008) [#21]
Never Mind below.. missed Monotonics above... will give to
Mary and see what happens...
much thanks for your efforts....
Marv

Mark,Monotonic
I know it's me.... I am claiming a senior moment..
Mono.. I do appreciate your answer and I realize I am not asking the questions clearly... your mind has all the complexities running around in it.. I do not understand all the implications you are taking for granted...

Sooooo.... Let me try this.. (Tks in advance for your patience)

if I use a Std Windows Picture box to render into..
and I tell the Blitz3dSDK this is my render target by specifying the picbox in SetBlitz3DHwnd... AND I put a cube in this picbox and Render AND then I click on the Cube should I be able to test forbbMouseHit, bbMouseX bbMouseY .....(Blitz mouse coords)...etc...
No Callback.. No special SetFocus .. just click on the cube...
????

...
My mind is assuming ONE THING:
BLITZ3dSDK is controlling the INPUT (Key and MOUSE) for WHATEVER the render target is.....
otherwise how could it set the internal vars... mousex etc..
and it IS NOT then passing on to WinOS.. Blitz gets the events for the render target.. uses them for Blitz purposes and dumps them...so I CAN NOT use the std events for the control I am using...


Moraldi(Posted 2008) [#22]
is it a standard windows control ?

It is a standard MS Window handle. No matter what type of control you are using. It can be a button! :)
monotonic:
I am glad for two reasons
First you manage to solve your problem! :)
Second my assumption became true ;)

I want to note once again that I believe strong in Blitz3DSDK and I will wait for the DX9 or better...


monotonic(Posted 2008) [#23]
I want to note once again that I believe strong in Blitz3DSDK and I will wait for the DX9 or better...


Me too, the SDK is superb. A DX9 version would be AWESOME!!!


marksibly(Posted 2008) [#24]
Hi,

The thing is, SetBlitz3DHWND doesn't actually set the HWND used by Blitz3D - it just sets a parent HWND, and setting the focus to this parent wont achieve much!

There doesn't actually appear to be a function to get the 'real' Blitz3D HWND in there yet - will add one soon.

In the meantime, you could grab the Blitz3D HWND in WM_CREATE in the event handler and store it in a global somewhere, then just use SetFocus on that.


Kanati(Posted 2008) [#25]
Ok... attempting the same thing monotonic did but in vb.net...

Added this to the form...
    Dim del As New DelegateBlitzEvents(AddressOf BlitzEvents)

    Private Delegate Function DelegateBlitzEvents(ByVal hwnd As Integer, ByVal msg As Integer, ByVal wparam As Integer, ByVal lparam As Integer) As Integer

    Private Function BlitzEvents(ByVal hwnd As Integer, ByVal msg As Integer, ByVal wparam As Integer, ByVal lparam As Integer) As Integer
        Select Case msg
            Case &H101
                MsgBox("KEY HIT!!")
        End Select
    End Function


Added this to the setup before calling beginblitz3d
        del = AddressOf BlitzEvents
        b3d.SetBlitz3DEventCallback(Marshal.GetFunctionPointerForDelegate(del))


Added this to the vb wrapper
    <DllImport("user32.dll")> _
    Public Shared Function SetFocus(ByVal hWnd As Integer) As Integer
    End Function


Added this to the loop
            SetFocus(PictureBox1.Handle.ToInt32)


The callback doesn't appear to be getting called. I'm not sure if it has to do with the way I'm setting up the delegate (first time messing with delegates and unmanaged code) or with the setfocus call. ARGH!

Why can't anything at all be simple like the old days? :)


marksibly(Posted 2008) [#26]
Hi,

Try adding "SetFocus(hwnd)" at the top of the BlitzEvents function.


Kanati(Posted 2008) [#27]
Unfortunately that didn't do it. I am pretty sure the callback code isn't getting called at all. It's PROBABLY the way I'm getting or setting the callback itself.


monotonic(Posted 2008) [#28]
Try adding this (in it's VB form)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]


just above your delegate declaration below
 Private Delegate Function DelegateBlitzEvents(ByVal hwnd As Integer, ByVal msg As Integer, ByVal wparam As Integer, ByVal lparam as Integer) as Integer 



Kanati(Posted 2008) [#29]
I'll give it a shot when I get back from my business trip... round about saturday.


Jolinah(Posted 2008) [#30]
Hi, I found another solution for .NET 2008 (maybe it works with 2005 too).

Edit: Oh, it seems that mouse input does not work... only keyboard...

Add the following class to your project (C#):

B3DMessageFilter.cs
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security.Permissions;


[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class B3DMessageFilter : IMessageFilter
{
    [DllImport("user32.dll")]
    extern private static int FindWindowEx(int parent_hwnd, int child_hwnd, int classname, int name);

    [DllImport("user32.dll")]
    extern private static int SetFocus(int hwnd);


    private IntPtr handle;
    private int child_hwnd;

    
    public B3DMessageFilter(IntPtr handle)
    {
        this.handle = handle;
    }


    #region IMessageFilter Members

    public bool PreFilterMessage(ref Message m)
    {
        if (m.HWnd == handle)
        {
            if (child_hwnd == 0) child_hwnd = FindWindowEx(handle.ToInt32(), 0, 0, 0);
            if (child_hwnd != 0) SetFocus(child_hwnd);
        }
        return false;
    }

    #endregion
}


This message filter filters messages for the specified render target control. Whenever a message is received it looks for the child control and sets the input focus to this control.


How to use the filter:
B3DMessageFilter filter = new B3DMessageFilter(render_target_control.Handle);
Application.AddMessageFilter(filter);

Blitz3DSDK.SetBlitz3DHWND(render_target_control.Handle.ToInt32());
Blitz3DSDK.BeginBlitz3D();

...

if (Blitz3DSDK.KeyHit(Blitz3DSDK.KEY_ESCAPE) == 1)
{
   ...
}

...

Blitz3DSDK.EndBlitz3D();

Application.RemoveMessageFilter(filter);



Beaker(Posted 2008) [#31]
I'm guessing that this is also a problem for BlitzMax (+MaxGui)? I found a solution based on what people Mark suggested above. Is it necessary tho, or is there another neater solution for BlitzMax?


Ricky Smith(Posted 2008) [#32]
Anyone found a fix for this yet ? As it stands mouse events seem ok using the event handler and keyboard events can be captured by adding the setfocus(hWnd) method described above but then you lose keyboard events for the standard controls. Even if you don't do a setfocus you still lose all keyboard events.
if( m_b_b3d_has_focus )
      SetFocus( hWnd );


where is the "m_b_b3d_has_focus" from ?