/// <summary> /// Used only by the Save class. /// </summary> bool _SaveStateNow() { if (DB == null) { return(true); } try { using (var trans = DB.Transaction()) { DB.Execute("REPLACE INTO _misc VALUES ('expanded',?)", string.Join(" ", Root.Descendants().Where(n => n.IsExpanded).Select(n => n.IdString))); using (new StringBuilder_(out var b)) { var a = OpenFiles; b.Append(a.IndexOf(_currentFile)); foreach (var v in a) { b.Append(' ').Append(v.IdString); //FUTURE: also save current position and scroll position, eg "id.pos.scroll" } DB.Execute("REPLACE INTO _misc VALUES ('open',?)", b.ToString()); } trans.Commit(); } return(true); } catch (SLException ex) { Debug_.Print(ex); return(false); } }
/// <summary> /// If possible, gets whether the window is DPI-scaled/virtualized, and gets physical and logical rects if scaled. /// Returns false if !osVersion.minWin10_1607 or if cannot get that info. /// Gets that info in a fast and reliable way. /// </summary> internal static bool GetScalingInfo_(wnd w, out bool scaled, out RECT rPhysical, out RECT rLogical) { scaled = false; rPhysical = default; rLogical = default; if (!osVersion.minWin10_1607) { return(false); } var awareness = WindowDpiAwareness(w); //fast on Win10 if (awareness is Awareness.System or Awareness.Unaware) //tested: unaware-gdi-scaled same as unaware { if (awareness == Awareness.System && Api.GetDpiForWindow(w) != System) /*fast*/ //Cannot get rLogical. It's rare and temporary, ie when the user recently changed DPI of the primary screen. //Even if this func isn't used to get rects, without this fast code could be unreliable. { Debug_.Print("w System DPI != our System DPI"); return(false); } for (; ;) { RECT r1 = w.Rect, r2, r3; //note: with ClientRect 4 times faster, but unreliable if small rect. Now fast enough. bool rectWorkaround = false; using (var u = new AwarenessContext(awareness == Awareness.System ? -2 : -1)) { if (Api.GetAwarenessFromDpiAwarenessContext(u.Previous_) != Awareness.PerMonitor) /*fast*/ //cannot get rPhysical. But let's set PM awareness and get it. Works even if this process is Unaware. { rectWorkaround = _GetRect(w, out r1); Debug_.Print("bad DPI awareness of this thread; workaround " + (rectWorkaround ? "OK" : "failed")); if (!rectWorkaround) { return(false); //unlikely. Then the caller probably will call the legacy func, it works with any DPI awareness. } } r2 = w.Rect; if (r2 == r1) { break; } } if (!rectWorkaround) { r3 = w.Rect; } else { _GetRect(w, out r3); } if (r3 != r1) { continue; //moved, resized or closed between Rect and Rect } scaled = true; rPhysical = r1; rLogical = r2; break; }
void _TextChanged() { string name = tName.Text; var a = new List <(string name, string code)>(); int nWild = 0; for (int i = 0; i < name.Length; i++) { switch (name[i]) { case '*': case '?': nWild++; break; } } if (name.Length > 0 && (nWild == 0 || name.Length - nWild >= 2)) { string sql; if (name.Contains(' ')) { sql = $"in ('{string.Join("', '", name.RxFindAll(@"\b[A-Za-z_]\w\w+", (RXFlags)0))}')"; } else if (name.FindAny("*?") >= 0) { sql = $"GLOB '{name}'"; } else { sql = $"= '{name}'"; } try { using var stat = _db.Statement("SELECT name, code FROM api WHERE name " + sql); //perf.first(); while (stat.Step()) { a.Add((stat.GetText(0), stat.GetText(1))); } //perf.nw(); //30 ms cold, 10 ms warm. Without index. } catch (SLException ex) { Debug_.Print(ex.Message); } } string s = ""; if (a.Count != 0) { s = a[0].code; if (a.Count > 1) { s = string.Join(s.Starts("internal const") ? "\r\n" : "\r\n\r\n", a.Select(o => o.code)); } s += "\r\n"; } code.ZSetText(s); }
public _NetDocumentationProvider() { try { _db = EdDatabases.OpenDoc(); //never mind: we don't dispose it on process exit if (_db.Get(out string s, "SELECT xml FROM doc WHERE name='.'")) { _refs = new HashSet <string>(s.Split('\n')); } } catch (SLException ex) { Debug_.Print(ex.Message); } }
void _ThreadProc() { WindowsHook hk = null, hm = null; WinEventHook hwe = null; try { try { if (_block.Has(BIEvents.Keys)) { hk = WindowsHook.Keyboard(_keyHookProc ??= _KeyHookProc); } if (_block.HasAny(BIEvents.MouseClicks | BIEvents.MouseMoving)) { hm = WindowsHook.Mouse(_mouseHookProc ??= _MouseHookProc); } } catch (AuException e1) { Debug_.Print(e1); _block = 0; return; } //failed to hook //This prevents occassional inserting a foreign key after the first our-script-pressed key. //To reproduce, let our script send small series of chars in loop, and simultaneously a foreign script send other chars. wait.doEvents(); //print.it("started"); Api.SetEvent(_syncEvent); //the hook detects Ctrl+Alt+Del, Win+L, UAC consent, etc. SystemEvents.SessionSwitch only Win+L. try { hwe = new WinEventHook(EEvent.SYSTEM_DESKTOPSWITCH, 0, _winEventProc ??= _WinEventProc); } catch (AuException e1) { Debug_.Print(e1); } //failed to hook wait.Wait_(-1, WHFlags.DoEvents, _stopEvent, _threadHandle); if (_blockedKeys != null) { bool onlyUp = _discardBlockedKeys || Environment.TickCount64 - _startTime > c_maxResendTime; _blockedKeys.SendBlocked_(onlyUp); } //print.it("ended"); } finally { _blockedKeys = null; hk?.Dispose(); hm?.Dispose(); hwe?.Dispose(); Api.SetEvent(_syncEvent); } GC.KeepAlive(this); }
nint _WndProc(wnd w, int message, nint wParam, nint lParam) { try { switch (message) { case Api.WM_USER + 1: //_ht.Return((int)wParam, false); //test speed without _KeyMouseEvent _KeyMouseEvent((int)wParam, (HooksThread.UsedEvents)lParam); return(0); case Api.WM_USER + 20: _windowTriggers.SimulateNew_(wParam, lParam); return(0); case Api.WM_USER + 30: _ShowToolbarsDialog(); return(0); } } catch (Exception ex) { Debug_.Print(ex.Message); return(default); }
/// <summary> /// Gets check state of this check box or radio button. /// Returns 0 if unchecked, 1 if checked, 2 if indeterminate. Also returns 0 if this is not a button or if failed to get state. /// </summary> /// <param name="useElm">Use <see cref="elm.State"/>. If false (default) and this button has a standard checkbox style, uses API <msdn>BM_GETCHECK</msdn>.</param> public int GetCheckState(bool useElm = false) { if (useElm || !_IsCheckbox()) { //info: Windows Forms controls are user-drawn and don't have one of the styles, therefore BM_GETCHECK does not work. try { //avoid exception in property-get functions using var e = elm.fromWindow(W, EObjid.CLIENT, flags: EWFlags.NoThrow); if (e == null) { return(0); } return(_GetElmCheckState(e)); } catch (Exception ex) { Debug_.Print(ex); } //CONSIDER: if fails, show warning. In all wnd property-get functions. return(0); } else { return((int)W.Send(BM_GETCHECK)); } }
/// <summary> /// Gets indices of owned windows of the specified window, including all descendants. /// Can be called multiple times for different owner windows; uses arrays created in ctor (the slowest part). /// </summary> /// <param name="owner">Owner window.</param> /// <param name="skip">A callback function that receives descendant indice and can return true to skip that window and its descendants.</param> /// <param name="andOwner">Add <i>owner</i> to the list too, at the position matching the Z order.</param> /// <returns>List of <see cref="all"/> indices of owned windows. Sorted like in the Z order. Not null.</returns> public List <int> GetIndices(wnd owner, Func <int, bool> skip = null, bool andOwner = false) { var ai = new List <int>(); _Owned(owner); void _Owned(wnd owner) { int oint = (int)owner; for (int i = 0; i < owners.Length; i++) { if (owners[i] == oint) { if (skip != null && skip(i)) { continue; } ai.Add(i); _Owned(all[i]); } } } if (andOwner) { int j = Array.IndexOf(all, owner); if (j >= 0) { ai.Add(j); } else { Debug_.Print("owner not in all"); } } ai.Sort(); return(ai); }
public static void LoadAndCreateToolbars() { var pm = PanelManager = new KPanels(); //FUTURE: later remove this code. Now may need to delete old custom Layout.xml. var customLayoutPath = AppSettings.DirBS + "Layout.xml"; if (filesystem.exists(customLayoutPath).File) { try { var s2 = filesystem.loadText(customLayoutPath); //print.it(s2); if (!s2.Contains("<panel name=\"Outline\"")) //v0.4 added several new panels etc, and users would not know the best place for them, or even how to move { filesystem.delete(customLayoutPath, FDFlags.RecycleBin); bool silent = s2.RxIsMatch(@"<document name=""documents"" ?/>\s*</tab>"); //very old and incompatible if (!silent) { print.it("Info: The window layout has been reset, because several new panels have been added in this app version.\r\n\tIf you want to undo it: 1. Exit the program. 2. Restore file Layout.xml from the Recycle Bin (replace the existing file). 3. Run the program. 4. Move panels from the bottom of the window to a better place."); } //rejected: show Yes/No dialog. Let users at first see the new default layout, then they can undo. } } catch (Exception e1) { Debug_.Print(e1.ToStringWithoutStack()); } } pm.BorderBrush = SystemColors.ActiveBorderBrush; //pm.Load(folders.ThisAppBS + @"Default\Layout.xml", null); pm.Load(folders.ThisAppBS + @"Default\Layout.xml", customLayoutPath); pm["Menu"].Content = Menu = new Menu(); TFile = _TB("File"); TEdit = _TB("Edit"); TRun = _TB("Run"); TTools = _TB("Tools"); THelp = _TB("Help", true); TCustom1 = _TB("Custom1"); TCustom2 = _TB("Custom2"); ToolBar _TB(string name, bool isHelp = false) { var c = new ToolBar { Name = name }; c.UiaSetName(name); c.HideGripAndOverflow(false); var tt = new ToolBarTray { IsLocked = true }; //because ToolBar looks bad if parent is not ToolBarTray tt.ToolBars.Add(c); #if true if (isHelp) { var p = new DockPanel { Background = tt.Background }; DockPanel.SetDock(tt, Dock.Right); p.Children.Add(tt); //FUTURE //var box = new TextBox { Height = 20, Margin = new Thickness(3, 1, 3, 2), Padding = new Thickness(1, 1, 1, 0) }; //p.Children.Add(box); pm[name].Content = p; } else { pm[name].Content = tt; } #else if (name == "Help") { c.Items.Add(new TextBox { Width = 150, Padding = new Thickness(1, 0, 1, 0) }); } pm[name].Content = tt; #endif return(c); } // ToolBar _TB(string name, bool isHelp = false) { // var c = new ToolBar { Name = name }; // var tt = new ToolBarTray { IsLocked = true }; //because ToolBar looks bad if parent is not ToolBarTray // c.UiaSetName(name); // tt.ToolBars.Add(c); //#if true // if (isHelp) { // var p = new DockPanel { Background = tt.Background }; // DockPanel.SetDock(tt, Dock.Right); // p.Children.Add(tt); // //FUTURE // //var box = new TextBox { Height = 20, Margin = new Thickness(3, 1, 3, 2), Padding = new Thickness(1, 1, 1, 0) }; // //p.Children.Add(box); // pm[name].Content = p; // } else { // pm[name].Content = tt; // } //#else // if (name == "Help") c.Items.Add(new TextBox { Width = 150, Padding = new Thickness(1, 0, 1, 0) }); // pm[name].Content = tt; //#endif // return c; // } }
/// <summary> /// Creates documentation provider for assembly <i>asmPath</i>. /// Returns null if its xml file does not exist. /// Returns _DocumentationProvider if xml file is big and found or successfully created and successfully loaded database for it. /// Else returns _XmlFileDocumentationProvider. /// </summary> public static DocumentationProvider Create(string asmPath) { if (s_d.TryGetValue(asmPath, out var dp)) { return(dp); } var xmlPath = Path.ChangeExtension(asmPath, "xml"); if (!filesystem.getProperties(xmlPath, out var px)) { return(null); } if (px.Size >= 10_000) { var md5 = new Hash.MD5Context(); md5.Add(xmlPath.Lower()); var dbPath = folders.ThisAppTemp + md5.Hash.ToString() + ".db"; try { if (!filesystem.getProperties(dbPath, out var pd) || pd.LastWriteTimeUtc != px.LastWriteTimeUtc) { //Debug_.Print($"creating db: {asmPath} -> {dbPath}"); filesystem.delete(dbPath); using (var d = new sqlite(dbPath)) { using var trans = d.Transaction(); d.Execute("CREATE TABLE doc (name TEXT PRIMARY KEY, xml TEXT)"); using var statInsert = d.Statement("INSERT INTO doc VALUES (?, ?)"); var xr = XmlUtil.LoadElem(xmlPath); foreach (var e in xr.Descendants("member")) { var name = e.Attr("name"); //remove <remarks> and <example>. foreach (var v in e.Descendants("remarks").ToArray()) { v.Remove(); } foreach (var v in e.Descendants("example").ToArray()) { v.Remove(); } using var reader = e.CreateReader(); reader.MoveToContent(); var xml = reader.ReadInnerXml(); //print.it(name, xml); statInsert.BindAll(name, xml).Step(); statInsert.Reset(); } trans.Commit(); d.Execute("VACUUM"); } File.SetLastWriteTimeUtc(dbPath, px.LastWriteTimeUtc); } var db = new sqlite(dbPath, SLFlags.SQLITE_OPEN_READONLY); //never mind: we don't dispose it on process exit s_d[asmPath] = dp = new _DocumentationProvider { _db = db }; return(dp); } catch (Exception ex) { Debug_.Print(ex.ToStringWithoutStack()); } } //return XmlDocumentationProvider.CreateFromFile(xmlPath); //no, need XML with root element. return(new _XmlFileDocumentationProvider(xmlPath)); }
bool _FillProperties(bool newWindow) { bool isCon = !_con.Is0; _WinInfo f = default; if (!_GetClassName(_wnd, out f.wClass)) { return(false); //note: get even if !newWindow, to detect closed window } if (isCon && !_GetClassName(_con, out f.cClass)) { return(false); } bool _GetClassName(wnd w, out string cn) { cn = w.ClassName; if (cn != null) { return(true); } _winInfo.zText = "Failed to get " + (w == _wnd ? "window" : "control") + " properties: \r\n" + lastError.message; _scroller.Visibility = Visibility.Hidden; return(false); } _noeventValueChanged = true; var wndName = _wnd.NameTL_; if (newWindow) { nameW.Set(true, TUtil.EscapeWindowName(wndName, true)); classW.Set(true, TUtil.StripWndClassName(f.wClass, true)); f.wProg = _wnd.ProgramName; var ap = new List <string> { f.wProg, "WOwner.Process(processId)", "WOwner.Thread(threadId)" }; if (!_wnd.Get.Owner.Is0) { ap.Add("WOwner.Window(ow)"); } programW.Set(wndName.NE(), f.wProg, ap); containsW.Set(false, null, _ContainsCombo_DropDown); } else if (wndName != _wndName) { if (TUtil.ShouldChangeTextBoxWildex(nameW.t.Text, wndName)) { nameW.Set(true, TUtil.EscapeWindowName(wndName, true)); } } f.wName = _wndName = wndName; if (isCon) { //name combo f.cName = _con.Name; int iSel = f.cName.NE() ? -1 : 0; var an = new List <string> { TUtil.EscapeWildex(f.cName) }; _ConNameAdd("***wfName ", f.cWF = _con.NameWinforms); /*bool isElm =*/ _ConNameAdd("***elmName ", f.cElm = _con.NameElm); //bool isLabel = _ConNameAdd("***label ", f.cLabel = _con.NameLabel); //if(isElm && isLabel && iSel == an.Count - 2 && f.cElm == f.cLabel) iSel++; //if label == elmName, prefer label if (iSel < 0) { iSel = 0; //never select text, even if all others unavailable } _ConNameAdd("***text ", f.cText = _con.ControlText); bool _ConNameAdd(string prefix, string value) { if (value.NE()) { return(false); } if (iSel < 0) { iSel = an.Count; } an.Add(prefix + TUtil.EscapeWildex(value)); return(true); } bool idUseful = TUtil.GetUsefulControlId(_con, _wnd, out f.cId); //idC.Visible = idUseful; idC.Set(idUseful, f.cId.ToS() + (idUseful ? null : " /*probably not useful*/")); string sName = an[iSel], sClass = TUtil.StripWndClassName(f.cClass, true); nameC.Set(!idUseful, sName, an); classC.Set(!idUseful, sClass); bool hiddenToo = !_con.IsVisible; cHiddenTooC.IsChecked = hiddenToo; var skip = idUseful ? null : TUtil.GetControlSkip(_wnd, _con, sName, sClass, hiddenToo); skipC.Set(skip != null, skip); } bool checkControl = isCon && _checkControl; _cControl.IsChecked = checkControl; _ShowControlProperties(showGrid: checkControl, showAll: isCon); _noeventValueChanged = false; _scroller.Visibility = Visibility.Visible; _FillWindowInfo(f); return(true); List <string> _ContainsCombo_DropDown() { try { var a1 = new List <string>(); //child foreach (var c in _wnd.Get.Children(onlyVisible: true)) { var cn = c.Name; if (cn.NE()) { continue; } cn = "c '" + TUtil.StripWndClassName(c.ClassName, true) + "' " + TUtil.EscapeWildex(cn); if (!a1.Contains(cn)) { a1.Add(cn); } } //elm var a2 = new List <string>(); var a3 = _wnd.Elm[name : "?*", prop : "notin=SCROLLBAR\0maxcc=100", flags : EFFlags.ClientArea].FindAll(); //all that have a name string prevName = null; for (int i = a3.Length; --i >= 0;) { if (!a3[i].GetProperties("Rn", out var prop)) { continue; } if (prop.Name == prevName && prop.Role == "WINDOW") { continue; } prevName = prop.Name; //skip parent WINDOW string rn = "e '" + prop.Role + "' " + TUtil.EscapeWildex(prop.Name); if (!a2.Contains(rn)) { a2.Add(rn); } } a2.Reverse(); a1.AddRange(a2); return(a1); //rejected: sort } catch (Exception ex) { Debug_.Print(ex); return(null); } } }
/// <summary> /// Makes triggers alive. /// </summary> /// <remarks> /// This function monitors hotkeys, activated windows and other events. When an event matches an added trigger, launches the thrigger's action, which runs in other thread by default. /// Does not return immediately. Runs until this process is terminated or <see cref="Stop"/> called. /// </remarks> /// <example>See <see cref="ActionTriggers"/>.</example> /// <exception cref="InvalidOperationException">Already running.</exception> /// <exception cref="AuException">Something failed.</exception> public unsafe void Run() { //Debug_.PrintLoadedAssemblies(true, true, true); ThrowIfRunning_(); //bool haveTriggers = false; HooksThread.UsedEvents hookEvents = 0; _windowTriggers = null; for (int i = 0; i < _t.Length; i++) { var t = _t[i]; if (t == null || !t.HasTriggers) { continue; } //haveTriggers = true; switch ((TriggerType)i) { case TriggerType.Hotkey: hookEvents |= HooksThread.UsedEvents.Keyboard; break; case TriggerType.Autotext: hookEvents |= HooksThread.UsedEvents.Keyboard | HooksThread.UsedEvents.Mouse; break; case TriggerType.Mouse: hookEvents |= (t as MouseTriggers).UsedHookEvents_; break; case TriggerType.Window: _windowTriggers = t as WindowTriggers; break; } } //print.it(haveTriggers, (uint)llHooks); //if(!haveTriggers) return; //no. The message loop may be used for toolbars etc. if (!s_wasRun) { s_wasRun = true; WndUtil.RegisterWindowClass(c_cn); } _wMsg = WndUtil.CreateMessageOnlyWindow(_WndProc, c_cn); _mainThreadId = Api.GetCurrentThreadId(); _winTimerPeriod = 0; _winTimerLastTime = 0; if (hookEvents != 0) { //prevent big delay later on first LL hook event while hook proc waits if (!s_wasKM) { s_wasKM = true; ThreadPool.QueueUserWorkItem(_ => { try { //using var p1 = perf.local(); new wndFinder("*a").IsMatch(wnd.getwnd.root); //if used window scopes etc _ = WindowsHook.LowLevelHooksTimeout; //slow JIT of registry functions Jit_.Compile(typeof(ActionTriggers), nameof(_WndProc), nameof(_KeyMouseEvent)); Jit_.Compile(typeof(TriggerHookContext), nameof(TriggerHookContext.InitContext), nameof(TriggerHookContext.PerfEnd), nameof(TriggerHookContext.PerfWarn)); Jit_.Compile(typeof(ActionTrigger), nameof(ActionTrigger.MatchScopeWindowAndFunc)); Jit_.Compile(typeof(HotkeyTriggers), nameof(HotkeyTriggers.HookProc)); AutotextTriggers.JitCompile(); MouseTriggers.JitCompile(); } catch (Exception ex) { Debug_.Print(ex); } }); } _thc = new TriggerHookContext(this); _ht = new HooksThread(hookEvents, _wMsg); } try { _evStop = Api.CreateEvent(false); _StartStopAll(true); IntPtr h = _evStop; _Wait(&h, 1); } finally { if (hookEvents != 0) { _ht.Dispose(); _ht = null; } Api.DestroyWindow(_wMsg); _wMsg = default; Stopping?.Invoke(this, EventArgs.Empty); _evStop.Dispose(); _StartStopAll(false); _mainThreadId = 0; _threads?.Dispose(); _threads = null; } void _StartStopAll(bool start) { foreach (var t in _t) { if (t?.HasTriggers ?? false) { t.StartStop(start); } } } }
/// <summary> /// Called at the end of opening this workspace. /// </summary> public void LoadState(bool expandFolders = false, bool openFiles = false) { if (DB == null) { return; } try { Save.LoadingState = true; if (expandFolders) { if (DB.Get(out string s, "SELECT data FROM _misc WHERE key='expanded'") && !s.NE()) { foreach (var v in s.Segments(" ")) { var f = FindById(s[v.Range]); //if (f != null) TreeControl.Expand(f, true); if (f != null) { f.SetIsExpanded(true); } } } } if (openFiles) { if (DB.Get(out string s, "SELECT data FROM _misc WHERE key='open'") && !s.NE()) { //format: indexOfActiveDocOrMinusOne id1 id2 ... int i = -2, iActive = s.ToInt(); FileNode fnActive = null; //perf.first(); foreach (var v in s.Segments(" ")) { i++; if (i < 0) { continue; } var fn = FindById(s[v.Range]); if (fn == null) { continue; } OpenFiles.Add(fn); if (i == iActive) { fnActive = fn; } } //perf.next(); if (fnActive == null || !SetCurrentFile(fnActive)) { _UpdateOpenFiles(null); //disable Previous command } //perf.nw(); } } } catch (Exception ex) { Debug_.Print(ex); } finally { Save.LoadingState = false; } }
nint _WndProc(wnd w, int message, nint wParam, nint lParam) { //WndUtil.PrintMsg(w, message, wParam, lParam); switch (message) { //case Api.WM_DESTROY: // Api.ChangeClipboardChain(w, _wPrevClipViewer); // break; case Api.WM_RENDERFORMAT: if (_paste && !Success) { IsBadWindow = !_IsTargetWindow(); //note: need to set clipboard data even if bad window. // Else the clipboard program may retry in loop. Eg Ditto. Then often pasting fails. // If IsBadWindow, we'll then sleep briefly. // Good clipboard programs get clipboard data with a delay. Therefore usually they don't interfere, unless the target app is very slow. // Eg Windows Clipboard History 200 ms. Eg Ditto default is 100 ms and can be changed. // Also, after setting clipboard data we cannot wait for good window, because we'll not receive second WM_RENDERFORMAT. try { _SetClipboard(_data, false); } catch (Exception ex) { FailedToSetData = ex; } //cannot throw in wndproc, will throw later waitVar = true; } return(0); case Api.WM_CLIPBOARDUPDATE: //posted, not sent. Once, not for each format. Added in WinVista. QM2 used SetClipboardViewer/WM_DRAWCLIPBOARD. if (!_paste) { waitVar = true; } return(0); } return(Api.DefWindowProc(w, message, wParam, lParam)); //Returns false if probably not the target app reads from the clipboard. Probably a clipboard viewer/manager/etc. bool _IsTargetWindow() { wnd wOC = Api.GetOpenClipboardWindow(); //int color = 0; if(wOC != _wFocus) color = wOC.ProcessId == _wFocus.ProcessId ? 0xFF0000 : 0xFF; //print.it($"<><c {color}>{wOC}</c>"); if (wOC == _wFocus) { return(true); } if (wOC.Is0) { return(true); //tested: none of tested apps calls OpenClipboard(0) } if (wOC.ProcessId == _wFocus.ProcessId) { return(true); //often classnamed "CLIPBRDWNDCLASS". Some clipboard managers too, eg Ditto. } if (osVersion.minWin10 && 0 != _wFocus.Window.IsUwpApp) { var prog = wOC.ProgramName; if (prog.Eqi("svchost.exe")) { return(true); } //if (prog.Eqi("RuntimeBroker.exe")) return true; //used to be Store apps //tested: no problems on Win8.1 } //tested: WinUI3 (cn "WinUIDesktopWin32WindowClass"): wOC != _wFocus, but same process. //CONSIDER: option to return true for user-known windows, eg using a callback. Print warning that includes wOC info. Debug_.Print(wOC.ToString()); return(false); //BlueStacks problems: // Uses an aggressive viewer. Always debugprints while it is running, even when other apps are active. // Sometimes pastes old text, usually after starting BlueStacks or after some time of not using it. // With or without clipboard restoring. // Then starts to work correctly always. Difficult to debug. // KeySpeedClipboard=100 usually helps, but sometimes even 300 does not help. } }
System.Windows.Documents.Section _FormatText(int iSel, bool userSelected) { _data.iSelected = iSel; if (userSelected) { _data.iUserSelected = iSel; } var r = _data.r; ISymbol currentItem = null; SignatureHelpParameter currentParameter = null; var x = new CiText(); //print.clear(); for (int i = 0; i < r.Items.Count; i++) { var sh = r.Items[i]; if (sh is AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem kk) { var sym = kk.Symbol; if (i == iSel) { currentItem = sym; } x.StartOverload(i == iSel, i); #if false x.AppendTaggedParts(sh.PrefixDisplayParts); //works, but formats not as I like (too much garbage). Has bugs with tuples. #else //if(nt != null) { // print.it(1, nt.IsGenericType, nt.IsTupleType, nt.IsUnboundGenericType, nt.Arity, nt.CanBeReferencedByName); // print.it(2, nt.IsAnonymousType, nt.IsDefinition, nt.IsImplicitlyDeclared, nt.Kind, nt.TypeKind); // print.it(3, nt.MemberNames); // print.it(4, nt.Name, nt.MetadataName, nt.OriginalDefinition, nt.TupleUnderlyingType); // print.it("TypeParameters:"); // print.it(nt.TypeParameters); // print.it("TypeArguments:"); // print.it(nt.TypeArguments); // print.it("TupleElements:"); // try { var te = nt.TupleElements; if(!te.IsDefault) print.it(te); } catch(Exception e1) { print.it(e1.ToStringWithoutStack()); } // print.it("---"); //} int isTuple = 0; //1 ValueTuple<...>, 2 (...) var nt = sym as INamedTypeSymbol; if (nt != null && nt.IsTupleType) { isTuple = nt.IsDefinition ? 1 : 2; } if (isTuple == 1) { x.Append("ValueTuple"); //AppendSymbolWithoutParameters formats incorrectly } else if (isTuple == 0) { x.AppendSymbolWithoutParameters(sym); } string b1 = "(", b2 = ")"; if (nt != null) { if (nt.IsGenericType && isTuple != 2) { b1 = "<"; b2 = ">"; } } else if (sym is IPropertySymbol) { b1 = "["; b2 = "]"; } x.Append(b1); #endif int iArg = r.ArgumentIndex, lastParam = sh.Parameters.Length - 1; int selParam = iArg <= lastParam ? iArg : (sh.IsVariadic ? lastParam : -1); if (!r.ArgumentName.NE()) { var pa = sh.Parameters; for (int pi = 0; pi < pa.Length; pi++) { if (pa[pi].Name == r.ArgumentName) { selParam = pi; break; } } } x.AppendParameters(sym, selParam, sh); //x.AppendParameters(sh, selParam); //works, but formats not as I like (too much garbage) #if false x.AppendTaggedParts(sh.SuffixDisplayParts); #else x.Append(b2); #endif if (i == iSel && selParam >= 0) { currentParameter = sh.Parameters[selParam]; } x.EndOverload(i == iSel); } else { Debug_.Print(sh); } } if (currentItem != null) { var tt = r.Items[iSel].DocumentationFactory?.Invoke(default);
static void _Statements(string s, ICSFlags flags, bool separate) { if (!App.Hmain.IsVisible) { App.ShowWindow(); } if (!CodeInfo.GetContextAndDocument(out var k, metaToo: true)) { print.it(s); return; } var root = k.syntaxRoot; var code = k.code; var pos = k.pos; var token = root.FindToken(pos); var node = token.Parent; //get the best valid insertion place bool havePos = false; var last = root.AttributeLists.LastOrDefault() as SyntaxNode ?? root.Usings.LastOrDefault() as SyntaxNode ?? root.Externs.LastOrDefault() as SyntaxNode ?? root.GetDirectives(o => o is DefineDirectiveTriviaSyntax).LastOrDefault(); if (last != null) { int e1 = last.FullSpan.End; if (havePos = pos <= e1) { pos = e1; } } if (!havePos) { var members = root.Members; if (members.Any()) { var g = members.LastOrDefault(o => o is GlobalStatementSyntax); int posAfterTLS = g?.FullSpan.End ?? members.First().FullSpan.Start; bool done1 = false; if (node is BlockSyntax) { done1 = node.Span.ContainsInside(pos); } else if (node is MemberDeclarationSyntax) { done1 = true; //don't use posAfterTLS if before the first type bool here = node == members.FirstOrDefault(o => o is not GlobalStatementSyntax) && pos <= node.SpanStart; pos = Math.Min(pos, here ? node.SpanStart : posAfterTLS); } else if (node is CompilationUnitSyntax && g != members[^ 1]) //after types { done1 = true; pos = Math.Min(pos, posAfterTLS); } if (!done1) { for (; node is not CompilationUnitSyntax; node = node.Parent) { //CiUtil.PrintNode(node); if (node is StatementSyntax) { var pa = node.Parent; if (node is BlockSyntax && pa is not(BlockSyntax or GlobalStatementSyntax)) { continue; } var span = node.Span; if (havePos = pos >= span.End && token.IsKind(SyntaxKind.CloseBraceToken)) { pos = node.FullSpan.End; } else if (havePos = pos >= span.Start) { pos = span.Start; } break; } if (node is MemberDeclarationSyntax) { pos = posAfterTLS; break; } } } havePos |= pos == posAfterTLS; } } if (k.meta.end > 0 && pos <= k.meta.end) { havePos = true; pos = k.meta.end; if (code.Eq(pos, "\r\n")) { pos += 2; } else if (code.Eq(pos, '\n')) { pos++; } } if (!havePos) //if in comments or directive or disabled code, move to the start of trivia or line { var trivia = root.FindTrivia(pos); var tk = trivia.Kind(); if (tk is not(SyntaxKind.EndOfLineTrivia or SyntaxKind.None)) { if (tk == SyntaxKind.DisabledTextTrivia) { while (pos > 0 && code[pos - 1] != '\n') { pos--; } } else { pos = trivia.FullSpan.Start; } //rejected: move to the start of entire #if ... block. // Rare, not easy, may be far, and maybe user wants to insert into disabled code. } } //rename symbols in s if need try { _RenameNewSymbols(ref s, k.document, node, pos); } catch (Exception e1) { Debug_.Print(e1); } //indent, newlines string breakLine = null; for (; pos > 0 && code[pos - 1] != '\n'; pos--) { if (code[pos - 1] is not(' ' or '\t')) { breakLine = "\r\n"; break; } } int replTo = pos; while (replTo < code.Length && code[replTo] is ' ' or '\t') { replTo++; } var d = k.sci; var t2 = root.FindToken(pos); if (t2.SpanStart >= pos) { t2 = t2.GetPreviousToken(); } bool afterOpenBrace = t2.IsKind(SyntaxKind.OpenBraceToken); bool beforeCloseBrace = replTo < code.Length && code[replTo] == '}'; int indent = d.zLineIndentationFromPos(true, pos); if (afterOpenBrace && breakLine != null && !(t2.Parent is BlockSyntax bs1 && bs1.Parent is GlobalStatementSyntax)) { indent++; }