home *** CD-ROM | disk | FTP | other *** search
/ PC World 1999 February / PCWorld_1999-02_cd.bin / temacd / HotKeys / hkEdit.pas < prev    next >
Pascal/Delphi Source File  |  1998-11-03  |  47KB  |  1,487 lines

  1. unit hkEdit;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   ComCtrls, StdCtrls, WComp, SysHot, ShellAPI, AniTray, Menus, ExtCtrls, IniFiles,
  8.   Buttons, BrowseEdit, hkClpbrd;
  9.  
  10. const
  11.   WM_EDITKEYS = WM_USER+2001;
  12.   WM_SENDKEYS = WM_USER+2002;
  13.   WM_MULTKEYS = WM_USER+2003;
  14.   WM_QUITHOTK = WM_USER+2004;
  15.  
  16. type
  17.   TfrmHotkeyEdit = class(TForm)
  18.     lvHotkeys: TListView;
  19.     SysHotkeys: TSysHotKey;
  20.     ppmTrayMenu: TPopupMenu;
  21.     mnuEditHotkeys: TMenuItem;
  22.     mnuAbout: TMenuItem;
  23.     mnuSeparator2: TMenuItem;
  24.     mnuExit: TMenuItem;
  25.     atiHotkeys: TAnimatedTrayIcon;
  26.     pnlControls: TPanel;
  27.     pnlEdit: TPanel;
  28.     pnlButtons: TPanel;
  29.     btnNew: TButton;
  30.     btnDelete: TButton;
  31.     btnApply: TButton;
  32.     btnClose: TButton;
  33.     grpHotkey: TGroupBox;
  34.     lblDescription: TLabel;
  35.     lblCommandLine: TLabel;
  36.     lblHotkey: TLabel;
  37.     edtDescription: TEdit;
  38.     chkCtrl: TCheckBox;
  39.     chkAlt: TCheckBox;
  40.     chkShift: TCheckBox;
  41.     chkWin: TCheckBox;
  42.     cboHotkey: TComboBox;
  43.     chkActive: TCheckBox;
  44.     mnuListHotkeys: TMenuItem;
  45.     pnlOptions: TPanel;
  46.     chkShowIcon: TCheckBox;
  47.     mnuSeparator1: TMenuItem;
  48.     mnuHotkeys: TMenuItem;
  49.     lblAction: TLabel;
  50.     cboActions: TComboBox;
  51.     edtCommandLine: TBrowseEdit;
  52.     cboParams: TComboBox;
  53.     mnuHelp: TMenuItem;
  54.     mnuSeparator0: TMenuItem;
  55.     edtKeysToSend: TEdit;
  56.     opdOpenFile: TOpenDialog;
  57.     edtID: TEdit;
  58.     lblID: TLabel;
  59.     lblShow: TLabel;
  60.     cboShow: TComboBox;
  61.     cboClipboard: TComboBox;
  62.     lblClipboards: TLabel;
  63.     edtClipboards: TEdit;
  64.     udClipboards: TUpDown;
  65.     imgIcon: TImage;
  66.     procedure btnNewClick(Sender: TObject);
  67.     procedure chkActiveClick(Sender: TObject);
  68.     procedure edtDescriptionChange(Sender: TObject);
  69.     procedure edtCommandLineChange(Sender: TObject);
  70.     procedure edtCommandLineButtonClick(Sender: TObject);
  71.     procedure edtCommandLineExit(Sender: TObject);
  72.     procedure chkCtrlClick(Sender: TObject);
  73.     procedure FormCreate(Sender: TObject);
  74.     procedure lvHotkeysClick(Sender: TObject);
  75.     procedure btnDeleteClick(Sender: TObject);
  76.     procedure btnCloseClick(Sender: TObject);
  77.     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  78.     procedure SysHotkeysHotKey(Sender: TObject; Index: Integer);
  79.     procedure FormDestroy(Sender: TObject);
  80.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  81.     procedure mnuEditHotkeysClick(Sender: TObject);
  82.     procedure mnuExitClick(Sender: TObject);
  83.     procedure btnApplyClick(Sender: TObject);
  84.     procedure FormResize(Sender: TObject);
  85.     procedure atiHotkeysEndAnimation(Sender: TObject);
  86.     procedure mnuAboutClick(Sender: TObject);
  87.     procedure mnuListHotkeysClick(Sender: TObject);
  88.     procedure chkShowIconClick(Sender: TObject);
  89.     procedure FormKeyDown(Sender: TObject; var Key: Word;
  90.       Shift: TShiftState);
  91.     procedure cboActionsClick(Sender: TObject);
  92.     procedure cboParamsClick(Sender: TObject);
  93.     procedure edtKeysToSendChange(Sender: TObject);
  94.     procedure mnuHelpClick(Sender: TObject);
  95.     procedure edtIDChange(Sender: TObject);
  96.     procedure edtIDExit(Sender: TObject);
  97.     procedure edtDescriptionExit(Sender: TObject);
  98.     procedure lvHotkeysChange(Sender: TObject; Item: TListItem;
  99.       Change: TItemChange);
  100.     procedure cboShowClick(Sender: TObject);
  101.     procedure cboClipboardClick(Sender: TObject);
  102.     procedure edtClipboardsExit(Sender: TObject);
  103.     procedure edtClipboardsChange(Sender: TObject);
  104.   private
  105.     FChanged        : Boolean;
  106.     Quitting, Ignore: Boolean;
  107.     CurModifiers    : THKModifiers;
  108.     CurVirtKey      : TVirtKey;
  109.     CommandLines    : TStringList;
  110.     WindowList      : TList;
  111.     Clipboards      : TClipboards;
  112.     hwndClipViewer  : hWnd;
  113.     procedure Quit;
  114.     procedure SetChanged(Value: Boolean);
  115.     function  WindowAnimation(Value: Integer): Integer;
  116.     function  HotkeyOK(sHotkey: String): Boolean;
  117.     procedure MultipleHotkeys(Command: String);
  118.     function  GetDelay(var Sel: String): Integer;
  119.     function  WindowsVersion: DWord;
  120.     procedure ExitWindowsCommand(Command: Integer);
  121.     procedure PerformAction(Action: Integer; Command: String; Index: Integer; Immediate: Boolean);
  122.     function  NextItem(var Commands: String): String;
  123.     procedure SetControls;
  124.     procedure ExecProgram(Command: String);
  125.     procedure SetClipboards;
  126.     procedure SwitchToClipboard(Index: Integer);
  127.     procedure DrawClipOnBmp(IcoBmp: TBitmap; sText: String);
  128.     procedure DrawClipboardStatus(Index: Integer);
  129.   protected
  130.     property IsChanged: Boolean read FChanged write SetChanged;
  131.     procedure EditHotkeys;
  132.     procedure ViewHotkeys;
  133.     procedure AboutBox;
  134.     procedure HelpIndex;
  135.     procedure MinimizeAll;
  136.     procedure UndoMinimize;
  137.     function  VirtKey(sHotkey: String): TVirtKey;
  138.     function  Modifiers(sHotkey: String): THKModifiers;
  139.     procedure AddTo(var sKey: String; Value: String);
  140.     procedure SetItem;
  141.     procedure GetHotkey;
  142.     procedure SetHotkey;
  143.     procedure ReadHotkeys;
  144.     procedure SaveHotkeys;
  145.     procedure LoadHotkeys;
  146.     procedure wmGetMinMaxInfo(var Msg: TWMGETMINMAXINFO); message WM_GETMINMAXINFO;
  147.     procedure wmDrawClipboard(var Msg: TMessage); message WM_DRAWCLIPBOARD;
  148.     procedure wmChangeCBChain(var Msg: TMessage); message WM_CHANGECBCHAIN;
  149.     procedure wmEditKeys(var Msg: TMessage); message WM_EDITKEYS;
  150.     procedure wmSendKeys(var Msg: TMessage); message WM_SENDKEYS;
  151.     procedure wmMultKeys(var Msg: TMessage); message WM_MULTKEYS;
  152.     procedure wmQuitHotK(var Msg: TMessage); message WM_QUITHOTK;
  153.   public
  154.     Item: TListItem;
  155.     function  ReadHotkey(Reader: TReader): String;
  156.     procedure HotkeyMenuClick(Sender: TObject);
  157.     procedure HotkeyPressed(Index: Integer);
  158.   end;
  159.  
  160. function MakeID(ListView: TListView; CurItem: TListItem; Command: String): String;
  161.  
  162. var
  163.   frmHotkeyEdit: TfrmHotkeyEdit;
  164.  
  165. const
  166.   ITEM_ID     = 0;
  167.   ITEM_ACTION = 1;
  168.   ITEM_DATA   = 2;
  169.   ITEM_HOTKEY = 3;
  170.   ITEM_ACTIVE = 4;
  171.   ITEM_SHOW   = 5;
  172.  
  173. implementation
  174.  
  175. {$R *.DFM}
  176.  
  177. uses hkAbout, hkList, hkError, hkSend, hkSelect;
  178.  
  179. const
  180.   Actives  : array[Boolean] of string = ('False', 'True');
  181.  
  182.   Params   : array[0..5] of String  = ('Shutdown', 'Log off', 'Reboot System', 'Restart Windows', 'Exit to DOS', 'Suspend');
  183.  
  184.   Actions  : array[0..10] of String = ('Execute Program',   'Send keystrokes',
  185.                                        'Execute Multiple Commands',
  186.                                        'Exit Windows',      'Edit Hotkeys',
  187.                                        'View Hotkeys',      'Display About Box',
  188.                                        'Hotkeys Help',      'Minimize All Windows',
  189.                                        'Undo Minimize All', 'Switch To Virtual Clipboard');
  190.  
  191. function MakeAlfa(Command: String): String;
  192. begin
  193.   Result := '';
  194.   while (Length(Result)<4) and (Command<>'') do
  195.    begin
  196.      if Command[1] in ['A'..'Z', 'a'..'z', '0'..'9'] then Result := Result + UpCase(Command[1]);
  197.      Delete(Command, 1, 1);
  198.    end;
  199. end;
  200.  
  201. function MakeID(ListView: TListView; CurItem: TListItem; Command: String): String;
  202. var
  203.   i, Counter : integer;
  204.   sCounter   : String;
  205.   Found: Boolean;
  206. begin
  207.   Result := MakeAlfa(Command);
  208.   Counter := 0;
  209.   while Length(Result)<4 do Result := Result + '0';
  210.  
  211.   i := 0;
  212.   Found := False;
  213.   if ListView.Items.Count>1 then
  214.    repeat
  215.      if i=ListView.Items.Count then i := 0;
  216.      if i=0 then Found := False;
  217.      if (ListView.Items[i]<>CurItem) and (ListView.Items[i].SubItems[ITEM_ID]=Result) then
  218.       begin
  219.         inc(Counter);
  220.         sCounter := IntToStr(Counter);
  221.         Result := Copy(Result, 1, 4-Length(sCounter)) + sCounter;
  222.         Found := True;
  223.       end
  224.      else
  225.       inc(i);
  226.    until (i=ListView.Items.Count) and not Found;
  227. end;
  228.  
  229. procedure TfrmHotkeyEdit.lvHotkeysClick(Sender: TObject);
  230. begin
  231.   if lvHotkeys.Selected<>nil then
  232.    begin
  233.      Item := lvHotkeys.Selected;
  234.      grpHotkey.Caption := 'Edit hotkey';
  235.      SetItem;
  236.    end
  237.   else if Item<>nil then lvHotkeys.Selected := Item;
  238. end;
  239.  
  240. procedure TfrmHotkeyEdit.btnNewClick(Sender: TObject);
  241. begin
  242.   Item := lvHotkeys.Items.Add;
  243.   Item.SubItems.Add('');
  244.   Item.SubItems.Add(cboActions.Items[0]);
  245.   Item.SubItems.Add('');
  246.   Item.SubItems.Add('');
  247.   Item.SubItems.Add('True');
  248.   Item.SubItems.Add(cboShow.Items[0]);
  249.   grpHotkey.Caption := 'Add hotkey';
  250.   SetItem;
  251.   lvHotkeys.Selected := Item;
  252.   IsChanged := True;
  253. end;
  254.  
  255. procedure TfrmHotkeyEdit.SetItem;
  256. begin
  257.   Ignore := True;
  258.   edtDescription.Text := Item.Caption;
  259.   cboActions.ItemIndex := cboActions.Items.IndexOf(Item.SubItems[ITEM_ACTION]);
  260.   edtID.Text := Item.SubItems[ITEM_ID];
  261.   case cboActions.ItemIndex of
  262.     0, 2 : edtCommandLine.Text := Item.SubItems[ITEM_DATA];
  263.     1    : edtKeysToSend.Text := Item.SubItems[ITEM_DATA];
  264.     3    : cboParams.ItemIndex := cboParams.Items.IndexOf(Item.SubItems[ITEM_DATA]);
  265.     10   : cboClipboard.ItemIndex := cboClipboard.Items.IndexOf(Item.SubItems[ITEM_DATA]);
  266.   end;
  267.   if cboActions.ItemIndex=0 then cboShow.ItemIndex := cboShow.Items.IndexOf(Item.SubItems[ITEM_SHOW]);
  268.   SetControls;
  269.   SetHotkey;
  270.   chkActive.Checked := (Item.SubItems[ITEM_ACTIVE] = 'True');
  271.   Ignore := False;
  272. end;
  273.  
  274. procedure TfrmHotkeyEdit.chkActiveClick(Sender: TObject);
  275. begin
  276.   if (Item<>nil) and not Ignore then
  277.    begin
  278.      if chkActive.Checked then Item.SubItems[ITEM_ACTIVE] := 'True' else Item.SubItems[ITEM_ACTIVE] := 'False';
  279.      IsChanged := True;
  280.    end;
  281. end;
  282.  
  283. procedure TfrmHotkeyEdit.edtDescriptionChange(Sender: TObject);
  284. begin
  285.   if (Item<>nil) and not Ignore then
  286.    begin
  287.      Item.Caption := edtDescription.Text;
  288.      IsChanged := True;
  289.    end;
  290. end;
  291.  
  292. procedure TfrmHotkeyEdit.edtCommandLineChange(Sender: TObject);
  293. begin
  294.   if (Item<>nil) and not Ignore then
  295.    begin
  296.      Item.SubItems[ITEM_DATA] := edtCommandLine.Text;
  297.      IsChanged := True;
  298.    end;
  299. end;
  300.  
  301. procedure TfrmHotkeyEdit.chkCtrlClick(Sender: TObject);
  302. begin
  303.   GetHotkey;
  304. end;
  305.  
  306. procedure TfrmHotkeyEdit.AddTo(var sKey: String; Value: String);
  307. begin
  308.   if sKey<>'' then sKey := sKey + '+';
  309.   sKey := sKey + Value;
  310. end;
  311.  
  312. function TfrmHotkeyEdit.HotkeyOK(sHotkey: String): Boolean;
  313. const
  314.   ErrorDescription = 'If you continue the hotkey combination for ''%s'' will not work.';
  315. var
  316.   i: Integer;
  317. begin
  318.   with lvHotkeys do
  319.    for i:=0 to Items.Count-1 do
  320.     if (Items[i]<>Item) and (Items[i].SubItems[ITEM_HOTKEY]=sHotkey) and (Items[i].SubItems[ITEM_ACTIVE]='True') then
  321.      with frmHotkeyError do
  322.       begin
  323.         ConflictingEntry := Items[i].Caption;
  324.         if Items[i].Index<Item.Index then
  325.          Description := Format(ErrorDescription, [Items[i].Caption])
  326.         else
  327.          Description := Format(ErrorDescription, [Item.Caption]);
  328.         Result := ShowModal = mrOk;
  329.         Exit;
  330.       end;
  331.   if not SysHotkeys.AddHotkey(Virtkey(sHotkey), Modifiers(sHotkey)).Registered then
  332.    begin
  333.      MessageBox(Handle, 'This hotkey combination is in use by another application.', 'Hotkey combination error', MB_ICONINFORMATION or MB_OK);
  334.      Result := False;
  335.    end
  336.   else
  337.    Result := True;
  338.   SysHotkeys.Delete(SysHotkeys.HotkeyCount-1);
  339. end;
  340.  
  341. procedure TfrmHotkeyEdit.GetHotkey;
  342. var
  343.   sHotkey: String;
  344. begin
  345.   sHotkey := '';
  346.   if (Item<>nil) and not Ignore then
  347.    begin
  348.      if chkCtrl.Checked then AddTo(sHotkey, 'Ctrl');
  349.      if chkAlt.Checked then AddTo(sHotkey, 'Alt');
  350.      if chkShift.Checked then AddTo(sHotkey, 'Shift');
  351.      if chkWin.Checked then AddTo(sHotkey, 'Win');
  352.      AddTo(sHotkey, cboHotkey.Items[cboHotkey.ItemIndex]);
  353.      if HotkeyOk(sHotkey) then
  354.       begin
  355.         Item.SubItems[ITEM_HOTKEY] := sHotkey;
  356.         IsChanged := True;
  357.       end
  358.      else
  359.       SetHotkey;
  360.    end;
  361.  
  362. end;
  363.  
  364. procedure TfrmHotkeyEdit.SetHotkey;
  365. var
  366.   sHotkey: String;
  367. begin
  368.   if Item<>nil then
  369.    begin
  370.      sHotkey := Item.SubItems[ITEM_HOTKEY];
  371.      CurVirtkey   := VirtKey(sHotkey);
  372.      CurModifiers := Modifiers(sHotkey);
  373.      chkCtrl.Checked := Pos('Ctrl', sHotkey)>0;
  374.      chkAlt.Checked := Pos('Alt', sHotkey)>0;
  375.      chkShift.Checked := Pos('Shift', sHotkey)>0;
  376.      chkWin.Checked := Pos('Win', sHotkey)>0;
  377.      while Pos('+', sHotkey)>0 do Delete(sHotkey, 1, Pos('+', sHotkey));
  378.      if sHotkey<>'' then
  379.       cboHotkey.ItemIndex := cboHotkey.Items.IndexOf(sHotkey)
  380.      else
  381.       cboHotkey.ItemIndex := -1;
  382.    end;
  383. end;
  384.  
  385. procedure TfrmHotkeyEdit.FormCreate(Sender: TObject);
  386. var
  387.   i      : integer;
  388.   IniFile: String;
  389. begin
  390.   Application.ShowMainForm := False;
  391.   if FindWindow('Shell_TrayWnd', nil)=0 then WindowState := wsMinimized;
  392.   atiHotkeys.HideAppIcon;
  393.  
  394.   for i:= Low(Actions) to High(Actions) do cboActions.Items.Add(Actions[i]);
  395.   for i:= Low(Params) to High(Params) do cboParams.Items.Add(Params[i]);
  396.  
  397.   cboParams.ItemIndex := 0;
  398.   Quitting := False;
  399.   Ignore := False;
  400.   cboShow.ItemIndex := 0;
  401.   Clipboards := TClipboards.Create;
  402.   hwndClipViewer := SetClipboardViewer(Handle);
  403.  
  404.   CommandLines := TStringList.Create;
  405.  
  406.   WindowList := TList.Create;
  407.   IniFile := ChangeFileExt(Application.ExeName, '.ini');
  408.   WindowState := wsNormal;
  409.   with TInifile.Create(IniFile) do
  410.    begin
  411.      chkShowIcon.Checked := ReadInteger('Settings', 'ShowTaskbarIcon', 1)=1;
  412.      chkShowIconClick(Self);
  413.      Ignore := True;
  414.      udClipboards.Position := ReadInteger('Settings', 'ClipboardCount', 5);
  415.      edtClipboards.Text := IntToStr(udClipboards.Position);
  416.      Ignore := False;
  417.      Width := ReadInteger('EditorWindow', 'Width', Width);
  418.      Height := ReadInteger('EditorWindow', 'Height',  Height);
  419.      for i:=0 to lvHotkeys.Columns.Count-1 do
  420.       with lvHotkeys.Columns[i] do
  421.        Width := ReadInteger('EWColumns', Caption, Width);
  422.      Free;
  423.    end;
  424.   SetClipboards;
  425.   SwitchToClipboard(0);
  426.   ReadHotkeys;
  427.   LoadHotkeys;
  428. end;
  429.  
  430. procedure TfrmHotkeyEdit.SetClipboards;
  431. var
  432.   sClip: String;
  433.   i    : integer;
  434. begin
  435.   Clipboards.NumClipboards := udClipboards.Position;
  436.   sClip := cboClipboard.Text;
  437.   cboClipboard.Clear;
  438.   for i:=1 to Clipboards.NumClipboards do cboClipboard.Items.Add(IntToStr(i));
  439.   cboClipboard.ItemIndex := cboClipboard.Items.IndexOf(sClip);
  440.   if cboClipboard.ItemIndex=-1 then cboClipboard.ItemIndex := 0;
  441. end;
  442.  
  443. function TfrmHotkeyEdit.ReadHotkey(Reader: TReader): String;
  444. begin
  445.   Result := '';
  446.   if Reader.ReadBoolean then AddTo(Result, 'Ctrl');
  447.   if Reader.ReadBoolean then AddTo(Result, 'Alt');
  448.   if Reader.ReadBoolean then AddTo(Result, 'Shift');
  449.   if Reader.ReadBoolean then AddTo(Result, 'Win');
  450.   AddTo(Result, cboHotKey.Items[Reader.ReadInteger]);
  451. end;
  452.  
  453. procedure TfrmHotkeyEdit.ReadHotkeys;
  454. var
  455.   Stream   : TFileStream;
  456.   Reader   : TReader;
  457.   sVersion : String;
  458.   iVersion : Integer;
  459.   Action,
  460.   Index    : Integer;
  461. begin
  462.   if Item<>nil then Index := Item.Index else Index := 0;
  463.   lvHotkeys.Items.BeginUpdate;
  464.   try
  465.     Stream := TFileStream.Create(ChangeFileExt(Application.ExeName, '.HKD'), fmOpenRead);
  466.     try
  467.       Reader := TReader.Create(Stream, 4096);
  468.       try
  469.         lvHotkeys.Items.Clear;
  470.         sVersion := Reader.ReadString;
  471.         iVersion := 120;
  472.         if sVersion = 'Hotkey definitions, version 1.0' then iVersion := 100;
  473.         if sVersion = 'Hotkey definitions, version 1.05' then iVersion := 105;
  474.         Reader.ReadListBegin;
  475.         while not Reader.EndOfList do
  476.          begin
  477.            Item := lvHotkeys.Items.Add;
  478.            Item.Caption := Reader.ReadString;
  479.            if iVersion=100 then Item.SubItems.Add(MakeID(lvHotkeys, Item, Item.Caption)) else Item.SubItems.Add(Reader.ReadString);
  480.            Action := Reader.ReadInteger;
  481.            if (iVersion=100) and (Action>1) then inc(Action);
  482.            Item.SubItems.Add(cboActions.Items[Action]);
  483.            case Action of
  484.              0, 1, 2: Item.SubItems.Add(Reader.ReadString);
  485.              3      : Item.SubItems.Add(cboParams.Items[Reader.ReadInteger]);
  486.              10     : Item.SubItems.Add(cboClipboard.Items[Reader.ReadInteger]);
  487.              else Item.SubItems.Add('');
  488.            end;
  489.            Item.SubItems.Add(ReadHotkey(Reader));
  490.            Item.SubItems.Add(Actives[Reader.ReadBoolean]);
  491.            if (Action=0) then
  492.             begin
  493.               if (iVersion=120) then
  494.                Item.SubItems.Add(Reader.ReadString)
  495.               else
  496.                Item.SubItems.Add(cboShow.Items[0]);
  497.             end;
  498.          end;
  499.         Reader.ReadListEnd;
  500.       finally
  501.         Reader.Free;
  502.       end;
  503.     finally
  504.       Stream.Free;
  505.     end;
  506.   except
  507.   end;
  508.   if lvHotkeys.Items.Count=0 then
  509.    btnNewClick(Self)
  510.   else
  511.    begin
  512.      lvHotkeys.Selected := lvHotkeys.Items[Index];
  513.      lvHotkeysClick(Self);
  514.      IsChanged := False;
  515.    end;
  516.   lvHotkeys.Items.EndUpdate;
  517. end;
  518.  
  519. procedure TfrmHotkeyEdit.SaveHotkeys;
  520. var
  521.   Stream: TFileStream;
  522.   Writer: TWriter;
  523.   i,
  524.   Index : Integer;
  525.   Hotkey: String;
  526. begin
  527.   try
  528.     Stream := TFileStream.Create(ChangeFileExt(Application.ExeName, '.HKD'), fmCreate);
  529.     try
  530.       Writer := TWriter.Create(Stream, 4096);
  531.       try
  532.         Writer.WriteString('Hotkey definitions, version 1.2');
  533.         Writer.WriteListBegin;
  534.         with lvHotkeys do
  535.          for i:=0 to Items.Count-1 do
  536.           begin
  537.             Writer.WriteString(Items[i].Caption);
  538.             Writer.WriteString(Items[i].SubItems[ITEM_ID]);
  539.             Index := cboActions.Items.IndexOf(Items[i].SubItems[ITEM_ACTION]);
  540.             Writer.WriteInteger(Index);
  541.             case Index of
  542.               0, 1, 2: Writer.WriteString(Items[i].SubItems[ITEM_DATA]);
  543.               3      : Writer.WriteInteger(cboParams.Items.IndexOf(Items[i].SubItems[ITEM_DATA]));
  544.               10     : Writer.WriteInteger(cboClipboard.Items.IndexOf(Items[i].SubItems[ITEM_DATA]));
  545.             end;
  546.             Hotkey := Items[i].SubItems[ITEM_HOTKEY];
  547.             Writer.WriteBoolean(Pos('Ctrl',  Hotkey)>0);
  548.             Writer.WriteBoolean(Pos('Alt',   Hotkey)>0);
  549.             Writer.WriteBoolean(Pos('Shift', Hotkey)>0);
  550.             Writer.WriteBoolean(Pos('Win',   Hotkey)>0);
  551.             while Pos('+', Hotkey)>0 do Delete(Hotkey, 1, Pos('+', Hotkey));
  552.             Writer.WriteInteger(cboHotkey.Items.IndexOf(Hotkey));
  553.             Writer.WriteBoolean(Items[i].SubItems[ITEM_ACTIVE]=Actives[True]);
  554.             if (Index=0) then Writer.WriteString(Items[i].SubItems[ITEM_SHOW]);
  555.           end;
  556.         Writer.WriteListEnd;
  557.       finally
  558.         Writer.Free;
  559.       end;
  560.     finally
  561.       Stream.Free;
  562.     end;
  563.   except
  564.   end;
  565.   IsChanged := False;
  566.   LoadHotkeys;
  567.   if Assigned(frmHotkeyList) and (frmHotkeyList.Visible) then frmHotkeyList.ReadHotkeys;
  568. end;
  569.  
  570. procedure TfrmHotkeyEdit.btnDeleteClick(Sender: TObject);
  571. begin
  572.   if Item<>nil then
  573.    begin
  574.      Item.Free;
  575.      if lvHotkeys.Items.Count>0 then
  576.       begin
  577.         lvHotkeys.Selected := lvHotkeys.Items[0];
  578.         lvHotkeysClick(Self);
  579.         IsChanged := True;
  580.       end
  581.      else
  582.       btnNewClick(Self);
  583.   end;
  584. end;
  585.  
  586. procedure TfrmHotkeyEdit.btnCloseClick(Sender: TObject);
  587. begin
  588.   Close;
  589. end;
  590.  
  591. procedure TfrmHotkeyEdit.FormCloseQuery(Sender: TObject;
  592.   var CanClose: Boolean);
  593. begin
  594.   if IsChanged then
  595.    case Application.MessageBox('Hotkey definitions have changed. Save changes?', 'Hotkey Editor', MB_ICONQUESTION or MB_YESNOCANCEL) of
  596.     IDYES: SaveHotkeys;
  597.     IDNO : begin
  598.              IsChanged := False;
  599.              ReadHotkeys;
  600.              LoadHotkeys;
  601.            end;
  602.     IDCANCEL: CanClose := False;
  603.    end;
  604. end;
  605.  
  606. procedure TfrmHotkeyEdit.LoadHotkeys;
  607. var
  608.   Stream       : TFileStream;
  609.   Reader       : TReader;
  610.   Action       : Integer;
  611.   sVersion     : String;
  612.   iVersion     : Integer;
  613.   sDescription,
  614.   sID,
  615.   sHotkey,
  616.   sCommandLine : String;
  617.   Item         : TMenuItem;
  618. begin
  619.   with SysHotkeys do
  620.    begin
  621.      try
  622.        try
  623.          Stream := TFileStream.Create(ChangeFileExt(Application.ExeName, '.HKD'), fmOpenRead);
  624.          try
  625.            Reader := TReader.Create(Stream, 4096);
  626.            try
  627.              CommandLines.Clear;
  628.              mnuEditHotkeys.Caption := '&Edit hotkeys...';
  629.              mnuListHotkeys.Caption := '&View hotkey list...';
  630.              mnuAbout.Caption := '&About...';
  631.              mnuHelp.Caption := 'Hotkeys &Help';
  632.              while mnuHotkeys.Count>0 do mnuHotkeys.Items[0].Free;
  633.              Clear;
  634.              sVersion := Reader.ReadString;
  635.              iVersion := 120;
  636.              if sVersion = 'Hotkey definitions, version 1.0' then iVersion:=100;
  637.              if sVersion = 'Hotkey definitions, version 1.05' then iVersion:=105;
  638.              Reader.ReadListBegin;
  639.              while not Reader.EndOfList do
  640.               begin
  641.                 sDescription := Reader.ReadString; // Hotkey description
  642.                 if (iVersion>100) then sID := Reader.ReadString;
  643.                 Action := Reader.ReadInteger;
  644.                 if (iVersion=100) and (Action>1) then inc(Action);
  645.                 case Action of
  646.                   0, 1, 2: sCommandLine := Reader.ReadString;            // Commandline
  647.                   3      : sCommandLine := IntToStr(Reader.ReadInteger); // Parameter
  648.                   10     : sCommandLine := IntToStr(Reader.ReadInteger); // Clipboard
  649.                 end;
  650.                 sHotkey := ReadHotkey(Reader);
  651.                 if Reader.ReadBoolean and ((Action>1) or (sCommandLine<>'')) then
  652.                  begin
  653.                    if (Action=0) then
  654.                     begin
  655.                       if (iVersion=120) then
  656.                        CommandLines.Add(IntToStr(Action) + '=' + sCommandLine+';'+Reader.ReadString)
  657.                       else
  658.                        CommandLines.Add(IntToStr(Action) + '=' + sCommandLine+';'+cboShow.Items[0]);
  659.                     end
  660.                    else
  661.                     CommandLines.Add(IntToStr(Action) + '=' + sCommandLine);
  662.  
  663.                    AddHotkey(Virtkey(sHotkey), Modifiers(sHotkey));
  664.                    case Action of
  665.                      0,2: begin
  666.                             Item := NewItem(sDescription+#9+sHotkey, 0, False, True, HotkeyMenuClick, 0, '');
  667.                             Item.Tag := CommandLines.Count-1;
  668.                             mnuHotkeys.Add(Item);
  669.                           end;
  670.                      4: mnuEditHotkeys.Caption := '&Edit hotkeys...'+#9+sHotkey;
  671.                      5: mnuListHotkeys.Caption := '&View hotkey list...'+#9+sHotkey;
  672.                      6: mnuAbout.Caption := '&About...'+#9+sHotkey;
  673.                      7: mnuHelp.Caption := 'Hotkeys &Help'+#9+sHotkey;
  674.                    end;
  675.                  end;
  676.               end;
  677.              Reader.ReadListEnd;
  678.            finally
  679.              Reader.Free;
  680.            end;
  681.          finally
  682.            Stream.Free;
  683.          end;
  684.        finally
  685.          mnuHotkeys.Visible := mnuHotkeys.Count>0;
  686.          mnuSeparator1.Visible := mnuHotkeys.Count>0;
  687.        end;
  688.      except
  689.      end;
  690.    end;
  691. end;
  692.  
  693. function TfrmHotkeyEdit.VirtKey(sHotkey: String): TVirtKey;
  694. begin
  695.   Result := vkNone;
  696.   while Pos('+', sHotkey)>0 do Delete(sHotkey, 1, Pos('+', sHotkey));
  697.   case cboHotKey.Items.IndexOf(sHotkey) of
  698.      0: Result := vkBack;      // Backspace
  699.      1: Result := vkTab;       // Tab
  700.      2: Result := vkReturn;    // Return
  701.      3: Result := vkPause;     // Pause
  702.      4: Result := vkCapital;   // Capslock
  703.      5: Result := vkEscape;    // Escape
  704.      6: Result := vkSpace;     // Space
  705.      7: Result := vkPrior;     // PgUp
  706.      8: Result := vkNext;      // PgDn
  707.      9: Result := vkHome;      // Home
  708.     10: Result := vkEnd;       // End
  709.     11: Result := vkLeft;      // Left Arrow
  710.     12: Result := vkUp;        // Up Arrow
  711.     13: Result := vkRight;     // Right Arrow
  712.     14: Result := vkDown;      // Down Arrow
  713.     15: Result := vkSnapshot;  // PrintScreen
  714.     16: Result := vkInsert;    // Insert
  715.     17: Result := vkDelete;    // Delete
  716.     18: Result := vk0;         // 0
  717.     19: Result := vk1;         // 1
  718.     20: Result := vk2;         // 2
  719.     21: Result := vk3;         // 3
  720.     22: Result := vk4;         // 4
  721.     23: Result := vk5;         // 5
  722.     24: Result := vk6;         // 6
  723.     25: Result := vk7;         // 7
  724.     26: Result := vk8;         // 8
  725.     27: Result := vk9;         // 9
  726.     28: Result := vkA;         // A
  727.     29: Result := vkB;         // B
  728.     30: Result := vkC;         // C
  729.     31: Result := vkD;         // D
  730.     32: Result := vkE;         // E
  731.     33: Result := vkF;         // F
  732.     34: Result := vkG;         // G
  733.     35: Result := vkH;         // H
  734.     36: Result := vkI;         // I
  735.     37: Result := vkJ;         // J
  736.     38: Result := vkK;         // K
  737.     39: Result := vkL;         // L
  738.     40: Result := vkM;         // M
  739.     41: Result := vkN;         // N
  740.     42: Result := vkO;         // O
  741.     43: Result := vkP;         // P
  742.     44: Result := vkQ;         // Q
  743.     45: Result := vkR;         // R
  744.     46: Result := vkS;         // S
  745.     47: Result := vkT;         // T
  746.     48: Result := vkU;         // U
  747.     49: Result := vkV;         // V
  748.     50: Result := vkW;         // W
  749.     51: Result := vkX;         // X
  750.     52: Result := vkY;         // Y
  751.     53: Result := vkZ;         // Z
  752.     54: Result := vkNumpad0;   // Num 0
  753.     55: Result := vkNumpad1;   // Num 1
  754.     56: Result := vkNumpad2;   // Num 2
  755.     57: Result := vkNumpad3;   // Num 3
  756.     58: Result := vkNumpad4;   // Num 4
  757.     59: Result := vkNumpad5;   // Num 5
  758.     60: Result := vkNumpad6;   // Num 6
  759.     61: Result := vkNumpad7;   // Num 7
  760.     62: Result := vkNumpad8;   // Num 8
  761.     63: Result := vkNumpad9;   // Num 9
  762.     64: Result := vkMultiply;  // Num *
  763.     65: Result := vkAdd;       // Num +
  764.     66: Result := vkSubtract;  // Num -
  765.     67: Result := vkDecimal;   // Num .
  766.     68: Result := vkDivide;    // Num /
  767.     69: Result := vkF1;        // F1
  768.     70: Result := vkF2;        // F2
  769.     71: Result := vkF3;        // F3
  770.     72: Result := vkF4;        // F4
  771.     73: Result := vkF5;        // F5
  772.     74: Result := vkF6;        // F6
  773.     75: Result := vkF7;        // F7
  774.     76: Result := vkF8;        // F8
  775.     77: Result := vkF9;        // F9
  776.     78: Result := vkF10;       // F10
  777.     79: Result := vkF11;       // F11
  778.     80: Result := vkF12;       // F12
  779.     81: Result := vkF13;       // F13
  780.     82: Result := vkF14;       // F14
  781.     83: Result := vkF15;       // F15
  782.     84: Result := vkF16;       // F16
  783.     85: Result := vkF17;       // F17
  784.     86: Result := vkF18;       // F18
  785.     87: Result := vkF19;       // F19
  786.     88: Result := vkF20;       // F20
  787.     89: Result := vkF21;       // F21
  788.     90: Result := vkF22;       // F22
  789.     91: Result := vkF23;       // F23
  790.     92: Result := vkF24;       // F24
  791.     93: Result := vkNumlock;   // Numlock
  792.     94: Result := vkScroll;    // Scrolllock
  793.     95: Result := vkApps;      // Application key
  794.   end;
  795. end;
  796.  
  797. function TfrmHotkeyEdit.Modifiers(sHotkey: String): THKModifiers;
  798. begin
  799.   Result := [];
  800.   if Pos('Ctrl',  sHotkey) > 0 then Include(Result, hkCtrl);
  801.   if Pos('Alt',   sHotkey) > 0 then Include(Result, hkAlt);
  802.   if Pos('Shift', sHotkey) > 0 then Include(Result, hkShift);
  803.   if Pos('Win',   sHotkey) > 0 then Include(Result, hkExt);
  804. end;
  805.  
  806. procedure TfrmHotkeyEdit.SysHotkeysHotKey(Sender: TObject; Index: Integer);
  807. begin
  808.   HotkeyPressed(Index);
  809. end;
  810.  
  811. procedure TfrmHotkeyEdit.FormDestroy(Sender: TObject);
  812. var
  813.   i : integer;
  814. begin
  815.   CommandLines.Free;
  816.   WindowList.Free;
  817.   ChangeClipboardChain(Handle, hwndClipViewer);
  818.   Clipboards.Free;
  819.   with TInifile.Create(ChangeFileExt(Application.ExeName, '.ini')) do
  820.    begin
  821.      WriteInteger('Settings', 'ClipboardCount', udClipboards.Position);
  822.      WriteInteger('EditorWindow', 'Width', Width);
  823.      WriteInteger('EditorWindow', 'Height',  Height);
  824.      for i:=0 to lvHotkeys.Columns.Count-1 do
  825.       with lvHotkeys.Columns[i] do
  826.        WriteInteger('EWColumns', Caption, Width);
  827.      Free;
  828.    end;
  829. end;
  830.  
  831. procedure TfrmHotkeyEdit.FormClose(Sender: TObject; var Action: TCloseAction);
  832. begin
  833.   if not Quitting then
  834.    begin
  835.      Action := caNone;
  836.      Hide;
  837.    end;
  838. end;
  839.  
  840. procedure TfrmHotkeyEdit.mnuEditHotkeysClick(Sender: TObject);
  841. begin
  842.   EditHotkeys;
  843. end;
  844.  
  845. procedure TfrmHotkeyEdit.wmEditKeys(var Msg: TMessage);
  846. begin
  847.   if Msg.wParam = WM_EDITKEYS then EditHotkeys;
  848. end;
  849.  
  850. procedure TfrmHotkeyEdit.wmQuitHotK(var Msg: TMessage);
  851. begin
  852.   if Msg.wParam = WM_QUITHOTK then Quit;
  853. end;
  854.  
  855. procedure TfrmHotkeyEdit.EditHotkeys;
  856. begin
  857.   WindowState := wsNormal;
  858.   Show;
  859.   SetWindowPos(Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW);
  860.   SetForeGroundWindow(Handle);
  861. end;
  862.  
  863. procedure TfrmHotkeyEdit.mnuExitClick(Sender: TObject);
  864. begin
  865.   Quit;
  866. end;
  867.  
  868. procedure TfrmHotkeyEdit.Quit;
  869. begin
  870.   Quitting := True;
  871.   Close;
  872. end;
  873.  
  874. procedure TfrmHotkeyEdit.SetChanged(Value: Boolean);
  875. begin
  876.   if FChanged<>Value then
  877.    begin
  878.      FChanged := Value;
  879.      if FChanged then SysHotkeys.Clear;
  880.      btnApply.Enabled := FChanged;
  881.    end;
  882. end;
  883.  
  884.  
  885. procedure TfrmHotkeyEdit.btnApplyClick(Sender: TObject);
  886. begin
  887.   SaveHotkeys;
  888. end;
  889.  
  890. procedure TfrmHotkeyEdit.FormResize(Sender: TObject);
  891. begin
  892.   cboHotkey.Width := ClientWidth - 376;
  893.   edtDescription.Width := ClientWidth - 184;
  894.   edtKeysToSend.Width := ClientWidth - 184;
  895.   cboActions.Width := ClientWidth - 184;
  896.   cboParams.Width := ClientWidth - 184;
  897.   cboClipboard.Width := ClientWidth - 184;
  898.   lblShow.Left := ClientWidth - 220;
  899.   cboShow.Left := ClientWidth - 185;
  900.   udClipboards.Left := ClientWidth - 107;
  901.   edtClipboards.Left := udClipboards.Left - edtClipboards.Width;
  902.   lblClipboards.Left := edtClipboards.Left - lblClipboards.Width - 5;
  903.   edtCommandLine.Width := ClientWidth - 310;
  904. end;
  905.  
  906. procedure TfrmHotkeyEdit.wmGetMinMaxInfo(var Msg: TWMGETMINMAXINFO);
  907. begin
  908.   Msg.MinMaxInfo^.ptMinTrackSize.X := 411;
  909.   Msg.MinMaxInfo^.ptMinTrackSize.Y := 244;
  910. end;
  911.  
  912. procedure TfrmHotkeyEdit.wmDrawClipboard(var Msg: TMessage);
  913. begin
  914.   DrawClipboardStatus(Clipboards.ActiveClipboard);
  915.   SendMessage(hWnd(Msg.lParam), Msg.Msg, Msg.wParam, Msg.lParam);
  916. end;
  917.  
  918. procedure TfrmHotkeyEdit.wmChangeCBChain(var Msg: TMessage);
  919. begin
  920.   if hWnd(Msg.wParam)=hwndClipViewer then
  921.    hwndClipViewer := hWnd(Msg.wParam)
  922.   else
  923.    SendMessage(hWnd(Msg.lParam), Msg.Msg, Msg.wParam, Msg.lParam);
  924. end;
  925.  
  926. procedure TfrmHotkeyEdit.atiHotkeysEndAnimation(Sender: TObject);
  927. begin
  928.   atiHotkeys.Style := tsNormal;
  929. end;
  930.  
  931. procedure TfrmHotkeyEdit.mnuAboutClick(Sender: TObject);
  932. begin
  933.   AboutBox;
  934. end;
  935.  
  936. procedure TfrmHotkeyEdit.AboutBox;
  937. begin
  938.   frmAbout.Show;
  939.   SetForeGroundWindow(frmAbout.Handle);
  940. end;
  941.  
  942. procedure TfrmHotkeyEdit.ViewHotkeys;
  943. begin
  944.   frmHotkeyList.Show;
  945.   SetForeGroundWindow(frmHotkeyList.Handle);
  946. end;
  947.  
  948. procedure TfrmHotkeyEdit.mnuListHotkeysClick(Sender: TObject);
  949. begin
  950.   ViewHotkeys;
  951. end;
  952.  
  953. procedure TfrmHotkeyEdit.HotkeyMenuClick(Sender: TObject);
  954. begin
  955.   HotkeyPressed(TMenuItem(Sender).Tag);
  956. end;
  957.  
  958. function TfrmHotkeyEdit.GetDelay(var Sel: String): Integer;
  959. var
  960.   P : Integer;
  961. begin
  962.   P := Pos('D=', Sel);
  963.   if P=1 then
  964.    begin
  965.      Delete(Sel, 1, P+1);
  966.      P := Pos(';', Sel);
  967.      Result := StrToIntDef(Copy(Sel, 1, P-1), 0);
  968.      Delete(Sel, 1, P);
  969.    end
  970.   else
  971.    Result := -1
  972. end;
  973.  
  974. function TfrmHotkeyEdit.NextItem(var Commands: String): String;
  975. var
  976.   P : Integer;
  977. begin
  978.   P := Pos(';', Commands);
  979.   if P>0 then
  980.    begin
  981.      Result := Copy(Commands, 1, P-1);
  982.      Delete(Commands, 1, P);
  983.    end
  984.   else
  985.    begin
  986.      Result := Commands;
  987.      Commands := '';
  988.    end;
  989. end;
  990.  
  991. procedure TfrmHotkeyEdit.MultipleHotkeys(Command: String);
  992. var
  993.   i,
  994.   iDelay,
  995.   iNDelay  : Integer;
  996.   ItemID   : String;
  997.   First    : Boolean;
  998. begin
  999.   iDelay := GetDelay(Command);
  1000.   if iDelay = -1 then iDelay := 0;
  1001.   ItemID := NextItem(Command);
  1002.   First := True;
  1003.   while ItemID<>'' do
  1004.    begin
  1005.      i := 0;
  1006.      while i<lvHotkeys.Items.Count do
  1007.       with lvHotkeys.Items[i] do
  1008.        if SubItems[ITEM_ID]=ItemID then
  1009.         begin
  1010.           if First then First := False else Sleep(iDelay);
  1011.           PerformAction(cboActions.Items.IndexOf(SubItems[ITEM_ACTION]), SubItems[ITEM_DATA], 0, True);
  1012.           i := lvHotkeys.Items.Count;
  1013.         end
  1014.        else
  1015.         inc(i);
  1016.      iNDelay := GetDelay(Command);
  1017.      if iNDelay<>-1 then iDelay := iNDelay;
  1018.      ItemID := NextItem(Command);
  1019.    end;
  1020. end;
  1021.  
  1022. function TfrmHotkeyEdit.WindowsVersion: DWord;
  1023. var
  1024.   Version    : TOSVersionInfo;
  1025. begin
  1026.   Version.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  1027.   GetVersionEx(Version);
  1028.   Result := Version.dwPlatformId;
  1029. end;
  1030.  
  1031. procedure TfrmHotkeyEdit.ExitWindowsCommand(Command: Integer);
  1032. const
  1033.   Flags: array[0..2] of integer = (EWX_SHUTDOWN, EWX_LOGOFF, EWX_REBOOT);
  1034. var
  1035.   OldPriv,
  1036.   CurPriv    : TTokenPrivileges;
  1037.   TokenHandle,
  1038.   CP         : THandle;
  1039.   PrivLen    : DWord;
  1040. begin
  1041.   if WindowsVersion = VER_PLATFORM_WIN32_NT then
  1042.    begin
  1043.      CP := GetCurrentProcess;
  1044.      if OpenProcessToken(CP, DWord(TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY), TokenHandle) then
  1045.       begin
  1046.         if LookupPrivilegeValue(nil, 'SeShutdownPrivilege', CurPriv.Privileges[0].LUID) then
  1047.          begin
  1048.            CurPriv.PrivilegeCount := 1;
  1049.            CurPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
  1050.            AdjustTokenPrivileges(TokenHandle, False, CurPriv, 0, OldPriv, PrivLen);
  1051.          end;
  1052.       end;
  1053.    end;
  1054.  
  1055.   case Command of
  1056.     0..2 : ExitWindowsEx(Flags[Command], 0);
  1057.     3    : WinExec(PChar(ExtractFilePath(Application.ExeName) + 'HKRESTRT.EXE'), SW_SHOW);
  1058.     4    : WinExec(PChar('HKTODOS.PIF'), SW_SHOW);
  1059.     5    : SetSystemPowerState(True, False);
  1060.   end;
  1061. end;
  1062.  
  1063. procedure TfrmHotkeyEdit.ExecProgram(Command: String);
  1064. const
  1065.   ShowModes: array[0..2] of UINT = (SW_NORMAL, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED);
  1066. var
  1067.   ShowMode: String;
  1068.   P : Integer;
  1069. begin
  1070.   P := Pos(';', Command);
  1071.   if P=0 then
  1072.    ShowMode := cboShow.Items[0]
  1073.   else
  1074.    begin
  1075.      ShowMode := Copy(Command, P+1, Length(Command));
  1076.      Delete(Command, P, Length(Command));
  1077.    end;
  1078.   WinExec(PChar(Command), ShowModes[cboShow.Items.IndexOf(ShowMode)]);
  1079. end;
  1080.  
  1081. procedure TfrmHotkeyEdit.DrawClipOnBmp(IcoBmp: TBitmap; sText: String);
  1082. var
  1083.   iWidth, iHeight: Integer;
  1084. begin
  1085.   with IcoBmp do
  1086.    begin
  1087.      Canvas.Font.Name := 'Small Fonts';
  1088.      Canvas.Font.Size := 6;
  1089.      Canvas.Font.Color := clWhite;
  1090.      if Clipboards.DataOnClipboard then Canvas.Brush.Color := clBlue else Canvas.Brush.Color := clNavy;
  1091.      Canvas.Pen.Style := psClear;
  1092.      iHeight := Canvas.TextHeight(sText);
  1093.      iWidth := Canvas.TextWidth(sText)+1;
  1094.      Canvas.Ellipse(Width-iWidth-2, Height-iHeight-1, Width+1, Height+1);
  1095.      Canvas.Brush.Style := bsClear;
  1096.      Canvas.TextOut(Width- ((iWidth+2) div 2) - (Canvas.TextWidth(sText) div 2)-1, Height-iHeight, sText);
  1097.      Canvas.Brush.Style := bsSolid;
  1098.    end;
  1099. end;
  1100.  
  1101. procedure TfrmHotkeyEdit.DrawClipboardStatus(Index: Integer);
  1102. var
  1103.   AndMask, XOrMask: TBitmap;
  1104.   NewIcon         : TIcon;
  1105.   IconInfo        : TIconInfo;
  1106. begin
  1107.   {Create the "XOr" mask}
  1108.   XOrMask := TBitmap.Create;
  1109.   try
  1110.     XOrMask.Width := imgIcon.Picture.Width;
  1111.     XOrMask.Height := imgIcon.Picture.Height;
  1112.  
  1113.     {Draw on the "XOr" mask}
  1114.     imgIcon.Transparent := False;
  1115.     XOrMask.Canvas.Draw(0, 0, imgIcon.Picture.Bitmap);
  1116.     DrawClipOnBmp(XorMask, IntToStr(Index+1));
  1117.     XOrMask.Canvas.Brush.Color := imgIcon.Picture.Bitmap.Canvas.Pixels[0,0];
  1118.  
  1119.     {Create the "And" mask}
  1120.     AndMask := TBitmap.Create;
  1121.     try
  1122.       AndMask.Monochrome := true;
  1123.       AndMask.Width := imgIcon.Picture.Width;
  1124.       AndMask.Height := imgIcon.Picture.Height;
  1125.  
  1126.       {Draw on the "And" mask}
  1127.       AndMask.Canvas.Brush.Color := clWhite;
  1128.       AndMask.Canvas.FillRect(Rect(0, 0, 16, 16));
  1129.       { Draw the "XOr" mask on the "And" mask }
  1130.       AndMask.Canvas.Draw(0, 0, XOrMask);
  1131.  
  1132.       {Redraw the image on the XOr mask}
  1133.       imgIcon.Transparent := True;
  1134.       XorMask.Canvas.Brush.Color := clBlack;
  1135.       XorMask.Canvas.FillRect(Rect(0, 0, 16, 16));
  1136.       XOrMask.Canvas.Draw(0, 0, imgIcon.Picture.Bitmap);
  1137.       DrawClipOnBmp(XorMask, IntToStr(Index+1));
  1138.  
  1139.       {Create a icon}
  1140.       NewIcon := TIcon.Create;
  1141.       try
  1142.         IconInfo.fIcon := True;
  1143.         IconInfo.xHotspot := 0;
  1144.         IconInfo.yHotspot := 0;
  1145.         IconInfo.hbmMask := AndMask.Handle;
  1146.         IconInfo.hbmColor := XOrMask.Handle;
  1147.         NewIcon.Handle := CreateIconIndirect(IconInfo);
  1148.  
  1149.         atiHotkeys.Icon := NewIcon;
  1150.       finally
  1151.         NewIcon.Free;
  1152.       end;
  1153.     finally
  1154.       AndMask.Free;
  1155.     end;
  1156.   finally
  1157.     XOrMask.Free;
  1158.   end
  1159. end;
  1160.  
  1161. procedure TfrmHotkeyEdit.SwitchToClipboard(Index: Integer);
  1162. begin
  1163.   Clipboards.SwitchToClipboard(Index, False);
  1164.   DrawClipboardStatus(Index);
  1165. end;
  1166.  
  1167. procedure TfrmHotkeyEdit.PerformAction(Action: Integer; Command: String; Index: Integer; Immediate: Boolean);
  1168. begin
  1169.   case Action of
  1170.     0: ExecProgram(Command);
  1171.     1: if Immediate then
  1172.         SendKeys(Command, True)
  1173.        else
  1174.         PostMessage(Handle, WM_SENDKEYS, WM_SENDKEYS, Index);
  1175.     2: PostMessage(Handle, WM_MULTKEYS, WM_MULTKEYS, Index);
  1176.     3: ExitWindowsCommand(StrToInt(Command));
  1177.     4: EditHotkeys;
  1178.     5: ViewHotkeys;
  1179.     6: AboutBox;
  1180.     7: HelpIndex;
  1181.     8: MinimizeAll;
  1182.     9: UndoMinimize;
  1183.    10: SwitchToClipboard(StrToIntDef(Command, 1));
  1184.   end;
  1185. end;
  1186.  
  1187. procedure TfrmHotkeyEdit.HotkeyPressed(Index: Integer);
  1188. var
  1189.   P,
  1190.   Action : Integer;
  1191.   Command: String;
  1192. begin
  1193.   if Index>CommandLines.Count then Exit;
  1194.   if CommandLines[Index]<>'' then
  1195.    begin
  1196.      atiHotkeys.Style := tsAnimated;
  1197.      P := Pos('=', CommandLines[Index]);
  1198.      Action := StrToInt(Copy(CommandLines[Index], 1, P-1));
  1199.      Command := Copy(CommandLines[Index], P+1, Length(CommandLines[Index]));
  1200.      PerformAction(Action, Command, Index, False);
  1201.    end;
  1202. end;
  1203.  
  1204. procedure TfrmHotkeyEdit.wmMultKeys(var Msg: TMessage);
  1205. var
  1206.   sCommand: String;
  1207. begin
  1208.   if Msg.wParam=WM_MULTKEYS then
  1209.    begin
  1210.      sCommand := CommandLines[Msg.lParam];
  1211.      Delete(sCommand, 1, Pos('=', sCommand));
  1212.      MultipleHotkeys(sCommand);
  1213.    end;
  1214. end;
  1215.  
  1216. procedure TfrmHotkeyEdit.wmSendKeys(var Msg: TMessage);
  1217. var
  1218.   sKeys: String;
  1219. begin
  1220.   if Msg.wParam=WM_SENDKEYS then
  1221.    begin
  1222.      sKeys := CommandLines[Msg.lParam];
  1223.      Delete(sKeys, 1, Pos('=', sKeys));
  1224.      SendKeys(sKeys, False);
  1225.    end;
  1226. end;
  1227.  
  1228. procedure TfrmHotkeyEdit.chkShowIconClick(Sender: TObject);
  1229. begin
  1230.   atiHotkeys.Active := chkShowIcon.Checked;
  1231.   with TInifile.Create(ChangeFileExt(Application.ExeName, '.INI')) do
  1232.    begin
  1233.      if chkShowIcon.Checked then
  1234.       WriteInteger('Settings', 'ShowTaskbarIcon', 1)
  1235.      else
  1236.       WriteInteger('Settings', 'ShowTaskbarIcon', 0);
  1237.      Free;
  1238.    end;
  1239. end;
  1240.  
  1241. procedure TfrmHotkeyEdit.FormKeyDown(Sender: TObject; var Key: Word;
  1242.   Shift: TShiftState);
  1243. begin
  1244.   if Key=VK_F1 then
  1245.    WinHelp(Handle, PChar(ChangeFileExt(Application.ExeName, '.hlp')+'>EditWnd'), HELP_CONTEXT, 3);
  1246. end;
  1247.  
  1248. procedure TfrmHotkeyEdit.SetControls;
  1249. var
  1250.   Index : Integer;
  1251. begin
  1252.   Index := cboActions.ItemIndex;
  1253.   edtCommandLine.Visible := (Index=0) or (Index=2);
  1254.   lblShow.Visible := edtCommandLine.Visible;
  1255.   cboShow.Visible := edtCommandLine.Visible;
  1256.   edtKeysToSend.Visible := (Index=1);
  1257.   cboParams.Visible := (Index=3);
  1258.   lblCommandLine.Visible := (Index<=3) or (Index=10);
  1259.   cboClipboard.Visible := (Index=10);
  1260.   case Index of
  1261.     0 : begin
  1262.           lblCommandLine.Caption := 'Co&mmandline:';
  1263.           lblCommandLine.FocusControl := edtCommandLine;
  1264.           edtCommandLine.Dialog := opdOpenFile;
  1265.         end;
  1266.     1 : begin
  1267.           lblCommandLine.Caption := '&Keys to send:';
  1268.           lblCommandLine.FocusControl := edtKeysToSend;
  1269.         end;
  1270.     2 : begin
  1271.           lblCommandLine.Caption := 'Com&mand IDs:';
  1272.           lblCommandLine.FocusControl := edtCommandLine;
  1273.           edtCommandLine.Dialog := nil;
  1274.         end;
  1275.     3 : begin
  1276.           lblCommandLine.Caption := 'Para&meters:';
  1277.           lblCommandLine.FocusControl := cboParams;
  1278.         end;
  1279.     10: begin
  1280.           lblCommandLine.Caption := 'Clip&board:';
  1281.           lblCommandLine.FocusControl := cboClipboard;
  1282.         end;
  1283.   end;
  1284. end;
  1285.  
  1286. procedure TfrmHotkeyEdit.cboActionsClick(Sender: TObject);
  1287. begin
  1288.   if Item.SubItems[ITEM_ACTION] <> cboActions.Items[cboActions.ItemIndex] then
  1289.    begin
  1290.      Item.SubItems[ITEM_ACTION] := cboActions.Items[cboActions.ItemIndex];
  1291.      case cboActions.ItemIndex of
  1292.        0,2: Item.SubItems[ITEM_DATA] := edtCommandLine.Text;
  1293.        1  : Item.SubItems[ITEM_DATA] := edtKeysToSend.Text;
  1294.        3  : Item.SubItems[ITEM_DATA] := cboParams.Items[cboParams.ItemIndex];
  1295.        10 : Item.SubItems[ITEM_DATA] := cboClipboard.Items[cboClipboard.ItemIndex];
  1296.        else Item.SubItems[ITEM_DATA] := '';
  1297.      end;
  1298.      IsChanged := True;
  1299.      SetControls;
  1300.    end;
  1301. end;
  1302.  
  1303. procedure TfrmHotkeyEdit.HelpIndex;
  1304. begin
  1305.   WinHelp(Handle, PChar(ChangeFileExt(Application.ExeName, '.hlp')), HELP_CONTENTS, 0);
  1306. end;
  1307.  
  1308. function EnumProc(Wnd: hWnd; lp: lParam): Bool; stdcall;
  1309. var
  1310.   pClass: array[0..255] of char;
  1311. begin
  1312. //  if GetWindowLong(Wnd, GWL_HWNDPARENT)<>0 then
  1313. //  repeat
  1314. //    Wnd := GetWindowLong(Wnd, GWL_HWNDPARENT);
  1315. //  until GetWindowLong(Wnd, GWL_HWNDPARENT)=0;
  1316.   GetClassName(Wnd, pClass, 255);
  1317.   if IsWindowVisible(Wnd) and not IsIconic(Wnd) and (StrPas(pClass)<>'Shell_TrayWnd') then
  1318.    frmHotkeyEdit.WindowList.Add(Pointer(Wnd));
  1319.   Result := True;
  1320. end;
  1321.  
  1322. function TfrmHotkeyEdit.WindowAnimation(Value: Integer): Integer;
  1323. var
  1324.   AniInfo: TAnimationInfo;
  1325. begin
  1326.   AniInfo.cbSize := Sizeof(TAnimationInfo);
  1327.   SystemParametersInfo(SPI_GETANIMATION, 0, @AniInfo, 0);
  1328.   Result := AniInfo.iMinAnimate;
  1329.   if AniInfo.iMinAnimate<>Value then
  1330.    begin
  1331.      AniInfo.iMinAnimate := Value;
  1332.      SystemParametersInfo(SPI_SETANIMATION, 0, @AniInfo, 0);
  1333.    end;
  1334. end;
  1335.  
  1336. procedure TfrmHotkeyEdit.MinimizeAll;
  1337. var
  1338.   i, Anim: Integer;
  1339. begin
  1340.   WindowList.Clear;
  1341.   EnumWindows(@EnumProc, 0);
  1342.   Anim := WindowAnimation(0);
  1343.   for i:=0 to WindowList.Count-1 do
  1344.    SendMessage(hWnd(WindowList[i]), WM_SYSCOMMAND, SC_MINIMIZE, 0);
  1345.   WindowAnimation(Anim);
  1346. end;
  1347.  
  1348. procedure TfrmHotkeyEdit.UndoMinimize;
  1349. var
  1350.   i, Anim: Integer;
  1351. begin
  1352.   Anim := WindowAnimation(0);
  1353.   for i:=WindowList.Count-1 downto 0 do
  1354.    SendMessage(hWnd(WindowList[i]), WM_SYSCOMMAND, SC_RESTORE, 0);
  1355.   WindowAnimation(Anim);
  1356. end;
  1357.  
  1358. procedure TfrmHotkeyEdit.cboParamsClick(Sender: TObject);
  1359. begin
  1360.   if Item.SubItems[ITEM_DATA] <> cboParams.Items[cboParams.ItemIndex] then
  1361.    begin
  1362.      Item.SubItems[ITEM_DATA] := cboParams.Items[cboParams.ItemIndex];
  1363.      IsChanged := True;
  1364.    end;
  1365. end;
  1366.  
  1367. procedure TfrmHotkeyEdit.edtKeysToSendChange(Sender: TObject);
  1368. begin
  1369.   if (Item<>nil) and not Ignore then
  1370.    begin
  1371.      Item.SubItems[ITEM_DATA] := edtKeysToSend.Text;
  1372.      IsChanged := True;
  1373.    end;
  1374. end;
  1375.  
  1376. procedure TfrmHotkeyEdit.mnuHelpClick(Sender: TObject);
  1377. begin
  1378.   HelpIndex;
  1379. end;
  1380.  
  1381. procedure TfrmHotkeyEdit.edtIDChange(Sender: TObject);
  1382. begin
  1383.   if (Item<>nil) and not Ignore then
  1384.    begin
  1385.      Item.SubItems[ITEM_ID] := MakeID(lvHotkeys, Item, edtID.Text);
  1386.      IsChanged := True;
  1387.    end;
  1388. end;
  1389.  
  1390. procedure TfrmHotkeyEdit.edtIDExit(Sender: TObject);
  1391. begin
  1392.   if (Item<>nil) and (edtID.Text <> Item.SubItems[ITEM_ID]) then
  1393.    edtID.Text := Item.SubItems[ITEM_ID];
  1394. end;
  1395.  
  1396. procedure TfrmHotkeyEdit.edtDescriptionExit(Sender: TObject);
  1397. begin
  1398.   if (Item<>nil) and (edtID.Text='') then
  1399.    edtID.Text := MakeID(lvHotkeys, Item, edtDescription.Text);
  1400. end;
  1401.  
  1402. procedure TfrmHotkeyEdit.edtCommandLineButtonClick(Sender: TObject);
  1403. begin
  1404.   if frmSelect.Execute(lvHotkeys, edtCommandLine.Text) then
  1405.    edtCommandLine.Text := frmSelect.Selection;
  1406. end;
  1407.  
  1408. procedure TfrmHotkeyEdit.lvHotkeysChange(Sender: TObject; Item: TListItem;
  1409.   Change: TItemChange);
  1410. begin
  1411.   if (Change=ctState) and Item.Selected then lvHotkeysClick(Sender);
  1412. end;
  1413.  
  1414. procedure TfrmHotkeyEdit.edtCommandLineExit(Sender: TObject);
  1415. var
  1416.   i        : Integer;
  1417.   sCommand,
  1418.   sItemID  : String;
  1419.   bFound,
  1420.   bError   : Boolean;
  1421. begin
  1422.   if cboActions.ItemIndex=2 then
  1423.    begin
  1424.      sCommand := edtCommandLine.Text;
  1425.      GetDelay(sCommand);
  1426.      sItemID := NextItem(sCommand);
  1427.      bError := False;
  1428.      while (sItemID<>'') and (not bError) do
  1429.       begin
  1430.         bFound := False;
  1431.         i := 0;
  1432.         while not bError and not bFound and (i<lvHotkeys.Items.Count) do
  1433.          if lvHotkeys.Items[i].SubItems[ITEM_ID]=sItemID then
  1434.           begin
  1435.             if cboActions.Items.IndexOf(lvHotkeys.Items[i].SubItems[ITEM_ACTION])=2 then
  1436.              bError := True
  1437.             else
  1438.              bFound := True;
  1439.           end
  1440.          else
  1441.           inc(i);
  1442.         if bFound then
  1443.          begin
  1444.            GetDelay(sCommand);
  1445.            sItemID := NextItem(sCommand);
  1446.          end
  1447.         else
  1448.          bError := True
  1449.       end;
  1450.      if bError then
  1451.       begin
  1452.         Application.MessageBox('This entry contains one or more invalid IDs (ID does not exist or ID belongs to Multiple Action command).', 'Invalid IDs found', MB_ICONEXCLAMATION or MB_OK);
  1453.         edtCommandLine.SetFocus;
  1454.       end;
  1455.    end;
  1456. end;
  1457.  
  1458. procedure TfrmHotkeyEdit.cboShowClick(Sender: TObject);
  1459. begin
  1460.   if Item.SubItems[ITEM_SHOW] <> cboShow.Items[cboShow.ItemIndex] then
  1461.    begin
  1462.      Item.SubItems[ITEM_SHOW] := cboShow.Items[cboShow.ItemIndex];
  1463.      IsChanged := True;
  1464.    end;
  1465. end;
  1466.  
  1467. procedure TfrmHotkeyEdit.cboClipboardClick(Sender: TObject);
  1468. begin
  1469.   if Item.SubItems[ITEM_DATA] <> cboClipboard.Items[cboClipboard.ItemIndex] then
  1470.    begin
  1471.      Item.SubItems[ITEM_DATA] := cboClipboard.Items[cboClipboard.ItemIndex];
  1472.      IsChanged := True;
  1473.    end;
  1474. end;
  1475.  
  1476. procedure TfrmHotkeyEdit.edtClipboardsExit(Sender: TObject);
  1477. begin
  1478.   edtClipboards.Text := IntToStr(udClipboards.Position);
  1479. end;
  1480.  
  1481. procedure TfrmHotkeyEdit.edtClipboardsChange(Sender: TObject);
  1482. begin
  1483.   if not Ignore then SetClipboards;
  1484. end;
  1485.  
  1486. end.
  1487.