Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 116 additions & 2 deletions Client/Forms/CMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public partial class CMain : RenderForm

public static KeyBindSettings InputKeys = new KeyBindSettings();

private static IntPtr _capsLockHook = IntPtr.Zero;
private static LowLevelKeyboardProc _capsLockProc;

public CMain()
{
InitializeComponent();
Expand All @@ -64,6 +67,7 @@ public CMain()
Deactivate += CMain_Deactivate;
MouseWheel += CMain_MouseWheel;

Application.AddMessageFilter(new CapsLockFilter());

SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.Selectable, true);
FormBorderStyle = Settings.FullScreen || Settings.Borderless ? FormBorderStyle.None : FormBorderStyle.FixedDialog;
Expand Down Expand Up @@ -132,8 +136,19 @@ private static void CMain_Deactivate(object sender, EventArgs e)
SpellTargetLock = false;
}

private static bool IsLoginSceneActive()
{
return MirScene.ActiveScene is Client.MirScenes.LoginScene;
}

public static void CMain_KeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.CapsLock || e.KeyCode == Keys.Capital) && IsLoginSceneActive())
{
e.Handled = true;
return;
}

Shift = e.Shift;
Alt = e.Alt;
Ctrl = e.Control;
Expand Down Expand Up @@ -386,7 +401,7 @@ private static void RenderEnvironment()
{
try
{
if (DXManager.DeviceLost)
if (DXManager.DeviceLost || DXManager.Device == null || DXManager.Sprite == null || DXManager.Device.Disposed)
{
DXManager.AttemptReset();
Thread.Sleep(1);
Expand All @@ -408,7 +423,9 @@ private static void RenderEnvironment()
catch (Direct3D9Exception ex)
{
DXManager.DeviceLost = true;
SaveError(ex.ToString());

if (ex.ResultCode.Code != ResultCode.DeviceLost.Code && ex.ResultCode.Code != ResultCode.DeviceNotReset.Code)
SaveError(ex.ToString());
}
catch (Exception ex)
{
Expand Down Expand Up @@ -698,6 +715,8 @@ private struct PeekMsg

private void CMain_FormClosing(object sender, FormClosingEventArgs e)
{
UninstallCapsLockHook();

if (CMain.Time < GameScene.LogTime && !Settings.UseTestConfig && !GameScene.Observing)
{
GameScene.Scene.ChatDialog.ReceiveChat(GameLanguage.ClientTextMap.GetLocalization((ClientTextKeys.CannotLeaveGame) , (GameScene.LogTime - CMain.Time) / 1000), ChatType.System);
Expand Down Expand Up @@ -731,6 +750,101 @@ protected override void WndProc(ref Message m)
base.WndProc(ref m);
}

private sealed class CapsLockFilter : IMessageFilter
{
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
private const int WM_SYSKEYDOWN = 0x104;
private const int WM_SYSKEYUP = 0x105;
private const int VK_CAPITAL = 0x14;

public bool PreFilterMessage(ref Message m)
{
if ((m.Msg == WM_KEYDOWN || m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYDOWN || m.Msg == WM_SYSKEYUP)
&& m.WParam.ToInt32() == VK_CAPITAL
&& MirScene.ActiveScene is Client.MirScenes.LoginScene)
{
return true;
}

return false;
}
}

private const int WH_KEYBOARD_LL = 13;
private const int VK_CAPITAL = 0x14;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll")]
private static extern short GetKeyState(int nVirtKey);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);

public static void InstallCapsLockHook()
{
try
{
if (_capsLockHook != IntPtr.Zero) return;

_capsLockProc = CapsLockHookCallback;
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
_capsLockHook = SetWindowsHookEx(WH_KEYBOARD_LL, _capsLockProc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
catch
{
}
}

public static void UninstallCapsLockHook()
{
try
{
if (_capsLockHook == IntPtr.Zero) return;
UnhookWindowsHookEx(_capsLockHook);
_capsLockHook = IntPtr.Zero;
_capsLockProc = null;
}
catch
{
}
}

private static IntPtr CapsLockHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MirScene.ActiveScene is Client.MirScenes.LoginScene)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == VK_CAPITAL)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
int msg = wParam.ToInt32();
if (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN)
{
bool capsOn = (GetKeyState(VK_CAPITAL) & 0x0001) != 0;
if (!capsOn)
return (IntPtr)1;
}
}
}

return CallNextHookEx(_capsLockHook, nCode, wParam, lParam);
}

public static Cursor[] Cursors;
public static MouseCursor CurrentCursor = MouseCursor.None;
Expand Down
96 changes: 76 additions & 20 deletions Client/MirControls/MirTextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ public MirTextBox()

TextBox.VisibleChanged += TextBox_VisibleChanged;
TextBox.ParentChanged += TextBox_VisibleChanged;
TextBox.KeyUp += TextBoxOnKeyUp;
TextBox.KeyDown += TextBoxOnKeyDown;
TextBox.KeyUp += TextBoxOnKeyUp;
TextBox.KeyPress += TextBox_KeyPress;

TextBox.KeyPress += TextBox_NeedRedraw;
Expand All @@ -299,8 +300,13 @@ public MirTextBox()
TextBox.MouseMove += CMain.CMain_MouseMove;
}

private static bool _creatingTexture;

private void TextBox_NeedRedraw(object sender, EventArgs e)
{
if (e is KeyEventArgs keyEvent && (keyEvent.KeyCode == Keys.CapsLock || keyEvent.KeyCode == Keys.Capital))
return;

TextureValid = false;
Redraw();
}
Expand All @@ -310,34 +316,72 @@ protected unsafe override void CreateTexture()
if (Size.IsEmpty)
return;

if (TextureSize != Size)
DisposeTexture();
if (_creatingTexture)
return;

if (ControlTexture == null || ControlTexture.Disposed)
_creatingTexture = true;
try
{
DXManager.ControlList.Add(this);
if (TextureSize != Size)
DisposeTexture();

ControlTexture = new Texture(DXManager.Device, Size.Width, Size.Height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
TextureSize = Size;
}
if (ControlTexture == null || ControlTexture.Disposed)
{
DXManager.ControlList.Add(this);

Point caret = GetCaretPosition();
ControlTexture = new Texture(DXManager.Device, Size.Width, Size.Height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
TextureSize = Size;
}

DataRectangle stream = ControlTexture.LockRectangle(0, LockFlags.Discard);
using (Bitmap bm = new Bitmap(Size.Width, Size.Height, Size.Width * 4, PixelFormat.Format32bppArgb, stream.Data.DataPointer))
{
TextBox.DrawToBitmap(bm, new Rectangle(0, 0, Size.Width, Size.Height));
using (Graphics graphics = Graphics.FromImage(bm))
Point caret = GetCaretPosition();
bool focused = TextBox.Focused;

using (Bitmap bm = new Bitmap(Size.Width, Size.Height, PixelFormat.Format32bppArgb))
{
graphics.DrawImage(bm, Point.Empty);
if (TextBox.Focused)
graphics.DrawLine(CaretPen, new Point(caret.X, caret.Y), new Point(caret.X, caret.Y + TextBox.Font.Height));
TextBox.DrawToBitmap(bm, new Rectangle(0, 0, Size.Width, Size.Height));
using (Graphics graphics = Graphics.FromImage(bm))
{
if (focused)
graphics.DrawLine(CaretPen, new Point(caret.X, caret.Y), new Point(caret.X, caret.Y + TextBox.Font.Height));
}

DataRectangle stream = ControlTexture.LockRectangle(0, LockFlags.Discard);
try
{
BitmapData data = bm.LockBits(new Rectangle(0, 0, Size.Width, Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
try
{
byte* src = (byte*)data.Scan0;
byte* dst = (byte*)stream.Data.DataPointer;
int dstPitch = stream.Pitch;
int srcPitch = Math.Abs(data.Stride);
for (int row = 0; row < Size.Height; row++)
{
Buffer.MemoryCopy(src + row * srcPitch, dst + row * dstPitch, dstPitch, srcPitch);
}
}
finally
{
bm.UnlockBits(data);
}
}
finally
{
ControlTexture.UnlockRectangle(0);
}
}

DXManager.Sprite.Flush();
TextureValid = true;
}
catch
{
TextureValid = false;
}
finally
{
_creatingTexture = false;
}
ControlTexture.UnlockRectangle(0);
DXManager.Sprite.Flush();
TextureValid = true;
}

public override void OnMouseDown(MouseEventArgs e)
Expand Down Expand Up @@ -372,8 +416,20 @@ private Point GetCaretPosition()
return result;
}

private void TextBoxOnKeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.CapsLock || e.KeyCode == Keys.Capital) && MirScene.ActiveScene is Client.MirScenes.LoginScene)
e.Handled = true;
}

private void TextBoxOnKeyUp(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.CapsLock || e.KeyCode == Keys.Capital) && MirScene.ActiveScene is Client.MirScenes.LoginScene)
{
e.Handled = true;
return;
}

switch (e.KeyCode)
{
case Keys.PrintScreen:
Expand Down
41 changes: 30 additions & 11 deletions Client/MirGraphics/DXManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ public static void AttemptReset()
{
try
{
if (Device == null || Device.Disposed) return;

Result result = DXManager.Device.TestCooperativeLevel();

if (result.Code == ResultCode.DeviceLost.Code) return;
Expand All @@ -272,6 +274,9 @@ public static void AttemptReset()
if (result.Code != ResultCode.Success.Code) return;

DXManager.DeviceLost = false;

if (Sprite == null || Sprite.Disposed)
LoadTextures();
}
catch
{
Expand All @@ -280,44 +285,58 @@ public static void AttemptReset()

public static void ResetDevice()
{
if (DXManager.Device == null || DXManager.Device.Disposed) return;

DXManager.CleanUp();
DXManager.DeviceLost = true;

if (DXManager.Parameters == null) return;
try
{
if (DXManager.Parameters == null) return;

Size clientSize = Program.Form.ClientSize;
Size clientSize = Program.Form.ClientSize;

if (clientSize.Width == 0 || clientSize.Height == 0) return;
if (clientSize.Width == 0 || clientSize.Height == 0) return;

DXManager.Parameters.Windowed = !Settings.FullScreen;
DXManager.Parameters.BackBufferWidth = clientSize.Width;
DXManager.Parameters.BackBufferHeight = clientSize.Height;
DXManager.Parameters.PresentationInterval = Settings.FPSCap ? PresentInterval.Default : PresentInterval.Immediate;
DXManager.Device.Reset(DXManager.Parameters);
DXManager.Parameters.Windowed = !Settings.FullScreen;
DXManager.Parameters.BackBufferWidth = clientSize.Width;
DXManager.Parameters.BackBufferHeight = clientSize.Height;
DXManager.Parameters.PresentationInterval = Settings.FPSCap ? PresentInterval.Default : PresentInterval.Immediate;
DXManager.Device.Reset(DXManager.Parameters);

DXManager.LoadTextures();
DXManager.LoadTextures();
DXManager.DeviceLost = false;
}
catch
{
DXManager.DeviceLost = true;
}
}

public static void AttemptRecovery()
{
try
{
Sprite.End();
if (Sprite != null && !Sprite.Disposed)
Sprite.End();
}
catch
{
}

try
{
Device.EndScene();
if (Device != null && !Device.Disposed)
Device.EndScene();
}
catch
{
}

try
{
if (Device == null || Device.Disposed) return;

MainSurface = Device.GetBackBuffer(0, 0);
CurrentSurface = MainSurface;
Device.SetRenderTarget(0, MainSurface);
Expand Down
Loading