PDA

View Full Version : Is "while keyboard button pressed/held do" possible?


doCHtor
01-01-2011, 07:39 PM
Hi,

is it possible to make a script that runs while a certain keyboard shortcut is held? Couldn't find anything in maxscript help or google.

Thanks

Kickflipkid687
01-01-2011, 09:27 PM
I just used a timer, and on tick did a check for if the shift key was pressed and rotated an object.

I've never learned how to use anything other than shift,ctrl and alt for keys though :(

PEN
01-01-2011, 10:15 PM
You can use dotNetClass "system.control" to be able to access mouse buttons and keyboard buttons and you will not be limited to what you can access.

Kickflipkid687
01-01-2011, 11:12 PM
Could you possibly provide an example if it's not too much trouble :).

PEN
01-02-2011, 11:30 PM
I'm not sitting at max so this is off the top of my head.

DnControl=dotNetClass "system.control"
If DnControl.keyBoard==DnControl.keyBoard.atl do...

Kickflipkid687
01-03-2011, 12:30 AM
Hmm, ok. Max says it's undefined, and can't find keyboard in undefined.

I'll poke around the web and see if I can find anything

thanks!

PEN
01-03-2011, 01:35 AM
I will be in front of max tomorrow if you are still having issues.

Kickflipkid687
01-03-2011, 01:42 AM
Ok, cool. Yeah, still not sure how to get it to work. I can't find that command on the MSDN either.

doCHtor
01-03-2011, 08:17 AM
Thanks guys, but for me .net is just too much, I'm happy I can do a bit in maxscript :)

PEN
01-03-2011, 03:31 PM
I wasn't even close.

con=dotNetClass "system.windows.forms.control"
showProperties con
showProperties con.modifierKeys

if con.modifierKeys==con.modifierKeys.alt do...

I left the showProperties in there so you understand where the information came from.

doCHtor
01-03-2011, 04:06 PM
Thanks, even though I don't want to touch (learn) .net yet, after "do" in your example a common maxscript stuff can follow?

PEN
01-03-2011, 04:15 PM
This is all just common Max script really, it is just calling on dotNet to test the keyboard input. Since you can cut and paste what I have put there it wouldn't be a problem for you to start using it in your scripts right now.

Kickflipkid687
01-03-2011, 05:53 PM
Dochtor, yeah dotNet is a little scary at first, but it's not that bad, really. Plus you can do alot of awesome stuff with it that maxscript can't, so it's a definately worth looking into at some point.

Thanks Pen! That's works perfect. Using that I can now access/use mouse buttons too :)

timer theTimer interval:1000 active:true
local con = dotNetClass "system.windows.forms.control"
on theTimer tick do
(
if con.MouseButtons==con.MouseButtons.middle do
(
print "wee"
)
)

The above code has to be in a Rollout menu though dochtor, if you are looking to test this. This is because of the Timer.

PEN
01-03-2011, 08:15 PM
You can also use a dotNet timer. Have a search and you will find some threads on it here I'm sure. If you use the dotNet timer you don't need to have a rollout.

doCHtor
01-03-2011, 08:38 PM
Thanks both of you, I will certainly try this.

Kickflipkid687
01-03-2011, 11:49 PM
Ah nice, I'll have to check that out for sure :D. Thanks again

zortech
01-04-2011, 10:59 AM
How would you check if any key is pressed? I checked the properties but they all seem to refer to certain keys.

I took a look at the msdn page but obviously don't know what to look for...I wanted to know this for quite some time but it never was worthy enough to open a new thread.

PEN
01-04-2011, 01:33 PM
none is also one of the properties. So...

if con.modifierKeys!=con.modifierKeys.none do...

zortech
01-04-2011, 02:10 PM
con = dotNetClass "system.windows.Forms.Control"
theTimer = dotNetObject "System.Windows.Forms.Timer"

fn printKey = (
if con.modifierKeys != con.modifierKeys.none do print "wee"
)

dotnet.addEventHandler theTimer "tick" printKey

theTimer.interval = 1000
theTimer.start()

--theTimer.stop()

I tried it like this but it only prints "wee" if you press shift, alt or ctrl. Sorry for the thread hi-jacking.

doCHtor
01-04-2011, 02:29 PM
Sorry for the thread hi-jacking.
No problem, my questions have been answered, so go on, this is also interesting.

PEN
01-04-2011, 07:35 PM
Not sure and I'm working on other things at the moment. I will have to play with this another day to see why it isn't working for you.

bcavett
01-05-2011, 05:03 AM
Will this allow you to create sticky keys in max? Like how xsi and modo's hotkeys work?

Say I'm in select mode and I hold down 'w',will it temporarily switch to the move tool and when I let go switch back to the select tool?

Kickflipkid687
01-05-2011, 05:35 AM
That seems like it would be possible.

U'd probably just have a counter, after 2000 or 3000 milliseconds it would trigger the switch, then set a variable so it isnt trying to switch to it again if your still holding the key. Then on key release, it switches that variable back and resets the counter and switch back to select.


Edit: Nevermind.. that key doesn't want to work. Also I'm not sure how to properly set that up right now. My method didn't work.. although I'm tired right now and probably not thinking this through very well at the moment.

Light
01-06-2011, 01:35 AM
Another way to do this that doesn't require using a timer is to use low level keyboard hooks and limit it to Max only. I did something similar and it worked but I didn't go further. It's basically doing something like this:

http://www.codeproject.com/KB/cs/CSLLKeyboardHook.aspx

Make a .NET assembly and load it in max, call the method that starts up the keyboard hook, and make sure it's only sending keys, if the foreground app is Max. You can even do fancy stuff like if the user is typing inside a field or Mxs listener, then you could filter them, or make them behave differently. It's mostly oldschool win32 methods so you will have to use PInvoke, but no big deal, just a handful of methods.

Just fire an event when a successful key press is made from your .NET assembly, and add a mxs function to that event to do what you want.




Light

Kickflipkid687
01-06-2011, 02:18 AM
Very cool Light. I will have to look into this :D

Thanks

denisT
01-06-2011, 05:33 AM
Another way to do this that doesn't require using a timer is to use low level keyboard hooks ...
Just fire an event when a successful key press is made from your .NET assembly, and add a mxs function to that event to do what you want.


i will be happy to see a mxs sample. the task doesn't look trivial for me.

Light
01-06-2011, 05:56 PM
i will be happy to see a mxs sample. the task doesn't look trivial for me.

Will try to find some code in my dev archive (:




Light

denisT
01-16-2011, 03:35 AM
Another way to do this that doesn't require using a timer is to use low level keyboard hooks and limit it to Max only. I did something similar and it worked but I didn't go further. It's basically doing something like this:

http://www.codeproject.com/KB/cs/CSLLKeyboardHook.aspx



IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);

does it make any sense?

Kickflipkid687
01-16-2011, 04:15 AM
So what does that code do exactly?

denisT
01-16-2011, 04:56 AM
So what does that code do exactly?

technically it's a right idea but with wrong implementation. it's what all keyloggers are based on. hopefully Light will show us a functional sample if it's not lost in an archive.

Light
01-17-2011, 06:52 PM
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);

does it make any sense?

Yep that's sort of the stuff I was doing. I looked some of my directories briefly but couldn't find it. But don't worry I am keeping this page open and will let you know if I find something.




Cheers,
Light

senor freebie
11-06-2011, 05:25 AM
There is a simple, yet rather unelegant solution to this.
Assign your shortcut, but make sure your script is very short and succint so that it doesn't interupt the users interaction. Then as normal assign it to a shortcut key.

The difficulty would come about when you stop the action. I guess a dotnet timer that you keep on resetting is the best option for this.

else

You could get lazy and spawn a dialog / delete the dialog


try (DestroyDialog test) catch (print "First Use")

rollout test "Test Timer"
(
timer clock "testClock" interval:1000 --tick once a second
on clock tick do
(
print "Executing final action"
DestroyDialog test
)
)
print "Executing intermediary action"
createDialog test

CGTalk Moderation
11-06-2011, 05:25 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.