wpf: make the cursor blink (#3415)

This commit is contained in:
Zoey Riordan 2019-11-04 21:41:02 +00:00 committed by Dustin L. Howett (MSFT)
parent a4c24f82e6
commit 6f36f8b23f
4 changed files with 78 additions and 1 deletions

View file

@ -396,3 +396,20 @@ HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions)
return publicTerminal->_terminal->UserResize(dimensions);
}
void _stdcall TerminalBlinkCursor(void* terminal)
{
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
if (!publicTerminal->_terminal->IsCursorBlinkingAllowed() && publicTerminal->_terminal->IsCursorVisible())
{
return;
}
publicTerminal->_terminal->SetCursorVisible(!publicTerminal->_terminal->IsCursorVisible());
}
void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible)
{
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
publicTerminal->_terminal->SetCursorVisible(visible);
}

View file

@ -35,6 +35,8 @@ __declspec(dllexport) void _stdcall TerminalSetTheme(void* terminal, TerminalThe
__declspec(dllexport) void _stdcall TerminalRegisterWriteCallback(void* terminal, const void __stdcall callback(wchar_t*));
__declspec(dllexport) void _stdcall TerminalSendKeyEvent(void* terminal, WPARAM wParam);
__declspec(dllexport) void _stdcall TerminalSendCharEvent(void* terminal, wchar_t ch);
__declspec(dllexport) void _stdcall TerminalBlinkCursor(void* terminal);
__declspec(dllexport) void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible);
};
struct HwndTerminal
@ -69,5 +71,7 @@ private:
friend void _stdcall TerminalSendKeyEvent(void* terminal, WPARAM wParam);
friend void _stdcall TerminalSendCharEvent(void* terminal, wchar_t ch);
friend void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR fontFamily, short fontSize, int newDpi);
friend void _stdcall TerminalBlinkCursor(void* terminal);
friend void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible);
void _UpdateFont(int newDpi);
};

View file

@ -21,6 +21,16 @@ namespace Microsoft.Terminal.Wpf
public enum WindowMessage : int
{
/// <summary>
/// The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus.
/// </summary>
WM_SETFOCUS = 0x0007,
/// <summary>
/// The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus.
/// </summary>
WM_KILLFOCUS = 0x0008,
/// <summary>
/// The WM_MOUSEACTIVATE message is sent when the cursor is in an inactive window and the user presses a mouse button. The parent window receives this message only if the child window passes it to the DefWindowProc function.
/// </summary>
@ -202,12 +212,24 @@ namespace Microsoft.Terminal.Wpf
[DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern void TerminalSetTheme(IntPtr terminal, [MarshalAs(UnmanagedType.Struct)] TerminalTheme theme, string fontFamily, short fontSize, int newDpi);
[DllImport("PublicTerminalCore.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void TerminalBlinkCursor(IntPtr terminal);
[DllImport("PublicTerminalCore.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void TerminalSetCursorVisible(IntPtr terminal, bool visible);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetFocus(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetFocus();
[DllImport("user32.dll", SetLastError = true)]
public static extern short GetKeyState(int keyCode);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetCaretBlinkTime();
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{

View file

@ -10,6 +10,7 @@ namespace Microsoft.Terminal.Wpf
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
/// <summary>
/// The container class that hosts the native hwnd terminal.
@ -22,7 +23,7 @@ namespace Microsoft.Terminal.Wpf
private ITerminalConnection connection;
private IntPtr hwnd;
private IntPtr terminal;
private DispatcherTimer blinkTimer;
private NativeMethods.ScrollCallback scrollCallback;
private NativeMethods.WriteCallback writeCallback;
@ -34,6 +35,21 @@ namespace Microsoft.Terminal.Wpf
this.MessageHook += this.TerminalContainer_MessageHook;
this.GotFocus += this.TerminalContainer_GotFocus;
this.Focusable = true;
var blinkTime = NativeMethods.GetCaretBlinkTime();
if (blinkTime != uint.MaxValue)
{
this.blinkTimer = new DispatcherTimer();
this.blinkTimer.Interval = TimeSpan.FromMilliseconds(blinkTime);
this.blinkTimer.Tick += (_, __) =>
{
if (this.terminal != IntPtr.Zero)
{
NativeMethods.TerminalBlinkCursor(this.terminal);
}
};
}
}
/// <summary>
@ -171,6 +187,15 @@ namespace Microsoft.Terminal.Wpf
NativeMethods.TerminalDpiChanged(this.terminal, (int)dpiScale.PixelsPerInchX);
}
if (NativeMethods.GetFocus() == this.hwnd)
{
this.blinkTimer?.Start();
}
else
{
NativeMethods.TerminalSetCursorVisible(this.terminal, false);
}
return new HandleRef(this, this.hwnd);
}
@ -193,6 +218,13 @@ namespace Microsoft.Terminal.Wpf
{
switch ((NativeMethods.WindowMessage)msg)
{
case NativeMethods.WindowMessage.WM_SETFOCUS:
this.blinkTimer?.Start();
break;
case NativeMethods.WindowMessage.WM_KILLFOCUS:
this.blinkTimer?.Stop();
NativeMethods.TerminalSetCursorVisible(this.terminal, false);
break;
case NativeMethods.WindowMessage.WM_MOUSEACTIVATE:
this.Focus();
NativeMethods.SetFocus(this.hwnd);
@ -215,8 +247,10 @@ namespace Microsoft.Terminal.Wpf
this.MouseMoveHandler((int)wParam, (int)lParam);
break;
case NativeMethods.WindowMessage.WM_KEYDOWN:
NativeMethods.TerminalSetCursorVisible(this.terminal, true);
NativeMethods.TerminalClearSelection(this.terminal);
NativeMethods.TerminalSendKeyEvent(this.terminal, wParam);
this.blinkTimer?.Start();
break;
case NativeMethods.WindowMessage.WM_CHAR:
NativeMethods.TerminalSendCharEvent(this.terminal, (char)wParam);