Preventing the ALT key from triggering menus...
BlitzMax Forums/BlitzMax GUI Programming/Preventing the ALT key from triggering menus...
Hi All.
When I press ALT in my app, it is supposed to rotate the camera, however, I need to use maxGUI for menu's.
What I'd like to do is prevent the ALT key from pausing my app and waiting for me to click on the menu items.
How can I do this?
uuuhg. i had the same problem. never did solve it though. Hope someone else did
never did solve it though
Darnit! :(
If your canvas (assuming you are using a canvas) pressing 'alt' will generate an EVENT_KEYDOWN when the canvas is the active gadget.
You could possibly use ActivateGadget to make it more or less permanently active.
yeah we have Ogre3D running in a Bmax canvas. The problem were having is that were using ALT as our camera mouselook control hotkey in our editor app, which works in a similar fashion to 3dsmax.
I'm afraid the "activategadget" idea doesnt work, the window is frozen before the code is executed :(
Thanks for the comment though, anything helps!!!
Normally I would say: use Hotkey event. But depending on what you want to do with the pressed ALT button this won't work.
But a different idea could be: if canvas is active and mouse within canvas, disable window menus.
hmm, good idea, but i've tried this.
The window is still frozen when no menus actually exist, I can stop this from happening by not using the "Window_TitleBar" flag when creating the window itself, but then, who wants to do that? :(
Thanks for your help guys, any more ideas let me know :)
Just tried it now.
If you handle the input through an eventhook you can easily use alt. Because if you use a mouse button while you are on alt, the menu won't be fired (at least XP Pro SP2)
Here is my testcode, perhaps I missed something:
SuperStrict
Global window:TGadget = CreateWindow("Canvas - ALT Test" , 0 , 0 , 800 , 600)
Global canvas:TGadget = CreateCanvas(0,0, 640,480, window)
SetGraphics CanvasGraphics(canvas)
Global mnu_main:TGadget = CreateMenu("File",0,WindowMenu(window))
CreateMenu("End",1,mnu_main)
UpdateWindowMenu window
Global flipTimer:TTimer = CreateTimer(60)
Global MX:Int, MY:Int
AddHook EmitEventHook, InputHook
Global altdown:Int = False
Repeat
WaitEvent()
Select EventID()
Case EVENT_GADGETPAINT
Cls
If altdown
DrawText "Alt is pressed", 0,0
Else
DrawText "Alt is not pressed!", 0,0
EndIf
DrawText "Mouse: ("+MX+","+MY+")",0,20
Flip
Case EVENT_TIMERTICK
Select EventSource()
Case flipTimer
RedrawGadget(canvas)
End Select
End Select
Forever
End
Function InputHook:Object(id:Int, data:Object, context:Object)
Local ev:TEvent = TEvent(data)
Select ev.id
Case EVENT_MOUSEENTER
If ev.source = Canvas
ShowMouse()
ActivateGadget(canvas)
EndIf
Case EVENT_MOUSELEAVE
If ev.source = Canvas
HideMouse()
ActivateGadget(window)
EndIf
Case EVENT_MOUSEMOVE
MX = ev.x
MY = ev.y
Case EVENT_KEYDOWN
Select ev.data
Case KEY_LALT, KEY_RALT
altdown=True
End Select
Case EVENT_KEYUP
Select ev.data
Case KEY_LALT, KEY_RALT
altdown=False
End Select
End Select
Return data
End Function
hmm, see the problem is that while it does know ALT has been pressed, it then highlights the menu's and the mouse information is no longer updated etc... until you click on the canvas. This is the behaveor im trying to stop if at all possible.
Thanks for looking into it for me Dreamora :)
If you want to have ALT for cam control, the canvas must be active anyway or at least the mouse must be over it (which is why I enable it on enter), because mouse events *which includes MOUSEMOVE* are only fired by Canvas and Panel with PANEL_ACTIVE flag.
Don't think you can disable this UI core behavior, as you can't stop Cacao from doing some stuff as it does them.
But you can prevent happening it by enable the "core action" gadget. If you want to use ALT / CTRL to have mouse based camera control, the mouse will be over the canvas anyway, so using the mouseenter to enable the gadget seems to be quite usable solution. If you want it to continue even outside the canvas, you will need to fill the window with a panel with PANEL_ACTIVE flag anyway or you won't get mousemove updates anymore.
Hmm, thanks for the insight. I figured it might be hard to do- Guess i may have to go without maxgui for now, or find a working alternate control system- activating the gadgets doesnt stop it. Bummer.
Thanks again though :)
Doesn't this work?
Strict
Local win:TGadget = CreateWindow("Hello",100,100,400,400,Null,WINDOW_TITLEBAR|WINDOW_STATUS|WINDOW_MENU|WINDOW_CLIENTCOORDS|WINDOW_RESIZABLE)
Local can:TGadget = CreateCanvas(0,0,ClientWidth(win),ClientHeight(win),win)
SetGadgetLayout can,1,1,1,1
Local men:TGadget = CreateMenu("&Test",0,WindowMenu(win))
CreateMenu("&Bla",0,men)
CreateMenu("&Cla",0,men)
UpdateWindowMenu win
Local x:Int = 10
Local y:Int = 10
Local r:Int = 0
Local s:Float = 1.0
Local mx:Int = 0
Local my:Int = 0
Local edit:Int = False
Local mode:Int = 0
While WaitEvent()
Select EventID()
Case EVENT_GADGETPAINT
Redraw(can,x,y,r,s)
Case EVENT_MOUSEENTER
If EventSource() = can
ActivateGadget(can)
EndIf
Case EVENT_MOUSEMOVE
Local dmx:Int = EventX()-mx
Local dmy:Int = EventY()-my
mx = EventX()
my = EventY()
If edit
If mode = 1
x :+ dmx
y :+ dmy
ElseIf mode = 2
r :+ dmy
ElseIf mode = 3
s :+ dmy*0.1
EndIf
Redraw(can,x,y,r,s)
EndIf
Case EVENT_MOUSEDOWN
If EventData() = MOUSE_LEFT
mode :| 1
ElseIf EventData() = MOUSE_RIGHT
mode :| 2
EndIf
Case EVENT_MOUSEUP
If EventData() = MOUSE_LEFT
mode :& (~1)
ElseIf EventData() = MOUSE_RIGHT
mode :& (~2)
EndIf
Case EVENT_KEYDOWN
Select EventData()
Case KEY_LALT, KEY_RALT
edit = True
EndSelect
Case EVENT_KEYUP
Select EventData()
Case KEY_LALT, KEY_RALT
edit = False
EndSelect
Case EVENT_WINDOWCLOSE
End
EndSelect
Wend
Function Redraw(canvas:TGadget,x:Int,y:Int,r:Int,s:Float)
SetGraphics CanvasGraphics(canvas)
SetViewport 0,0,ClientWidth(canvas),ClientHeight(canvas)
Cls
SetRotation r
SetScale s,s
DrawRect x,y,40,40
Flip
End Function
hmm, not sure thats any different from before- interesting bit of code there.
The only problem with these bits of code is that the code execution stops as soon as alt is pressed then removed, because the menu is hilighted.
I will play with it again a bit tonight, maybe i can fathom something out.
The next thing I will need to do is grab an image of the canvas, which for some reason doesn't work when it it used as a render target from another lib
Thanks guys.
[edit]
Fredborg, I will try that code out when I get home.
Fredborg- Nope, not sure what your code is doing either hehe :) cheers for the help though.
Press and hold alt and use the mouse to pan, rotate and scale. I was under the impression that's what you needed?
Ah lol, well, I already have all that working you see, but as soon as you let go of alt, the menu is hilighted and the app is paused. thats what I need to stop, if possible. Doesn't look like it is though.
Thanks for your efforts though mate, Much apreciated.
Why do you need to stop that? Surely being able to access the menu by keyboard is something you don't want to disable.
its a specific app that needs to use the ALT key to control the camera. it would probrably be best if a quick tap of the alt key triggers menu's, but the functionality is more crippled by the behaveor.
We are creating a CAD application basically. the control is similar to that of 3DS Max.
On my machine the example I gave works exactly the same as 3dsmax.
Okay, here's a rough workaround example:
SuperStrict
Const MENU_EXIT:Int = 101
Const SUBWIN_OFFX:Int = 7
Const SUBWIN_OFFY:Int = 60
Local window:TGadget = CreateWindow("ALT Test" , 0 , 0 , 800 , 600)
Local panel:TGadget = CreatePanel(0, 0, 800, 600, window, PANEL_ACTIVE)
Local subwindow:TGadget = CreateWindow("", GadgetX(window) + SUBWIN_OFFX, GadgetY(window) + SUBWIN_OFFY, 400, 400, window, 0)
Local canvas:TGadget = CreateCanvas(0,0, 640,480, subwindow)
SetGraphics CanvasGraphics(canvas)
Local filemenu:TGadget = CreateMenu("File", 0, WindowMenu(window))
CreateMenu("Exit", MENU_EXIT, filemenu)
UpdateWindowMenu window
ActivateWindow(window)
ActivateGadget(panel)
Local flipTimer:TTimer = CreateTimer(100)
Local mx:Int, my:Int
Local altdown:Int = False
Local msg:String = ""
Repeat
PollEvent
Select EventID()
Case EVENT_WINDOWCLOSE
End
Case EVENT_GADGETPAINT
Cls
DrawText msg, 0,0
DrawText mx + "," + my, 0, 20
Flip
Case EVENT_TIMERTICK
If EventSource() = flipTimer Then RedrawGadget(canvas)
Case EVENT_MOUSEMOVE
mx = EventX()
my = EventY()
Case EVENT_KEYDOWN
Local data:Int = EventData()
If (data = KEY_LALT) Or (data = KEY_RALT)
If EventSource() = panel
ActivateWindow(subwindow)
ActivateGadget(canvas)
EndIf
altdown = True
EndIf
Case EVENT_KEYUP
Local data:Int = EventData()
If (data = KEY_LALT) Or (data = KEY_RALT)
If EventSource() = canvas
ActivateWindow(window)
ActivateGadget(panel)
EndIf
altdown = False
EndIf
Case EVENT_MENUACTION
Local data:Int = EventData()
If data = MENU_EXIT Then End
Case EVENT_WINDOWMOVE
Local x:Int = GadgetX(window) + SUBWIN_OFFX
Local y:Int = GadgetY(window) + SUBWIN_OFFY
SetGadgetShape(subwindow, x, y, 400, 400)
End Select
If altdown
msg = "Alt is pressed."
Else
msg = "Alt is NOT pressed."
EndIf
Forever
End
Basically you must utilise a style-less sub-window to 'trap' the ALT keyup event so it's not handled by the main window's menu.
You will need to implement decent EVENT_WINDOWMOVE and EVENT_WINDOWSIZE event handling code.
If your target platform is Windows only, you may need to utilise the Win32 API for a better solution.
Thanks, that works... In fact Chris tried this method, and the problem is that the windows dont update until you let go of the button. if blitz didnt behave like this, the solution would be perfect :-)
Nice bit of code there cheers!