Search code examples
windowsinno-setupshortcut-file

Allow users choose hotkeys for icon/shortcut in Inno Setup


I'm looking to allow users, who run an installer made trough Inno Setup, to choose whether to use hot keys or not, and if yes, allow them to choose which hot keys use.

[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}";  \
    HotKey: "ctrl+alt+b"

Name: "{autoprograms}\{#MyAppName2}"; Filename: "{app}\{#MyAppExeName2}"; \
    HotKey: "ctrl+alt+x"

This is my [Icons] section


Solution

  • The Icons section HotKey parameter cannot be modified at run time. So you will have to create the whole shortcut programmatically. An easy API that allows creating a shortcut with a hot key is WScript.Shell.CreateShortcut.

    [Code]
    var
      App1HotKeyCombo: TNewComboBox;
      App2HotKeyCombo: TNewComboBox;
    
    const
      NoneHotKey = 'None';
    
    procedure InitializeWizard();
    var
      HotKeysPage: TWizardPage;
      ALabel: TNewStaticText;
    begin
      Log('InitializeWizard');
      HotKeysPage := CreateCustomPage(wpSelectTasks, 'Select your hot keys', '');
    
      App1HotKeyCombo := TNewComboBox.Create(HotKeysPage);
      App1HotKeyCombo.Parent := HotKeysPage.Surface;
      App1HotKeyCombo.Left := ScaleX(200);
      App1HotKeyCombo.Top := 0;
      App1HotKeyCombo.Width := ScaleX(100);
      App1HotKeyCombo.Style := csDropDownList;
      App1HotKeyCombo.Items.Add(NoneHotKey);
      App1HotKeyCombo.Items.Add('Ctrl+Alt+A');
      App1HotKeyCombo.Items.Add('Ctrl+Alt+B');
      App1HotKeyCombo.Items.Add('Ctrl+Alt+C');
      App1HotKeyCombo.ItemIndex := 1;
      ALabel := TNewStaticText.Create(HotKeysPage);
      ALabel.Parent := HotKeysPage.Surface;
      ALabel.Top := App1HotKeyCombo.Top + ScaleY(4);
      ALabel.Left := 0;
      ALabel.Caption := 'Hot key for application 1:';
      ALabel.FocusControl := App1HotKeyCombo;
    
      App2HotKeyCombo := TNewComboBox.Create(HotKeysPage);
      App2HotKeyCombo.Parent := HotKeysPage.Surface;
      App2HotKeyCombo.Left := App1HotKeyCombo.Left;
      App2HotKeyCombo.Top := App1HotKeyCombo.Top + App1HotKeyCombo.Height + ScaleY(8);
      App2HotKeyCombo.Width := App1HotKeyCombo.Width;
      App2HotKeyCombo.Style := csDropDownList;
      App2HotKeyCombo.Items.Assign(App1HotKeyCombo.Items);
      App2HotKeyCombo.ItemIndex := 2;
      ALabel := TNewStaticText.Create(HotKeysPage);
      ALabel.Parent := HotKeysPage.Surface;
      ALabel.Top := App2HotKeyCombo.Top + ScaleY(4);
      ALabel.Left := 0;
      ALabel.Caption := 'Hot key for application 2:';
      ALabel.FocusControl := App2HotKeyCombo;
    end;
    
    procedure CreateShortCut(IconName, Path: string; AppHotKeyCombo: TNewComboBox);
    var
      WshShell: Variant;
      ShellLink: Variant;
      Msg: string;
    begin
      WshShell := CreateOleObject('WScript.Shell');
      IconName := ExpandConstant(IconName) + '.lnk';
      ShellLink := WshShell.CreateShortcut(IconName)
      ShellLink.TargetPath := ExpandConstant(Path);
      ShellLink.WindowStyle := SW_SHOWNORMAL;
      if AppHotKeyCombo.Text <> NoneHotKey then
        ShellLink.Hotkey := AppHotKeyCombo.Text;
      ShellLink.Save;
      Msg := 'Created "%s" icon pointing to "%s" with "%s" hotkey';
      Log(Format(Msg, [IconName, ShellLink.TargetPath, ShellLink.Hotkey]));
    end;
    
    procedure CurStepChanged(CurStep: TSetupStep);
    begin
      if CurStep = ssInstall then
      begin
        CreateShortCut('{autoprograms}\MyProg1', '{app}\MyProg.exe', App1HotKeyCombo);
        CreateShortCut('{autoprograms}\MyProg2', '{app}\MyProg.exe', App2HotKeyCombo);
      end;
    end;
    

    enter image description here


    A more robust API, is IShellLink. That's what Inno Setup uses internally. Though it requires considerably alot more code. For some examples, see Check for existence of a shortcut pointing to a specific target in Inno Setup.


    You will also have to ensure that the shortcuts get deleted on uninstall. You can use UninstallDelete section for that.


    If you do not want to code the shortcut creation, an alternative approach would be to use preprocessor to generate separate [Icons] entry for each shortcut you want to offer and use Check parameters to activate only the entry corresponding to the shortcut the user selects.