home *** CD-ROM | disk | FTP | other *** search
/ Softwarová Záchrana 3 / Softwarova-zachrana-3.bin / ArsClip / source.zip / UnitFrmMainPopup.pas < prev    next >
Pascal/Delphi Source File  |  2004-11-09  |  67KB  |  2,171 lines

  1. unit UnitFrmMainPopup;
  2. {
  3.     This unit displays the main popup menu when a hotkey is pressed
  4.  
  5.     UnitFrmConfig is responsible for setting/releasing the hotkey -
  6.     I had a good reason why, but I don't remeber it. I think there
  7.     was a circular reference where each form required the other during
  8.     creation.
  9.  
  10.  
  11.     NOTE:
  12.     Ignore the clipboard from Hotkey until Popup Dismissal
  13.     Ignore the clipboard from paste start until paste end
  14.  
  15.     Inform the FrmClipboardManager any time we paste an item.
  16.     (in routines SendText and OtherItemClickEvent)
  17.  
  18.  
  19.  
  20.  
  21. Update:
  22.     Fix to detect accidental single/double click on System Tray Icon to show popup
  23.     Show "Paste as Plain Text" when pasting as Complex Item by default
  24.  
  25.     ----------------------
  26.     Mouse Position always used no matter the configuration
  27.     Problem pasting from ArsClip into ArsClip
  28.  
  29.     ---------------------
  30.     "All Items..." support
  31.     Default mouse position when carat not found - Mozilla tweak
  32.  
  33.     --------------------
  34.     Fixed duplicate hotkey detection to work with the Tooltip Popup hotkeys
  35.     --------------------
  36.     Changed to allow ArsClip to paste into its own windows, like
  37.     Permanent Items. (Relies on new 'place on clipboard' method
  38.     ArsClip uses)
  39.  
  40.     --------------------
  41.     Duplicate Hotkey message detection
  42.     Optional paste as Complex Item
  43.  
  44.     --------------------
  45.     "Current:" item for text & nontext items
  46.     Updates to paste Permanent Items with embeded keystrokes
  47.  
  48.     --------------------
  49.     New CTRL+Click option for Rich Text - only shown when rich text
  50.     found associated to a text clip.
  51.  
  52.     Updated for option to show popup on double-click
  53.     Save Removed Items on Close.....
  54.     Handle Tooltip hotkeys
  55.     Tooltips for
  56.  
  57.     ------
  58.     New Form Mode / Next Field buttons
  59.     Number 1 - 9, 0, A-Z on popup
  60.     --
  61.     Ignore the Hotkey while the Popup is being displayed.
  62.  
  63.     New secondary popup menu for text items (alternative to
  64.     function key + clicking on items)
  65.  
  66.     Updated the focus rules for asking the user about "no-paste" windows
  67.     in the hotkey message method.
  68.                   s
  69.     --
  70.  
  71.     New SHIFT+INSERT pasting method
  72.  
  73.     Shift + Click to preview a picture (non-text item)
  74.     F1 + Click to copy to clipboard only a non-text item
  75.  
  76.     Non-text items shown in Newest-To-Oldest order
  77.  
  78.     Flush non-text items command in Full Mode
  79.     Flush text items command in Full Mode
  80.  
  81.     --
  82.  
  83.     Show configured (either on popup or in submenu) for
  84.     permanent item groups in full mode - default to on popup when not
  85.     specified
  86.  
  87.     New F1+Click to copy to clipboard only
  88.     New F2+Click to make into a new Permanent Item
  89.     Cleaned up special Key+Click code
  90.  
  91.  
  92.     New 'Full Mode/Configured Mode' toggle.
  93.  
  94.     Code cleanup - made SendCTRL_V procedure.
  95.  
  96.     Allow user to specify "NoPaste" for programs that don't
  97.     have a target control.
  98.  
  99.     New option for quick-change of Permanent Item groups
  100.  
  101.     CTRL+Clicks on Menu Items, Last, Current, Permanent Items will open
  102.     files, urls, folders, etc.
  103.  
  104.     Using UnitClipQueue
  105.     New handling for tabs in the display of clip items
  106.     Focus is now returned when ESC is pressed
  107.  
  108. }
  109.  
  110.  
  111. interface
  112. uses
  113.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  114.   Dialogs, StdCtrls, Clipbrd, Menus, StrUtils, ShellAPI, ExtCtrls, Buttons,
  115.   IniFiles {for hashed}, UnitTooltipPopup,
  116.    UnitMyPopup, UnitClipQueue, UnitTWideChar;
  117.  
  118.  
  119.   type
  120.   TFrmMainPopup = class(TForm)
  121.     Memo1: TMemo;
  122.     btnHide: TButton;
  123.     imgA: TImage;
  124.     imgRightArrow: TImage;
  125.     imgIcon: TImage;
  126.     imgFull: TImage;
  127.     pmItemOptions: TPopupMenu;
  128.     Run1: TMenuItem;
  129.     MakePermanentItem1: TMenuItem;
  130.     PasteusingMimicTyping1: TMenuItem;
  131.     Placeonclipboard1: TMenuItem;
  132.     Preview1: TMenuItem;
  133.     back1: TMenuItem;
  134.     Cancel1: TMenuItem;
  135.     N2: TMenuItem;
  136.     PasteusingSHIFTINS1: TMenuItem;
  137.     N1: TMenuItem;
  138.     PasteusingCTRLV1: TMenuItem;
  139.     imgPasteAll: TImage;
  140.     imgPaste: TImage;
  141.     imgEdit: TImage;
  142.     imgFlush: TImage;
  143.     imgConfMode: TImage;
  144.     imgPermCasc: TImage;
  145.     imgRemoved: TImage;
  146.     N0PasteasRichText1: TMenuItem;
  147.     tim: TTimer;
  148.     AMakePermanentas1: TMenuItem;
  149.     N3: TMenuItem;
  150.  
  151.     procedure FormCreate(Sender: TObject);
  152.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  153.     procedure btnHideClick(Sender: TObject);
  154.     procedure Run1Click(Sender: TObject);
  155.     procedure MakePermanentItem1Click(Sender: TObject);
  156.     procedure PasteusingMimicTyping1Click(Sender: TObject);
  157.     procedure Placeonclipboard1Click(Sender: TObject);
  158.     procedure Preview1Click(Sender: TObject);
  159.     procedure back1Click(Sender: TObject);
  160.     procedure PasteusingSHIFTINS1Click(Sender: TObject);
  161.     procedure PasteusingCTRLV1Click(Sender: TObject);
  162.     procedure N0PasteasRichText1Click(Sender: TObject);
  163.     procedure FormShow(Sender: TObject);
  164.     procedure AMakePermanentas1Click(Sender: TObject);
  165.     procedure MimicTyping1Click(Sender: TObject);
  166.     procedure N2SHIFTINSERT1Click(Sender: TObject);
  167.     procedure N3CTRLV1Click(Sender: TObject);
  168.     procedure N4ClipboardOnly1Click(Sender: TObject);
  169.     procedure N5Default1Click(Sender: TObject);
  170.     //procedure timTimer(Sender: TObject);
  171.   private
  172.     { Private declarations }
  173.  
  174.     HotKeyForeWindow: cardinal;         {target window for text pasting}
  175.     HotKeyTarget: cardinal;             {target control with keyboard focus}
  176.     TargetEXE : string;                  {name of program that created window}
  177.     TargetX, TargetY : integer;
  178.  
  179.     Popup: TMyPopupMenu;                  {text pasting popup}
  180.     PopupShowing : boolean;
  181.     
  182.     LastStringSelected : string;         {last selected queue item from Popup}
  183.     MenuItemText : string;
  184.     CurrentClipboard : TClipItem;
  185.     CTRLClickedItem : TClipItem;
  186.  
  187.     ThreadOurs : cardinal;               {Used soley by ThreadAttach/Detach}
  188.     ThreadTarget : cardinal;
  189.     ThreadAttached : boolean;
  190.  
  191.     {configuration options}
  192.     PopupUseKB : boolean;
  193.     VisibleCharCount : longint;
  194.     UsePermanentItems : boolean;
  195.     DoShowEditHistory : boolean;
  196.     DoShowPasteAll : boolean;
  197.     DoMoveSelectedToTop : boolean;
  198.     DoShowCurrentItem : boolean;
  199.     DoShowPermanentItemGroups : boolean;
  200.     DoShowPermanentItemSubmenu : boolean;
  201.     DoRememberHistory : boolean;
  202.     DoShowLast : boolean;
  203.     DoShowFormMode : boolean;
  204.     IgnoreHotkey : boolean;
  205.  
  206.     {UsePermanentItemsMore : boolean;
  207.     PermanentItemsToShow : integer;}
  208.     PermanentItemsCurrentTop : integer;
  209.  
  210.     {keystrokes monitored when an item is clicked}
  211.     CopyKey : integer;
  212.     PermanentKey : integer;
  213.     MimicKey : integer;
  214.  
  215.     {non-text items}
  216.     UseOtherClipboardOnly : boolean;
  217.     UseOtherPasting : boolean;
  218.     UseFormMode : boolean;
  219.     UseCtrlClickOpen, UseCtrlClickMenu : boolean;
  220.  
  221.  
  222.     FullMode : boolean; // user pressed Full Mode command
  223.  
  224.  
  225.  
  226.     //NoPastePrograms : THashedStringList;    // List of programs that ArsClip will use
  227.                                             // clipboard only mode.
  228.  
  229.     TooltipPopup : TTooltipPopup;
  230.     HotkeyActive : boolean;
  231.     PopupActive : boolean;
  232.     
  233.     {unicode poup}
  234.  
  235.     procedure HandleCloseEvent;
  236.     procedure HandleFormMode;
  237.     function ThreadAttach(TargetWindow: cardinal) : boolean;
  238.     procedure ThreadDetach();
  239.  
  240.     procedure GatherTargetWindowData;
  241.     procedure GetTargetControl(ParentWindow: cardinal;
  242.         var TargetHandle: cardinal;
  243.         var TargetX: integer;
  244.         var TargetY: integer);
  245.  
  246.     {
  247.     // possible future use
  248.     procedure MyOnDraw(Sender: TObject; ACanvas: TCanvas;
  249.             ARect: TRect; Selected: Boolean);
  250.     procedure MyOnMeasure(Sender: TObject; ACanvas: TCanvas;
  251.             var Width, Height: Integer);
  252.     }
  253.     procedure ShowPopupWithFocusRules;
  254.     procedure ShowPopup(X,Y: integer);
  255.  
  256.  
  257.     //
  258.     // util functions
  259.     //
  260.     procedure ShowPreviewForm;
  261.     function KeyPressedOverride(s : string; ci : TClipItem = nil) : boolean;
  262.  
  263.  
  264.  
  265.   protected
  266.   public
  267.     {public declarations}
  268.     procedure SendText(s : string; ci : TClipItem = nil);
  269.     procedure ShowOnNextWindow(ShowPopup : boolean = true);
  270.     function GetNextWindowProgramName : string;
  271.     {configuration}
  272.     procedure SetPopupUseKeyboard(usekb: boolean);
  273.     procedure SetVisibleCharacterCount(count: longint);
  274.     procedure SetPermanentItems(DoUse: boolean);
  275.     procedure SetShowPermeanentItemGroups(enable : boolean);
  276.     procedure SetShowPermanentItemSubmenu(value : boolean);
  277.  
  278.     procedure SetOtherPasteMethodPasting();
  279.     procedure SetOtherPasteMethodClipboardOnly();
  280.     procedure SetShowEditHistory(value : boolean);
  281.  
  282.     procedure SetShowPasteAll(DoShow: boolean);
  283.     procedure SetMoveSelectedItemToTop(DoMove : boolean);
  284.     procedure SetShowCurrentItem(DoShow: boolean);
  285.     procedure SetRememberHistory(DoRemember: boolean);
  286.     procedure SetDoShowLast(DoShow: boolean);
  287.     procedure SetShowFormMode(DoShow : boolean);
  288.     procedure SetCopyKey(key : integer);
  289.     procedure SetPermanentKey(key : integer);
  290.     procedure SetMimicKey(key : integer);
  291.     procedure SetCtrlClickOpen(value : boolean);
  292.     procedure SetCtrlClickMenu(value : boolean);
  293.  
  294.  
  295.     {these are shared with FrmDummyUnicodePopup}
  296.     //
  297.     // menu items selected on Popup window
  298.     //
  299.     function GetUsePermanentItems : boolean;
  300.     function GetDoShowEditHistory : boolean;
  301.     function GetDoShowPasteAll : boolean;
  302.     function GetDoMoveSelectedToTop : boolean;
  303.     function GetDoShowCurrentItem : boolean;
  304.     function GetDoShowPermanentItemGroups : boolean;
  305.     function GetDoShowPermanentItemSubmenu : boolean;
  306.     function GetDoRememberHistory : boolean;
  307.     function GetDoShowLast : boolean;
  308.     function GetDoShowFormMode : boolean;
  309.  
  310.     function GetLastStringSelected : string;
  311.     function GetUseFormMode : boolean;
  312.     function GetFullMode : boolean;
  313.     function GetAccelerator(i: integer): char;
  314.     function GetTrimmedItem(item : string) : string;
  315.  
  316.     procedure MenuItemClickEvent(Sender: TObject);
  317.     procedure FlushTextItemsClickEvent(Sender: TObject);
  318.     procedure EditHistoryItemClickEvent(Sender : TObject);
  319.     procedure OtherItemClickEvent(Sender: TObject);
  320.     procedure FlushOtherItemsClickEvent(Sender: TObject);
  321.     procedure LastMenuItemClickEvent(Sender: TObject);
  322.     procedure CancelMenuItemClickEvent(Sender: TObject);
  323.     procedure PermanentMenuItemClickEvent(sender: TObject); overload;
  324.     procedure PermanentMenuItemClickEvent(s : string); overload;
  325.     procedure PermanentGroupItemClickEvent(sender: TObject); overload;
  326.     procedure PermanentGroupItemClickEvent(s : string); overload;
  327.     procedure PasteAllMenuItemClickEvent(sender: TObject);
  328.     procedure PasteSelectedMenuItemClickEvent(sender: TOBject);
  329.     procedure CurrentMenuItemClickEvent(Sender: TObject);
  330.     procedure FullModeMenuItemClickEvent(Sender : TObject);
  331.     procedure FormModeMenuItemClickEvent(Sender : TObject);
  332.     procedure NextFieldModeMenuItemClickEvent(Sender : TObject);
  333.  
  334.     {system tray stuff/ windows messages}
  335.     procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
  336.     procedure WMEndSession(var msg : TWMQueryEndSession); message WM_QUERYENDSESSION;
  337.  
  338.     procedure AppendLog(s : string);
  339.     procedure ShowOnSystemTray;
  340.  
  341.  
  342.   end;
  343.  
  344. var
  345.   FrmMainPopup: TFrmMainPopup;
  346. implementation
  347.  
  348. uses UnitFrmConfig, UnitFrmClipboardManager,
  349.   UnitFrmPasteSelected, UnitOtherQueue, UnitKeyboardQuery,
  350.   TLHelp32, UnitFrmPreview, UnitFrmPermanentNew,
  351.   UnitFrmRemoved, UnitFrmSysTrayMenu, UnitPaste, UnitMisc, Math,
  352.   CommCtrl, UnitFrmDummyUnicodeTooltip, UnitfrmDummyUnicodePopup ;
  353.  
  354. CONST PASTE_ONLY_FILE : string = 'nopaste.txt';
  355.  
  356. {$R *.dfm}
  357.  
  358. {
  359. --========================
  360. -- // Public Interface //
  361. --========================
  362. }
  363.  
  364. procedure TFrmMainPopup.SetShowFormMode(DoShow : boolean);
  365. begin
  366.     self.DoShowFormMode := DoShow;
  367. end;
  368. procedure TFrmMainPopup.SetCtrlClickOpen(value : boolean);
  369. begin
  370.     self.UseCtrlClickOpen := value;
  371.     self.UseCtrlClickMenu := not value;
  372. end;
  373. procedure TFrmMainPopup.SetCtrlClickMenu(value : boolean);
  374. begin
  375.     self.UseCtrlClickOpen := not value;
  376.     self.UseCtrlClickMenu := value;
  377. end;
  378.  
  379. procedure TFrmMainPopup.SetMimicKey(key : integer);
  380. begin
  381.     self.MimicKey := VK_F1 + key;
  382. end;
  383. procedure TFrmMainPopup.SetCopyKey(key : integer);
  384. begin
  385.     self.CopyKey := VK_F1 + key;
  386. end;
  387. procedure TFrmMainPopup.SetPermanentKey(key : integer);
  388. begin
  389.     self.PermanentKey := VK_F1 + key;
  390. end;
  391.  
  392. procedure TFrmMainPopup.SetShowEditHistory(value : boolean);
  393. begin
  394.     self.DoShowEditHistory := value;
  395. end;
  396.  
  397. procedure TFrmMainPopup.SetShowPermanentItemSubmenu(value : boolean);
  398. begin
  399.     if (value) then begin
  400.         DoShowPermanentItemSubmenu := true;
  401.         DoShowPermanentItemGroups := false;
  402.     end;
  403. end;
  404. procedure TFrmMainPopup.SetShowPermeanentItemGroups(enable : boolean);
  405. begin
  406.     if (enable) then begin
  407.         DoShowPermanentItemSubmenu := false;
  408.         DoShowPermanentItemGroups := true;
  409.     end;
  410. end;
  411. procedure TFrmMainPopup.SetOtherPasteMethodPasting();
  412. begin
  413.     self.UseOtherClipboardOnly := false;
  414.     self.UseOtherPasting := true;
  415. end;
  416. procedure TFrmMainPopup.SetOtherPasteMethodClipboardOnly();
  417. begin
  418.     self.UseOtherClipboardOnly := true;
  419.     self.UseOtherPasting := false;
  420. end;
  421.  
  422. procedure TFrmMainPopup.SetDoShowLast(DoShow: boolean);
  423. begin
  424.     self.DoShowLast := DoShow;
  425. end;
  426. procedure TFrmMainPopup.SetRememberHistory(DoRemember: boolean);
  427. begin
  428.     self.DoRememberHistory := DoRemember;
  429. end;
  430. procedure TFrmMainPopup.SetVisibleCharacterCount(count: longint);
  431. begin
  432.     self.VisibleCharCount := count;
  433. end;
  434. procedure TFrmMainPopup.SetShowCurrentItem(DoShow: boolean);
  435. begin
  436.     self.DoShowCurrentItem := doshow;
  437. end;
  438.  
  439. procedure TFrmMainPopup.SetShowPasteAll(DoShow: boolean);
  440. begin
  441.     self.DoShowPasteAll := DoShow;
  442. end;
  443. procedure TFrmMainPopup.SetPopupUseKeyboard(usekb: boolean);
  444. begin
  445.     self.PopupUseKB := usekb;
  446. end;
  447.  
  448. procedure TFrmMainPopup.SetPermanentItems(DoUse: boolean);
  449. begin
  450.     self.UsePermanentItems := douse;
  451. end;
  452.  
  453. procedure TFrmMainPopup.SetMoveSelectedItemToTop(DoMove : boolean);
  454. begin
  455.     DoMoveSelectedToTop := DoMove;
  456. end;
  457.  
  458.  
  459. {
  460. --========================
  461. -- // Create/Destroy   //
  462. --========================
  463.  
  464. Popup menu
  465. NoPaste file
  466. Init vars
  467.  
  468. Handle a form close or a logoff/shutdown
  469. }
  470.  
  471.  
  472. procedure TFrmMainPopup.FormCreate(Sender: TObject);
  473. begin
  474.     //
  475.     // popup & menu items init
  476.     //
  477.     self.ShowHint := true;
  478.     Popup := TMyPopupMenu.Create(self);
  479.  
  480.     TooltipPopup := TTooltipPopup.Create;
  481.  
  482.  
  483.     ThreadAttached := false;
  484.  
  485.     {
  486.     NoPastePrograms := THashedStringList.Create;
  487.     f := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName)) +
  488.         PASTE_ONLY_FILE;
  489.     If FileExists(f) then begin
  490.         NoPastePrograms.LoadFromFile(f);
  491.     end;
  492.     }
  493.     self.CurrentClipboard := TClipItem.Create;
  494.  
  495. end;
  496.  
  497. procedure TFrmMainPopup.FormClose(Sender: TObject; var Action: TCloseAction);
  498. begin
  499.     self.HandleCloseEvent;
  500. end;
  501.  
  502. //
  503. // When OS is shutting down/logging off
  504. //
  505. procedure TFrmMainPopup.WMEndSession(var msg : TWMQueryEndSession);
  506. begin
  507.     self.HandleCloseEvent;
  508.     msg.Result := 1;       // do allow close
  509. end;
  510.  
  511.  
  512. procedure TFrmMainPopup.HandleCloseEvent;
  513. begin
  514.     if self.DoRememberHistory then begin
  515.         frmClipboardManager.SaveHistory;
  516.         //frmRemoved.SaveHistory;
  517.     end;
  518.  
  519.     {
  520.     if NoPastePrograms.Count > 0 then begin
  521.         f := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName)) +
  522.           PASTE_ONLY_FILE;
  523.         NoPastePrograms.SaveToFile(f);
  524.     end;
  525.     }
  526.     FrmConfig.SaveLastPermPath;
  527.     FrmPermanent.Close;
  528.     
  529.     //
  530.     // clean up resources
  531.     //
  532.     //MyFree(NoPastePrograms);
  533.     Popup.Items.Clear;
  534.     MyFree(Popup);
  535.     MyFree(Self.CurrentClipboard);
  536. end;
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547. {
  548. --======================
  549. -- // HotKey Message  //
  550. --======================
  551.  
  552. Description:
  553.     Find the target control
  554.     - Handle case when no target control
  555.     - allow user to add problematic program to "No Paste" list
  556.  
  557.     Finally, pass control to  ShowPopupWithFocusRules
  558.  
  559.  
  560. info collected here:
  561.     HotKeyForeWindow
  562.     HotKeyTarget
  563.     TargetX
  564.     TargetY
  565.     TargetEXE
  566. }
  567.  
  568. procedure TFrmMainPopup.WMHotKey(var Msg: TWMHotKey);
  569. label EXIT_CODE;
  570. begin
  571.     // Duplicate message detection
  572.     Windows.SetLastError(ERROR_SUCCESS);
  573.     if (self.HotkeyActive) then begin
  574.         UnitMisc.AppendLog('Duplicate hotkey press detected');
  575.         EXIT;
  576.     end;
  577.     self.HotkeyActive := true;
  578.  
  579.     // Ignore any hotkeys that don't belong to us
  580.     if (msg.HotKey <> FrmConfig.GetHotKeyID) and
  581.         (msg.HotKey <> FrmCOnfig.GetTTHotKeyID)and
  582.         (msg.HotKey <> FrmCOnfig.GetPTTHotKeyID)
  583.         then begin
  584.         goto EXIT_CODE;
  585.     end;
  586.  
  587.     if self.ThreadAttached then begin
  588.         sleep(100);
  589.         if self.ThreadAttached then begin
  590.             UnitMisc.AppendLog('wm_hotkey - thread already attached');
  591.             goto EXIT_CODE;
  592.         end;
  593.     end;
  594.     // Ignore the clipboard as soon as the hotkey is pressed
  595.     // Stop ignoring on an error exit
  596.     // Each invididual menu item is responsible to stop ingoring the clipboard
  597.     //frmClipboardManager.SetIgnoreClipboard(true);
  598.  
  599.     UnitMisc.AppendLog('WM_Hotkey - received');
  600.     if (self.IgnoreHotkey) then begin
  601.         UnitMisc.AppendLog('ignoring hotkey');
  602.         //frmClipboardManager.SetIgnoreClipboard(false);
  603.         goto EXIT_CODE;
  604.     end;
  605.  
  606.     // get current foreground window
  607.     // get the data needed to show the popup from the window
  608.  
  609.     self.HotKeyForeWindow := Windows.GetForegroundWindow();
  610.     if (self.HotKeyForeWindow = 0) then begin
  611.         ShowMessage('Couldn''t get foreground window');
  612.         //frmClipboardManager.SetIgnoreClipboard(false);
  613.         goto EXIT_CODE;
  614.     end;
  615.     self.GatherTargetWindowData;
  616.  
  617.  
  618.     // Show the Popup, Next Tooltip, or Previous Toolip
  619.     if (msg.HotKey = FrmConfig.GetHotKeyID)  then begin
  620.         self.FullMode := false;
  621.         self.ShowPopupWithFocusRules;
  622.     end else if (msg.HotKey = FrmConfig.GetTTHotKeyID) then begin
  623.         self.HotkeyActive := false;
  624.         TooltipPopup.ShowTooltipNext(targetx + 10, targety+20);
  625.     end else if (msg.HotKey = FrmConfig.GetPTTHotKeyID) then begin
  626.         self.HotkeyActive := false;
  627.         TooltipPopup.ShowTooltipPrev(targetx + 10, targety+20);
  628.     end;
  629.  
  630. EXIT_CODE:
  631.     self.HotkeyActive := false;
  632. end;
  633.  
  634. procedure TFrmMainPopup.GatherTargetWindowData;
  635. var answer : longint;
  636. begin
  637.     Windows.SetLastError(ERROR_SUCCESS);
  638.  
  639.     // find control with focus on foreground window
  640.     // ingore error when pasting option is "Clipboard Only"
  641.  
  642.     self.GetTargetControl(self.HotKeyForeWindow, self.HotKeyTarget,
  643.             TargetX, TargetY);
  644.     if (FrmConfig.cbDisplayAtMouseCursor.Checked) then begin
  645.         TargetX := Mouse.CursorPos.X;
  646.         TargetY := Mouse.CursorPos.Y;
  647.     end;
  648.     self.TargetEXE := WindowHandleToEXEName(self.HotKeyForeWindow);
  649.  
  650.  
  651.     Paste.ClearOnceFlags;
  652.     case Paste.GetPasteMethod(self.TargetEXE) of
  653.     PASTE_CTRL_V    :
  654.         begin
  655.             Paste.SetUsePasteCVOnce;
  656.         end;
  657.     PASTE_SHIFT_INS :
  658.         begin
  659.             Paste.SetUsePasteSIOnce;
  660.         end;
  661.     PASTE_MIMIC     :
  662.         begin
  663.             Paste.SetKeyboardMimicOnce;
  664.         end;
  665.     PASTE_CLIPBOARD :
  666.         begin
  667.             Paste.SetClipboardOnlyOnce;
  668.         end;
  669.     PASTE_DEFAULT :
  670.         begin
  671.         end;
  672.     end;
  673.  
  674.  
  675.     //
  676.     // Default to mouse position when can't target a control
  677.     //
  678.     if (HotKeyTarget = 0) then begin
  679.         {
  680.         Windows.GetWindowPlacement(self.HotKeyForeWindow, @wp);
  681.         TargetX := wp.rcNormalPosition.Left;
  682.         TargetY := wp.rcNormalPosition.Top;
  683.         }
  684.         TargetX := Mouse.CursorPos.X;
  685.         TargetY := Mouse.CursorPos.Y;
  686.  
  687.         //
  688.         // Bitch if were not in ClipboardOnly mode
  689.         // or per-program override can't paste the item right by default.
  690.         // Allow user to always use ClipboardOnly for the problematic
  691.         // program
  692.         // [Answer Yes = add EXE name to NoPaste file]
  693.         //
  694.  
  695.         if (not (Paste.GetPasteMethod(self.TargetEXE) in [PASTE_CLIPBOARD, PASTE_MIMIC]))
  696.             and
  697.            (not (Paste.GetDefaultPasteMethod in [PASTE_CLIPBOARD, PASTE_MIMIC]))
  698.             then begin
  699.  
  700.             Windows.SetForegroundWindow(self.Handle);
  701.             answer := MessageDlg('Coudn''t find control to target in program ' + uppercase(self.TargetEXE) + #13#10
  702.                 + 'Would you like to use "Copy to clipboard only" for this program?',
  703.                 mtConfirmation, [mbyes, mbno],0 );
  704.  
  705.             if (answer = mryes) then begin
  706.                 //NoPastePrograms.Add(self.TargetEXE);
  707.                 Paste.AssignPaste(self.TargetEXE, PASTE_CLIPBOARD);
  708.             end;
  709.  
  710.             if (answer <> mryes) then begin
  711.                 Windows.SetForegroundWindow(self.HotKeyForeWindow);
  712.                 //frmClipboardManager.SetIgnoreClipboard(false);
  713.                 EXIT;
  714.             end;
  715.             //Paste.SetClipboardOnlyOnce;
  716.         end;
  717.  
  718.         Windows.SetForegroundWindow(self.Handle);
  719.     end;
  720. end;
  721.  
  722.  
  723. procedure TfrmMainPopup.GetTargetControl(ParentWindow: cardinal;
  724.     var TargetHandle: cardinal;
  725.     var TargetX: integer;
  726.     var TargetY: integer);
  727. var CaretPos: TPoint;
  728.     Rect: TRect;
  729. begin
  730.     Windows.SetLastError(ERROR_SUCCESS);
  731.  
  732.     // attempt to get target control's handle and
  733.     // the position of the caret in the text window
  734.     //
  735.     TargetHandle := 0;
  736.     if (self.ThreadAttach(ParentWindow)) then begin
  737.         TargetHandle := Windows.GetFocus();
  738.         if (TargetHandle <> 0) then begin
  739.             Windows.GetCaretPos(CaretPos);
  740.             Windows.GetWindowRect(HotKeyTarget, Rect);
  741.  
  742.             TargetX := Rect.left + CaretPos.X;
  743.             TargetY := Rect.top + CaretPos.Y;
  744.         end;
  745.         self.ThreadDetach;
  746.     end;
  747. end;
  748.  
  749.  
  750.  
  751.  
  752.  
  753. //
  754. // ShowPopupWithFocusRules: Wrapper function to call ShowPopup enforcing the
  755. // focus rules. The rule is to return focus to the original window.
  756. //
  757. // Once the Hotkey has been pressed, you can reshow the
  758. // popup again by calling this procedure.
  759. //
  760. // Program flow continues to a XXXClickEvent routine when the user
  761. // selects an item from the popup window
  762.  
  763. procedure TFrmMainPopup.ShowPopupWithFocusRules;
  764. begin
  765.     Windows.SetLastError(ERROR_SUCCESS);
  766.     // Attaching to the target keeps the popup from
  767.     // taking away focus from the target item.
  768.     // Example, pasting to the name of a desktop icon. If you remove
  769.     // focus, you remove the rename box
  770.  
  771.     if (self.PopupUseKB) then begin
  772.         // we need to be foreground for keyboard focus
  773.         Windows.SetForegroundWindow(self.Handle);
  774.         self.ShowPopup(TargetX, TargetY);
  775.  
  776.         // make sure focus is returned
  777.         if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  778.             SetForegroundWindow(self.HotKeyForeWindow);
  779.             self.ThreadDetach;
  780.         end;
  781.     end else begin
  782.         if (not self.ThreadAttach(self.HotKeyForeWindow)) then begin
  783.             ShowMessage('ERROR: Couldn''t attach popup menu to this window');
  784.             //frmClipboardManager.SetIgnoreClipboard(false);
  785.             exit;
  786.         end;
  787.  
  788.         self.ShowPopup(TargetX, TargetY);
  789.         self.ThreadDetach();
  790.     end;
  791. end;
  792.  
  793.  
  794.  
  795.  
  796. procedure TfrmMainPopup.ShowPopup(X,Y: integer);
  797.     procedure DrawIconOnMenuItem(m : TMenuItem; icon : HICON);
  798.     begin
  799.         if (icon <> 0) then begin
  800.             //DrawIcon(imgIcon.Canvas.Handle,0,0,icon);
  801.             m.bitmap.width := 32;
  802.             m.bitmap.height := 32;
  803.             m.bitmap.pixelformat := pf24bit;
  804.             if not DrawIcon(m.Bitmap.Canvas.Handle,0,0,icon) then begin
  805.                 UnitMisc.AppendLog('DrawIcon failed:' + SysUtils.SysErrorMessage(getlasterror) );
  806.             end;
  807.         end;
  808.     end;
  809.  
  810.  
  811.     procedure PopulatePopupANSI;
  812.     var i, j : integer;
  813.         m, subm, subm2 : TMenuItem;
  814.         s : string;
  815.         icon : HICON;
  816.         ci : TClipItem;
  817.     begin
  818.  
  819.        //
  820.         // Recreate the menuitems
  821.         //
  822.         popup.Items.Clear;
  823.  
  824.         for i := 0 to (ClipQueue.GetQueueCount - 1) do begin
  825.             m := TMenuItem.Create(popup);
  826.             s := ClipQueue.GetItemText(i);
  827.             if (self.PopupUseKB) then begin
  828.                 m.Caption  := '&' + GetAccelerator(i) + ': ' + GetTrimmedItem(s);
  829.             end else begin
  830.                 m.Caption  :=  GetTrimmedItem(s);
  831.             end;
  832.  
  833.  
  834.  
  835.             m.hint := s;
  836.  
  837.             ci := ClipQueue.GetClipItem(i);
  838.             icon := 0;
  839.             if ci <> nil then begin
  840.                 icon := ci.CData.GetHICON;
  841.                 if (FrmConfig.cbShowTypes.Checked) then begin
  842.                     m.caption := UnitMisc.GetCliptypeSymbol(ci.GetFormat) + ' ' + m.Caption;
  843.                 end;
  844.             end;
  845.  
  846.             DrawIconOnMenuItem(m, icon);
  847.             m.OnClick := self.MenuItemClickEvent;
  848.             popup.Items.Add(M);
  849.         end;
  850.         {
  851.         if (self.FullMode) then begin
  852.             m := TMenuItem.Create(Popup);
  853.             m.Caption := 'Flush Text';
  854.             m.OnClick := self.FlushTextItemsClickEvent;
  855.             m.Bitmap := imgFlush.Picture.Bitmap;
  856.             popup.Items.Add(m);
  857.         end;
  858.         }
  859.         if (self.DoShowEditHistory) or (self.FullMode) then begin
  860.             m := TMenuItem.Create(Popup);
  861.             m.Caption := 'Edit History...';
  862.             m.OnClick := self.EditHistoryItemClickEvent;
  863.             m.Bitmap := imgEdit.Picture.Bitmap;
  864.             popup.Items.Add(m);
  865.         end;
  866.  
  867.         //
  868.         // other clipboard items
  869.         // The hint contains the items index in the queue
  870.         //
  871.         if (OtherQueue.GetQueueCount > 0) then begin
  872.             popup.Items.Add(NewLine());
  873.  
  874.             for i := (OtherQueue.GetQueueCount - 1) downto 0 do begin
  875.                 m := TMenuItem.Create(popup);
  876.                 m.Caption := OtherQueue.GetClipItem(i).GetAsText  + ': size ' +
  877.                     IntToStr(Trunc(OtherQueue.GetClipItem(i).GetDataSize  / 1024)) +
  878.                     ' KB';
  879.                 //m.Hint := IntToStr(i);
  880.                 m.ImageIndex := i;
  881.                 DrawIconOnMenuItem(m, OtherQueue.GetClipItem(i).CData.GetHICON);
  882.                 m.OnClick := OtherItemClickEvent;
  883.  
  884.                 popup.items.Add(m);
  885.             end;
  886.  
  887.             {
  888.             if (self.FullMode) then begin
  889.                 m := TMenuItem.Create(popup);
  890.                 m.Caption := 'Flush non-text';
  891.                 m.OnClick := FlushOtherItemsClickEvent;
  892.  
  893.                 m.Bitmap := imgFlush.Picture.Bitmap;
  894.  
  895.                 popup.Items.Add(m);
  896.             end;
  897.             }
  898.         end;
  899.  
  900.         //
  901.         // divider line cancel cancel
  902.         // divider line Last string option
  903.         //
  904.         popup.Items.Add(NewLine());
  905.         m := TMenuItem.Create(popup);
  906.         m.caption := 'Cancel';
  907.         m.OnClick := self.CancelMenuItemClickEvent;
  908.         popup.Items.Add(m);
  909.  
  910.         if ((self.DoShowLast) or (self.FullMode))and (trim(LastStringSelected) <> '') then begin
  911.             popup.Items.Add(Menus.NewLine());
  912.             m := TMenuItem.Create(popup);
  913.             m.caption := 'Last: ' + GetTrimmedItem(LastStringSelected);
  914.             m.OnClick := self.LastMenuItemClickEvent;
  915.  
  916.             popup.Items.Add(m);
  917.         end;
  918.  
  919.         // current clipboard item
  920.         // (may need to add line if 'Last' doesn't exist yet)
  921.         if (self.DoShowCurrentItem)  or (self.FullMode) then begin
  922.             if (trim(LastStringSelected) = '') or (not (self.DoShowLast or FullMode)) then begin
  923.                 popup.Items.Add(Menus.NewLine());
  924.             end;
  925.             m := TMenuItem.Create(popup);
  926.             self.CurrentClipboard.GetClipboardItem(0);
  927.             if (self.CurrentClipboard.HasText) then begin
  928.                 s := self.CurrentClipboard.GetAsText;
  929.             end else begin
  930.                 s := self.CurrentClipboard.GetFormatName;
  931.             end;
  932.             m.Hint := s;
  933.             if (s = '') then begin
  934.                 m.Caption :=  GetTrimmedItem('Current: ' +self.CurrentClipboard.GetFormatName);
  935.             end else begin
  936.                 m.caption := GetTrimmedItem('Current: ' + self.CurrentClipboard.GetAsText);
  937.             end;
  938.             m.OnClick := self.CurrentMenuItemClickEvent;
  939.             popup.Items.Add(m);
  940.         end;
  941.  
  942.         //
  943.         // paste all / paste selected
  944.         //
  945.         if (self.DoShowPasteAll)  or (self.FullMode)
  946.             or (self.DoShowFormMode) or (self.UseFormMode) then begin
  947.             popup.Items.Add(menus.NewLine());
  948.  
  949.             if (self.DoShowPasteAll) or (self.FullMode) then begin
  950.                 m := TMenuItem.Create(popup);
  951.                 m.caption := 'Paste All';
  952.                 m.OnClick := self.PasteAllMenuItemClickEvent;
  953.                 m.Bitmap := self.imgPasteAll.Picture.Bitmap;
  954.                 popup.Items.Add(m);
  955.  
  956.                 m := TMenuItem.Create(popup);
  957.                 m.caption := 'Paste Selected...';
  958.                 m.OnClick := self.PasteSelectedMenuItemClickEvent;
  959.                 m.Bitmap := self.imgPaste.Picture.Bitmap;
  960.                 popup.Items.Add(m);
  961.             end;
  962.             if (self.DoShowFormMode) or (self.FullMode) or (self.UseFormMode) then begin
  963.                 m := TMenuItem.Create(popup);
  964.                 if self.UseFormMode then begin
  965.                     m.caption := 'Form Mode OFF';
  966.                 end else begin
  967.                     m.caption := 'Form Mode ON';
  968.                 end;
  969.  
  970.                 m.AutoCheck  := true;
  971.                 m.Checked := self.UseFormMode;
  972.                 m.OnClick := self.FormModeMenuItemClickEvent;
  973.                 m.Bitmap := self.imgEdit.Picture.Bitmap;
  974.                 popup.Items.Add(m);
  975.  
  976.                 m := TMenuItem.Create(popup);
  977.                 m.caption := '>> Next Field';
  978.                 m.AutoCheck  := true;
  979.                 m.OnClick := self.NextFieldModeMenuItemClickEvent;
  980.                 m.Bitmap := self.imgEdit.Picture.Bitmap;
  981.                 popup.Items.Add(m);
  982.  
  983.             end;
  984.  
  985.         end;
  986.         //
  987.         // permanent items groups
  988.         //
  989.         if (self.UsePermanentItems) or (self.FullMode)  then begin
  990.             {if not frmSysTrayMenu.GetJustSwitched then begin
  991.                 FrmPermanent.AutoSwitch(self.TargetEXE);
  992.             end;}
  993.             popup.Items.Add(menus.NewLine());
  994.             for i := 0 to frmPermanent.GetCount - 1 do begin
  995.                 m := TMenuItem.Create(popup);
  996.                 m.hint := frmPermanent.GetItemText(i);
  997.                 m.Caption := FrmPermanent.GetItemName(i);
  998.                 m.OnClick := self.PermanentMenuItemClickEvent;
  999.                 m.Tag := -1;
  1000.                 popup.Items.Add(m);
  1001.             end;
  1002.  
  1003.             //
  1004.             // don't show in full mode if user specified submenu for Permanent
  1005.             // Items
  1006.             //
  1007.             if (FrmConfig.cbShowSwitchTo.Checked or self.FullMode) then begin
  1008.                 if (self.DoShowPermanentItemGroups)
  1009.                     or (self.FullMode and (not self.DoShowPermanentItemSubmenu)) then begin
  1010.                     s := lowercase(frmPermanent.GetPermanentPath);
  1011.                     for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin
  1012.                         if (lowercase(frmPermanent.PermFoldersGetItem(i)) <> s) then begin
  1013.                             m := TMenuItem.Create(popup);
  1014.                             m.Hint := frmPermanent.PermFoldersGetItem(i);
  1015.                             m.Caption := 'Switch to ' + m.Hint;
  1016.                             m.OnClick := self.PermanentGroupItemClickEvent;
  1017.                             m.Bitmap := imgRightArrow.Picture.Bitmap;
  1018.                             popup.Items.Add(m);
  1019.                         end;
  1020.                     end;
  1021.                 end;
  1022.             end;
  1023.             //
  1024.             // permanent items submenu
  1025.             //
  1026.             if (FrmConfig.cbShowSwitchTo.Checked or self.FullMode) then begin
  1027.                 if (self.DoShowPermanentItemSubmenu) then begin
  1028.                     subm := TMenuItem.Create(popup);
  1029.                     subm.Hint := '';
  1030.                     subm.Caption := 'Permanent Items...';
  1031.                     subm.Bitmap := imgPermCasc.Picture.Bitmap;
  1032.                     s := lowercase(frmPermanent.GetPermanentPath);
  1033.  
  1034.                     for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin
  1035.                         m := TMenuItem.Create(popup);
  1036.                         m.Hint := frmPermanent.PermFoldersGetItem(i);
  1037.                         if (lowercase(frmPermanent.PermFoldersGetItem(i)) <> s) then begin
  1038.                             m.Caption := 'Switch to ' + m.Hint;
  1039.                         end else begin
  1040.                             m.Caption := 'Switch to ' + m.Hint + ' (Current)';
  1041.                         end;
  1042.                         m.OnClick := self.PermanentGroupItemClickEvent;
  1043.                         subm.Add(m);
  1044.                     end;
  1045.  
  1046.                     popup.items.Add(subm);
  1047.                 end;
  1048.             end;
  1049.  
  1050.             // All Items as submenu
  1051.             if (FrmConfig.cbShowAllItems.checked) or (self.fullmode) then begin
  1052.                 subm := TMenuItem.Create(popup);
  1053.                 subm.Hint := '';
  1054.                 subm.Caption := 'All Items...';
  1055.                 subm.Bitmap := imgPermCasc.Picture.Bitmap;
  1056.                 subm.OnClick := nil;
  1057.                 s := lowercase(frmPermanent.GetPermanentPath);
  1058.  
  1059.                 FrmPermanent.PermFolderPush;
  1060.                 for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin
  1061.                     if (lowercase(frmPermanent.PermFoldersGetItem(i)) <> s) then begin
  1062.                         m := TMenuItem.Create(popup);
  1063.                         m.Caption := frmPermanent.PermFoldersGetItem(i);
  1064.                         m.Hint := m.Caption;
  1065.                         FrmPermanent.SetPermanentPath(m.Hint);
  1066.                         for j := 0 to FrmPermanent.GetCount - 1 do begin
  1067.                             subm2 := TMenuItem.Create(popup);
  1068.                             subm2.Caption := FrmPermanent.GetItemName(j);
  1069.                             subm2.Hint := FrmPermanent.GetItemText(j);
  1070.                             subm2.tag := i;
  1071.                             subm2.OnClick := self.PermanentMenuItemClickEvent;
  1072.                             m.Add(subm2);
  1073.                         end;
  1074.  
  1075.                         m.OnClick := nil;
  1076.                         subm.Add(m);
  1077.                     end;
  1078.  
  1079.                 end;
  1080.  
  1081.                 FrmPermanent.PermFolderPop;
  1082.                 popup.items.Add(subm);
  1083.             end;
  1084.         end;
  1085.  
  1086.         if (self.FullMode) then begin
  1087.             m := TMenuItem.Create(popup);
  1088.             m.Caption := 'System';
  1089.             m.Hint := '';
  1090.             m.Bitmap := self.imgPermCasc.Picture.Bitmap;
  1091.             frmSysTrayMenu.ShowPopup(m);
  1092.             m.OnClick := nil;
  1093.             popup.Items.Add(m);
  1094.         end;
  1095.         //
  1096.         // full mode/ configured mode
  1097.         //
  1098.         popup.Items.Add(menus.NewLine());
  1099.         m := TMenuItem.Create(popup);
  1100.         if (self.FullMode = true) then begin
  1101.             m.Caption := 'Configured Mode';
  1102.             m.Bitmap := self.imgConfMode.Picture.Bitmap;
  1103.         end else begin
  1104.             m.Caption := 'Full Mode';
  1105.             m.Bitmap := self.imgFull.Picture.Bitmap;
  1106.         end;
  1107.         m.OnClick := self.FullModeMenuItemClickEvent;
  1108.             m.Hint := '';
  1109.         popup.Items.Add(m);
  1110.     end;
  1111.  
  1112. begin
  1113.     self.IgnoreHotkey := true;
  1114.     if (self.PopupActive) then begin
  1115.         EXIT;
  1116.     end;
  1117.     self.PopupActive := true;
  1118.  
  1119.     if (self.PopupUseKB) then begin
  1120.         popup.AutoHotkeys := maAutomatic;
  1121.     end else begin
  1122.         popup.AutoHotkeys := maManual;
  1123.     end;
  1124.     if not frmSysTrayMenu.GetJustSwitched then begin
  1125.         FrmPermanent.AutoSwitch(self.TargetEXE);
  1126.     end;
  1127.  
  1128.     If (FrmConfig.cbDisplayUnicode.Checked) then begin
  1129.         Popup.OwnerDraw := false;
  1130.         PopulatePopupANSI;
  1131.         FrmDummyUnicodePopup.ShowPopup(x,y, popup);
  1132.     end else begin
  1133.         Popup.OwnerDraw := false;
  1134.         PopulatePopupANSI;
  1135.         UnitMisc.AppendLog('Popup Activated');
  1136.         popup.Popup(x, y);
  1137.         UnitMisc.AppendLog('Popup End');
  1138.     end;
  1139.     //
  1140.     // show
  1141.     // NOTE: This code finishes before .SendText() is ever executed
  1142.     //       I need to stop ignoring here because the popup can be dismissed
  1143.     //       by ESC key or focus lost.
  1144.     //frmClipboardManager.SetIgnoreClipboard(false);
  1145.     self.IgnoreHotkey := false;
  1146.     self.PopupActive := false;
  1147. end;
  1148.  
  1149. //
  1150. // create a 1..9/0 keys for items 0 to 9 and A to Z keys for items 10 and so no
  1151. //
  1152. function TFrmMainPopup.GetAccelerator(i: integer): char;
  1153. begin
  1154.     case (i) of
  1155.     0..8: result := chr(byte('1') + i);
  1156.     9:    result := '0';
  1157.     else
  1158.           result := chr(byte('A') + (i - 10));
  1159.     end;
  1160. end;
  1161.  
  1162. // show a ' ...' when item is too long
  1163. // handle tabs  and handle ampersans
  1164. function TFrmMainPopup.GetTrimmedItem(item : string) : string;
  1165. begin
  1166.     result := item;
  1167.     if (length(result) > VisibleCharCount) then begin
  1168.         result := leftstr(item, VisibleCharCount) + '...';
  1169.     end;
  1170.  
  1171.     // tabs make the windows too damn long
  1172.     // the #10 will make a funky box in the tab's place
  1173.     result := stringreplace(result, #9,#10, [rfReplaceAll]);
  1174.     result := stringreplace(result, #13,#10, [rfReplaceAll]);
  1175.     result := stringreplace(result, '&', '&&', [rfReplaceAll]);
  1176. end;
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186. procedure TFrmMainPopup.FormShow(Sender: TObject);
  1187. begin
  1188.     UnitMisc.FlushLog;
  1189. end;
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200. {
  1201. --============================
  1202. -- // Popup MenuItem Clicks //
  1203. --============================
  1204.  
  1205. Description:
  1206.  
  1207. Handle a normal menu item,
  1208. other item,
  1209. 'cancel' item,
  1210. Last item,
  1211. Current item,
  1212. Paste All,
  1213. Paste Selected,
  1214. Permanent item
  1215.  
  1216. Text item make use of the SendText routing to enforce configuration
  1217. option.
  1218.  
  1219. Remember the last selected text item for the 'last' menu item option.
  1220.  
  1221. Inform the clipboard manager of any pasting we do.
  1222. }
  1223.  
  1224.  
  1225. //
  1226. // KeyPressedOverride
  1227. // Returns TRUE when an alternate action has taken place
  1228. // because of a KEYSTROKE+Click action by the user
  1229. // Returns FALSE when no override took place
  1230. //
  1231. function TFrmMainPopup.KeyPressedOverride(s : string; ci : TClipItem = nil) : boolean;
  1232.     //
  1233.     // run text as shell command
  1234.     // or show CTRL+Click menu
  1235.     //
  1236.     function CTRLOpen(s : string) : boolean;
  1237.     var    i : integer;
  1238.     begin
  1239.         result := true;
  1240.  
  1241.         // detect held CTRL key
  1242.         // Execute item or show menu
  1243.         if (KeyboardQuery.IsPressed(VK_CONTROL)) then begin
  1244.             if (self.UseCtrlClickMenu) then begin
  1245.                 if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  1246.                     Windows.SetForegroundWindow(self.Handle);
  1247.                     self.ThreadDetach;
  1248.                 end;
  1249.  
  1250.                 for i := 0 to (pmItemOptions.Items.Count - 1) do begin
  1251.                     pmItemOptions.Items[i].Enabled := true;
  1252.                 end;
  1253.                 
  1254.                 // Show the format in the "Paste as" Menu option
  1255.                 N0PasteasRichText1.Enabled := false;
  1256.                 N0PasteasRichText1.Caption := '&0  [no "paste as" format]';
  1257.                 AMakePermanentas1.Enabled := false;
  1258.                 AMakePermanentas1.Caption := '&A  [no complex format]';
  1259.  
  1260.                {
  1261.                  BAssignPasteMethodto1.Caption := '&B  Assign Paste Method to '
  1262.                     + self.TargetEXE;
  1263.                }
  1264.                 self.CTRLClickedItem := ci;
  1265.                 if (self.CTRLClickedItem = nil) then begin
  1266.                     i := ClipQueue.IndexOf(s);
  1267.                     if (i <> -1) then begin
  1268.                         self.CTRLClickedItem := ClipQueue.GetClipItem(i);
  1269.                     end;
  1270.                 end;
  1271.  
  1272.                 if (self.CTRLClickedItem <> nil) then begin
  1273.                     if self.CTRLClickedItem.GetFormat = FrmClipboardManager.CF_RICHTEXT then begin
  1274.                         N0PasteasRichText1.Enabled  := true;
  1275.                         if (FrmConfig.cbPasteComplex.Checked) then begin
  1276.                             N0PasteasRichText1.Caption := '&0  Paste as Plain Text';
  1277.                         end else begin
  1278.                             N0PasteasRichText1.Caption := '&0  Paste as Rich Text';
  1279.                         end;
  1280.                         AMakePermanentas1.Enabled := true;
  1281.                         AMakePermanentas1.Caption := '&A  Make Permanent as Rich Text';
  1282.                     end;
  1283.                     if self.CTRLClickedItem.GetFormat = Windows.CF_UNICODETEXT then begin
  1284.                         pmItemOptions.Items[0].Enabled := true;
  1285.                         if (FrmConfig.cbPasteComplex.Checked) then begin
  1286.                             N0PasteasRichText1.Caption := '&0  Paste as Plain Text';
  1287.                         end else begin
  1288.                             N0PasteasRichText1.Caption := '&0  Paste as UNICODE';
  1289.                         end;
  1290.                         AMakePermanentas1.Enabled := true;
  1291.                         AMakePermanentas1.Caption := '&A  Make Permanent as UNICODE';
  1292.                     end;
  1293.                     if (self.CTRLClickedItem.GetFormat = Windows.CF_HDROP) then begin
  1294.                         N0PasteasRichText1.Enabled := true;
  1295.                         N0PasteasRichText1.Caption := '&0  Paste as Files';
  1296.                         AMakePermanentas1.Enabled := true;
  1297.                         AMakePermanentas1.Caption := '&A  Make Permanent as Files';
  1298.                     end;
  1299.  
  1300.                     if (self.CTRLClickedItem.GetFormat = FrmClipboardManager.CF_HTML) then begin
  1301.                         N0PasteasRichText1.Enabled := true;
  1302.                         N0PasteasRichText1.Caption := '&0  Paste as HTML';
  1303.                         AMakePermanentas1.Enabled := true;
  1304.                         AMakePermanentas1.Caption := '&A  Make Permanent as HTML';
  1305.                     end;
  1306.                 end;
  1307.  
  1308.                 pmItemOptions.Items.RethinkHotkeys;
  1309.                 Run1.Caption := '&1  Run "'
  1310.                     + self.GetTrimmedItem(s)
  1311.                     + '..."';
  1312.                 pmItemOptions.Popup(self.TargetX, self.TargetY );
  1313.  
  1314.                 // make sure focus is returned
  1315.                 if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  1316.                     SetForegroundWindow(self.HotKeyForeWindow);
  1317.                     self.ThreadDetach;
  1318.                 end;
  1319.             end else begin
  1320.                 //
  1321.                 // use the CTRL+Click Menu to do this
  1322.                 //
  1323.                 self.Run1.Click;
  1324.             end;
  1325.             EXIT;
  1326.         end;
  1327.         result := false;
  1328.     end;
  1329.  
  1330.  
  1331.     //
  1332.     //  Show a preview of item when SHIFT-Clicked
  1333.     //
  1334.     function SHIFTOpen(s : string) : boolean;
  1335.     begin
  1336.         result := true;
  1337.         if (KeyboardQuery.IsPressed(VK_SHIFT)) then begin
  1338.             self.Preview1.Click;
  1339.             EXIT;
  1340.         end;
  1341.         result := false;
  1342.     end;
  1343.  
  1344.     function CopyKeyOpen(s : string) : boolean;
  1345.     begin
  1346.         //
  1347.         // just turn on "Paste Only" toggle and let
  1348.         // selected menu item handle sending the text as normal
  1349.         //
  1350.         if (KeyboardQuery.IsPressed(self.CopyKey)) then begin
  1351.             Paste.SetClipboardOnlyOnce;
  1352.         end;
  1353.         result := false;
  1354.     end;
  1355.  
  1356.     function PermanentKeyOpen(s : string) : boolean;
  1357.     begin
  1358.         //
  1359.         // Show Permanent Items dialog with new entry
  1360.         //
  1361.         result := true;
  1362.         if (KeyboardQuery.IsPressed(Self.PermanentKey)) then begin
  1363.             Windows.SetForegroundWindow(FrmPermanent.Handle);
  1364.             frmPermanent.ShowWithNewItem(s);
  1365.             EXIT;
  1366.         end;
  1367.         result := false;
  1368.     end;
  1369.  
  1370.     function MimicKeyOpen(s : string) : boolean;
  1371.     begin
  1372.         // just turn on "Mimic Typing" toggle and let
  1373.         // selected menu item handle sending the text as normal
  1374.         if (KeyboardQuery.IsPressed(self.MimicKey)) then begin
  1375.             Paste.SetKeyboardMimicOnce;
  1376.         end;
  1377.         result := false;
  1378.     end;
  1379. begin
  1380.     result := CTRLOpen(s);
  1381.     if (result) then EXIT;
  1382.  
  1383.     result := SHIFTOpen(s);
  1384.     if (result) then EXIT;
  1385.  
  1386.     result := CopyKeyOpen(s);
  1387.     if (result) then EXIT;
  1388.  
  1389.     result := MimicKeyOpen(s);
  1390.     if (result) then EXIT;
  1391.  
  1392.     result := PermanentKeyOpen(s);
  1393.     if (result) then EXIT;
  1394.  
  1395. end;
  1396.  
  1397. procedure TFrmMainPopup.ShowPreviewForm;
  1398. begin
  1399.     Windows.SetForegroundWindow(FrmPreview.Handle);
  1400.  
  1401.     FrmPreview.Left := Self.TargetX;
  1402.     FrmPreview.Top := Self.TargetY;
  1403.     FrmPreview.ShowModal;
  1404.     self.ShowPopupWithFocusRules;
  1405. end;
  1406.  
  1407.  
  1408. procedure TfrmMainPopup.MenuItemClickEvent(Sender: TObject);
  1409. var s : string;
  1410.     i : integer;
  1411.     pasted : boolean;
  1412. begin
  1413.     //
  1414.     // The item is passed is a TMenuItem by default, but
  1415.     // my hacked Unicode popup isn't that smart
  1416.     //
  1417.     if (Sender is TMenuItem) then begin
  1418.         with Sender as TMenuItem do begin
  1419.             s := Hint;
  1420.             MenuItemText := s;
  1421.             i := ClipQueue.IndexOf(s);
  1422.             self.CTRLClickedItem  := ClipQueue.GetClipItem(i);
  1423.         end;
  1424.     end else begin
  1425.         self.CTRLClickedItem := TClipItem(sender);
  1426.         s := self.CTRLClickedItem.GetAsText;
  1427.         MenuItemText := s;
  1428.     end;
  1429.  
  1430.     UnitMisc.AppendLog('MenuItem format=' + self.CTRLClickedItem.GetFormatName );
  1431.     if (self.KeyPressedOverride(s, self.CTRLClickedItem)) then begin
  1432.         EXIT;
  1433.     end;
  1434.  
  1435.     LastStringSelected := s;
  1436.     if (self.DoMoveSelectedToTop) then
  1437.         ClipQueue.MoveToStart( ClipQueue.IndexOf(self.CTRLClickedItem) );
  1438.  
  1439.     //
  1440.     // Legacy Note: The ClipItem may have no handle and no format and may
  1441.     // only contain the plain text version of an item
  1442.     //
  1443.     pasted := false;
  1444.     if (self.CTRLClickedItem  <> nil) and (self.CTRLClickedItem.GetFormat <> 0) then begin
  1445.         if (not Paste.GetKeyboardMimicOnce) then begin
  1446.             if (self.CTRLClickedItem.GetFormat = Windows.CF_UNICODETEXT) or
  1447.                 (FrmConfig.cbPasteComplex.checked) then begin
  1448.                 UnitMisc.AppendLog('Sending UNICODE by default ');
  1449.                 self.SendText('', self.CTRLClickedItem);
  1450.                 pasted := true;
  1451.                 UnitMisc.AppendLog('inserting done');
  1452.             end;
  1453.         end;
  1454.     end;
  1455.     if (not pasted) then begin
  1456.         UnitMisc.AppendLog('Sending plaing text ');
  1457.         self.SendText(s);
  1458.         UnitMisc.AppendLog('inserting done');
  1459.     end;
  1460.  
  1461.  
  1462.     self.HandleFormMode;
  1463. end;
  1464.  
  1465. procedure TFrmMainPopup.FlushTextItemsClickEvent(Sender: TObject);
  1466. begin
  1467.     ClipQueue.ClearQueue;
  1468.     self.FullMode := false;
  1469.     self.ShowPopupWithFocusRules;
  1470. end;
  1471. procedure TFrmMainPopup.EditHistoryItemClickEvent(Sender : TObject);
  1472. begin
  1473.     // show the edit window
  1474.     // re-show the popup when the edit window it closed
  1475.     Windows.SetForegroundWindow(frmClipboardManager.Handle);
  1476.     frmClipboardManager.ShowModal;
  1477.     self.ShowPopupWithFocusRules;
  1478. end;
  1479.  
  1480. procedure TFrmMainPopup.OtherItemClickEvent(Sender: TObject);
  1481. var i : integer;
  1482.     ci : TClipItem;
  1483. begin
  1484.     if (Sender is TMenuItem) then begin
  1485.         with Sender as TMenuItem do begin
  1486.             i := ImageIndex;
  1487.         end;
  1488.         ci := OtherQueue.GetClipItem(i);
  1489.     end else begin
  1490.         ci := TClipItem(Sender);
  1491.     end;
  1492.  
  1493.     // preview only
  1494.     if (KeyboardQuery.IsPressed(VK_SHIFT)) then begin
  1495.         FrmPreview.SetPicture;
  1496.         ci.GetDIB(FrmPreview.imgPreview.picture);
  1497.         self.ShowPreviewForm;
  1498.         EXIT;
  1499.     end;
  1500.  
  1501.     // Copy - with no paste
  1502.  
  1503.     if (KeyboardQuery.IsPressed(VK_F1)) then begin
  1504.         // try to clear phantom keystroke from entering other program
  1505.         keybd_event(VK_F1, VkKeyScan(char(VK_F1)), KEYEVENTF_KEYUP, 0);
  1506.         Paste.SetClipboardOnlyOnce;
  1507.     end;
  1508.  
  1509.  
  1510.     if (KeyboardQuery.IsPressed(VK_CONTROL) and (self.UseCtrlClickMenu)) then begin
  1511.         if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  1512.             Windows.SetForegroundWindow(self.Handle);
  1513.             self.ThreadDetach;
  1514.         end;
  1515.  
  1516.         // Show the format in the "Paste as" Menu option
  1517.         pmItemOptions.Items[0].Enabled := false;
  1518.         pmItemOptions.Items[0].Caption := '&0  [no "paste as" format]';
  1519.         pmItemOptions.Items[9].Enabled := false;
  1520.         pmItemOptions.Items[9].Caption := '&A  [no complex format]';
  1521.  
  1522.         self.CTRLClickedItem := ci;
  1523.         if (self.CTRLClickedItem <> nil) then begin
  1524.             pmItemOptions.Items[0].Enabled  := true;
  1525.             pmItemOptions.Items[0].Caption := '&0  Paste' + self.CTRLClickedItem.GetFormatName;
  1526.             pmItemOptions.Items[9].Enabled := true;
  1527.             pmItemOptions.Items[9].Caption := '&A  Make Permanent as ' + self.CTRLClickedItem.GetFormatName;
  1528.         end;
  1529.  
  1530.         pmItemOptions.Items.RethinkHotkeys;
  1531.         pmItemOptions.Items[1].Caption := '[no run format]';
  1532.         pmItemOptions.Items[1].Caption := '&1  Run ...';
  1533.         pmItemOptions.Popup(self.TargetX, self.TargetY );
  1534.  
  1535.         // make sure focus is returned
  1536.         if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  1537.             SetForegroundWindow(self.HotKeyForeWindow);
  1538.             self.ThreadDetach;
  1539.         end;
  1540.     end else begin
  1541.         Paste.SendText('', ci);
  1542.     end;
  1543.  
  1544.     // try to clear phantom keystroke from entering other program
  1545.     keybd_event(VK_F1, VkKeyScan(char(VK_F1)), KEYEVENTF_KEYUP, 0);
  1546. end;
  1547.  
  1548. procedure TFrmMainPopup.FlushOtherItemsClickEvent(Sender: TObject);
  1549. begin
  1550.     OtherQueue.ClearQueue;
  1551.     self.FullMode := false;
  1552.     self.ShowPopupWithFocusRules;
  1553. end;
  1554.  
  1555. procedure TFrmMainPopup.CurrentMenuItemClickEvent(Sender: TObject);
  1556. begin
  1557.     if (self.KeyPressedOverride('', self.CurrentClipboard)) then begin
  1558.         EXIT;
  1559.     end;
  1560.  
  1561.     UnitMisc.AppendLog('Sending Current Item ');
  1562.     self.SendText('', self.CurrentClipboard);
  1563.     UnitMisc.AppendLog('inserting done');
  1564. end;
  1565.  
  1566. procedure TfrmMainPopup.LastMenuItemClickEvent(Sender: TObject);
  1567. begin
  1568.     UnitMisc.AppendLog('Inserting last selected string');
  1569.     if (self.KeyPressedOverride(LastStringSelected)) then begin
  1570.         EXIT;
  1571.     end;
  1572.     self.SendText(LastStringSelected);
  1573. end;
  1574.  
  1575. procedure TfrmMainPopup.CancelMenuItemClickEvent(Sender: TObject);
  1576. begin
  1577.     // since using the keyboard takes away focus from the target
  1578.     // window, it must be returned
  1579.     if (self.PopupUseKB) then begin
  1580.         if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  1581.             Windows.SetForegroundWindow(self.HotKeyForeWindow);
  1582.             self.ThreadDetach;
  1583.         end;
  1584.     end;
  1585.  
  1586.     self.UseFormMode := false;
  1587. end;
  1588.  
  1589. procedure TfrmMainPopup.PermanentMenuItemClickEvent(sender: TObject);
  1590. var s : string;
  1591.     pid : integer;
  1592. begin
  1593.     with sender as tmenuitem do begin
  1594.         s := TMenuITem(sender).hint;
  1595.         pid := TMenuItem(sender).tag;
  1596.     end;
  1597.  
  1598.     if (pid <> - 1) then begin
  1599.         FrmPermanent.PermFolderPush;
  1600.         FrmPermanent.SetPermanentPath(FrmPermanent.PermFoldersGetItem(pid));
  1601.     end;
  1602.     self.PermanentMenuItemClickEvent(s);
  1603.     if (pid <> -1) then begin
  1604.         FrmPermanent.PermFolderPop;
  1605.     end;
  1606. end;
  1607.  
  1608. procedure TFrmMainPopup.PermanentMenuItemClickEvent(s: string);
  1609. begin
  1610.     MenuItemText := s;
  1611.     if (self.KeyPressedOverride(s)) then begin
  1612.         EXIT;
  1613.     end;
  1614.  
  1615.     self.SendText( s );
  1616.     self.HandleFormMode;
  1617. end;
  1618.  
  1619. procedure TFrmMainPopup.PermanentGroupItemClickEvent(sender: TObject);
  1620. var s : string;
  1621. begin
  1622.     with sender as tmenuitem do begin
  1623.         s := Hint;
  1624.     end;
  1625.     self.PermanentGroupItemClickEvent(s); 
  1626. end;
  1627.  
  1628. procedure TFrmMainPopup.PermanentGroupItemClickEvent(s: string);
  1629. begin
  1630.     // Explicitly assign the permanent group to the current EXE
  1631.     frmPermanent.SetPermanentPath(s);
  1632.     FrmPermanent.AssignPIG(self.TargetEXE);
  1633.  
  1634.     self.ShowPopupWithFocusRules;
  1635. end;
  1636.  
  1637.  
  1638. procedure TfrmMainPopup.PasteAllMenuItemClickEvent(sender: TObject);
  1639. var i : longint;
  1640.     s : string;
  1641. begin
  1642.     s := '';
  1643.     for i := 0 to (ClipQueue.GetQueueCount  - 1) do begin
  1644.         if (Cardinal(i) = (ClipQueue.GetQueueCount  - 1)) then begin
  1645.             s := s + ClipQueue.GetItemText(i);
  1646.         end else begin
  1647.             s := s + ClipQueue.GetItemText(i) + #13#10;
  1648.         end;
  1649.     end;
  1650.  
  1651.     self.SendText(s);
  1652. end;
  1653.  
  1654. procedure TfrmMainPopup.PasteSelectedMenuItemClickEvent(sender: TOBject);
  1655. var s : string;
  1656. begin
  1657.     s := FrmPasteSelected.GetSelectedItems;
  1658.     // the above windows takes away focus from target
  1659.     // here, so it needs it back before pasting
  1660.     if (not self.PopupUseKB) then begin
  1661.         self.ThreadAttach(self.HotKeyForeWindow);
  1662.         Windows.SetForegroundWindow(self.HotKeyForeWindow);
  1663.         self.ThreadDetach;
  1664.     end;
  1665.  
  1666.     if (s <> '') then begin
  1667.         self.SendText(s);
  1668.     end else begin
  1669.         self.CancelMenuItemClickEvent(self);
  1670.     end;
  1671. end;
  1672.  
  1673. procedure TFrmMainPopup.FormModeMenuItemClickEvent(Sender: TObject);
  1674. begin
  1675.     self.UseFormMode := not self.UseFormMode;
  1676.     self.ShowPopupWithFocusRules;
  1677. end;
  1678.  
  1679.  
  1680. procedure TFrmMainPopup.NextFieldModeMenuItemClickEvent(Sender: TObject);
  1681. var b : boolean;
  1682. begin
  1683.     b := self.UseFormMode;
  1684.     self.UseFormMode := true;
  1685.     self.HandleFormMode;
  1686.     self.UseFormMode := b;
  1687. end;
  1688.  
  1689.  
  1690. procedure TFrmMainPopup.HandleFormMode;
  1691. var w : word;
  1692. begin
  1693.     if self.UseFormMode then begin
  1694.         // focus back on target window and control
  1695.         // press tab
  1696.         // get current target window control again
  1697.         // re-show the popup
  1698.         if (self.PopupUseKB) then begin
  1699.             if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  1700.                 Windows.SetForegroundWindow(self.HotKeyForeWindow);
  1701.                 Windows.SetFocus(self.HotKeyTarget);
  1702.             end else begin
  1703.                 showmessage('ERROR: Unable to paste into target');
  1704.                 exit;
  1705.             end;
  1706.         end;
  1707.  
  1708.         w := VkKeyScan(#9);
  1709.         keybd_event(VK_TAB, w, 0, 0);
  1710.         sleep(10);
  1711.         keybd_event(VK_TAB, w, KEYEVENTF_KEYUP, 0);
  1712.         sleep(100);
  1713.  
  1714.         if (self.PopupUseKB) then begin
  1715.             self.ThreadDetach;
  1716.         end;
  1717.         self.GetTargetControl(self.HotKeyForeWindow, self.HotKeyTarget,
  1718.             TargetX, TargetY);
  1719.  
  1720.  
  1721.         self.ShowPopupWithFocusRules;
  1722.     end;
  1723. end;
  1724.  
  1725. //
  1726. // ShowOnNextWindow - This lets another window cause the popup
  1727. // to show up on the text field that just lost focus
  1728. //
  1729. procedure TFrmMainPopup.ShowOnNextWindow(ShowPopup : boolean = true);
  1730. var h : THandle;
  1731. begin
  1732.     Windows.SetLastError(ERROR_SUCCESS);
  1733.     if (self.PopupShowing) then EXIT;
  1734.     self.PopupShowing := true;
  1735.  
  1736.     // find the current foreground window
  1737.     // find the "next" window (which means below the current, not above)
  1738.     // skip any invisible windows
  1739.     h := Windows.GetForegroundWindow;
  1740.     if (h = 0) then begin
  1741.         UnitMisc.AppendLog('Can''t get foreground window', true);
  1742.     end;
  1743.     h := Windows.GetNextWindow(h, GW_HWNDNEXT);
  1744.     if (h = 0) then begin
  1745.         UnitMisc.AppendLog('Can''t get next window', true);
  1746.     end;
  1747.  
  1748.     while (not Windows.IsWindowVisible(h)) and (h <> 0) do begin
  1749.         h := Windows.GetNextWindow(h, GW_HWNDNEXT);
  1750.         if (h = 0) then begin
  1751.             UnitMisc.AppendLog('Can''t get next window in loop', true);
  1752.         end;
  1753.  
  1754.     end;
  1755.     // move back the the "next" window and attempt
  1756.     // to make the previously focused control get keyboard focus again
  1757.  
  1758.  
  1759.     if (ShowPopup) then begin
  1760.         if (self.ThreadAttach(h)) then begin
  1761.             Windows.SetForegroundWindow(h);
  1762.             self.ThreadDetach;
  1763.         end;
  1764.     end;
  1765.  
  1766.     self.HotKeyForeWindow := h;
  1767.     self.GatherTargetWindowData;
  1768.  
  1769.     if (ShowPopup) then begin
  1770.         self.ShowPopupWithFocusRules;
  1771.     end;
  1772.  
  1773.     self.PopupShowing := false;
  1774. end;
  1775.  
  1776. function TFrmMainPopup.GetNextWindowProgramName: string;
  1777. var h : THandle;
  1778.     i : integer;
  1779. begin
  1780.     Windows.SetLastError(ERROR_SUCCESS);
  1781.  
  1782.     // find the current foreground window
  1783.     // find the "next" window (which means below the current, not above)
  1784.     // skip any invisible windows
  1785.     h := Windows.GetForegroundWindow;
  1786.     i := 0;
  1787.     while (h=0) and (i<10) do begin
  1788.         h := Windows.GetForegroundWindow;
  1789.         inc(i);
  1790.         sleep(20);
  1791.     end;
  1792.     if (h = 0) then begin
  1793.         UnitMisc.AppendLog('Can''t get foreground window', true);
  1794.     end;
  1795.  
  1796.     h := Windows.GetNextWindow(h, GW_HWNDNEXT);
  1797.     i := 0;
  1798.     while (h=0) and (i<10) do begin
  1799.         h := Windows.GetForegroundWindow;
  1800.         inc(i);
  1801.         sleep(20);
  1802.     end;
  1803.     if (h = 0) then begin
  1804.         UnitMisc.AppendLog('Can''t get next window', true);
  1805.     end;
  1806.  
  1807.     while (not Windows.IsWindowVisible(h)) and (h <> 0) do begin
  1808.         h := Windows.GetNextWindow(h, GW_HWNDNEXT);
  1809.         if (h = 0) then begin
  1810.             UnitMisc.AppendLog('Can''t get next window in loop', true);
  1811.         end;
  1812.  
  1813.     end;
  1814.  
  1815.     if (h <> 0) then begin
  1816.         result := ExtractFilename(WindowHandleToEXEName(h));
  1817.     end else begin
  1818.         result := '';
  1819.     end;
  1820. end;
  1821.  
  1822.  
  1823.  
  1824. procedure TFrmMainPopup.ShowOnSystemTray;
  1825. var h : THandle;
  1826.     CursorPos : TPoint;
  1827. begin
  1828.     Windows.SetLastError(ERROR_SUCCESS);
  1829.     if (self.PopupShowing) then EXIT;
  1830.     self.PopupShowing := true;
  1831.  
  1832.     // find the current foreground window
  1833.     // find the "next" window (which means below the current, not above)
  1834.     // skip any invisible windows
  1835.     h := Windows.GetForegroundWindow;
  1836.     h := Windows.GetNextWindow(h, GW_HWNDNEXT);
  1837.     while not Windows.IsWindowVisible(h) do begin
  1838.         h := Windows.GetNextWindow(h, GW_HWNDNEXT);
  1839.     end;
  1840.     self.HotKeyForeWindow := h;
  1841.     self.HotKeyTarget := 0;
  1842.  
  1843.     Windows.GetCursorPos(CursorPos);
  1844.     self.TargetX := CursorPos.x;
  1845.     self.TargetY := CursorPos.Y;
  1846.  
  1847.     Windows.SetForegroundWindow(self.Handle);
  1848.     self.ShowPopup(CursorPos.x, CursorPos.y);
  1849.     
  1850.     self.PopupShowing := false;
  1851. end;
  1852.  
  1853.  
  1854. procedure TFrmMainPopup.FullModeMenuItemClickEvent(Sender : TObject);
  1855. begin
  1856.     //
  1857.     // toggle Full->Configured and Configured->Full
  1858.     //
  1859.     self.FullMode := self.FullMode xor true;
  1860.     self.ShowPopupWithFocusRules;
  1861. end;
  1862.  
  1863.  
  1864.  
  1865.  
  1866. procedure TFrmMainPopup.SendText(s: string; ci : TClipItem = nil);
  1867. var prefix : string;
  1868. begin
  1869.     Windows.SetLastError(ERROR_SUCCESS);
  1870.  
  1871.     //
  1872.     // Since the popup may have stolen focus from the target,
  1873.     // it must be given keyboard focus again
  1874.     //
  1875.     if (self.PopupUseKB) then begin
  1876.         if (self.ThreadAttach(self.HotKeyForeWindow)) then begin
  1877.             Windows.SetForegroundWindow(self.HotKeyForeWindow);
  1878.             if (self.HotKeyTarget <> 0) then begin
  1879.                 Windows.SetFocus(self.HotKeyTarget);
  1880.             end;
  1881.         end else begin
  1882.             showmessage('ERROR: Unable to paste into target');
  1883.             EXIT;
  1884.         end;
  1885.     end;
  1886.  
  1887.     prefix :=uppercase(leftstr(s,6));
  1888.  
  1889.     if (prefix  = '[KEYS]') then begin
  1890.         Paste.SendTextWithKeystrokes(s);
  1891.     end else if (FrmPermanent.IsComplexItem(s)) then begin
  1892.         ci := FrmPermanent.GetComplexItem(s);
  1893.  
  1894.         Paste.SendText('', ci);
  1895.         MyFree(ci);
  1896.     end else begin
  1897.         Paste.SendText(s, ci);
  1898.     end;
  1899.  
  1900.     if (self.PopupUseKB) then begin
  1901.         self.ThreadDetach;
  1902.     end;
  1903. end;
  1904.  
  1905.  
  1906.  
  1907. {
  1908. --============================
  1909. -- // Thead utility methods //
  1910. --============================
  1911.  
  1912. Description: Mimic being part of the targeted window. This method is used
  1913. to get the keyboard focused item of an outside process and to associate a
  1914. popup menu with an outside process.
  1915.  
  1916. Update: Changed to allow ArsClip to paste into its own windows, like
  1917. Permanent Items.
  1918. }
  1919.  
  1920. function TfrmMainPopup.ThreadAttach(TargetWindow: cardinal) : boolean;
  1921. begin
  1922.     If (ThreadAttached) then begin
  1923.         showmessage('Error: Thread already attached');
  1924.         self.Close;
  1925.     end;
  1926.  
  1927.     ThreadTarget := Windows.GetWindowThreadProcessId(TargetWindow, nil);
  1928.     ThreadOurs := Windows.GetCurrentThreadId();
  1929.     if (ThreadTarget <> ThreadOurs) then begin
  1930.         result := Windows.AttachThreadInput(ThreadTarget, ThreadOurs, true);
  1931.     end else begin
  1932.         result := true;
  1933.     end;
  1934.     ThreadAttached := true;
  1935. end;
  1936. procedure TfrmMainPopup.ThreadDetach();
  1937. begin
  1938.     {
  1939.     If (not ThreadAttached) then begin
  1940.         showmessage('Error: Thread not attached');
  1941.         self.Close;
  1942.     end;
  1943.     }
  1944.     if (ThreadTarget <> ThreadOurs) then begin
  1945.         Windows.AttachThreadInput(ThreadTarget, ThreadOurs, false);
  1946.     end;
  1947.     ThreadAttached := false;
  1948. end;
  1949.  
  1950.  
  1951.  
  1952.  
  1953. {
  1954. --===========
  1955. -- // Etc. //
  1956. --===========
  1957. }
  1958. procedure TfrmMainPopup.AppendLog(s : string);
  1959. begin
  1960.     if length(memo1.text) > 30000 then memo1.Text := '';
  1961.     // Cheezy Debugging Info[tm]
  1962.     // make sure we don't overflow the text, only accept 1000 characters
  1963.     // at a time
  1964.     memo1.Text := leftstr(s, 1000) + #13 + #10 + memo1.text;
  1965. end;
  1966.  
  1967. procedure TfrmMainPopup.btnHideClick(Sender: TObject);
  1968. begin
  1969.     self.Hide;
  1970. end;
  1971.  
  1972. {
  1973. --====================
  1974. -- CTRL option menu items
  1975. --===================
  1976. }
  1977. procedure TFrmMainPopup.Run1Click(Sender: TObject);
  1978. var s : string;
  1979.     i : integer;
  1980. begin
  1981.     Windows.SetLastError(ERROR_SUCCESS);
  1982.     //
  1983.     // try to run it as a mail address if it fails
  1984.     // the first time - report any error otherwise
  1985.  
  1986.     // trim any whitespace - CRLFs
  1987.     s := trim(self.MenuItemText);
  1988.     if s = '' then EXIT;
  1989.  
  1990.     while s[length(s)] in [#13, #10] do begin
  1991.         s := Copy(s, 1, length(s) - 1);
  1992.     end;
  1993.  
  1994.     i := ShellAPI.ShellExecute(self.Handle,nil,
  1995.         PChar(s),nil,nil,SW_NORMAL);
  1996.     if (i <= 32) then begin
  1997.  
  1998.         if (pos('@',s) <> 0) then begin
  1999.             s := 'mailto:' + s;
  2000.             i := shellAPI.ShellExecute(self.Handle,nil,
  2001.                 PChar(s),nil,nil,SW_NORMAL);
  2002.         end;
  2003.     end;
  2004.  
  2005.     if (i <= 32) then begin
  2006.         Windows.SetForegroundWindow(self.Handle);
  2007.         ShowMessage(SysErrorMessage(i));
  2008.     end;
  2009.     //frmClipboardManager.SetIgnoreClipboard(false); // just incase
  2010. end;
  2011.  
  2012. procedure TFrmMainPopup.MakePermanentItem1Click(Sender: TObject);
  2013. begin
  2014.     Windows.SetForegroundWindow(FrmPermanent.Handle);
  2015.     frmPermanent.ShowWithNewItem(self.MenuItemText);
  2016. end;
  2017.  
  2018.  
  2019. procedure TFrmMainPopup.AMakePermanentas1Click(Sender: TObject);
  2020. begin
  2021.     Windows.SetForegroundWindow(FrmPermanent.Handle);
  2022.     frmPermanent.ShowWithNewComplexItem(self.CTRLClickedItem);
  2023. end;
  2024.  
  2025.  
  2026. procedure TFrmMainPopup.PasteusingMimicTyping1Click(Sender: TObject);
  2027. begin
  2028.     Paste.SetKeyboardMimicOnce;
  2029.     self.SendText(self.MenuItemText);
  2030. end;
  2031.  
  2032. procedure TFrmMainPopup.Placeonclipboard1Click(Sender: TObject);
  2033. var i : integer;
  2034.     ci : TClipItem;
  2035. begin
  2036.     //
  2037.     // always default to the Unicode version, if available
  2038.     //
  2039.     Paste.SetClipboardOnlyOnce;
  2040.     i := ClipQueue.IndexOf(self.MenuItemText);
  2041.     ci := ClipQueue.GetClipItem(i);
  2042.     if (ci <> nil) then begin
  2043.         if (ci.GetFormat = CF_UNICODETEXT) then begin
  2044.             self.SendText('',ci);
  2045.             EXIT;
  2046.         end;
  2047.     end;
  2048.  
  2049.     self.SendText(self.MenuItemText);
  2050. end;
  2051.  
  2052. procedure TFrmMainPopup.Preview1Click(Sender: TObject);
  2053. begin
  2054.     FrmPreview.SetText(self.MenuItemText);
  2055.     self.ShowPreviewForm;
  2056. end;
  2057.  
  2058. procedure TFrmMainPopup.back1Click(Sender: TObject);
  2059. begin
  2060.     self.ShowPopupWithFocusRules;
  2061. end;
  2062.  
  2063. procedure TFrmMainPopup.PasteusingSHIFTINS1Click(Sender: TObject);
  2064. begin
  2065.     Paste.SetUsePasteSIOnce;
  2066.     self.SendText(self.MenuItemText);
  2067. end;
  2068.  
  2069. procedure TFrmMainPopup.PasteusingCTRLV1Click(Sender: TObject);
  2070. begin
  2071.     Paste.SetUsePasteCVOnce;
  2072.     self.SendText(self.MenuItemText);
  2073. end;
  2074.  
  2075. procedure TFrmMainPopup.N0PasteasRichText1Click(Sender: TObject);
  2076. begin
  2077.     // Paste as Plain text when Complex is default
  2078.     // Paste as Rich Text when not using Complex by default
  2079.     if (FrmConfig.cbPasteComplex.Checked) then begin
  2080.         Paste.SendText(self.MenuItemText, nil);
  2081.     end else begin
  2082.         Paste.SendText(self.MenuItemText, self.CTRLClickedItem);
  2083.     end;
  2084. end;
  2085.  
  2086.  
  2087. function TFrmMainPopup.GetLastStringSelected: string;
  2088. begin
  2089.     result := self.LastStringSelected;
  2090. end;
  2091. function TFrmMainPopup.GetUseFormMode: boolean;
  2092. begin
  2093.     result := self.UseFormMode;
  2094. end;
  2095. function TFrmMainPopup.GetFullMode: boolean;
  2096. begin
  2097.     result := self.FullMode;
  2098. end;
  2099. function TFrmMainPopup.GetDoMoveSelectedToTop: boolean;
  2100. begin
  2101.     result := DoMoveSelectedToTop;
  2102. end;
  2103. function TFrmMainPopup.GetDoRememberHistory: boolean;
  2104. begin
  2105.     result := DoRememberHistory;
  2106. end;
  2107. function TFrmMainPopup.GetDoShowCurrentItem: boolean;
  2108. begin
  2109.     result := DoShowCurrentItem;
  2110. end;
  2111. function TFrmMainPopup.GetDoShowEditHistory: boolean;
  2112. begin
  2113.     result := DoShowEditHistory;
  2114. end;
  2115. function TFrmMainPopup.GetDoShowFormMode: boolean;
  2116. begin
  2117.     result := DoShowFormMode;
  2118. end;
  2119. function TFrmMainPopup.GetDoShowLast: boolean;
  2120. begin
  2121.     result := DoShowLast;
  2122. end;
  2123. function TFrmMainPopup.GetDoShowPasteAll: boolean;
  2124. begin
  2125.     result := DoShowPasteAll;
  2126. end;
  2127. function TFrmMainPopup.GetDoShowPermanentItemGroups: boolean;
  2128. begin
  2129.     result := DoShowPermanentItemGroups;
  2130. end;
  2131. function TFrmMainPopup.GetDoShowPermanentItemSubmenu: boolean;
  2132. begin
  2133.     result := DoShowPermanentItemSubmenu
  2134. end;
  2135. function TFrmMainPopup.GetUsePermanentItems: boolean;
  2136. begin
  2137.     result := UsePermanentItems;
  2138. end;
  2139.  
  2140.  
  2141.  
  2142.  
  2143.  
  2144. procedure TFrmMainPopup.MimicTyping1Click(Sender: TObject);
  2145. begin
  2146.     Paste.AssignPaste(self.TargetEXE, PASTE_MIMIC);
  2147. end;
  2148.  
  2149. procedure TFrmMainPopup.N2SHIFTINSERT1Click(Sender: TObject);
  2150. begin
  2151.     Paste.AssignPaste(self.TargetEXE, PASTE_SHIFT_INS);
  2152. end;
  2153.  
  2154. procedure TFrmMainPopup.N3CTRLV1Click(Sender: TObject);
  2155. begin
  2156.     Paste.AssignPaste(self.TargetEXE, PASTE_CTRL_V);
  2157. end;
  2158.  
  2159. procedure TFrmMainPopup.N4ClipboardOnly1Click(Sender: TObject);
  2160. begin
  2161.     Paste.AssignPaste(self.TargetEXE, PASTE_CLIPBOARD);
  2162. end;
  2163.  
  2164. procedure TFrmMainPopup.N5Default1Click(Sender: TObject);
  2165. begin
  2166.     Paste.AssignPaste(self.TargetEXE, PASTE_DEFAULT);
  2167. end;
  2168.  
  2169.  
  2170. end.
  2171.