Browse Source

Inplemented double and triple click in TextBox.

Copied a load of stuff from Moonlight regarding finding next/prev word
that I've put in StringUtils.
pull/12/head
Steven Kirk 12 years ago
parent
commit
00aa02964f
  1. 17
      Gtk/Perspex.Gtk/GtkPlatform.cs
  2. 4
      Gtk/Perspex.Gtk/WindowImpl.cs
  3. 1
      Perspex.Controls/Perspex.Controls.csproj
  4. 2
      Perspex.Controls/Primitives/SelectingItemsControl.cs
  5. 2
      Perspex.Controls/Primitives/Thumb.cs
  6. 85
      Perspex.Controls/TextBox.cs
  7. 261
      Perspex.Controls/Utils/StringUtils.cs
  8. 2
      Perspex.Input/FocusManager.cs
  9. 2
      Perspex.Input/IInputElement.cs
  10. 8
      Perspex.Input/InputElement.cs
  11. 27
      Perspex.Input/MouseDevice.cs
  12. 2
      Perspex.Input/Perspex.Input.csproj
  13. 17
      Perspex.Input/Platform/IPlatformSettings.cs
  14. 13
      Perspex.Input/PointerPressEventArgs.cs
  15. 5
      Perspex.Input/Raw/RawInputEventArgs.cs
  16. 9
      Perspex.Input/Raw/RawKeyEventArgs.cs
  17. 3
      Perspex.Input/Raw/RawMouseEventArgs.cs
  18. 3
      Perspex.Input/Raw/RawMouseWheelEventArgs.cs
  19. 22
      Perspex.SceneGraph/Rect.cs
  20. 110
      Windows/Perspex.Win32/Interop/UnmanagedMethods.cs
  21. 21
      Windows/Perspex.Win32/Win32Platform.cs
  22. 6
      Windows/Perspex.Win32/WindowImpl.cs

17
Gtk/Perspex.Gtk/GtkPlatform.cs

@ -13,7 +13,7 @@ namespace Perspex.Gtk
using Splat;
using Gtk = global::Gtk;
public class GtkPlatform : IPlatformThreadingInterface
public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings
{
private static GtkPlatform instance = new GtkPlatform();
@ -22,11 +22,26 @@ namespace Perspex.Gtk
Gtk.Application.Init();
}
public Size DoubleClickSize
{
get
{
// TODO: Is there a setting for this somewhere?
return new Size(4, 4);
}
}
public TimeSpan DoubleClickTime
{
get { return TimeSpan.FromMilliseconds(Gtk.Settings.Default.DoubleClickTime); }
}
public static void Initialize()
{
var locator = Locator.CurrentMutable;
locator.Register(() => new WindowImpl(), typeof(IWindowImpl));
locator.Register(() => GtkKeyboardDevice.Instance, typeof(IKeyboardDevice));
locator.Register(() => instance, typeof(IPlatformSettings));
locator.Register(() => instance, typeof(IPlatformThreadingInterface));
}

4
Gtk/Perspex.Gtk/WindowImpl.cs

@ -69,6 +69,7 @@ namespace Perspex.Gtk
{
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
this.owner,
RawMouseEventType.LeftButtonDown,
new Point(evnt.X, evnt.Y));
@ -80,6 +81,7 @@ namespace Perspex.Gtk
{
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
this.owner,
RawMouseEventType.LeftButtonUp,
new Point(evnt.X, evnt.Y));
@ -109,6 +111,7 @@ namespace Perspex.Gtk
{
var e = new RawKeyEventArgs(
GtkKeyboardDevice.Instance,
evnt.Time,
RawKeyEventType.KeyDown,
GtkKeyboardDevice.ConvertKey(evnt.Key),
new string((char)Gdk.Keyval.ToUnicode((uint)evnt.Key), 1));
@ -135,6 +138,7 @@ namespace Perspex.Gtk
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
this.owner,
RawMouseEventType.Move,
position);

1
Perspex.Controls/Perspex.Controls.csproj

@ -74,6 +74,7 @@
<Compile Include="Primitives\Track.cs" />
<Compile Include="Primitives\Thumb.cs" />
<Compile Include="TextWrapping.cs" />
<Compile Include="Utils\StringUtils.cs" />
<Compile Include="Window.cs" />
<Compile Include="RowDefinition.cs" />
<Compile Include="RowDefinitions.cs" />

2
Perspex.Controls/Primitives/SelectingItemsControl.cs

@ -114,7 +114,7 @@ namespace Perspex.Controls.Primitives
e.Handled = true;
}
protected override void OnPointerPressed(PointerEventArgs e)
protected override void OnPointerPressed(PointerPressEventArgs e)
{
IVisual source = (IVisual)e.Source;
var selectable = source.GetVisualAncestors()

2
Perspex.Controls/Primitives/Thumb.cs

@ -74,7 +74,7 @@ namespace Perspex.Controls.Primitives
}
}
protected override void OnPointerPressed(PointerEventArgs e)
protected override void OnPointerPressed(PointerPressEventArgs e)
{
e.Device.Capture(this);
this.lastPoint = e.GetPosition(this);

85
Perspex.Controls/TextBox.cs

@ -10,6 +10,7 @@ namespace Perspex.Controls
using System.Collections.Generic;
using System.Linq;
using Perspex.Controls.Primitives;
using Perspex.Controls.Utils;
using Perspex.Input;
using Perspex.Media;
using Perspex.Styling;
@ -93,11 +94,31 @@ namespace Perspex.Controls
set { this.SetValue(TextWrappingProperty, value); }
}
protected override void OnPointerPressed(PointerEventArgs e)
protected override void OnPointerPressed(PointerPressEventArgs e)
{
var point = e.GetPosition(this.textBoxView);
this.CaretIndex = this.SelectionStart = this.SelectionEnd =
this.textBoxView.GetCaretIndex(point);
var index = this.CaretIndex = this.textBoxView.GetCaretIndex(point);
var text = this.Text;
switch (e.ClickCount)
{
case 1:
this.SelectionStart = this.SelectionEnd = index;
break;
case 2:
if (!StringUtils.IsStartOfWord(text, index))
{
this.SelectionStart = StringUtils.PreviousWord(text, index, false);
}
this.SelectionEnd = StringUtils.NextWord(text, index, false);
break;
case 3:
this.SelectionStart = 0;
this.SelectionEnd = text.Length;
break;
}
e.Device.Capture(this);
}
@ -148,7 +169,14 @@ namespace Perspex.Controls
if ((modifiers & ModifierKeys.Control) != 0)
{
count = this.NextWord(text, count, caretIndex);
if (count > 0)
{
count = StringUtils.NextWord(text, caretIndex, false) - caretIndex;
}
else
{
count = StringUtils.PreviousWord(text, caretIndex, false) - caretIndex;
}
}
this.CaretIndex = caretIndex += count;
@ -256,6 +284,7 @@ namespace Perspex.Controls
return false;
}
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
string text = this.Text ?? string.Empty;
@ -381,53 +410,5 @@ namespace Perspex.Controls
return i;
}
private int NextWord(string text, int direction, int caretIndex)
{
int pos = caretIndex;
bool foundNonWhiteSpace = false;
for (; ;)
{
pos += direction;
if (direction < 0 && pos <= 0)
{
pos = 0;
break;
}
else if (direction > 0 && pos >= text.Length)
{
pos = text.Length;
break;
}
else if (char.IsWhiteSpace(text[pos]))
{
if (foundNonWhiteSpace)
{
if (direction < 0)
{
++pos;
break;
}
else
{
while (pos < text.Length && char.IsWhiteSpace(text[pos]))
{
++pos;
}
break;
}
}
}
else
{
foundNonWhiteSpace = true;
}
}
return pos - caretIndex;
}
}
}

261
Perspex.Controls/Utils/StringUtils.cs

@ -0,0 +1,261 @@
// -----------------------------------------------------------------------
// <copyright file="StringUtils.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
using System.Globalization;
namespace Perspex.Controls.Utils
{
internal static class StringUtils
{
public static bool IsEol(char c)
{
return c == '\r' || c == '\n';
}
public static bool IsStartOfWord(string text, int index)
{
// A 'word' starts with an AlphaNumeric or some punctuation symbols immediately
// preceeded by lwsp.
if (index > 0 && !char.IsWhiteSpace(text[index - 1]))
{
return false;
}
switch (CharUnicodeInfo.GetUnicodeCategory(text[index]))
{
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.TitlecaseLetter:
case UnicodeCategory.UppercaseLetter:
case UnicodeCategory.DecimalDigitNumber:
case UnicodeCategory.LetterNumber:
case UnicodeCategory.OtherNumber:
case UnicodeCategory.DashPunctuation:
case UnicodeCategory.InitialQuotePunctuation:
case UnicodeCategory.OpenPunctuation:
case UnicodeCategory.CurrencySymbol:
case UnicodeCategory.MathSymbol:
return true;
// TODO: How do you do this in .NET?
//case UnicodeCategory.OtherPunctuation:
// // words cannot start with '.', but they can start with '&' or '*' (for example)
// return g_unichar_break_type(buffer->text[index]) == G_UNICODE_BREAK_ALPHABETIC;
default:
return false;
}
}
public static int PreviousWord(string text, int cursor, bool gtkMode)
{
int begin;
int i;
int cr;
int lf;
lf = LineBegin(text, cursor) - 1;
if (lf > 0 && text[lf] == '\n' && text[lf - 1] == '\r')
{
cr = lf - 1;
}
else
{
cr = lf;
}
// if the cursor is at the beginning of the line, return the end of the prev line
if (cursor - 1 == lf)
{
return (cr > 0) ? cr : 0;
}
if (gtkMode)
{
CharClass cc = GetCharClass(text[cursor - 1]);
begin = lf + 1;
i = cursor;
// skip over the word, punctuation, or run of whitespace
while (i > begin && GetCharClass(text[i - 1]) == cc)
{
i--;
}
// if the cursor was at whitespace, skip back a word too
if (cc == CharClass.CharClassWhitespace && i > begin)
{
cc = GetCharClass(text[i - 1]);
while (i > begin && GetCharClass(text[i - 1]) == cc)
{
i--;
}
}
}
else
{
begin = lf + 1;
i = cursor;
if (cursor < text.Length)
{
// skip to the beginning of this word
while (i > begin && !char.IsWhiteSpace(text[i - 1]))
{
i--;
}
if (i < cursor && IsStartOfWord(text, i))
{
return i;
}
}
// skip to the start of the lwsp
while (i > begin && char.IsWhiteSpace(text[i - 1]))
{
i--;
}
if (i > begin)
{
i--;
}
// skip to the beginning of the word
while (i > begin && !IsStartOfWord(text, i))
{
i--;
}
}
return i;
}
public static int NextWord(string text, int cursor, bool gtkMode)
{
int i, lf, cr;
cr = LineEnd(text, cursor);
if (cr < text.Length && text[cr] == '\r' && text[cr + 1] == '\n')
{
lf = cr + 1;
}
else
{
lf = cr;
}
// if the cursor is at the end of the line, return the starting offset of the next line
if (cursor == cr || cursor == lf)
{
if (lf < text.Length)
{
return lf + 1;
}
return cursor;
}
if (gtkMode)
{
CharClass cc = GetCharClass(text[cursor]);
i = cursor;
// skip over the word, punctuation, or run of whitespace
while (i < cr && GetCharClass(text[i]) == cc)
{
i++;
}
// skip any whitespace after the word/punct
while (i < cr && char.IsWhiteSpace(text[i]))
{
i++;
}
}
else
{
i = cursor;
// skip to the end of the current word
while (i < cr && !char.IsWhiteSpace(text[i]))
{
i++;
}
// skip any whitespace after the word
while (i < cr && char.IsWhiteSpace(text[i]))
{
i++;
}
// find the start of the next word
while (i < cr && !IsStartOfWord(text, i))
{
i++;
}
}
return i;
}
private static CharClass GetCharClass(char c)
{
if (char.IsWhiteSpace(c))
{
return CharClass.CharClassWhitespace;
}
else if (char.IsLetterOrDigit(c))
{
return CharClass.CharClassAlphaNumeric;
}
else
{
return CharClass.CharClassUnknown;
}
}
private static int LineBegin(string text, int pos)
{
while (pos > 0 && !IsEol(text[pos - 1]))
{
pos--;
}
return pos;
}
private static int LineEnd(string text, int cursor, bool include = false)
{
while (cursor < text.Length && !IsEol(text[cursor]))
{
cursor++;
}
if (include && cursor < text.Length)
{
if (text[cursor] == '\r' && text[cursor + 1] == '\n')
{
cursor += 2;
}
else
{
cursor++;
}
}
return cursor;
}
private enum CharClass
{
CharClassUnknown,
CharClassWhitespace,
CharClassAlphaNumeric,
}
}
}

2
Perspex.Input/FocusManager.cs

@ -48,7 +48,7 @@ namespace Perspex.Input
.OfType<IFocusScope>()
.FirstOrDefault();
if (scope != null)
if (scope != null && control != current)
{
this.focusScopes[scope] = control;

2
Perspex.Input/IInputElement.cs

@ -21,7 +21,7 @@ namespace Perspex.Input
event EventHandler<PointerEventArgs> PointerLeave;
event EventHandler<PointerEventArgs> PointerPressed;
event EventHandler<PointerPressEventArgs> PointerPressed;
event EventHandler<PointerEventArgs> PointerReleased;

8
Perspex.Input/InputElement.cs

@ -49,8 +49,8 @@ namespace Perspex.Input
public static readonly RoutedEvent<PointerEventArgs> PointerMovedEvent =
RoutedEvent.Register<InputElement, PointerEventArgs>("PointerMove", RoutingStrategy.Bubble);
public static readonly RoutedEvent<PointerEventArgs> PointerPressedEvent =
RoutedEvent.Register<InputElement, PointerEventArgs>("PointerPressed", RoutingStrategy.Bubble);
public static readonly RoutedEvent<PointerPressEventArgs> PointerPressedEvent =
RoutedEvent.Register<InputElement, PointerPressEventArgs>("PointerPressed", RoutingStrategy.Bubble);
public static readonly RoutedEvent<PointerEventArgs> PointerReleasedEvent =
RoutedEvent.Register<InputElement, PointerEventArgs>("PointerReleased", RoutingStrategy.Bubble);
@ -119,7 +119,7 @@ namespace Perspex.Input
remove { this.RemoveHandler(PointerMovedEvent, value); }
}
public event EventHandler<PointerEventArgs> PointerPressed
public event EventHandler<PointerPressEventArgs> PointerPressed
{
add { this.AddHandler(PointerPressedEvent, value); }
remove { this.RemoveHandler(PointerPressedEvent, value); }
@ -222,7 +222,7 @@ namespace Perspex.Input
{
}
protected virtual void OnPointerPressed(PointerEventArgs e)
protected virtual void OnPointerPressed(PointerPressEventArgs e)
{
}

27
Perspex.Input/MouseDevice.cs

@ -11,10 +11,17 @@ namespace Perspex.Input
using System.Reactive.Linq;
using Perspex.Input.Raw;
using Perspex.Interactivity;
using Perspex.Platform;
using Splat;
public abstract class MouseDevice : IMouseDevice
{
private int clickCount;
private Rect lastClickRect;
private uint lastClickTime;
public MouseDevice()
{
this.InputManager.RawEventReceived
@ -73,7 +80,7 @@ namespace Perspex.Input
this.MouseMove(mouse, e.Root, e.Position);
break;
case RawMouseEventType.LeftButtonDown:
this.MouseDown(mouse, e.Root, e.Position);
this.MouseDown(mouse, e.Timestamp, e.Root, e.Position);
break;
case RawMouseEventType.LeftButtonUp:
this.MouseUp(mouse, e.Root, e.Position);
@ -118,7 +125,7 @@ namespace Perspex.Input
}
}
private void MouseDown(IMouseDevice device, IInputElement root, Point p)
private void MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p)
{
IVisual hit = root.InputHitTest(p);
@ -128,12 +135,26 @@ namespace Perspex.Input
if (source != null)
{
source.RaiseEvent(new PointerEventArgs
var settings = Locator.Current.GetService<IPlatformSettings>();
var doubleClickTime = settings.DoubleClickTime.TotalMilliseconds;
if (!this.lastClickRect.Contains(p) || timestamp - this.lastClickTime > doubleClickTime)
{
this.clickCount = 0;
}
++this.clickCount;
this.lastClickTime = timestamp;
this.lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(settings.DoubleClickSize.Width / 2, settings.DoubleClickSize.Height / 2));
source.RaiseEvent(new PointerPressEventArgs
{
Device = this,
RoutedEvent = InputElement.PointerPressedEvent,
OriginalSource = source,
Source = source,
ClickCount = this.clickCount,
});
}

2
Perspex.Input/Perspex.Input.csproj

@ -68,6 +68,8 @@
<Compile Include="IPointerDevice.cs" />
<Compile Include="Key.cs" />
<Compile Include="KeyboardDevice.cs" />
<Compile Include="Platform\IPlatformSettings.cs" />
<Compile Include="PointerPressEventArgs.cs" />
<Compile Include="PointerWheelEventArgs.cs" />
<Compile Include="Raw\RawMouseWheelEventArgs.cs" />
<Compile Include="Raw\RawSizeEventArgs.cs" />

17
Perspex.Input/Platform/IPlatformSettings.cs

@ -0,0 +1,17 @@
// -----------------------------------------------------------------------
// <copyright file="IPlatformSettings.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Platform
{
using System;
public interface IPlatformSettings
{
Size DoubleClickSize { get; }
TimeSpan DoubleClickTime { get; }
}
}

13
Perspex.Input/PointerPressEventArgs.cs

@ -0,0 +1,13 @@
// -----------------------------------------------------------------------
// <copyright file="PointerEventArgs.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Input
{
public class PointerPressEventArgs : PointerEventArgs
{
public int ClickCount { get; set; }
}
}

5
Perspex.Input/Raw/RawInputEventArgs.cs

@ -10,13 +10,16 @@ namespace Perspex.Input.Raw
public class RawInputEventArgs : EventArgs
{
public RawInputEventArgs(IInputDevice device)
public RawInputEventArgs(IInputDevice device, uint timestamp)
{
Contract.Requires<ArgumentNullException>(device != null);
this.Device = device;
this.Timestamp = timestamp;
}
public IInputDevice Device { get; private set; }
public uint Timestamp { get; private set; }
}
}

9
Perspex.Input/Raw/RawKeyEventArgs.cs

@ -14,8 +14,13 @@ namespace Perspex.Input.Raw
public class RawKeyEventArgs : RawInputEventArgs
{
public RawKeyEventArgs(KeyboardDevice device, RawKeyEventType type, Key key, string text)
: base(device)
public RawKeyEventArgs(
KeyboardDevice device,
uint timestamp,
RawKeyEventType type,
Key key,
string text)
: base(device, timestamp)
{
this.Key = key;
this.Type = type;

3
Perspex.Input/Raw/RawMouseEventArgs.cs

@ -21,10 +21,11 @@ namespace Perspex.Input.Raw
{
public RawMouseEventArgs(
IInputDevice device,
uint timestamp,
IInputElement root,
RawMouseEventType type,
Point position)
: base(device)
: base(device, timestamp)
{
Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);

3
Perspex.Input/Raw/RawMouseWheelEventArgs.cs

@ -13,10 +13,11 @@ namespace Perspex.Input.Raw
{
public RawMouseWheelEventArgs(
IInputDevice device,
uint timestamp,
IInputElement root,
Point position,
Vector delta)
: base(device, root, RawMouseEventType.Wheel, position)
: base(device, timestamp, root, RawMouseEventType.Wheel, position)
{
this.Delta = delta;
}

22
Perspex.SceneGraph/Rect.cs

@ -259,6 +259,28 @@ namespace Perspex
rect.height);
}
/// <summary>
/// Inflates the rectangle.
/// </summary>
/// <param name="thickness">The thickness.</param>
/// <returns>The inflated rectangle.</returns>
public Rect Inflate(double thickness)
{
return this.Inflate(thickness);
}
/// <summary>
/// Inflates the rectangle.
/// </summary>
/// <param name="thickness">The thickness.</param>
/// <returns>The inflated rectangle.</returns>
public Rect Inflate(Thickness thickness)
{
return new Rect(
new Point(this.x - thickness.Left, this.y - thickness.Top),
this.Size.Inflate(thickness));
}
/// <summary>
/// Deflates the rectangle.
/// </summary>

110
Windows/Perspex.Win32/Interop/UnmanagedMethods.cs

@ -64,6 +64,107 @@ namespace Perspex.Win32.Interop
SWP_RESIZE = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER
}
public enum SystemMetric
{
SM_CXSCREEN = 0, // 0x00
SM_CYSCREEN = 1, // 0x01
SM_CXVSCROLL = 2, // 0x02
SM_CYHSCROLL = 3, // 0x03
SM_CYCAPTION = 4, // 0x04
SM_CXBORDER = 5, // 0x05
SM_CYBORDER = 6, // 0x06
SM_CXDLGFRAME = 7, // 0x07
SM_CXFIXEDFRAME = 7, // 0x07
SM_CYDLGFRAME = 8, // 0x08
SM_CYFIXEDFRAME = 8, // 0x08
SM_CYVTHUMB = 9, // 0x09
SM_CXHTHUMB = 10, // 0x0A
SM_CXICON = 11, // 0x0B
SM_CYICON = 12, // 0x0C
SM_CXCURSOR = 13, // 0x0D
SM_CYCURSOR = 14, // 0x0E
SM_CYMENU = 15, // 0x0F
SM_CXFULLSCREEN = 16, // 0x10
SM_CYFULLSCREEN = 17, // 0x11
SM_CYKANJIWINDOW = 18, // 0x12
SM_MOUSEPRESENT = 19, // 0x13
SM_CYVSCROLL = 20, // 0x14
SM_CXHSCROLL = 21, // 0x15
SM_DEBUG = 22, // 0x16
SM_SWAPBUTTON = 23, // 0x17
SM_CXMIN = 28, // 0x1C
SM_CYMIN = 29, // 0x1D
SM_CXSIZE = 30, // 0x1E
SM_CYSIZE = 31, // 0x1F
SM_CXSIZEFRAME = 32, // 0x20
SM_CXFRAME = 32, // 0x20
SM_CYSIZEFRAME = 33, // 0x21
SM_CYFRAME = 33, // 0x21
SM_CXMINTRACK = 34, // 0x22
SM_CYMINTRACK = 35, // 0x23
SM_CXDOUBLECLK = 36, // 0x24
SM_CYDOUBLECLK = 37, // 0x25
SM_CXICONSPACING = 38, // 0x26
SM_CYICONSPACING = 39, // 0x27
SM_MENUDROPALIGNMENT = 40, // 0x28
SM_PENWINDOWS = 41, // 0x29
SM_DBCSENABLED = 42, // 0x2A
SM_CMOUSEBUTTONS = 43, // 0x2B
SM_SECURE = 44, // 0x2C
SM_CXEDGE = 45, // 0x2D
SM_CYEDGE = 46, // 0x2E
SM_CXMINSPACING = 47, // 0x2F
SM_CYMINSPACING = 48, // 0x30
SM_CXSMICON = 49, // 0x31
SM_CYSMICON = 50, // 0x32
SM_CYSMCAPTION = 51, // 0x33
SM_CXSMSIZE = 52, // 0x34
SM_CYSMSIZE = 53, // 0x35
SM_CXMENUSIZE = 54, // 0x36
SM_CYMENUSIZE = 55, // 0x37
SM_ARRANGE = 56, // 0x38
SM_CXMINIMIZED = 57, // 0x39
SM_CYMINIMIZED = 58, // 0x3A
SM_CXMAXTRACK = 59, // 0x3B
SM_CYMAXTRACK = 60, // 0x3C
SM_CXMAXIMIZED = 61, // 0x3D
SM_CYMAXIMIZED = 62, // 0x3E
SM_NETWORK = 63, // 0x3F
SM_CLEANBOOT = 67, // 0x43
SM_CXDRAG = 68, // 0x44
SM_CYDRAG = 69, // 0x45
SM_SHOWSOUNDS = 70, // 0x46
SM_CXMENUCHECK = 71, // 0x47
SM_CYMENUCHECK = 72, // 0x48
SM_SLOWMACHINE = 73, // 0x49
SM_MIDEASTENABLED = 74, // 0x4A
SM_MOUSEWHEELPRESENT = 75, // 0x4B
SM_XVIRTUALSCREEN = 76, // 0x4C
SM_YVIRTUALSCREEN = 77, // 0x4D
SM_CXVIRTUALSCREEN = 78, // 0x4E
SM_CYVIRTUALSCREEN = 79, // 0x4F
SM_CMONITORS = 80, // 0x50
SM_SAMEDISPLAYFORMAT = 81, // 0x51
SM_IMMENABLED = 82, // 0x52
SM_CXFOCUSBORDER = 83, // 0x53
SM_CYFOCUSBORDER = 84, // 0x54
SM_TABLETPC = 86, // 0x56
SM_MEDIACENTER = 87, // 0x57
SM_STARTER = 88, // 0x58
SM_SERVERR2 = 89, // 0x59
SM_MOUSEHORIZONTALWHEELPRESENT = 91, // 0x5B
SM_CXPADDEDBORDER = 92, // 0x5C
SM_DIGITIZER = 94, // 0x5E
SM_MAXIMUMTOUCHES = 95, // 0x5F
SM_REMOTESESSION = 0x1000, // 0x1000
SM_SHUTTINGDOWN = 0x2000, // 0x2000
SM_REMOTECONTROL = 0x2001, // 0x2001
SM_CONVERTABLESLATEMODE = 0x2003,
SM_SYSTEMDOCKED = 0x2004,
}
[Flags]
public enum WindowStyles : uint
{
@ -377,15 +478,24 @@ namespace Perspex.Win32.Interop
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out POINT lpPoint);
[DllImport("user32.dll")]
public static extern uint GetDoubleClickTime();
[DllImport("user32.dll")]
public static extern bool GetKeyboardState(byte[] lpKeyState);
[DllImport("user32.dll")]
public static extern sbyte GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
[DllImport("user32.dll")]
public static extern int GetMessageTime();
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(SystemMetric smIndex);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

21
Windows/Perspex.Win32/Win32Platform.cs

@ -9,26 +9,39 @@ namespace Perspex.Win32
using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
using Perspex.Input;
using Perspex.Platform;
using Perspex.Threading;
using Perspex.Win32.Input;
using Perspex.Win32.Interop;
using Splat;
public class Win32Platform : IPlatformThreadingInterface
public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings
{
private static Win32Platform instance = new Win32Platform();
private List<Delegate> delegates = new List<Delegate>();
public Size DoubleClickSize
{
get
{
return new Size(
UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDOUBLECLK),
UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDOUBLECLK));
}
}
public TimeSpan DoubleClickTime
{
get { return TimeSpan.FromMilliseconds(UnmanagedMethods.GetDoubleClickTime()); }
}
public static void Initialize()
{
var locator = Locator.CurrentMutable;
locator.Register(() => new WindowImpl(), typeof(IWindowImpl));
locator.Register(() => WindowsKeyboardDevice.Instance, typeof(IKeyboardDevice));
locator.Register(() => instance, typeof(IPlatformSettings));
locator.Register(() => instance, typeof(IPlatformThreadingInterface));
}

6
Windows/Perspex.Win32/WindowImpl.cs

@ -145,6 +145,7 @@ namespace Perspex.Win32
private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
const double WheelDelta = 120.0;
uint timestamp = unchecked((uint)UnmanagedMethods.GetMessageTime());
RawInputEventArgs e = null;
@ -164,6 +165,7 @@ namespace Perspex.Win32
WindowsKeyboardDevice.Instance.UpdateKeyStates();
e = new RawKeyEventArgs(
WindowsKeyboardDevice.Instance,
timestamp,
RawKeyEventType.KeyDown,
KeyInterop.KeyFromVirtualKey((int)wParam),
WindowsKeyboardDevice.Instance.StringFromVirtualKey((uint)wParam));
@ -172,6 +174,7 @@ namespace Perspex.Win32
case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN:
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
timestamp,
this.owner,
RawMouseEventType.LeftButtonDown,
new Point((uint)lParam & 0xffff, (uint)lParam >> 16));
@ -180,6 +183,7 @@ namespace Perspex.Win32
case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
timestamp,
this.owner,
RawMouseEventType.LeftButtonUp,
new Point((uint)lParam & 0xffff, (uint)lParam >> 16));
@ -188,6 +192,7 @@ namespace Perspex.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
timestamp,
this.owner,
RawMouseEventType.Move,
new Point((uint)lParam & 0xffff, (uint)lParam >> 16));
@ -196,6 +201,7 @@ namespace Perspex.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSEWHEEL:
e = new RawMouseWheelEventArgs(
WindowsMouseDevice.Instance,
timestamp,
this.owner,
this.ScreenToClient((uint)lParam & 0xffff, (uint)lParam >> 16),
new Vector(0, ((int)wParam >> 16) / WheelDelta));

Loading…
Cancel
Save