HookProc
-
Did you ever wanted to make a sketchup plugin that would use keyboard and mouse devices, without letting sketchup shortcuts interferring with it?
Well [Hook Procedure](http://msdn.microsoft.com/en-us/library/ms632589(v), is that powerful to do that.
The plugin allows the user to monitor, make decision, and run the script within the keyboard or/and mouse message activation.
It is provided with [KeyboardProc](http://msdn.microsoft.com/en-us/library/ms644984(v), [MouseProc](http://msdn.microsoft.com/en-us/library/ms644988(v), [LowLevelKeyboardProc](http://msdn.microsoft.com/en-us/library/ms644985(v), and with [LowLevelMouseProc](http://msdn.microsoft.com/en-us/library/ms644986(v) hook procedures. Supported with windows virual-key-codes, and mouse and keyboard input notification constants. Uses win32-api, windows-api, forwardable.rb, and rbconfig.rb. Though my rbconfig.rb CONFIG Hash is filled with Windows XP information. If you use different platform then, use your own rbconfig that is in ruby library folder.
The plugin is writen and tested in Windows XP operating system. Works in Sketchup 7 and SU 8.
Usage and example is in file myInputProc.rb.Note: In later time I'll probably add linux and mac virtual key codes, but for now its only supported with windows. I don't even know if this plugin would work on mac and linux operating system, so reply on how it works on yours.
-
Does it works alright on Windows 7, and other windows platforms?
And
Can anyone please check if it works on mac or linux>?
I need some feedback here
-
@anton_s said:
Can anyone please check if it works on mac or linux>?
I need some feedback here
i would check for you on mac but to be honest, i'm not even sure what it's supposed to do
-
@unknownuser said:
i would check for you on mac but to be honest, i'm not even sure what it's supposed to do
Yes, from reading my own post, I need to explain things better...
Let's say you're creating a plugin and you want the plugin to do some task when press key 'a'. You can do that by getting input in onKeyDown method. Though there is one thing: Key 'a' is a shortcut key to an arc tool - when you press key 'a' your tool deactivates, and the arc tool activates. But, how can you make it so that key 'a' doesn't interfere with arc tool? - Well there are two answers I know of:
1st Answer: Go to shortcuts menu and remove key 'a' from being a shortcut to some tool.
2nd Answer: Use hook procedure, simple as I know of.
1st answer is not good. If you wanted to set shortcuts back, you would have take some time for doing that, and if you wanted to upload a plugin to internet, so that others could use, before activating your plugin they would also have to remove shortcuts, and after activating, set tool shortcuts back. I think that's just a waist of time and no one would want to do that, so cross the first answer off and we're left with 2nd.
So anyways, what is Hook Procedure?
"A hook is a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure."The hook is not only capable of monetering keyboard messages, it's also capable of monetering mouse messages, which include the MouseWheel. Not only that, it's not only capable of monitoring messages, it is also capable to prevent messages from being sent to window procedure. And this is what we want. We could prevent key 'a' from being proccesed, and still get the input of it.
How we do that? (Or how we use hook procedure)
First off all here is a link to hooks: [Hooks](http://msdn.microsoft.com/en-us/library/ms632589(v)
We would need to initiate a function [SetWindowsHookEx](http://msdn.microsoft.com/en-us/library/ms644990(v), using win32-api and windows-api:
API.new('SetWindowsHookEx', 'IKII', 'I', 'User32')
Since, we wan't to monitor and process key 'a' message, we could use WH_KEYBOARD or [KeyboardProc](http://msdn.microsoft.com/en-us/library/ms644984(v). To do that we first need to create callback function. Since Win32API is not a good liblrary and is not capable to create calback functions, I decided to use win32-api. So here is the callback:
@keyboard_proc = Win32::API::Callback.new('ILI', 'I'){|code, wParam, lParam| #my script 0 #Return value: 0 - process the message, where 1 is to remove the message. }
This is a simple look at keyboard procedure, though the hook sometimes requires the keyboard proc callback function to call [CallNextHookEx](http://msdn.microsoft.com/en-us/library/ms644974(v). The details on how and when the hookproc should be called is in the "return value" section of the KeyboardProc. Note if you want to understand it, read it slowly, it confused me a bunch of times. By following all the rules of that, the callback should look like that.
@keyboard_proc=Win32::API::Callback.new("ILI", 'I'){|nCode, wParam, lParam| #my script return_val = some value 0 or 1
Following the instructions:If nCode is less than zero, then the callback should call CallNextHookEx and return the value returned by CallNextHookEx.
If return_val is 1 or any other value, but not zero, then the callback should call CallNextHookEx and return the return_val value.
If return_val is 0 then, don't have to call CallNextHookEx.
By following the instrcutions, it would look like this:
CallNextHookEx.call(@hooks["keyboard"], nCode, wParam, lParam) if (return_val==1 and nCode>=0) if nCode<0 then CallNextHookEx.call(nil, nCode, wParam, lParam) else return_val end }
Before we set hook, we need first know what to set the hook to. To the module handle or to the Thread. Setting a hook to module or global handle, will monitor and process messages that are to be sent to all window proceduers. Setting a hook to certain thread, will monitor and proceess messages sent to the current window procedure. We need to set it sketchup window.
To get a thread id of sketchup, we have to call many other functions, getting some kind of data that matches it. Since, when we activate our plugins we are in the sketchup window, we can call the function GetCurrentThreadId, without writing extra script that would find sletchup thread id.
ThreadID = GetCurrentThreadId.call
Now since we have it we, can hook the function:
@hHook = SetWindowsHookEx.call(WH_KEYBOARD or 2, @keyboard_proc, 0, ThreadId)
The hook now calls@keyboard_proc
, whenever there's a keyboard message is sent to sketchup window.Okay, we have this working, but how to set it back?
Well that's a job for function [UnhookWindowsHookEx](http://msdn.microsoft.com/en-us/library/ms644993(v).UnhookWindowsHookEx.call(@hHook)
To get module handle, you would want to call [GetModuleHandle](http://msdn.microsoft.com/en-us/library/ms683199(v).
HMod = GetModuleHandle.call
Hook it:
@hHook = SetWindowsHookEx.call(WH_KEYBOARD or 2, @keyboard_proc, HMod, 0)
And unhook when need to:
UnhookWindowsHookEx.call(@hHook)
Though, not all hook callback functions are supported in being set to thread or global scope. In Remarks section of SetWindowsHookEx, scroll a bit down and there'll be a table of all hooks that show the scope they can be in or should be set to.
To get information about the mouse messages you could use MouseProc or/and LowLevelMouseProc. Hook also provides some more callback functions that could monitor mouse messages, but they can't make a decision for it. They can't state however the message to be processed. In other words, they can't prevent the message from being sent to the thread and the global scope.
MouseProc can give the mouse all mouse messages and data the user needs, expect the mouse-wheel rotation direction data. On theother hand, LowLevelMouseProc can give all mouse messages, including the mouse wheel rotation direction, but it cannot be set to thread. It can only be set to global. So if want to monitor and process the whole data of mouse messages, you should use two functions.
Now the Plugin:
The plugin consists of HookProc.rb (main), core.rb (My library), VirtualKeyCodes.rb, Mouse Input.rb (the constant names assigned to the mouse messages), Keyboard Input.rb (Also Constant names), and MyInputProcedure, a simple example to the HookProc usage.
The example plugin is myInputProcedure.rb file
MyInputProcedure.rb should automatically create sketchup text and write messages to it, whenever the user presses/holds down/releases keys or mouse button or rotates mousewheel, depending on menu item the user has selected. The example removes KeyboardProc, LowLelelKeyboardProc, and mouseProc messages. Where LowLevelMouseProc is set to process the mouse messages. If the LowLevelMouseProc would remove all mouse messages it receives, then it would act like the mouse is off.
USing the MyInputProcedure Example Plugin is simple. Toggle bettween the items you want. To set hook, select the menu item once. To unhook, select again or select "unhook all" menu item in "MyInputProcedure" submenu.
Note this plugin is not really useful. You can't define method initiate in ur class. If you would then it would remove the data stored in previous HookProc initiate method. I will update it, so that it would work a bit similar to Sketchup Tool and so it'll be useful.
-
hey anton,
uh. yeah. i don't think i have any use for this and i wouldn't be much help at all with mac debugging and what not.
sorry. -
hi Anton,
as is this definitely won't work on mac's
john
-
@driven said:
as is this definitely won't work on mac's
No, it won't work on Macs because it uses the Windows operating system API.
[Also, moving topic to Dev forum]
-
Ah, well okay, its for windows operating system then...
Thanks for checking
-
Hi, Anton!
Can your plugin to solve the problem described in this report? -
First of all, I'm also russian, you can write the post in russian and in english (if want to)and i'll reply in two languages.
So, what you wanted was to get hotkeys input?
- The actual plugin hookproc can't get hotkeys (key-combinations) input, though there should be a way to get it. I'll do some research on it... and then write a plugin for that.
Advertisement