What manufacturers do not come up with to attract the attention of buyers, especially in the segment of games and entertainment. Keyboards and mice have evolved from an input device into a work of art or a showpiece of high technology, striking in their appearance or technical capabilities. But we will talk about a programming technique that will significantly improve the convenience of working with any program.

Hot keys is a combination of keystrokes keys on the keyboard that perform certain actions. 

Most users love the mouse so much that they don’t even realize that all the operations that they do with this convenient manipulator can be performed using the keyboard. And if we are talking about entering textual information, then it is better to put the mouse aside.

In My Visual Database, key table operations (adding, editing, and deleting records) are usually implemented by programming buttons that the user has to click on with the mouse. The standard version with the keyboard is even worse – you need to press the Tab key several times to move the focus to the button, and then press the Enter key. Therefore, to increase the speed of data entry, it is necessary to add a hotkey mechanism to the program.

Theory

In the Windows operating system, interaction between the user and the program proceeds through events: each keystroke, mouse movement, or rotation of the mouse buttons causes a message to be sent about the user’s action.

Essentially, message passing is implemented as a call to a message handling method: the message is first passed to the form, but it is processed according to the component layout hierarchy. It first goes to those elements that have the input focus (for keyboard messages) or which are located on top of other elements (for mouse messages). If a component receives a message, then it is usually destroyed and no longer gets to other components standing in the message processing queue.

In addition to a pre-programmed reaction to a message, the component can itself create events, for processing which the programmer writes a special procedure – an event handler. In fact, the entire program is a set of handlers for such events. Even the code that is in the main begin end block can be considered as an event handler that occurs when the program starts.

The mechanism of action of hotkeys is based on the ability to change the sequence of processing the queue of messages from the keyboard: when you set the form property KeyPreview = True, such messages first start arriving to the form, regardless of where the input focus is now. Thus, by writing a keypress handler for a form and enabling the KeyPreview mechanism, you can create a hotkey system within a single form. In the case of ClassExplorer, you need to add such a handler to the frmMain form and process keyboard keystrokes: press buttons in the interface or call main menu items.

Practice

As always, we will keep our code as abstract as possible so that it can be easily reused in other applications. We will use arrays to store the settings, and the Hotkey_Init() procedure to initialize them.

const
  HOTKEY_COUNT = 4; // number of hotkeys

var
  HotKey_Code: array of bytes; // virtual code
  HotKey_Shift: array of boolean; // Shift press flag
  HotKey_Alt: array of boolean; // Alt press flag
  HotKey_Ctrl: array of boolean; // Ctrl press flag
  HotKey_Command: array of string; // executed command: name of the button or menu item
Code language: Delphi (delphi)

Initialization looks cumbersome, perhaps in the future it will be performed from the database. Probably in the future you may need several processing options for different forms, but for now this is enough:

procedure Hotkey_Init(Sender:TObject);
// connection to the form
// Sender - the form for which the hotkey system is connected
var
  tmpForm:TAForm;
  i:integer;
begin
  tmpForm := TAForm(Sender);
  tmpForm.KeyPreview := True;
  AssignEvents(tmpForm);
  tmpForm.dbOnKeyDown := 'Hotkey_OnKeyDown';
  // array initialization
  SetLength(HotKey_Code, HOTKEY_COUNT);
  SetLength(HotKey_Shift,HOTKEY_COUNT);
  SetLength(HotKey_Alt,HOTKEY_COUNT);
  SetLength(HotKey_Ctrl,HOTKEY_COUNT);
  SetLength(HotKey_Command, HOTKEY_COUNT);
  // setup hotkeys
  i := 0;
  // add new entry
  HotKey_Code[i] := VK_F2;
  HotKey_Shift[i] := False;
  HotKey_Alt[i] := False;
  HotKey_Ctrl[i] := False;
  HotKey_Command[i] := 'btnNew';
  inc(i);
  // edit entry
  HotKey_Code[i] := VK_F4;
  HotKey_Shift[i] := False;
  HotKey_Alt[i] := False;
  HotKey_Ctrl[i] := False;
  HotKey_Command[i] := 'btnEdit';
  inc(i);
  // delete entry
  HotKey_Code[i] := VK_F8;
  HotKey_Shift[i] := False;
  HotKey_Alt[i] := False;
  HotKey_Ctrl[i] := False;
  HotKey_Command[i] := 'btnDelete';
  inc(i);
  // show "About" window
  HotKey_Code[i] := VK_F11;
  HotKey_Shift[i] := False;
  HotKey_Alt[i] := False;
  HotKey_Ctrl[i] := False;
  HotKey_Command[i] := 'mniAbout';
  inc(i);
  //
end;Code language: Delphi (delphi)

And finally, the click handler itself is Hotkey_OnKeyDown(). Please note that for searching in the menu, the global variable MainForm is used, which stores a link to the main form of the application. The main one in the sense that it contains the system menu and service components of My Visual Database. If in the future you need to search in the menu that was created for the form to which the data handler was added, then you will need to search using the value of the tmpForm variable (line 30).

procedure Hotkey_OnKeyDown(Sender: TObject; var Key: Word; Shift, Alt, Ctrl: boolean);
// handle hotkeys
var
  tmpForm:TForm;
  tmpButton: TdbButton;
  tmpName:string;
  tmpComponent: TComponent;
  i:integer;
begin
  tmpForm := TForm(Sender);
  tmpName := '';
  for i := 0 to HOTKEY_COUNT-1 do
  begin
    // match found
    if (Key = HotKey_Code[i]) and (Shift =HotKey_Shift[i]) and (Alt = HotKey_Alt[i]) and (Ctrl = HotKey_Ctrl[i]) then
    begin
      tmpName := HotKey_Command[i];
      // looking for a button
      FindC(tmpForm,tmpName,tmpComponent,False);
      if tmpComponent <> nil then
      begin
        if tmpComponent is TdbButton then
          TdbButton(tmpComponent).Click
        else
        if tmpComponent is TMenuItem then
          TMenuItem(tmpComponent).Click
      end
      else // search in the main menu...
      begin
        FindC(MainForm,tmpName,tmpComponent,False);
        if tmpComponent <> nil then
        begin
          if tmpComponent is TMenuItem then
            TMenuItem(tmpComponent).Click
        end
      end;
      break;
    end;
  end;
end;
Code language: Delphi (delphi)

For the system to work, you need to call the procedure Hotkey_Init() when initializing the application:

procedure frmMain_OnShow(Sender: TObject; Action: string);
// display the main form
begin
  CE_Init(MainForm); // the main menu is on the main form, but is displayed where necessary
  Hotkey_Init(Sender); // enable hotkeys
  UserApp_InitBase; // database initialization
  frmMain.pgcMain.ActivePage := frmMain.tshNavigation; // open the "Navigation" tab
  frmMain.pgcNavigation.ActivePage := frmMain.tshTask; // open the "Tasks" tab
end;
Code language: Delphi (delphi)

Links

Leave a Reply

Your email address will not be published. Required fields are marked *