mariuszhermansdorfer / SandWorm

Augmented Reality Sandbox for Grasshopper & Rhino
MIT License
20 stars 11 forks source link

Add keyboard shortcut control #103

Closed philipbelesky closed 2 years ago

philipbelesky commented 2 years ago

This is a quick prototype / RFC for adding keyboard shortcuts to control common options in the component UI. The use case here is both ease of access and a better ability to run things 'headless' - e.g. with the controlling computer more out of the way.

In my case I have a small numpad I'd imagined for this purpose, and might consider something like a StreamDeck for exhibition-like contexts. The keys on either of those options can be remapped to whatever, so the use of F10-F20 below is relatively arbitrary and could be made to be either more intuitive or more obscure.

If this is of value, the todo list is:

mariuszhermansdorfer commented 2 years ago

Thanks for the last commits @philipbelesky!

I've already merged the other two and added fixed some minor bugs in the process. I think we've ran into this issue before - sometimes in your commits the if statements don't have curly brackets and only the first line is interpreted as part of it: image

I also added another button for flood modelling and bundled unmanaged Kinect libraries into the .gha file. If you don't have any other feature requests - I would publish the current state as a Yak package and advertise it to the community.

This would officially mark our 2.0 release. All additional functionality would be added in future point releases.

I very much like the idea of adding Hotkeys to the plugin - the only reason why I'm not merging this yet is to release the milestone version first and then merge that into a new development branch. Makes sense?

philipbelesky commented 2 years ago

Hi Mariusz, thanks for the note on the brackets. Too many python assumptions crossing over on my end.

The plan for the 2.0 release sounds good. I've been back in isolation since that first hotkey commit so I'll aim to finish it up after the milestone release. I believe sandworm.la builds off develop so I might make some additions there that could also be post-release.

mariuszhermansdorfer commented 2 years ago

Sounds good with the sandworm.la part. The package is up for Rhino 6, 7 & 8. Could you please test whether it works with the older Kinect 2? I'm not sure I bundled everything with the gha file. image

philipbelesky commented 2 years ago

Hey, I've tested with the older Kinect and everything is looking good. I didn't do a 'fresh' install (e.g. the Kinect SDK/runtime were already setup) but the Rhino/Grasshopper side of things installed/loaded without issue

mariuszhermansdorfer commented 2 years ago

Please rebase to master and open a separate issue for discussion.

philipbelesky commented 2 years ago

Ok, I think this is ready for review whenever you had the time. Some notes:

mariuszhermansdorfer commented 2 years ago

Thanks for sending this across, @philipbelesky.

I can't get shift+standard fkey to return the f13-f24 range. Is there a Windows setting I'm missing?

To handle key events independent of whether the Rhino or the Grasshopper window is in focus, try replacing:

Grasshopper.Instances.DocumentEditor.KeyDown += new KeyEventHandler(SandwormShortcutHandler); with: Rhino.RhinoApp.KeyboardEvent += new Rhino.RhinoApp.KeyboardHookEvent(RhinoShortcutHandler);

The handler itself would look like this. Here I'm listening for the A key:

private void RhinoShortcutHandler(int key)
  {
    switch (key)
    {
      case 65:
        Rhino.RhinoApp.WriteLine("A");
        break;

      default:
        break;
    }
  }

EDIT: I believe this event is raised both on KeyDown and KeyUp, so we'd need some logic to prevent it from firing twice.

Also, make sure to remove the event handler to prevent them from accumulating over multiple loads while switching between windows:

Rhino.RhinoApp.KeyboardEvent -= new Rhino.RhinoApp.KeyboardHookEvent(RhinoShortcutHandler);
Rhino.RhinoApp.KeyboardEvent += new Rhino.RhinoApp.KeyboardHookEvent(RhinoShortcutHandler);

Other than that it's great!. As a side note, while recently recording a Sandworm video tutorial I totally felt your pain of not having a keyboard-driven UI implemented yet!

philipbelesky commented 2 years ago

To handle key events independent of whether the Rhino or the Grasshopper window is in focus, try replacing:

Thanks for the updated methods for handling the keypress in Rhino! As mentioned, the KeyboardHookEvent seems to fire on both KeyDown and KeyUp. It also seems to trigger repeatedly while the key is held - even if the press time is very brief. On a keypad that should nominally send key combos simultaneously/instantly, I was seeing usually at least 2 or 3 hits to the function.

As far as I can tell KeyboardHookEvent method doesn't expose any other parameters other than the key identifier. Without any idea about the state of the keypress, I instead implemented a relatively crude keypress de-duplication/debouncing approach. It basically logs the last time a particular key identifier was pressed and only proceeds to activate the function if it has been longer than a few hundred milliseconds.

I can't get shift+standard fkey to return the f13-f24 range. Is there a Windows setting I'm missing?

Hmm, I'm not sure was going on here but I can't replicate it on one computer either. Instead, I've added the SHIFT modifier detection into the function described above and remapped the function keys to use F2-F12. (Shift+F1 was already a shortcut).

Also, make sure to remove the event handler to prevent them from accumulating over multiple loads while switching between windows:

Done! (assuming the removal takes place immediately before in AddedToDocument()).

philipbelesky commented 2 years ago

I've tested the above with both a macropad (which has, e.g., just one button to do SHIFT+F3) and just using a normal keyboard to do the SHIFT+F3 chord normally. I also added in a Rhino log-line whenever an activation happens - this might be useful to help users remember each key combination? Or as a way to explain what/why has happened if the keys are triggered accidentally?

Anyway, let me know if you have any problems with it or additional suggestions!