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!