The flags parameter to Tool#onKeyDown and Tool#onKeyUp doesn't make sense

bug
ruby

#1

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


#2

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

#3

The readership should know that this issue is discussed at length in the OP’s other thread at SketchUcation:

http://sketchucation.com/forums/viewtopic.php?f=180&t=67837

In this thread, I gave links to other topic threads there over the years some like 8 or more years ago.


Short version of long story: We’ve always seen some weird things with the flags, and discrepant behavior between the onKeyDown and onKeyUp callbacks.


#4

Hmm… this had me confused as well. I don’t think I’ve ever used the onKey* flags before.

I would have to dig deeper to be certain, these values is being passed through from the OS. So it’s platform dependent.

CONSTRAIN_MODIFIER_MASK, COPY_MODIFIER_MASK and ALT_MODIFIER_MASK seems to correlate to the flags passed along with the mouse events: onLButton* etc.

# Shift (Windows)
'%32b' % CONSTRAIN_MODIFIER_MASK
                             100

# Ctrl (Windows)
'%32b' % COPY_MODIFIER_MASK
                            1000

# Alt (Windows)
'%32b' % ALT_MODIFIER_MASK
                          100000
#Shift
onLButtonDown: flags = 5
                             101

onLButtonUp: flags = 4
                             100
Ctrl
onLButtonDown: flags = 9
                            1001

onLButtonUp: flags = 8
                            1000
Alt
onLButtonDown: flags = 33
                          100001

onLButtonUp: flags = 32
                          100000

For the key event these masks doesn’t appear to apply. The docs are not clear here.

Looking up at MSDN I found this:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646280(v=vs.85).aspx

Since this is OEM dependent I haven’t been able to find any table for the scan code values.


#5

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.)

MK_ALT, MK_COMMAND, MK_CONTROL, MK_LBUTTON, MK_MBUTTON, MK_RBUTTON, MK_SHIFT


MSDN: Key Scan Codes (Visual Studio 6.0)



#6

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.


#7

Another approach is to not check the flags in onKeyUp/Down but do it onMouseMove, on clicks etc.


#8

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.


#9

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).


#10

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 ?


#11

For Windows machines, I believe that the key codes, etc., are contained in winuser.h. For example, the constants:

CONSTRAIN_MODIFIER_KEY 010000 (10h)
COPY_MODIFIER_KEY 010001 (11h)
ALT_MODIFIER_KEY 010010 (12h)

correspond to the virtual Windows key codes:

#define VK_SHIFT          0x10
#define VK_CONTROL        0x11
#define VK_MENU           0x12

Similarly, the virtual mouse codes correlate to the MK_X codes that @tt_su mentioned:

#define MK_LBUTTON          0x0001
#define MK_RBUTTON          0x0002
#define MK_SHIFT            0x0004
#define MK_CONTROL          0x0008
#define MK_MBUTTON          0x0010

I’m still not entirely clear what the masks do …


#12

Hi Jim, none of that is in dispute.

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.)

I explained it in the 2nd post of the “companion” SCF thread:
http://sketchucation.com/forums/viewtopic.php?f=180&t=67837


#13

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.