How do I add the key binding Shift+Ctrl+H X to the Delphi IDE using the ToolsApi?

853 views Asked by At

Adding a new ShortCut to the Delphi IDE is not too difficult because the Open Tools API provides a service for this. I am trying something apparently more complex: Add a Wordstar like additional ShortCut:

I want something to happen when the user presses

Shift+Ctrl+H followed by the single key X

where X should work regardless of the state of the Shift key.

This is my code:

procedure TGxKeyboardBinding.BindKeyboard(const BindingServices: IOTAKeyBindingServices);
const
  DefaultKeyBindingsFlag = kfImplicitShift + kfImplicitModifier + kfImplicitKeypad;
var
  GExpertsShortcut: Byte;
  ShiftState: TShiftState;
  FirstShortCut: TShortCut;
  SecondShortCut: TShortCut;
begin
  GExpertsShortcut := Ord('H');
  ShiftState := [ssShift, ssCtrl];
  FirstShortCut := ShortCut(GExpertsShortcut, ShiftState);
  SecondShortCut := ShortCut(Ord('X'), []);
  BindingServices.AddKeyBinding([FirstShortCut, SecondShortCut],
    TwoKeyBindingHandler, nil,
    DefaultKeyBindingsFlag, '', '');
end;

So, if I set ShiftState := [ssCtrl] pressing

Ctrl+H X

calls my TwoKeyBindingHandler method.

But with ShiftState := [ssShift, ssCtrl] pressing

Shift+Ctrl+H X

does nothing.

Oddly enough, when specifying ShiftState := [ssShift, ssCtrl] (which should only affect the first key) pressing

Shift+Ctrl+H Shift+X

calls my TwoKeyBindingHandler method, even though the second ShortCut is added without a modifier key.

Any idea? Is this maybe a known limitation/bug of the Delphi IDE/Open Tools API? Is there a known workaround?

I tried it in Delphi 2007 and Delphi 10 Seattle, no difference.

2

There are 2 answers

3
Helen Fairgrieve On

You should be able to do it using the GetKeyState function.

The program has two operations - Think of it as opening a drop down menu item. When ctr-shift-h is pressed your programme will need to flag that the 'Menu' is now open and that subsequent keypresses will either activate an option or close the 'menu' if an invalid key is presses.

function IsKeyDown(const VK: integer): boolean;
begin
  IsKeyDown := GetKeyState(VK) and $8000 <> 0;
end;

procedure Form1.OnkeyDown(...)   
begin
 if Not H_MenuOpen then 
 if IsKeyDown(vk_Control) and IskeyDown(vk_Shift) and IsKeyDown(vk_H) then
 begin
      //Some Boolean in the form
      H_MenuOpen:=True;
      //Will probably need to invalidate some parameters here so that 
      //no control tries to process the key
      exit;
 end;

 if H_MenuOpen then
 begin
      if key=vk_X then 
      begin
          //x has been pressed
          *Your code here* 
          //possibly invalidate some of the params again
          exit;
      end;
     //Nothing valid
    H_MenuOpen:=False;
 end;

end;

0
dummzeuch On

OK, since apparently nobody has found an answer, here is what I ended up doing:

I had already planned to show a hint window listing all possible characters for the second key (actually that code was already working fine, using the approach suggested by Helen Fairgrieve in her answer to this question). Instead, I now register only a one-key shortcut:

BindingServices.AddKeyBinding([FirstShortCut],
  TwoKeyBindingHandler, nil,
  DefaultKeyBindingsFlag, '', '');

And in the TwoKeyBindingHandler method, I show a popup menu which contains those characters as the shortcuts. The IDE/VCL/Windows then handles the rest for me.

This is what it looks like: animated GIF with the result

It's not an answer to the actual question but it solves my problem. Sorry if you got here expecting something more.