In a tool: Adding puts '%32b' % flags to both onKeyDown and onKeyUp, I see the following:
Hitting ctrl:
onKeyDown prints 11101 (meaning, so it seems, that both ctrl and shift are pressed)
onKeyUp prints 1100000000011101.
Hitting shift:
onKeyDown prints 101010 (as if ctrl is pressed, it is not)
onKeyUp prints 1100000000101010
Hitting ctrl+shift as ctrl, keeping pressed and then shift:
onKeyDown prints 11101 on hitting ctrl, note again the flags mean both ctrl and shift are down (only ctrl is down)
onKeyDown prints 101010 on hitting shift (when the ctrl is still down) which suggests it “forgets” the shift is down.
Similarly when releasing the keys, the values are for shift and ctrl only
Just some month ago I ran i to this myself. My code was built around the flags and comparing them to flags given by other methods so I created this method that I call within onKeyDown and onKeyUp. It only works for Ctrl/Command, Alt/Option and Shift but can be extended to support more keys.
# Custom method to get flags from keycode since flags attributes has random
# arbitrary shitty value for onKeyUp and onKeyDown.
def flags_from_key(keycode)
{
CONSTRAIN_MODIFIER_KEY => CONSTRAIN_MODIFIER_MASK,
COPY_MODIFIER_KEY => COPY_MODIFIER_MASK,
ALT_MODIFIER_KEY => ALT_MODIFIER_MASK
}[keycode]
end
Short version of long story: We’ve always seen some weird things with the flags, and discrepant behavior between the onKeyDown and onKeyUp callbacks.
It seems (from my take on what the OP was saying in the older SCF thread,) that he wishes to detect when the user is switching a tool in and out of either “copy” or “constrain” mode, (ie, pressing the CTRL and SHIFT keys.)
A tool would need to do this to return the correct cursor (assuming the coder has created cursors for each mode along with a combo mode,) … these modes would be saved in a variable, and checked within a conditional statement in the onSetCursor() callback method so SketchUp could display the correct cursor for the mode.
Other tool functionality, may also need to know what “mode” the tool is in if the method is not fired by one of the key-callbacks, such as onCancel(), onReturn() or onUserText().
BUT, as I said in the SCF thread, you would not use the masks and flags bitfield, … instead you use the keycode constants (I give below,) and key parameter because it is the keypress you need to detect, not it’s use as a modifier.
Correct the keycodes for comparison are these constants:
CONSTRAIN_MODIFIER_KEY, COPY_MODIFIER_KEY and ALT_MODIFIER_KEY
Agree, the keycodes and flag masks are mixed together into one list at the bottom of the Tool class’ introductory docstring.
They should be separated into 2 lists, and the caption should be more exact, saying that the masks are used to compare against the flags bitfield, and the keys to compare against the key parameter.
Also, these virtual mouse key constants do not appear in the TopLevel Namespace constants list, and are not listed anywhere in the Tool class doc page (but are defined globally.)
You’d be correct in many cases BUT, if I’m trying to detect when ctrl and shift are down simultaneously, then key code would only have one of the keys (say, if ctrl is pressed first, followed by shift, then it would contain shift). If the flags contain the other key, then it is just a matter of combining the key code and flags to see all keys that are currently down. But without this information in the flags variable, it means the tool needs to keep state over the key down and key up callbacks. This is not a complex thing of course, BUT it would have been nicer to not have to do it.
But then the +/- indicators would only appear when the mouse moves or is clicked.
Also, what if I want to develop keyboard shortcuts in my tool? I don’t see why for mouse events I have instant knowledge of what modifiers are pressed, but for keyboard events I have to manage it on my own.
That is more or less why I made the code shown above (except I needed the cursor to change to an eye dropper when Alt was pressed).
Somewhat off topic to the original post but changing mouse cursor from key presses seems slightly glitched. The docs says UI.set_cursor only works when called from onSetCursor in the Tool interface but this method doesn’t appear to be called on key presses. However, calling UI.set_cursor directly in the onKeyDown method seems to work (although the docs says it shouldn’t).
Cursor objects need to be loaded and later accessed via an integer id. It is best to hold these ids in class variables of the tool.
Regarding my scenario above, I (personally) set a “current cursor” reference to point toward one of the class’ cursor id references, depending upon the tool’s state. (This can be any of the other input, key or mouse handling callbacks, or some internal method.)
Then the tool’s onSetCursor() callback would simply be:
def onSetCursor()
UI.set_cursor(@current_cursor)
end
I cannot see attempting to set a cursor anywhere else, as the smallest of mouse moves would cause SketchUp to fire the onSetCursor() callback.
I’d also expect the mouse entering the client modeling window to fire the onSetCursor() callback as well (at least by default if the onMouseEnter callback is not implemented. But, test to be sure.)
One of the long time “gripes” we have with SketchUp API tools is that the main application’s shortcuts are not suspended whilst out tools are active. So any other shortcut can interfere with your idea of how your tool should react to keypresses.
I seem to remember @tt_su having a hacky workaround to solve this.
Thomas, do you have a link to where you shared this ?
SketchUp used it’s own named modifier key (and mask) constants because the key names differ on the Mac, so they named them according to SketchUp’s traditional functionality, (ie, toggling inference constraint, toggling copy mode, etc.)