I have an indicator which scrols in chart using Sendkeys.SendWat(“{PGUP}”). this works ok, but when i try to scroll using - arrow left - it does not work SendKeys.SendWait(“{LEFT}”);
Why is there difference in behavior?
using System;
using System.Threading;
using System.Windows;
using System.Windows.Interop;
namespace NinjaTrader.NinjaScript.Indicators
{
public partial class Golem_TradeBrowser
{
///
/// Pomocná metoda: získá aktuální viditelný rozsah barů.
/// Vrátí true a nastaví firstVisible/lastVisible.
///
private bool GetVisibleBarRange(out int firstVisible, out int lastVisible)
{
firstVisible = -1; lastVisible = -1;
if (ChartControl == null || Bars == null) return false;
lastVisible = ChartControl.LastSlotPainted;
firstVisible = Bars.GetBar(ChartControl.FirstTimePainted);
if (firstVisible < 0 || lastVisible < 0)
{
lastVisible = Bars.Count - 1;
firstVisible = Math.Max(0, lastVisible - VisibleRangeBars);
}
return true;
}
/// <summary>
/// Odskroluj na chartu tak, aby byl bar s indexem targetBarIndex viditelný.
/// </summary>
/// <param name="targetBarIndex"></param>
/// <param name="trade"></param>
/// <param name="pauseMs"></param>
/// <param name="maxAttempts"></param>
private void ScrollUntilBarVisible(int targetBarIndex, Trade trade, int pauseMs = 100, int maxAttempts = 200)
{
if (ChartControl == null || Bars == null || Bars.Count == 0) return;
int first = -1, last = -1;
if (!GetVisibleBarRange(out first, out last))
{
Print("GetVisibleBarRange selhalo."); return;
}
bool moveLeft = targetBarIndex < first;
string pageKey = moveLeft ? "{PGUP}" : "{PGDN}";
IntPtr prevForeground = IntPtr.Zero;
IntPtr targetHwnd = IntPtr.Zero;
try
{
ChartControl.Dispatcher.Invoke(() =>
{
Window ownerWindow = Window.GetWindow(ChartControl);
if (ownerWindow != null) targetHwnd = new WindowInteropHelper(ownerWindow).Handle;
});
prevForeground = GetForegroundWindow();
if (targetHwnd != IntPtr.Zero && prevForeground != targetHwnd) { SetForegroundWindow(targetHwnd); Thread.Sleep(60); }
}
catch (Exception ex) { Print("Nelze nastavit foreground: " + ex.Message); }
try
{
// 1) základní stránkování PageUp/PageDown aby se target dostal do rozsahu (pokud to jde)
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
try { System.Windows.Forms.SendKeys.SendWait(pageKey); System.Windows.Forms.Application.DoEvents(); }
catch (Exception ex) { Print("SendKeys selhalo: " + ex.Message); break; }
Thread.Sleep(Math.Max(50, pauseMs));
int f2 = -1, l2 = -1;
if (!GetVisibleBarRange(out f2, out l2))
{
Print($"GetVisibleBarRange selhalo po pokusu {attempt}.");
break;
}
if (targetBarIndex >= f2 && targetBarIndex <= l2)
{
first = f2; last = l2;
goto SimpleFineTune; // target je viditelný -> jdi na jednoduché dolaďování
}
if (f2 == first && l2 == last && attempt > 5) { break; }
first = f2; last = l2;
}
// Po page loop zkusíme získat poslední rozsah
if (!GetVisibleBarRange(out first, out last)) return;
SimpleFineTune:
// --- JEDNODUCHÉ DOLAĎOVÁNÍ: spočítat rozdíl a stisknout potřebný počet šipek ---
int desiredOffsetFromRight = 20; // pevně pro test, můžeme později parametrizovat
int visibleCount = Math.Max(1, last - first + 1);
// desired nemůže být >= visibleCount, upravíme ho
desiredOffsetFromRight = Math.Min(desiredOffsetFromRight, Math.Max(0, visibleCount - 1));
// currentDistance = kolik svící je mezi target a pravým okrajem (last)
// pokud currentDistance < 0 -> target je napravo od last (novější než zobrazované)
int currentDistance = last - targetBarIndex;
Print($"SimpleFineTune: first={first}, last={last}, target={targetBarIndex}, currentDistance={currentDistance}, desired={desiredOffsetFromRight}, visibleCount={visibleCount}");
// Spočti kolik stisknutí potřebuji (kladné = RIGHT, záporné = LEFT)
int movesNeeded;
bool pressRight; // RIGHT zvětší last -> zvětší currentDistance
if (currentDistance < desiredOffsetFromRight)
{
movesNeeded = desiredOffsetFromRight - currentDistance;
pressRight = true;
}
else if (currentDistance > desiredOffsetFromRight)
{
movesNeeded = currentDistance - desiredOffsetFromRight;
pressRight = false;
}
else
{
Print("SimpleFineTune: target již na požadované pozici (nic dělat).");
return;
}
// Bezpečnostní limit: neskákat moc
int maxArrowMoves = Math.Max(200, visibleCount * 3);
movesNeeded = Math.Min(movesNeeded, maxArrowMoves);
Print($"SimpleFineTune: provedu {movesNeeded}x {(pressRight ? "RIGHT" : "LEFT")} (limit {maxArrowMoves}).");
ChartControl.Dispatcher.Invoke(() =>
{
for (int i = 0; i < movesNeeded; i++)
{
Print($"SimpleFineTune: stisk číslo {i + 1} / {movesNeeded}.");
try
{
if (pressRight)
System.Windows.Forms.SendKeys.SendWait("{RIGHT}");
else
{
System.Windows.Forms.SendKeys.SendWait("{LEFT}");
}
System.Windows.Forms.Application.DoEvents();
}
catch (Exception ex)
{
Print("SendKeys šipka selhalo: " + ex.Message);
break;
}
Thread.Sleep(Math.Max(50, pauseMs));
int f3 = -1, l3 = -1;
if (!GetVisibleBarRange(out f3, out l3)) break;
// pokud target přestal být viditelný, necháme to, ale vypíšeme info
if (!(targetBarIndex >= f3 && targetBarIndex <= l3))
{
Print($"SimpleFineTune: během tombolování target není viditelný (f3={f3}, l3={l3}), i={i}.");
// pokusíme se dál (může být potřeba více stisků RIGHT pokud byl napravo)
}
}
});
// poslední kontrola
if (GetVisibleBarRange(out first, out last))
{
int finalDistance = last - targetBarIndex;
Print($"SimpleFineTune finished: finalDistance={finalDistance}, desired={desiredOffsetFromRight}");
}
}
finally
{
try { if (prevForeground != IntPtr.Zero && targetHwnd != IntPtr.Zero && prevForeground != targetHwnd) SetForegroundWindow(prevForeground); } catch { }
}
Print($"GolemTradeBrowser: jednoduché dolaďování dokončeno.");
}
}
}