Try fix sequence mode
This commit is contained in:
@@ -37,13 +37,15 @@ class KeyboardHook {
|
|||||||
int pero = (int)wParam * 1000 + vkCode;
|
int pero = (int)wParam * 1000 + vkCode;
|
||||||
if (pero != previousEvent) {
|
if (pero != previousEvent) {
|
||||||
if (wParam == (IntPtr)WM_KEYDOWN) {
|
if (wParam == (IntPtr)WM_KEYDOWN) {
|
||||||
|
Console.WriteLine($"KeyboardHook: KeyDown event for key {vkCode}");
|
||||||
KeyDown?.Invoke(null, vkCode);
|
KeyDown?.Invoke(null, vkCode);
|
||||||
} else if (wParam == (IntPtr)WM_KEYUP) {
|
} else if (wParam == (IntPtr)WM_KEYUP) {
|
||||||
|
Console.WriteLine($"KeyboardHook: KeyUp event for key {vkCode}");
|
||||||
KeyUp?.Invoke(null, vkCode);
|
KeyUp?.Invoke(null, vkCode);
|
||||||
}
|
}
|
||||||
previousEvent = pero;
|
previousEvent = pero;
|
||||||
} else {
|
} else {
|
||||||
Console.WriteLine("Same event");
|
Console.WriteLine($"KeyboardHook: Same event filtered out - vkCode: {vkCode}, wParam: {wParam}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CallNextHookEx(_hookID, nCode, wParam, lParam);
|
return CallNextHookEx(_hookID, nCode, wParam, lParam);
|
||||||
|
@@ -36,48 +36,75 @@ namespace DD2Switcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void StartSequenceMode() {
|
public static void StartSequenceMode() {
|
||||||
|
Console.WriteLine($"StartSequenceMode called. FirstIndex: {FirstIndex}, LastIndex: {LastIndex}");
|
||||||
if (FirstIndex >= 0 && LastIndex >= 0 && FirstIndex <= LastIndex) {
|
if (FirstIndex >= 0 && LastIndex >= 0 && FirstIndex <= LastIndex) {
|
||||||
SequenceMode = true;
|
CurrentState = SequenceState.PROCESSING;
|
||||||
CurrentSequenceIndex = FirstIndex;
|
CurrentSequenceIndex = FirstIndex;
|
||||||
|
Console.WriteLine($"Starting sequence mode, tabbing to index {CurrentSequenceIndex + 1}");
|
||||||
TabTo(CurrentSequenceIndex + 1); // Tab to first window
|
TabTo(CurrentSequenceIndex + 1); // Tab to first window
|
||||||
|
CurrentState = SequenceState.WAITING;
|
||||||
|
Console.WriteLine($"State changed to: {CurrentState}");
|
||||||
|
} else {
|
||||||
|
Console.WriteLine("Cannot start sequence mode - invalid first/last indices");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NextSequenceStep() {
|
public static void NextSequenceStep() {
|
||||||
if (!SequenceMode)
|
Console.WriteLine(
|
||||||
|
$"NextSequenceStep called. State: {CurrentState}, CurrentIndex: {CurrentSequenceIndex}, LastIndex: {LastIndex}");
|
||||||
|
if (CurrentState == SequenceState.INACTIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
CurrentState = SequenceState.PROCESSING;
|
||||||
CurrentSequenceIndex++;
|
CurrentSequenceIndex++;
|
||||||
|
Console.WriteLine($"Advanced to index {CurrentSequenceIndex}");
|
||||||
if (CurrentSequenceIndex > LastIndex) {
|
if (CurrentSequenceIndex > LastIndex) {
|
||||||
// End of sequence
|
// End of sequence
|
||||||
|
Console.WriteLine("End of sequence reached, exiting sequence mode");
|
||||||
ExitSequenceMode();
|
ExitSequenceMode();
|
||||||
} else {
|
} else {
|
||||||
|
Console.WriteLine($"Tabbing to index {CurrentSequenceIndex + 1}");
|
||||||
TabTo(CurrentSequenceIndex + 1);
|
TabTo(CurrentSequenceIndex + 1);
|
||||||
|
CurrentState = SequenceState.WAITING;
|
||||||
|
Console.WriteLine($"State changed to: {CurrentState}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ExitSequenceMode() {
|
public static void ExitSequenceMode() {
|
||||||
SequenceMode = false;
|
CurrentState = SequenceState.INACTIVE;
|
||||||
CurrentSequenceIndex = -1;
|
CurrentSequenceIndex = -1;
|
||||||
|
Console.WriteLine($"State changed to: {CurrentState}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInSequenceMode() {
|
||||||
|
return CurrentState != SequenceState.INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateSequenceHotkey(Keys newKey) {
|
public static void UpdateSequenceHotkey(Keys newKey) {
|
||||||
|
Console.WriteLine($"UpdateSequenceHotkey called with new key: {newKey} (code: {(int)newKey})");
|
||||||
|
Console.WriteLine($"Old SequenceKeybind before update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
|
||||||
|
|
||||||
// Unregister old hotkey
|
// Unregister old hotkey
|
||||||
if (sequenceHotkeyId != -1) {
|
if (sequenceHotkeyId != -1) {
|
||||||
|
Console.WriteLine($"Unregistering old hotkey ID: {sequenceHotkeyId}");
|
||||||
HotKeyManager.UnregisterHotKey(sequenceHotkeyId);
|
HotKeyManager.UnregisterHotKey(sequenceHotkeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register new hotkey
|
// Register new hotkey
|
||||||
sequenceHotkeyId = HotKeyManager.RegisterHotKey(newKey, KeyModifiers.NoRepeat);
|
sequenceHotkeyId = HotKeyManager.RegisterHotKey(newKey, KeyModifiers.NoRepeat);
|
||||||
|
Console.WriteLine($"Registered new hotkey ID: {sequenceHotkeyId} for key: {newKey}");
|
||||||
SequenceKeybind = newKey;
|
SequenceKeybind = newKey;
|
||||||
|
Console.WriteLine($"New SequenceKeybind after update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static properties for first/last selection persistence
|
// Static properties for first/last selection persistence
|
||||||
public static int FirstIndex { get; set; } = -1;
|
public static int FirstIndex { get; set; } = -1;
|
||||||
public static int LastIndex { get; set; } = -1;
|
public static int LastIndex { get; set; } = -1;
|
||||||
|
|
||||||
// Sequence mode state
|
// Sequence mode state engine
|
||||||
public static bool SequenceMode { get; set; } = false;
|
public enum SequenceState { INACTIVE, WAITING, PROCESSING }
|
||||||
|
|
||||||
|
public static SequenceState CurrentState { get; set; } = SequenceState.INACTIVE;
|
||||||
public static int CurrentSequenceIndex { get; set; } = -1;
|
public static int CurrentSequenceIndex { get; set; } = -1;
|
||||||
public static Keys SequenceKeybind { get; set; } = Keys.F1;
|
public static Keys SequenceKeybind { get; set; } = Keys.F1;
|
||||||
private static int sequenceHotkeyId = -1;
|
private static int sequenceHotkeyId = -1;
|
||||||
@@ -107,6 +134,48 @@ namespace DD2Switcher {
|
|||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
|
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern IntPtr SetWindowsHookEx(int idHook, IntPtr lpfn, IntPtr hMod, uint dwThreadId);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||||
|
|
||||||
|
private const int WH_MOUSE_LL = 14;
|
||||||
|
private const int WM_LBUTTONDOWN = 0x0201;
|
||||||
|
private const int WM_RBUTTONDOWN = 0x0204;
|
||||||
|
private const int WM_MBUTTONDOWN = 0x0207;
|
||||||
|
private static IntPtr mouseHookId = IntPtr.Zero;
|
||||||
|
private static IntPtr mouseHookProc = IntPtr.Zero;
|
||||||
|
private static MouseHookProc mouseHookDelegate; // Keep reference to prevent GC
|
||||||
|
|
||||||
|
private delegate IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
private static void HandleSequenceEvent() {
|
||||||
|
if (CurrentState == SequenceState.WAITING) {
|
||||||
|
Console.WriteLine($"Event detected in state: {CurrentState}, advancing to next step");
|
||||||
|
NextSequenceStep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr MouseHookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
|
||||||
|
if (nCode >= 0) {
|
||||||
|
int wParamInt = (int)wParam;
|
||||||
|
if (wParamInt == WM_LBUTTONDOWN || wParamInt == WM_RBUTTONDOWN || wParamInt == WM_MBUTTONDOWN) {
|
||||||
|
if (CurrentState == SequenceState.WAITING) {
|
||||||
|
Console.WriteLine($"Mouse click detected in state: {CurrentState}");
|
||||||
|
HandleSequenceEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CallNextHookEx(mouseHookId, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
private static void CleanWindows() {
|
private static void CleanWindows() {
|
||||||
for (int i = 0; i < NumProc; i++) {
|
for (int i = 0; i < NumProc; i++) {
|
||||||
var window = windows[i];
|
var window = windows[i];
|
||||||
@@ -293,6 +362,7 @@ namespace DD2Switcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void TabTo(int index) {
|
private static void TabTo(int index) {
|
||||||
|
Console.WriteLine($"TabTo called with index: {index}");
|
||||||
index = (index - 1) % NumProc;
|
index = (index - 1) % NumProc;
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
index = NumProc - 1;
|
index = NumProc - 1;
|
||||||
@@ -302,6 +372,9 @@ namespace DD2Switcher {
|
|||||||
Console.WriteLine($"Tab to window at index {index}");
|
Console.WriteLine($"Tab to window at index {index}");
|
||||||
|
|
||||||
var window = windows[index];
|
var window = windows[index];
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Window at index {index}: {(window == null ? "NULL" : window.ProcessName + " PID:" + window.Id)}");
|
||||||
|
|
||||||
if (window == null || window.MainWindowHandle == IntPtr.Zero) {
|
if (window == null || window.MainWindowHandle == IntPtr.Zero) {
|
||||||
Console.WriteLine($"Window at index {index} does not exist, removing from tracked windows");
|
Console.WriteLine($"Window at index {index} does not exist, removing from tracked windows");
|
||||||
windows[index] = null;
|
windows[index] = null;
|
||||||
@@ -309,10 +382,27 @@ namespace DD2Switcher {
|
|||||||
if (ActiveIndex != -1)
|
if (ActiveIndex != -1)
|
||||||
PushHistory(ActiveIndex);
|
PushHistory(ActiveIndex);
|
||||||
|
|
||||||
|
Console.WriteLine($"Setting foreground window to: {window.ProcessName} PID:{window.Id}");
|
||||||
|
bool result = SetForegroundWindow(window.MainWindowHandle);
|
||||||
|
Console.WriteLine($"SetForegroundWindow result: {result}");
|
||||||
|
|
||||||
|
// Force window to front with additional methods
|
||||||
|
if (result) {
|
||||||
|
// Bring window to front and activate it
|
||||||
SetForegroundWindow(window.MainWindowHandle);
|
SetForegroundWindow(window.MainWindowHandle);
|
||||||
|
System.Threading.Thread.Sleep(50); // Small delay
|
||||||
|
|
||||||
|
// Check if it actually worked
|
||||||
|
var currentForeground = GetForegroundWindow();
|
||||||
|
bool actuallySwitched = (currentForeground == window.MainWindowHandle);
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Actually switched: {actuallySwitched} (Current: {currentForeground}, Target: {window.MainWindowHandle})");
|
||||||
|
}
|
||||||
|
|
||||||
ActiveIndex = index;
|
ActiveIndex = index;
|
||||||
AdjustAffinities();
|
AdjustAffinities();
|
||||||
AdjustPriorities();
|
AdjustPriorities();
|
||||||
|
Console.WriteLine($"Successfully switched to window at index {index}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,6 +450,7 @@ namespace DD2Switcher {
|
|||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
private static void Main() {
|
private static void Main() {
|
||||||
|
// AllocConsole(); // Enable console for debug output
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
|
||||||
@@ -374,6 +465,12 @@ namespace DD2Switcher {
|
|||||||
|
|
||||||
bool onlyAlt = false;
|
bool onlyAlt = false;
|
||||||
KeyboardHook.Start();
|
KeyboardHook.Start();
|
||||||
|
|
||||||
|
// Set up mouse hook for sequence mode
|
||||||
|
mouseHookDelegate = new MouseHookProc(MouseHookCallback);
|
||||||
|
mouseHookProc = Marshal.GetFunctionPointerForDelegate(mouseHookDelegate);
|
||||||
|
mouseHookId = SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc,
|
||||||
|
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
|
||||||
KeyboardHook.KeyDown += (sender, e) => {
|
KeyboardHook.KeyDown += (sender, e) => {
|
||||||
Console.WriteLine($"Key down: {e}");
|
Console.WriteLine($"Key down: {e}");
|
||||||
if (e == 164 && !onlyAlt) {
|
if (e == 164 && !onlyAlt) {
|
||||||
@@ -391,6 +488,17 @@ namespace DD2Switcher {
|
|||||||
onlyAlt = false;
|
onlyAlt = false;
|
||||||
TabToPrevious();
|
TabToPrevious();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle sequence mode event detection with KeyUp
|
||||||
|
if (CurrentState == SequenceState.WAITING) {
|
||||||
|
// Ignore the sequence keybind itself
|
||||||
|
if (e != (int)SequenceKeybind) {
|
||||||
|
Console.WriteLine($"Key up detected in state: {CurrentState} - Key: {e}");
|
||||||
|
HandleSequenceEvent();
|
||||||
|
} else {
|
||||||
|
Console.WriteLine($"Ignoring sequence keybind release: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HotKeyManager.RegisterHotKey(Keys.Capital, KeyModifiers.NoRepeat);
|
HotKeyManager.RegisterHotKey(Keys.Capital, KeyModifiers.NoRepeat);
|
||||||
@@ -402,21 +510,37 @@ namespace DD2Switcher {
|
|||||||
|
|
||||||
HotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Alt);
|
HotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Alt);
|
||||||
sequenceHotkeyId = HotKeyManager.RegisterHotKey(SequenceKeybind, KeyModifiers.NoRepeat);
|
sequenceHotkeyId = HotKeyManager.RegisterHotKey(SequenceKeybind, KeyModifiers.NoRepeat);
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Initial sequence hotkey registration - ID: {sequenceHotkeyId}, Key: {SequenceKeybind} (code: {(int)SequenceKeybind})");
|
||||||
HotKeyManager.HotKeyPressed += HotKeyManager_HotKeyPressed;
|
HotKeyManager.HotKeyPressed += HotKeyManager_HotKeyPressed;
|
||||||
|
|
||||||
void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e) {
|
void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e) {
|
||||||
|
Console.WriteLine($"Hotkey pressed: {e.Key} with modifiers {e.Modifiers}");
|
||||||
|
Console.WriteLine($"Current sequence keybind: {SequenceKeybind}");
|
||||||
|
Console.WriteLine($"Key codes - Pressed: {(int)e.Key}, Expected: {(int)SequenceKeybind}");
|
||||||
|
|
||||||
// Check for sequence mode keybind
|
// Check for sequence mode keybind
|
||||||
if (e.Key == SequenceKeybind && e.Modifiers == KeyModifiers.NoRepeat) {
|
Console.WriteLine(
|
||||||
if (SequenceMode) {
|
$"Checking sequence keybind - Key: {e.Key} == {SequenceKeybind} = {e.Key == SequenceKeybind}");
|
||||||
|
Console.WriteLine($"Checking modifiers - Received: {e.Modifiers}, Expected: {KeyModifiers.NoRepeat}");
|
||||||
|
if (e.Key == SequenceKeybind) {
|
||||||
|
Console.WriteLine("Sequence keybind detected!");
|
||||||
|
if (CurrentState != SequenceState.INACTIVE) {
|
||||||
|
Console.WriteLine("Advancing sequence step");
|
||||||
NextSequenceStep();
|
NextSequenceStep();
|
||||||
} else {
|
} else {
|
||||||
|
Console.WriteLine("Starting sequence mode");
|
||||||
StartSequenceMode();
|
StartSequenceMode();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Sequence keybind check failed - Key match: {e.Key == SequenceKeybind}, Modifiers match: {e.Modifiers == KeyModifiers.NoRepeat}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel sequence mode on any manual window switching
|
// Cancel sequence mode on any manual window switching
|
||||||
if (SequenceMode && e.Modifiers == KeyModifiers.Alt) {
|
if (CurrentState != SequenceState.INACTIVE && e.Modifiers == KeyModifiers.Alt) {
|
||||||
|
Console.WriteLine("Manual window switching detected, cancelling sequence mode");
|
||||||
ExitSequenceMode();
|
ExitSequenceMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,6 +572,11 @@ namespace DD2Switcher {
|
|||||||
// Run the WinForms application with Form1 as the main form
|
// Run the WinForms application with Form1 as the main form
|
||||||
Application.Run(new Form1());
|
Application.Run(new Form1());
|
||||||
KeyboardHook.Stop();
|
KeyboardHook.Stop();
|
||||||
|
|
||||||
|
// Clean up mouse hook
|
||||||
|
if (mouseHookId != IntPtr.Zero) {
|
||||||
|
UnhookWindowsHookEx(mouseHookId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,6 @@ namespace DD2Switcher {
|
|||||||
private FlowLayoutPanel windowsPanel;
|
private FlowLayoutPanel windowsPanel;
|
||||||
private Label sequenceKeybindLabel;
|
private Label sequenceKeybindLabel;
|
||||||
private TextBox sequenceKeybindTextBox;
|
private TextBox sequenceKeybindTextBox;
|
||||||
private Timer statusTimer;
|
|
||||||
|
|
||||||
public SettingsForm() {
|
public SettingsForm() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -107,6 +106,7 @@ namespace DD2Switcher {
|
|||||||
this.Name = "SettingsForm";
|
this.Name = "SettingsForm";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
this.Text = "DD2Switcher Settings";
|
this.Text = "DD2Switcher Settings";
|
||||||
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SettingsForm_FormClosing);
|
||||||
this.tabControl.ResumeLayout(false);
|
this.tabControl.ResumeLayout(false);
|
||||||
this.windowsTab.ResumeLayout(false);
|
this.windowsTab.ResumeLayout(false);
|
||||||
this.sequenceTab.ResumeLayout(false);
|
this.sequenceTab.ResumeLayout(false);
|
||||||
@@ -236,13 +236,29 @@ namespace DD2Switcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sequenceKeybindTextBox_Leave(object sender, EventArgs e) {
|
private void sequenceKeybindTextBox_Leave(object sender, EventArgs e) {
|
||||||
|
Console.WriteLine($"sequenceKeybindTextBox_Leave called with text: {sequenceKeybindTextBox.Text}");
|
||||||
try {
|
try {
|
||||||
KeysConverter converter = new KeysConverter();
|
KeysConverter converter = new KeysConverter();
|
||||||
Keys newKey = (Keys)converter.ConvertFromString(sequenceKeybindTextBox.Text);
|
Keys newKey = (Keys)converter.ConvertFromString(sequenceKeybindTextBox.Text);
|
||||||
|
Console.WriteLine($"Converted key: {newKey} (code: {(int)newKey})");
|
||||||
Program.UpdateSequenceHotkey(newKey);
|
Program.UpdateSequenceHotkey(newKey);
|
||||||
} catch {
|
Console.WriteLine("Keybind updated successfully!");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine($"Error converting key: {ex.Message}");
|
||||||
sequenceKeybindTextBox.Text = Program.SequenceKeybind.ToString();
|
sequenceKeybindTextBox.Text = Program.SequenceKeybind.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SettingsForm_FormClosing(object sender, FormClosingEventArgs e) {
|
||||||
|
Console.WriteLine("SettingsForm closing - saving keybind");
|
||||||
|
try {
|
||||||
|
KeysConverter converter = new KeysConverter();
|
||||||
|
Keys newKey = (Keys)converter.ConvertFromString(sequenceKeybindTextBox.Text);
|
||||||
|
Console.WriteLine($"Saving keybind on close: {newKey}");
|
||||||
|
Program.UpdateSequenceHotkey(newKey);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine($"Error saving keybind on close: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user