Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vs-editor-api.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/Editor/Text/Util/TextUIUtil')
-rw-r--r--src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs42
-rw-r--r--src/Editor/Text/Util/TextUIUtil/BaseProxyService.cs4
-rw-r--r--src/Editor/Text/Util/TextUIUtil/ChangeBrushes.cs34
-rw-r--r--src/Editor/Text/Util/TextUIUtil/DefaultStatusBarService.cs15
-rw-r--r--src/Editor/Text/Util/TextUIUtil/DefaultUIThreadOperationExecutor.cs2
-rw-r--r--src/Editor/Text/Util/TextUIUtil/DifferenceBrushManager.cs119
-rw-r--r--src/Editor/Text/Util/TextUIUtil/ExtensionMethods.cs2
-rw-r--r--src/Editor/Text/Util/TextUIUtil/IDragDropMouseProcessor.cs27
-rw-r--r--src/Editor/Text/Util/TextUIUtil/IOrderableContentTypeAndTextViewRoleMetadata.cs15
-rw-r--r--src/Editor/Text/Util/TextUIUtil/IScrollMap2.cs28
-rw-r--r--src/Editor/Text/Util/TextUIUtil/Markers.cs78
-rw-r--r--src/Editor/Text/Util/TextUIUtil/MultiSelectionMouseState.cs63
-rw-r--r--src/Editor/Text/Util/TextUIUtil/PerformanceBlockMarker.cs72
-rw-r--r--src/Editor/Text/Util/TextUIUtil/StatusBarService.cs20
-rw-r--r--src/Editor/Text/Util/TextUIUtil/Strings.Designer.cs279
-rw-r--r--src/Editor/Text/Util/TextUIUtil/Strings.resx213
-rw-r--r--src/Editor/Text/Util/TextUIUtil/TelemetryLogger.cs126
-rw-r--r--src/Editor/Text/Util/TextUIUtil/TextUIUtil.csproj49
-rw-r--r--src/Editor/Text/Util/TextUIUtil/TransformedDispatcherCollection.cs268
-rw-r--r--src/Editor/Text/Util/TextUIUtil/UIExtensionSelector.cs4
-rw-r--r--src/Editor/Text/Util/TextUIUtil/UIThreadOperationExecutor.cs2
-rw-r--r--src/Editor/Text/Util/TextUIUtil/VacuousTextViewModel.cs2
-rw-r--r--src/Editor/Text/Util/TextUIUtil/WpfHelper.cs853
23 files changed, 2309 insertions, 8 deletions
diff --git a/src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs b/src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs
new file mode 100644
index 0000000..4567dde
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Security.Permissions;
+
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.Input.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.Classification.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.DragDrop.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.AdornmentLibrary.TextMarker.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.AdornmentLibrary.ToolTip.Wpf.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.TextMarkerAdornment.UnitTests, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.CurrentLineHighlighter.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.GlyphMargin.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.DifferenceViewer.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.OverviewMargin.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.OverviewMargin.UnitTests, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.UI.Utilities.UnitTests, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.TextViewUnitTestHelper, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.View.UnitTests, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Wpf.Input.UnitTests, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.Differencing.DifferenceViewer.UnitTests, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Language.Intellisense.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Commanding.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Commanding.Implementation.UnitTests, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.Editor.PrintingService.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("EditorTestApp, PublicKey=" + ThisAssembly.PublicKey)]
+[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: SecurityPermission(SecurityAction.RequestMinimum, Flags = SecurityPermissionFlag.Execution)]
+[assembly: ReliabilityContract(Consistency.MayCorruptProcess, Cer.MayFail)]
diff --git a/src/Editor/Text/Util/TextUIUtil/BaseProxyService.cs b/src/Editor/Text/Util/TextUIUtil/BaseProxyService.cs
index 0062990..c2467a4 100644
--- a/src/Editor/Text/Util/TextUIUtil/BaseProxyService.cs
+++ b/src/Editor/Text/Util/TextUIUtil/BaseProxyService.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
@@ -32,4 +32,4 @@ namespace Microsoft.VisualStudio.Utilities
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/ChangeBrushes.cs b/src/Editor/Text/Util/TextUIUtil/ChangeBrushes.cs
new file mode 100644
index 0000000..e527d11
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/ChangeBrushes.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ using System.Collections.Generic;
+ using Microsoft.VisualStudio.Text.Document;
+ using Microsoft.VisualStudio.Text.Tagging;
+
+ internal static class ChangeBrushes
+ {
+ public static NormalizedSnapshotSpanCollection[] GetUnifiedChanges(ITextSnapshot snapshot, IEnumerable<IMappingTagSpan<ChangeTag>> tags)
+ {
+ List<Span>[] unnormalizedChanges = new List<Span>[4] { null,
+ new List<Span>(),
+ new List<Span>(),
+ new List<Span>()
+ };
+ foreach (IMappingTagSpan<ChangeTag> change in tags)
+ {
+ int type = (int)(change.Tag.ChangeTypes & (ChangeTypes.ChangedSinceOpened | ChangeTypes.ChangedSinceSaved));
+ if (type != 0)
+ unnormalizedChanges[type].AddRange((NormalizedSpanCollection)(change.Span.GetSpans(snapshot)));
+ }
+
+ NormalizedSnapshotSpanCollection[] changes = new NormalizedSnapshotSpanCollection[4];
+ for (int i = 1; (i <= 3); ++i)
+ changes[i] = new NormalizedSnapshotSpanCollection(snapshot, unnormalizedChanges[i]);
+
+ return changes;
+ }
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/DefaultStatusBarService.cs b/src/Editor/Text/Util/TextUIUtil/DefaultStatusBarService.cs
new file mode 100644
index 0000000..f604b55
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/DefaultStatusBarService.cs
@@ -0,0 +1,15 @@
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Utilities;
+
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ [ExportImplementation(typeof(IStatusBarService))]
+ [Name("default")]
+ internal class DefaultStatusBarService : IStatusBarService
+ {
+ public Task SetTextAsync(string text)
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/DefaultUIThreadOperationExecutor.cs b/src/Editor/Text/Util/TextUIUtil/DefaultUIThreadOperationExecutor.cs
index c6c349d..4067a15 100644
--- a/src/Editor/Text/Util/TextUIUtil/DefaultUIThreadOperationExecutor.cs
+++ b/src/Editor/Text/Util/TextUIUtil/DefaultUIThreadOperationExecutor.cs
@@ -37,4 +37,4 @@ namespace Microsoft.VisualStudio.UI.Text.Commanding.Implementation
{
}
}
-} \ No newline at end of file
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/DifferenceBrushManager.cs b/src/Editor/Text/Util/TextUIUtil/DifferenceBrushManager.cs
new file mode 100644
index 0000000..8773c20
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/DifferenceBrushManager.cs
@@ -0,0 +1,119 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+// This file contain implementations details that are subject to change without notice.
+// Use at your own risk.
+//
+using System;
+using System.Linq;
+using System.Windows.Media;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ class DifferenceBrushManager
+ {
+ public static DifferenceBrushManager GetBrushManager(ITextView3 view, IEditorFormatMapService formatMapService)
+ {
+ return view.Properties.GetOrCreateSingletonProperty(() => new DifferenceBrushManager(view, formatMapService.GetEditorFormatMap(view)));
+ }
+
+ public static DifferenceBrushManager GetBrushManager(ITextView3 view, IEditorFormatMap formatMap)
+ {
+ return view.Properties.GetOrCreateSingletonProperty(() => new DifferenceBrushManager(view, formatMap));
+ }
+
+ // internal for unit testing
+ internal static readonly SolidColorBrush _defaultRemovedLineBrush = Brushes.PaleVioletRed;
+ internal static readonly SolidColorBrush _defaultAddedLineBrush = Brushes.LightYellow;
+ internal static readonly SolidColorBrush _defaultRemovedWordBrush = Brushes.Red;
+ internal static readonly SolidColorBrush _defaultAddedWordBrush = Brushes.Yellow;
+
+ IEditorFormatMap _formatMap;
+
+ #region Public properties (brushes) and changed event
+
+ public Brush RemovedLineBrush { get; private set; }
+ public Brush AddedLineBrush { get; private set; }
+
+ public Brush RemovedWordBrush { get; private set; }
+ public Brush RemovedWordForegroundBrush { get; private set; }
+ public Pen RemovedWordForegroundPen { get; private set; }
+ public Brush AddedWordBrush { get; private set; }
+ public Brush AddedWordForegroundBrush { get; private set; }
+ public Pen AddedWordForegroundPen { get; private set; }
+
+ public Brush ViewportBrush { get; private set; }
+ public Pen ViewportPen { get; private set; }
+ public Brush OverviewBrush { get; private set; }
+
+ public event EventHandler<EventArgs> BrushesChanged;
+
+ #endregion
+
+ internal DifferenceBrushManager(ITextView3 view, IEditorFormatMap formatMap)
+ {
+ _formatMap = formatMap;
+
+ InitializeBrushes();
+
+ _formatMap.FormatMappingChanged += FormatMapChanged;
+ view.Closed += (s,a) => { _formatMap.FormatMappingChanged -= FormatMapChanged; };
+ }
+
+ void InitializeBrushes()
+ {
+ RemovedLineBrush = GetBrushValue("deltadiff.remove.line", _defaultRemovedLineBrush);
+ RemovedWordBrush = GetBrushValue("deltadiff.remove.word", _defaultRemovedWordBrush);
+ RemovedWordForegroundBrush = GetBrushValue("deltadiff.remove.word", _defaultRemovedWordBrush, EditorFormatDefinition.ForegroundBrushId);
+ RemovedWordForegroundPen = new Pen(RemovedWordForegroundBrush, 2.0);
+ RemovedWordForegroundPen.Freeze();
+
+ AddedLineBrush = GetBrushValue("deltadiff.add.line", _defaultAddedLineBrush);
+ AddedWordBrush = GetBrushValue("deltadiff.add.word", _defaultAddedWordBrush);
+ AddedWordForegroundBrush = GetBrushValue("deltadiff.add.word", _defaultAddedWordBrush, EditorFormatDefinition.ForegroundBrushId);
+ AddedWordForegroundPen = new Pen(AddedWordForegroundBrush, 2.0);
+ AddedWordForegroundPen.Freeze();
+
+ ViewportBrush = GetBrushValue("deltadiff.overview.color", Brushes.DarkGray, EditorFormatDefinition.ForegroundBrushId);
+ ViewportPen = new Pen(ViewportBrush, 2.0);
+ ViewportPen.Freeze();
+
+ OverviewBrush = GetBrushValue("deltadiff.overview.color", Brushes.Gray);
+
+ var temp = BrushesChanged;
+ if (temp != null)
+ temp(this, EventArgs.Empty);
+ }
+
+ Brush GetBrushValue(string formatName, Brush defaultValue, string resource = EditorFormatDefinition.BackgroundBrushId)
+ {
+ var formatProperties = _formatMap.GetProperties(formatName);
+ if (formatProperties != null && formatProperties.Contains(resource))
+ {
+ var brushValue = formatProperties[resource] as Brush;
+ if (brushValue != null)
+ return brushValue;
+ }
+
+ return defaultValue;
+ }
+
+ void FormatMapChanged(object sender, FormatItemsEventArgs e)
+ {
+ bool updateRequired = e.ChangedItems.Any(item =>
+ string.Equals(item, "deltadiff.add.word", System.StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(item, "deltadiff.add.line", System.StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(item, "deltadiff.remove.word", System.StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(item, "deltadiff.remove.line", System.StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(item, "deltadiff.overview.color", System.StringComparison.OrdinalIgnoreCase));
+
+ if (updateRequired)
+ {
+ InitializeBrushes();
+ }
+ }
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/ExtensionMethods.cs b/src/Editor/Text/Util/TextUIUtil/ExtensionMethods.cs
index 4d93bce..9c1ba00 100644
--- a/src/Editor/Text/Util/TextUIUtil/ExtensionMethods.cs
+++ b/src/Editor/Text/Util/TextUIUtil/ExtensionMethods.cs
@@ -81,7 +81,7 @@ namespace Microsoft.VisualStudio.Text.MultiSelection
//The indentation specified by the smart indent service is desired column position of the caret. Find out how much virtual space
//need to be at the end of the line to satisfy that.
// TODO: need a way to determine column width in xplat scenarios, bug https://devdiv.visualstudio.com/DevDiv/_workitems/edit/637741
- double columnWidth = 7;
+ double columnWidth = (textView is ITextView3 textView3) ? textView3.FormattedLineSource.ColumnWidth : throw new NotSupportedException();
indentationWidth = Math.Max(0.0, (((double)indentation.Value) * columnWidth - textLine.TextWidth));
// if the coordinate is specified by the user and the user has selected a coordinate to the left
diff --git a/src/Editor/Text/Util/TextUIUtil/IDragDropMouseProcessor.cs b/src/Editor/Text/Util/TextUIUtil/IDragDropMouseProcessor.cs
new file mode 100644
index 0000000..185f0a8
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/IDragDropMouseProcessor.cs
@@ -0,0 +1,27 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ using System.Windows;
+ using System.Windows.Input;
+
+ /// <summary>
+ /// This interface is a used as an abstraction of the DragDropMouseProcessor so that it can be called from the left margin
+ /// to handle drag/drop.
+ /// </summary>
+ public interface IDragDropMouseProcessor
+ {
+ void DoPreprocessMouseLeftButtonDown(MouseButtonEventArgs e, Point position);
+ void DoPreprocessMouseLeftButtonUp(MouseButtonEventArgs e, Point position);
+ void DoPostprocessMouseLeftButtonUp(MouseButtonEventArgs e, Point position);
+ void DoPreprocessMouseMove(MouseEventArgs e, Point position);
+ void DoPreprocessDrop(DragEventArgs e, Point position);
+ void DoPreprocessDragEnter(DragEventArgs e, Point position);
+ void DoPreprocessDragLeave(DragEventArgs e);
+ void DoPreprocessDragOver(DragEventArgs e, Point position);
+ void DoPreprocessQueryContinueDrag(QueryContinueDragEventArgs e);
+ void DoPostprocessMouseLeave(MouseEventArgs e);
+ }
+} \ No newline at end of file
diff --git a/src/Editor/Text/Util/TextUIUtil/IOrderableContentTypeAndTextViewRoleMetadata.cs b/src/Editor/Text/Util/TextUIUtil/IOrderableContentTypeAndTextViewRoleMetadata.cs
new file mode 100644
index 0000000..8f24867
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/IOrderableContentTypeAndTextViewRoleMetadata.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+using Microsoft.VisualStudio.Utilities;
+
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ /// <summary>
+ /// Metadata which includes Ordering, Content Types and Text View Roles
+ /// </summary>
+ public interface IOrderableContentTypeAndTextViewRoleMetadata : IContentTypeAndTextViewRoleMetadata, IOrderable
+ {
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/IScrollMap2.cs b/src/Editor/Text/Util/TextUIUtil/IScrollMap2.cs
new file mode 100644
index 0000000..3f02d06
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/IScrollMap2.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ using Microsoft.VisualStudio.Text.Editor;
+
+ /// <summary>
+ /// <para>Defines the mapping between character positions and scrollmap coordinates. This is not
+ /// the same as the coordinate system in which the scrollbar is rendered.</para>
+ /// </summary>
+ /// <remarks>
+ /// <para>Valid text positions range are [0...TextView.TextSnapshot.Length].</para>
+ /// <para>Corresponding scrollmap coordinates are [0.0 ... CoordinateOfBufferEnd].</para>
+ /// <para>Not every buffer position will have a distinct scrollmap coordinate. For example, every character on the same line of text will,
+ /// generally, have the same scrollmap coordinate.</para>
+ /// <para>Different scrollmap coordinates may map to the same buffer position. For example, scrollmap coordinates in the range [0.0, 1.0) will, generally,
+ /// map to the first character of the buffer.</para>
+ /// </remarks>
+ public interface IScrollMap2 : IScrollMap
+ {
+ void GetThumbTopAndBottom(out double thumbTop, out double thumbBottom);
+
+ void ScrollToCoordinate(double coordinate);
+ void CenterOnCoordinate(double coordinate);
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/Markers.cs b/src/Editor/Text/Util/TextUIUtil/Markers.cs
new file mode 100644
index 0000000..186c0a3
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/Markers.cs
@@ -0,0 +1,78 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Windows;
+ using System.Windows.Media;
+ using Microsoft.VisualStudio.Text;
+ using Microsoft.VisualStudio.Text.Editor;
+ using Microsoft.VisualStudio.Text.Formatting;
+
+ internal static class Markers
+ {
+ // pad the bottom part by 1 pixel to take advantage of the extra 1 pixel that's available in the default
+ // line transform at the bottom of each line
+ public readonly static Thickness SingleLinePadding = new Thickness(0.0, 0.0, 0.0, 1.0);
+ public readonly static Thickness MultiLinePadding = new Thickness(0.0);
+
+ public static bool MarkerGeometrySpansMultipleLines(ITextViewLineCollection collection, SnapshotSpan bufferSpan)
+ {
+ ITextViewLine start = collection.GetTextViewLineContainingBufferPosition(bufferSpan.Start);
+
+ return (start == null || bufferSpan.End > start.EndIncludingLineBreak);
+ }
+
+
+ //use double.MinValue/double.MaxValue for leftClip & rightClip to avoid clipping.
+ public static IList<Rect> GetRectanglesFromBounds(IList<TextBounds> bounds, Thickness padding, double leftClip, double rightClip, bool useTextBounds)
+ {
+ Debug.Assert(bounds != null);
+
+ List<Rect> newBounds = new List<Rect>(bounds.Count);
+ foreach (var b in bounds)
+ {
+ double x1 = Math.Max(leftClip, b.Left - padding.Left);
+ double x2 = Math.Min(rightClip, b.Right + padding.Right);
+ if (x1 < x2)
+ {
+ double y1 = (useTextBounds ? b.TextTop : b.Top) - padding.Top;
+ double y2 = (useTextBounds ? b.TextBottom : b.Bottom) + padding.Bottom;
+
+ newBounds.Add(new Rect(x1, y1, x2 - x1, y2 - y1));
+ }
+ }
+
+ return newBounds;
+ }
+
+ public static Geometry GetMarkerGeometryFromRectangles(IList<Rect> rectangles)
+ {
+ Debug.Assert(rectangles != null);
+
+ if (rectangles.Count == 0)
+ return null;
+
+ // Set up the initial geometry
+ PathGeometry geometry = new PathGeometry();
+ geometry.FillRule = FillRule.Nonzero;
+
+ foreach (var rectangle in rectangles)
+ {
+ geometry.AddGeometry(new RectangleGeometry(rectangle));
+ }
+ geometry.Freeze();
+
+ if (rectangles.Count > 1)
+ {
+ geometry = geometry.GetOutlinedPathGeometry();
+ geometry.Freeze();
+ }
+ return geometry;
+ }
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/MultiSelectionMouseState.cs b/src/Editor/Text/Util/TextUIUtil/MultiSelectionMouseState.cs
new file mode 100644
index 0000000..a18587c
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/MultiSelectionMouseState.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.MultiSelection;
+
+namespace Microsoft.VisualStudio.Text.UI.Utilities
+{
+ public class MultiSelectionMouseState
+ {
+ public static MultiSelectionMouseState GetStateForView(ITextView textView)
+ {
+ return textView.Properties.GetOrCreateSingletonProperty(() =>
+ {
+ return new MultiSelectionMouseState(textView);
+ });
+ }
+
+ private MultiSelectionMouseState(ITextView textView)
+ {
+ _textView = textView;
+ textView.LayoutChanged += OnLayoutChanged;
+ }
+
+ private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
+ {
+ if (_provisionalSelection != Selection.Invalid)
+ {
+ _provisionalSelection = _provisionalSelection.MapToSnapshot(e.NewSnapshot, _textView);
+ }
+ }
+
+ private Selection _provisionalSelection = Selection.Invalid;
+ private ITextView _textView;
+
+ public Selection ProvisionalSelection
+ {
+ get
+ {
+ return _provisionalSelection;
+ }
+ set
+ {
+ if (_provisionalSelection != value)
+ {
+ _provisionalSelection = value;
+ FireProvisionalSelectionChanged();
+ }
+ }
+ }
+
+ public event EventHandler ProvisionalSelectionChanged;
+
+ private void FireProvisionalSelectionChanged()
+ {
+ ProvisionalSelectionChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ public bool UserIsDraggingSelection { get; set; } = false;
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/PerformanceBlockMarker.cs b/src/Editor/Text/Util/TextUIUtil/PerformanceBlockMarker.cs
new file mode 100644
index 0000000..13dd4fc
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/PerformanceBlockMarker.cs
@@ -0,0 +1,72 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ [Export]
+ [PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class PerformanceBlockMarker
+ {
+ [ImportMany]
+ private List<Lazy<IPerformanceMarkerBlockProvider>> _performanceMarkerBlockProviders = null;
+
+ internal IDisposable CreateBlock(string blockName)
+ {
+ // Unit tests case
+ if (_performanceMarkerBlockProviders == null || _performanceMarkerBlockProviders.Count == 0)
+ {
+ return new Block();
+ }
+
+ // Optimize for the most common case
+ if (_performanceMarkerBlockProviders.Count == 1)
+ {
+ IDisposable block = _performanceMarkerBlockProviders[0].Value?.CreateBlock(blockName);
+ if (block != null)
+ {
+ return block;
+ }
+ }
+
+ var providedBlocks = new FrugalList<IDisposable>();
+ for (int i = 0; i < _performanceMarkerBlockProviders.Count; i++)
+ {
+ providedBlocks.Add(_performanceMarkerBlockProviders[i].Value?.CreateBlock(blockName));
+ }
+
+ return new Block(providedBlocks);
+ }
+
+ private class Block : IDisposable
+ {
+ private readonly FrugalList<IDisposable> _markers;
+
+ public Block(FrugalList<IDisposable> markers)
+ {
+ _markers = markers;
+ }
+
+ public Block()
+ {
+ }
+
+ public void Dispose()
+ {
+ if (_markers == null)
+ {
+ return;
+ }
+
+ foreach (var marker in _markers)
+ {
+ marker?.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/StatusBarService.cs b/src/Editor/Text/Util/TextUIUtil/StatusBarService.cs
new file mode 100644
index 0000000..77b6b23
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/StatusBarService.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Utilities;
+
+namespace Microsoft.VisualStudio.Text.UI.Utilities
+{
+ [Export(typeof(IStatusBarService))]
+ internal class StatusBarService : BaseProxyService<IStatusBarService>, IStatusBarService
+ {
+ [ImportImplementations(typeof(IStatusBarService))]
+ protected override IEnumerable<Lazy<IStatusBarService, IOrderable>> UnorderedImplementations { get; set; }
+
+ public Task SetTextAsync(string text)
+ {
+ return BestImplementation.SetTextAsync(text);
+ }
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/Strings.Designer.cs b/src/Editor/Text/Util/TextUIUtil/Strings.Designer.cs
new file mode 100644
index 0000000..938895a
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/Strings.Designer.cs
@@ -0,0 +1,279 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.0
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Microsoft.VisualStudio.Text.Utilities {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ public class Strings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Strings() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.VisualStudio.Text.UI.Utilities.Strings", typeof(Strings).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to backslash.
+ /// </summary>
+ public static string Backslash {
+ get {
+ return ResourceManager.GetString("Backslash", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to capital.
+ /// </summary>
+ public static string Capital {
+ get {
+ return ResourceManager.GetString("Capital", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to We don&apos;t support child elements in Text yet..
+ /// </summary>
+ public static string ChildElementsNotSupported {
+ get {
+ return ResourceManager.GetString("ChildElementsNotSupported", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to colon.
+ /// </summary>
+ public static string Colon {
+ get {
+ return ResourceManager.GetString("Colon", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to comma.
+ /// </summary>
+ public static string Comma {
+ get {
+ return ResourceManager.GetString("Comma", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to double quote.
+ /// </summary>
+ public static string DoubleQuote {
+ get {
+ return ResourceManager.GetString("DoubleQuote", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to empty line.
+ /// </summary>
+ public static string EmptyLine {
+ get {
+ return ResourceManager.GetString("EmptyLine", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The Visual Studio text editor only supports movements by word, character, document and line..
+ /// </summary>
+ public static string InvalidTextMovementUnit {
+ get {
+ return ResourceManager.GetString("InvalidTextMovementUnit", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to left angled bracket.
+ /// </summary>
+ public static string LeftAngledBracket {
+ get {
+ return ResourceManager.GetString("LeftAngledBracket", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to left curly brace.
+ /// </summary>
+ public static string LeftCurlyBrace {
+ get {
+ return ResourceManager.GetString("LeftCurlyBrace", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to left parenthesis.
+ /// </summary>
+ public static string LeftParenthesis {
+ get {
+ return ResourceManager.GetString("LeftParenthesis", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to left square bracket.
+ /// </summary>
+ public static string LeftSquareBracket {
+ get {
+ return ResourceManager.GetString("LeftSquareBracket", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to period.
+ /// </summary>
+ public static string Period {
+ get {
+ return ResourceManager.GetString("Period", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to question mark.
+ /// </summary>
+ public static string QuestionMark {
+ get {
+ return ResourceManager.GetString("QuestionMark", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Supplied range is not valid..
+ /// </summary>
+ public static string RangeNotValid {
+ get {
+ return ResourceManager.GetString("RangeNotValid", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to right angled bracket.
+ /// </summary>
+ public static string RightAngledBracket {
+ get {
+ return ResourceManager.GetString("RightAngledBracket", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to right curly brace.
+ /// </summary>
+ public static string RightCurlyBrace {
+ get {
+ return ResourceManager.GetString("RightCurlyBrace", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to right parenthesis.
+ /// </summary>
+ public static string RightParenthesis {
+ get {
+ return ResourceManager.GetString("RightParenthesis", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to right square bracket.
+ /// </summary>
+ public static string RightSquareBracket {
+ get {
+ return ResourceManager.GetString("RightSquareBracket", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to semicolon.
+ /// </summary>
+ public static string Semicolon {
+ get {
+ return ResourceManager.GetString("Semicolon", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to single quote.
+ /// </summary>
+ public static string SingleQuote {
+ get {
+ return ResourceManager.GetString("SingleQuote", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to slash.
+ /// </summary>
+ public static string Slash {
+ get {
+ return ResourceManager.GetString("Slash", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Supplied target range is not valid..
+ /// </summary>
+ public static string TargetRangeNotValid {
+ get {
+ return ResourceManager.GetString("TargetRangeNotValid", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The Visual Studio text editor does not support search based on text formatting attributes..
+ /// </summary>
+ public static string UnsupportedSearchBasedOnTextFormatted {
+ get {
+ return ResourceManager.GetString("UnsupportedSearchBasedOnTextFormatted", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/Strings.resx b/src/Editor/Text/Util/TextUIUtil/Strings.resx
new file mode 100644
index 0000000..1811dbb
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/Strings.resx
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="Backslash" xml:space="preserve">
+ <value>backslash</value>
+ <comment>Used to represent \ in code for accessibility readers</comment>
+ </data>
+ <data name="Capital" xml:space="preserve">
+ <value>capital</value>
+ <comment>Used to signify an upper case letter, e.g. C as capital c, used for accessibility readers</comment>
+ </data>
+ <data name="ChildElementsNotSupported" xml:space="preserve">
+ <value>We don't support child elements in Text yet.</value>
+ </data>
+ <data name="Colon" xml:space="preserve">
+ <value>colon</value>
+ <comment>Used to represent : in code for accessibility readers</comment>
+ </data>
+ <data name="Comma" xml:space="preserve">
+ <value>comma</value>
+ <comment>Used to represent , in code for accessibility readers</comment>
+ </data>
+ <data name="DoubleQuote" xml:space="preserve">
+ <value>double quote</value>
+ <comment>Used to represent " in code for accessibility readers</comment>
+ </data>
+ <data name="EmptyLine" xml:space="preserve">
+ <value>empty line</value>
+ <comment>Used for screen readers to read "empty line" when the line is empty or contains white spaces only</comment>
+ </data>
+ <data name="InvalidTextMovementUnit" xml:space="preserve">
+ <value>The Visual Studio text editor only supports movements by word, character, document and line.</value>
+ <comment>Error message shown to the user when they try to move the caret by a text unit other than word, line, document or character using automation clients.</comment>
+ </data>
+ <data name="LeftAngledBracket" xml:space="preserve">
+ <value>left angled bracket</value>
+ <comment>Used to represent &lt; in code for accessibility readers</comment>
+ </data>
+ <data name="LeftCurlyBrace" xml:space="preserve">
+ <value>left curly brace</value>
+ <comment>Used to represent { in code for accessibility readers</comment>
+ </data>
+ <data name="LeftParenthesis" xml:space="preserve">
+ <value>left parenthesis</value>
+ <comment>Used to represent ( in code for accessibility readers</comment>
+ </data>
+ <data name="LeftSquareBracket" xml:space="preserve">
+ <value>left square bracket</value>
+ <comment>Used to represent [ in code for accessibility readers</comment>
+ </data>
+ <data name="Period" xml:space="preserve">
+ <value>dot</value>
+ <comment>Used to represent . in code for accessibility readers</comment>
+ </data>
+ <data name="QuestionMark" xml:space="preserve">
+ <value>question mark</value>
+ <comment>Used to represent ? in code for accessibility readers</comment>
+ </data>
+ <data name="RangeNotValid" xml:space="preserve">
+ <value>Supplied range is not valid.</value>
+ </data>
+ <data name="RightAngledBracket" xml:space="preserve">
+ <value>right angled bracket</value>
+ <comment>Used to represent &gt; in code for accessibility readers</comment>
+ </data>
+ <data name="RightCurlyBrace" xml:space="preserve">
+ <value>right curly brace</value>
+ <comment>Used to represent } in code for accessibility readers</comment>
+ </data>
+ <data name="RightParenthesis" xml:space="preserve">
+ <value>right parenthesis</value>
+ <comment>Used to represent ) in code for accessibility readers</comment>
+ </data>
+ <data name="RightSquareBracket" xml:space="preserve">
+ <value>right square bracket</value>
+ <comment>Used to represent ] in code for accessibility readers</comment>
+ </data>
+ <data name="Semicolon" xml:space="preserve">
+ <value>semicolon</value>
+ <comment>Used to represent ; in code for accessibility readers</comment>
+ </data>
+ <data name="SingleQuote" xml:space="preserve">
+ <value>single quote</value>
+ <comment>Used to represent ' in code for accessibility readers</comment>
+ </data>
+ <data name="Slash" xml:space="preserve">
+ <value>slash</value>
+ <comment>Used to represent / in code for accessibility readers</comment>
+ </data>
+ <data name="TargetRangeNotValid" xml:space="preserve">
+ <value>Supplied target range is not valid.</value>
+ </data>
+ <data name="UnsupportedSearchBasedOnTextFormatted" xml:space="preserve">
+ <value>The Visual Studio text editor does not support search based on text formatting attributes.</value>
+ <comment>Error message shown to the user when they try to search for some text based on its formatting attributes through an automation client.</comment>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/Editor/Text/Util/TextUIUtil/TelemetryLogger.cs b/src/Editor/Text/Util/TextUIUtil/TelemetryLogger.cs
new file mode 100644
index 0000000..55871e4
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/TelemetryLogger.cs
@@ -0,0 +1,126 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+using System;
+using System.ComponentModel.Composition;
+using System.Windows.Threading;
+
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ [Export]
+ [PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class TelemetryLogger
+ {
+ // This import may fail if we are running outside of VS, in scenarios such as CodeFlow. That is ok
+ // and this logging code should gracefully no-op in that case.
+ [Import(AllowDefault = true)]
+ private ILoggingServiceInternal LoggingService { get; set; }
+
+ public const string VSEditorKey = "VS/Editor";
+
+ DispatcherTimer _touchZoomTimer = null;
+ DispatcherTimer _touchScrollTimer = null;
+ DispatcherTimer _zoomTimer = null;
+ DispatcherTimer _scrollTimer = null;
+
+ uint _lastZoomLevel = 0;
+ readonly TimeSpan _timeout = TimeSpan.FromMilliseconds(1000.0);
+
+ public void LogTouchZoom()
+ {
+ if (LoggingService != null)
+ {
+ if (_touchZoomTimer == null)
+ {
+ _touchZoomTimer = new DispatcherTimer();
+ _touchZoomTimer.Interval = _timeout;
+ _touchZoomTimer.Tick += (s, e) =>
+ {
+ _touchZoomTimer.Stop();
+ LoggingService.AdjustCounter(TelemetryLogger.VSEditorKey, "TouchZoom", delta: 1);
+ };
+ }
+
+ // Restart timer
+ _touchZoomTimer.Stop();
+ _touchZoomTimer.Start();
+ }
+ }
+
+ public void LogZoom(uint finalZoomLevel)
+ {
+ if (LoggingService != null)
+ {
+ if (_zoomTimer == null)
+ {
+ _zoomTimer = new DispatcherTimer();
+ _zoomTimer.Interval = _timeout;
+ _zoomTimer.Tick += (s, e) =>
+ {
+ _zoomTimer.Stop();
+ LoggingService.PostEvent("VS/Editor/Zoom", "VS.Editor.Zoom.LastZoomLevel", _lastZoomLevel);
+ };
+ }
+
+ // Restart timer
+ _zoomTimer.Stop();
+
+ // Set _lastZoomLevel between stop and start out of paranoia regarding race conditions that shouldn't
+ // actually occur while using DispatcherTimer, since it runs all on the same thread. However, if the
+ // underlying timer get's changed, and this set were above the stop, there's a chance that we could
+ // occasionally log incorrect data if the set happened, and then tick occurred before the stop.
+ _lastZoomLevel = finalZoomLevel;
+
+ _zoomTimer.Start();
+ }
+ }
+
+ public void LogTouchScroll()
+ {
+ if (LoggingService != null)
+ {
+ if (_touchScrollTimer == null)
+ {
+ _touchScrollTimer = new DispatcherTimer();
+ _touchScrollTimer.Interval = _timeout;
+ _touchScrollTimer.Tick += (s, e) =>
+ {
+ _touchScrollTimer.Stop();
+ LoggingService.AdjustCounter(TelemetryLogger.VSEditorKey, "TouchScroll", delta: 1);
+ };
+ }
+
+ // Restart timer
+ _touchScrollTimer.Stop();
+ _touchScrollTimer.Start();
+ }
+ }
+
+ public void LogScroll()
+ {
+ if (LoggingService != null)
+ {
+ if (_scrollTimer == null)
+ {
+ _scrollTimer = new DispatcherTimer();
+ _scrollTimer.Interval = _timeout;
+ _scrollTimer.Tick += (s, e) =>
+ {
+ _scrollTimer.Stop();
+ LoggingService.AdjustCounter(TelemetryLogger.VSEditorKey, "Scroll", delta: 1);
+ };
+ }
+
+ // Restart timer
+ _scrollTimer.Stop();
+ _scrollTimer.Start();
+ }
+ }
+
+ public void PostCounters()
+ {
+ LoggingService.PostCounters();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Editor/Text/Util/TextUIUtil/TextUIUtil.csproj b/src/Editor/Text/Util/TextUIUtil/TextUIUtil.csproj
new file mode 100644
index 0000000..91594fb
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/TextUIUtil.csproj
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <AssemblyName>Microsoft.VisualStudio.Text.UI.Utilities</AssemblyName>
+ <RootNamespace>$(AssemblyName)</RootNamespace>
+ <NoWarn>649;436;618;8073;$(NoWarn)</NoWarn>
+ <AssemblyAttributeClsCompliant>true</AssemblyAttributeClsCompliant>
+ <TargetFramework>$(TargetFramework)</TargetFramework>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.Composition" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Runtime" />
+ <Reference Include="UIAutomationClient" />
+ <Reference Include="UIAutomationProvider" />
+ <Reference Include="UIAutomationTypes" />
+ <Reference Include="System.Xaml" />
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="System.Collections.Immutable" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Core\Def\CoreUtility.csproj" />
+ <ProjectReference Include="..\..\Def\TextData\TextData.csproj" />
+ <ProjectReference Include="..\..\Def\TextLogic\TextLogic.csproj" />
+ <ProjectReference Include="..\..\Def\TextUI\TextUI.csproj" />
+ <ProjectReference Include="..\..\Def\TextUIWpf\TextUIWpf.csproj" />
+ <ProjectReference Include="..\..\Def\Internal\Internal.csproj" />
+ <ProjectReference Include="..\..\Util\TextDataUtil\TextDataUtil.csproj" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Update="Strings.resx">
+ <Generator>PublicResXFileCodeGenerator</Generator>
+ <LastGenOutput>Strings.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Update="Strings.Designer.cs">
+ <DesignTime>true</DesignTime>
+ <AutoGen>true</AutoGen>
+ <DependentUpon>Strings.resx</DependentUpon>
+ </Compile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/Editor/Text/Util/TextUIUtil/TransformedDispatcherCollection.cs b/src/Editor/Text/Util/TextUIUtil/TransformedDispatcherCollection.cs
new file mode 100644
index 0000000..e6cebc6
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/TransformedDispatcherCollection.cs
@@ -0,0 +1,268 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ internal class TransformedDispatcherCollection<TSourceCollection, TSourceElement, TTargetElement> : ReadOnlyCollection<TTargetElement>, INotifyCollectionChanged, INotifyPropertyChanged, IWeakEventListener, IDisposable
+ where TSourceCollection : class, IEnumerable<TSourceElement>, INotifyCollectionChanged
+ {
+ #region Fields
+ private readonly Dispatcher dispatcher;
+ private readonly TSourceCollection sourceCollection;
+ private readonly Func<TSourceElement, TTargetElement> setup;
+ private readonly Action<TTargetElement> teardown;
+ private bool disposed;
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Creates a new transformed collection wrapping a source collection.
+ /// </summary>
+ /// <param name="sourceCollection">The source collection that this collection wraps.</param>
+ /// <param name="setup">The logic for creating a transformed element from a source element.</param>
+ /// <param name="teardown">The logic for destroying a transformed element when removed from the transformed collection.</param>
+ public TransformedDispatcherCollection(Dispatcher dispatcher, TSourceCollection sourceCollection, Func<TSourceElement, TTargetElement> setup, Action<TTargetElement> teardown = null) :
+ base(new List<TTargetElement>(sourceCollection.Select(setup)))
+ {
+ ArgumentValidation.NotNull(dispatcher, "dispatcher");
+ ArgumentValidation.NotNull(sourceCollection, "sourceCollection");
+ ArgumentValidation.NotNull(setup, "setup");
+
+ this.setup = setup;
+ this.teardown = teardown;
+
+ this.dispatcher = dispatcher;
+ this.sourceCollection = sourceCollection;
+ CollectionChangedEventManager.AddListener(this.sourceCollection, this);
+ }
+ #endregion
+
+ #region Events
+ /// <summary>
+ /// Occurs when the collection changes.
+ /// </summary>
+ public event NotifyCollectionChangedEventHandler CollectionChanged;
+
+ /// <summary>
+ /// Occurs when a property changes.
+ /// </summary>
+ public event PropertyChangedEventHandler PropertyChanged;
+ #endregion
+
+ #region Public Methods
+ /// <summary>
+ /// Tears down all elements of the transformed collection, clears the transformed collection, and stops listening to change events on the source collection.
+ /// </summary>
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
+ {
+ if (!this.ReceiveWeakEvent(managerType, sender, e))
+ {
+ Debug.Fail("Weak event was not handled");
+ return false;
+ }
+
+ return true;
+ }
+ #endregion
+
+ #region Protected Methods
+ protected TSourceCollection SourceCollection
+ {
+ get
+ {
+ return this.sourceCollection;
+ }
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!this.disposed)
+ {
+ if (disposing)
+ {
+ // Cleanup managed resources
+ CollectionChangedEventManager.RemoveListener(this.sourceCollection, this);
+
+ if (this.teardown != null)
+ {
+ foreach (var target in this.Items)
+ {
+ this.teardown(target);
+ }
+ }
+
+ this.Items.Clear();
+ }
+
+ // Cleanup unmanaged resources
+
+ // Mark the object as disposed
+ this.disposed = true;
+ }
+ }
+
+ protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
+ {
+ if (this.CollectionChanged != null)
+ {
+ this.CollectionChanged(this, e);
+ }
+ }
+
+ protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
+ {
+ if (this.PropertyChanged != null)
+ {
+ this.PropertyChanged(this, e);
+ }
+ }
+
+ protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
+ {
+ if (object.ReferenceEquals(sender, this.sourceCollection))
+ {
+ var collectionChangedEventArgs = e as NotifyCollectionChangedEventArgs;
+ if (collectionChangedEventArgs != null)
+ {
+ this.OnSourceCollectionChanged(sender, collectionChangedEventArgs);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ #endregion
+
+ #region Private Methods
+
+ private async void OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ TSourceElement[] snapshot = null;
+ if (e.Action == NotifyCollectionChangedAction.Reset)
+ {
+ snapshot = this.sourceCollection.ToArray();
+ }
+
+ await CheckAccessInvokeAsync(() => UpdateCollectionOnDispatcherThread(e, snapshot)).ConfigureAwait(false);
+ }
+
+ private void UpdateCollectionOnDispatcherThread(NotifyCollectionChangedEventArgs e, TSourceElement[] newElementsSnapshot)
+ {
+ NotifyCollectionChangedEventArgs collectionChangedEventArgs = null;
+
+ if (e.Action == NotifyCollectionChangedAction.Reset)
+ {
+ if (this.teardown != null)
+ {
+ foreach (var target in this.Items)
+ {
+ this.teardown(target);
+ }
+ }
+
+ this.Items.Clear();
+
+ foreach (var source in newElementsSnapshot)
+ {
+ this.Items.Add(this.setup(source));
+ }
+
+ collectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
+ }
+ else
+ {
+ List<object> oldItems = null;
+ if (e.OldItems != null)
+ {
+ oldItems = new List<object>();
+ for (int i = 0; i < e.OldItems.Count; i++)
+ {
+ TTargetElement target = this.Items[e.OldStartingIndex];
+ oldItems.Add(target);
+
+ if (this.teardown != null)
+ {
+ this.teardown(target);
+ }
+
+ this.Items.RemoveAt(e.OldStartingIndex);
+ }
+ }
+
+ List<object> newItems = null;
+ if (e.NewItems != null)
+ {
+ newItems = new List<object>();
+ for (int i = 0; i < e.NewItems.Count; i++)
+ {
+ TTargetElement target = this.setup((TSourceElement)e.NewItems[i]);
+ newItems.Add(target);
+ this.Items.Insert(i + e.NewStartingIndex, target);
+ }
+ }
+
+ if (e.Action == NotifyCollectionChangedAction.Remove)
+ {
+ collectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItems, e.OldStartingIndex);
+ }
+ else if (e.Action == NotifyCollectionChangedAction.Add)
+ {
+ collectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItems, e.NewStartingIndex);
+ }
+ else if (e.Action == NotifyCollectionChangedAction.Move)
+ {
+ collectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, newItems, e.NewStartingIndex, e.OldStartingIndex);
+ }
+ else if (e.Action == NotifyCollectionChangedAction.Replace)
+ {
+ collectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItems, oldItems, e.NewStartingIndex);
+ }
+ }
+
+ this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
+ this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
+
+ this.OnCollectionChanged(collectionChangedEventArgs);
+ }
+
+ /// <summary>
+ /// Executes the specified action on a thread associated with object's dispatcher.
+ /// This invokes a InvokeAsync on the Dispatcher, does not wait for the action
+ /// to complete -- returns immediately.
+ /// </summary>
+ /// <param name="action">An action to execute.</param>
+ /// <returns>A task that completes when action has completed.</returns>
+ private async Task CheckAccessInvokeAsync(Action action)
+ {
+ ArgumentValidation.NotNull(action, "action");
+
+ if (this.dispatcher.CheckAccess())
+ {
+ action();
+ }
+ else
+ {
+ await this.dispatcher.InvokeAsync(action, DispatcherPriority.Normal);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/UIExtensionSelector.cs b/src/Editor/Text/Util/TextUIUtil/UIExtensionSelector.cs
index 124c4e8..db336d1 100644
--- a/src/Editor/Text/Util/TextUIUtil/UIExtensionSelector.cs
+++ b/src/Editor/Text/Util/TextUIUtil/UIExtensionSelector.cs
@@ -12,7 +12,7 @@ namespace Microsoft.VisualStudio.Text.Utilities
/// <summary>
/// Helper class to perform ContentType and TextViewRole match against a set of extensions.
/// </summary>
- public static class UIExtensionSelector
+ internal static class UIExtensionSelector
{
/// <summary>
/// Given a list of extensions that provide text view roles, filter the list and return that
@@ -70,7 +70,7 @@ namespace Microsoft.VisualStudio.Text.Utilities
ITextViewRoleSet viewRoles,
Func<TExtensionFactory, TExtensionInstance> getter,
IContentTypeRegistryService contentTypeRegistryService,
- GuardedOperations guardedOperations,
+ IGuardedOperations guardedOperations,
object errorSource)
where TMetadataView : IContentTypeAndTextViewRoleMetadata // both content type and text view role are required
where TExtensionFactory : class
diff --git a/src/Editor/Text/Util/TextUIUtil/UIThreadOperationExecutor.cs b/src/Editor/Text/Util/TextUIUtil/UIThreadOperationExecutor.cs
index 592c814..3e068fd 100644
--- a/src/Editor/Text/Util/TextUIUtil/UIThreadOperationExecutor.cs
+++ b/src/Editor/Text/Util/TextUIUtil/UIThreadOperationExecutor.cs
@@ -31,4 +31,4 @@ namespace Microsoft.VisualStudio.Text.Utilities
return BestImplementation.Execute(executionOptions, action);
}
}
-} \ No newline at end of file
+}
diff --git a/src/Editor/Text/Util/TextUIUtil/VacuousTextViewModel.cs b/src/Editor/Text/Util/TextUIUtil/VacuousTextViewModel.cs
index baf84fa..f7ea58e 100644
--- a/src/Editor/Text/Util/TextUIUtil/VacuousTextViewModel.cs
+++ b/src/Editor/Text/Util/TextUIUtil/VacuousTextViewModel.cs
@@ -14,7 +14,7 @@ namespace Microsoft.VisualStudio.Text.Utilities
/// is the same as the edit buffer, which is in turn the same as the data buffer if no edit buffer is specified.
/// This is the default if no view model provider is specified or if the specified one declines to build a model.
/// </summary>
- public class VacuousTextViewModel : ITextViewModel
+ internal class VacuousTextViewModel : ITextViewModel
{
private ITextDataModel dataModel;
private ITextBuffer editBuffer;
diff --git a/src/Editor/Text/Util/TextUIUtil/WpfHelper.cs b/src/Editor/Text/Util/TextUIUtil/WpfHelper.cs
new file mode 100644
index 0000000..65219ac
--- /dev/null
+++ b/src/Editor/Text/Util/TextUIUtil/WpfHelper.cs
@@ -0,0 +1,853 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+//
+#pragma warning disable 1634, 1691
+
+namespace Microsoft.VisualStudio.Text.Utilities
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Runtime.InteropServices;
+ using System.Security;
+ using System.Text;
+ using System.Windows;
+ using System.Windows.Input;
+ using System.Windows.Interop;
+ using System.Windows.Media;
+
+ /// <summary>
+ /// Helpful utilities related to WPF and the windows platform, including input method editor support.
+ /// </summary>
+ public static class WpfHelper
+ {
+ public const int WM_IME_STARTCOMPOSITION = 0x010D;
+ public const int WM_IME_ENDCOMPOSITION = 0x010E;
+ public const int WM_IME_COMPOSITION = 0x010F;
+ public const int WM_IME_SETCONTEXT = 0x0281;
+ public const int WM_IME_NOTIFY = 0x0282;
+ public const int WM_IME_CONTROL = 0x0283;
+ public const int WM_IME_COMPOSITIONFULL = 0x0284;
+ public const int WM_IME_SELECT = 0x0285;
+ public const int WM_IME_CHAR = 0x0286;
+ public const int WM_IME_REQUEST = 0x0288;
+ public const int WM_IME_KEYDOWN = 0x0290;
+
+ public const int WM_KEYDOWN = 0x0100;
+
+ public const int GCS_COMPSTR = 0x0008;
+ public const int GCS_RESULTSTR = 0x0800;
+
+ public const int VK_HANJA = 0x19;
+
+ public const int IMR_RECONVERTSTRING = 0x0004;
+ public const int IMR_CONFIRMRECONVERTSTRING = 0x0005;
+
+ public const int LCID_KOREAN = 1042;
+
+ [ThreadStatic] //Unit tests run each test in its own thread and we can't reused thread managers across threads.
+ static NativeMethods.ITfThreadMgr _threadMgr;
+
+ [ThreadStatic]
+ static bool _threadMgrFailed = false;
+
+ public static readonly double DeviceScaleX;
+ public static readonly double DeviceScaleY;
+
+#pragma warning disable CA1810 // Initialize reference type static fields inline
+ static WpfHelper()
+#pragma warning restore CA1810 // Initialize reference type static fields inline
+ {
+ //Get the device DPI (which can only be changed via a restart so we
+ //can save the result in a static).
+ IntPtr dc = NativeMethods.GetDC(IntPtr.Zero);
+ if (dc != IntPtr.Zero)
+ {
+ const double LogicalDpi = 96.0;
+ DeviceScaleX = LogicalDpi / NativeMethods.GetDeviceCaps(dc, NativeMethods.LOGPIXELSX);
+ DeviceScaleY = LogicalDpi / NativeMethods.GetDeviceCaps(dc, NativeMethods.LOGPIXELSY);
+
+ NativeMethods.ReleaseDC(IntPtr.Zero, dc);
+ }
+ else
+ {
+ DeviceScaleX = 1.0;
+ DeviceScaleY = 1.0;
+ }
+ }
+
+#if false
+ /// <summary>
+ /// Given a point relative to a visual, gets the Screen co-ordinates
+ /// </summary>
+ public static Point GetScreenCoordinates(Point point, Visual relativeTo)
+ {
+ // Validate
+ if (relativeTo == null)
+ throw new ArgumentNullException("relativeTo");
+
+ Visual root = GetRootVisual(relativeTo);
+ Point rootTranslatedPoint = relativeTo.TransformToAncestor(root).Transform(point);
+
+ // Get the Hwnd for this visual
+ HwndSource hwndSource = GetHwndSource(relativeTo);
+ if (hwndSource != null)
+ {
+ NativeMethods.POINT pt = new NativeMethods.POINT();
+ pt.x = (int)rootTranslatedPoint.X;
+ pt.y = (int)rootTranslatedPoint.Y;
+ NativeMethods.ClientToScreen(hwndSource.Handle, ref pt);
+ return new Point(pt.x, pt.y);
+ }
+
+ return rootTranslatedPoint;
+ }
+
+ /// <summary>
+ /// Gets the screen rectangle that contains the point relative to the given visual
+ /// </summary>
+ public static Rect GetScreenRect(Point pt, Visual relativeTo)
+ {
+ // Validate
+ if (relativeTo == null)
+ throw new ArgumentNullException("relativeTo");
+
+ Point screenCoordinates = GetScreenCoordinates(pt, relativeTo);
+ NativeMethods.POINT screenPoint = new NativeMethods.POINT();
+ screenPoint.x = (int)screenCoordinates.X;
+ screenPoint.y = (int)screenCoordinates.Y;
+ IntPtr monitor = NativeMethods.MonitorFromPoint(screenPoint, NativeMethods.MONITOR_DEFAULTTONEAREST);
+
+ NativeMethods.MONITORINFO monitorInfo = new NativeMethods.MONITORINFO();
+ monitorInfo.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(monitorInfo);
+ if (NativeMethods.GetMonitorInfo(monitor, ref monitorInfo))
+ return new Rect(new Point(monitorInfo.rcWork.left, monitorInfo.rcWork.top), new Point(monitorInfo.rcWork.right, monitorInfo.rcWork.bottom));
+ else
+ return SystemParameters.WorkArea;
+ }
+#endif
+ /// <summary>
+ /// Gets the screen rectangle that contains given screen point.
+ /// </summary>
+ public static Rect GetScreenRect(Point screenCoordinates)
+ {
+ NativeMethods.POINT screenPoint = new NativeMethods.POINT();
+ screenPoint.x = (int)screenCoordinates.X;
+ screenPoint.y = (int)screenCoordinates.Y;
+ IntPtr monitor = NativeMethods.MonitorFromPoint(screenPoint, NativeMethods.MONITOR_DEFAULTTONEAREST);
+
+ NativeMethods.MONITORINFO monitorInfo = new NativeMethods.MONITORINFO();
+ monitorInfo.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(monitorInfo);
+ if (NativeMethods.GetMonitorInfo(monitor, ref monitorInfo))
+ return new Rect(new Point(monitorInfo.rcWork.left, monitorInfo.rcWork.top), new Point(monitorInfo.rcWork.right, monitorInfo.rcWork.bottom));
+ else
+ return SystemParameters.WorkArea;
+ }
+
+ /// <summary>
+ /// Determine whether two brushes are equal.
+ /// </summary>
+ /// <param name="brush">The first brush.</param>
+ /// <param name="other">The second brush.</param>
+ /// <returns><c>true</c> if the two are equal, <c>false</c> otherwise.</returns>
+ /// <remarks>internal for testability</remarks>
+ public static bool BrushesEqual(Brush brush, Brush other)
+ {
+ if (brush == null || other == null)
+ {
+ return object.ReferenceEquals(brush, other);
+ }
+ else
+ {
+ if (brush.Opacity == 0 && other.Opacity == 0)
+ return true;
+
+ SolidColorBrush colorBrush1 = brush as SolidColorBrush;
+ SolidColorBrush colorBrush2 = other as SolidColorBrush;
+
+ // If both brushes are SolidColorBrushes check the color of each
+ if (colorBrush1 != null && colorBrush2 != null)
+ {
+ if (colorBrush1.Color.A == 0 && colorBrush2.Color.A == 0)
+ return true;
+
+ return colorBrush1.Color == colorBrush2.Color &&
+ Math.Abs(colorBrush1.Opacity - colorBrush2.Opacity) < 0.01;
+ }
+
+ // as a last resort try brush.Equals (which pretty much is the equivalent of returning false here since
+ // it doesn't compare any of the core properties of brushes)
+ return brush.Equals(other);
+ }
+ }
+
+ public static string GetImmCompositionString(IntPtr immContext, int dwIndex)
+ {
+ if (immContext == IntPtr.Zero)
+ return null;
+
+ // get buffer size
+ int size = NativeMethods.ImmGetCompositionStringW(immContext, dwIndex, null, 0);
+ if (size <= 0)
+ {
+ //If there is no composition string we return
+ return null;
+ }
+
+ //Get the string in an appropriately sized buffer
+ StringBuilder result = new StringBuilder(size / 2); //We get the size in bytes.
+ size = NativeMethods.ImmGetCompositionStringW(immContext, dwIndex, result, size);
+ if (size <= 0)
+ {
+ Debug.Assert(false); //This should never happen? why did we succeed the first time?
+
+ //But handle it gracefully.
+ return null;
+ }
+
+ return result.ToString().Substring(0, size / 2);
+ }
+
+ public static bool ImmNotifyIME(IntPtr immContext, int dwAction, int dwIndex, int dwValue)
+ {
+ return NativeMethods.ImmNotifyIME(immContext, dwAction, dwIndex, dwValue);
+ }
+
+ public static bool HanjaConversion(IntPtr context, IntPtr keyboardLayout, char selection)
+ {
+ const int IME_ESC_HANJA_MODE = 0x1008;
+
+ if (context != IntPtr.Zero)
+ {
+ IntPtr charsPtr = Marshal.StringToHGlobalUni(new string(selection, 1));
+
+ IntPtr hr = NativeMethods.ImmEscapeW(keyboardLayout, context, IME_ESC_HANJA_MODE, charsPtr);
+
+ // Free the allocated memory
+ Marshal.FreeHGlobal(charsPtr);
+
+ if (hr != IntPtr.Zero)
+ return true;
+ }
+
+ return false;
+ }
+
+ private static SnapshotSpan GetSelectionContext(SnapshotSpan selection)
+ {
+ const int padding = 20; //Consistent with Win7 code.
+ SnapshotPoint start = new SnapshotPoint(selection.Snapshot,
+ Math.Max(0, selection.Start.Position - padding));
+ SnapshotPoint end = new SnapshotPoint(selection.Snapshot,
+ Math.Min(selection.Snapshot.Length, selection.End.Position + padding));
+ return new SnapshotSpan(start, end);
+
+ }
+
+ /// <summary>
+ /// Size or fill-in a RECONVERTSTRING structure that contains the selection (with padding)
+ /// </summary>
+ public static IntPtr ReconvertString(IntPtr lParam, SnapshotSpan selection)
+ {
+ SnapshotSpan selectionContext = GetSelectionContext(selection);
+ int sizeofRCS = Marshal.SizeOf(typeof(NativeMethods.RECONVERTSTRING));
+
+ if (lParam != IntPtr.Zero)
+ {
+ NativeMethods.RECONVERTSTRING reconvertString = (NativeMethods.RECONVERTSTRING)(Marshal.PtrToStructure(lParam, typeof(NativeMethods.RECONVERTSTRING)));
+
+ if (selection.Length >= ((reconvertString.dwSize - sizeofRCS) / 2))
+ {
+ //We didn't get space for all the characters we requested.
+ return IntPtr.Zero;
+ }
+
+ Marshal.WriteInt32((IntPtr)((long)lParam + (long)Marshal.OffsetOf(typeof(NativeMethods.RECONVERTSTRING), "dwStrLen")), selectionContext.Length);
+ Marshal.WriteInt32((IntPtr)((long)lParam + (long)Marshal.OffsetOf(typeof(NativeMethods.RECONVERTSTRING), "dwStrOffset")), sizeofRCS);
+
+ Marshal.WriteInt32((IntPtr)((long)lParam + (long)Marshal.OffsetOf(typeof(NativeMethods.RECONVERTSTRING), "dwCompStrLen")), selection.Length);
+ Marshal.WriteInt32((IntPtr)((long)lParam + (long)Marshal.OffsetOf(typeof(NativeMethods.RECONVERTSTRING), "dwCompStrOffset")), (selection.Start.Position - selectionContext.Start.Position) * 2);
+
+ Marshal.WriteInt32((IntPtr)((long)lParam + (long)Marshal.OffsetOf(typeof(NativeMethods.RECONVERTSTRING), "dwTargetStrLen")), selection.Length);
+ Marshal.WriteInt32((IntPtr)((long)lParam + (long)Marshal.OffsetOf(typeof(NativeMethods.RECONVERTSTRING), "dwTargetStrOffset")), (selection.Start.Position - selectionContext.Start.Position) * 2);
+
+ Marshal.Copy(selection.Snapshot.GetText(selectionContext).ToCharArray(), 0, (IntPtr)((long)lParam + (long)sizeofRCS), selectionContext.Length);
+ Marshal.WriteInt16((IntPtr)((long)lParam + (long)(sizeofRCS + (selectionContext.Length * 2))), 0);
+ }
+
+ return new IntPtr(sizeofRCS + ((selectionContext.Length + 1) * 2));
+ }
+
+ /// <summary>
+ /// Generate a selection from a RECONVERTSTRING block.
+ /// </summary>
+ public static SnapshotSpan ConfirmReconvertString(IntPtr lParam, SnapshotSpan selection)
+ {
+ if (lParam != IntPtr.Zero)
+ {
+ SnapshotSpan selectionContext = GetSelectionContext(selection);
+
+ NativeMethods.RECONVERTSTRING reconvertString = (NativeMethods.RECONVERTSTRING)(Marshal.PtrToStructure(lParam, typeof(NativeMethods.RECONVERTSTRING)));
+
+ return new SnapshotSpan(selectionContext.Start + (reconvertString.dwCompStrOffset / 2), reconvertString.dwCompStrLen);
+ }
+
+ return new SnapshotSpan(selection.Snapshot, 0, 0);
+ }
+
+ private static class CompositionFontMapper
+ {
+ private static IDictionary<int, LanguageFontMapping> _languageMap = new Dictionary<int, LanguageFontMapping>(9);
+ private static IDictionary<string, FontSizeMapping> _fontMap = new Dictionary<string, FontSizeMapping>(25);
+ private static IDictionary<string, FontSizeMapping> _consolasFontMap = new Dictionary<string, FontSizeMapping>(6);
+ private static IDictionary<string, FontSizeMapping> _courierNewFontMap = new Dictionary<string, FontSizeMapping>(6);
+
+ static CompositionFontMapper()
+ {
+ LanguageFontMapping simplifiedChinese = new LanguageFontMapping("SimSun", "Microsoft YaHei");
+ LanguageFontMapping traditionalChinese = new LanguageFontMapping("MingLiU", "Microsoft JhengHei");
+ LanguageFontMapping japanese = new LanguageFontMapping("MS Gothic", "Meiryo");
+
+ _languageMap.Add(0x0004, simplifiedChinese); //zh-CHS Chinese-China (Simplified)
+ _languageMap.Add(0x0804, simplifiedChinese); //zh-CN Chinese-China
+ _languageMap.Add(0x1004, simplifiedChinese); //zh-SG Chinese-Singapore
+
+ _languageMap.Add(0x7c04, traditionalChinese); //zh-CHT Chinese-China (Traditional)
+ _languageMap.Add(0x0c04, traditionalChinese); //zh-HK Chinese-Hong Kong SAR
+ _languageMap.Add(0x1404, traditionalChinese); //zh-MO Chinese-Macau
+ _languageMap.Add(0x0404, traditionalChinese); //zh-TW Chinese-Taiwan
+
+ _languageMap.Add(0x0011, japanese); //ja Japanese
+ _languageMap.Add(0x0411, japanese); //ja-JP Japanese - Japan
+
+ //This is a map of conversions from a Consolas base font to the specified composition font used in the composition window
+ _consolasFontMap.Add("SimSun", new FontSizeMapping(-2.0, 2.0, -2.0));
+ _consolasFontMap.Add("SimSun-ExtB", new FontSizeMapping(-2.0, 2.0, -2.0));
+ _consolasFontMap.Add("Microsoft YaHei", new FontSizeMapping(1.0, 2.0, 2.0));
+ _consolasFontMap.Add("MingLiU", new FontSizeMapping(-2.0, 2.0, -3.0));
+ _consolasFontMap.Add("Microsoft JhengHei", new FontSizeMapping(2.0, 2.0, 3.0));
+ _consolasFontMap.Add("MS Gothic", new FontSizeMapping(-1.0, 2.0, -2.0));
+ _consolasFontMap.Add("Meiryo", new FontSizeMapping(1.0, 2.0, 4.0));
+
+ //This is a map of conversions from a Courier New base font to the specified composition font used in the composition window
+ _courierNewFontMap.Add("SimSun", new FontSizeMapping(-2.0, 2.0, -3.0));
+ _courierNewFontMap.Add("SimSun-ExtB", new FontSizeMapping(-2.0, 2.0, -3.0));
+ _courierNewFontMap.Add("Microsoft YaHei", new FontSizeMapping(1.0, 2.0, 2.0));
+ _courierNewFontMap.Add("MingLiU", new FontSizeMapping(-2.0, 2.0, -4.0));
+ _courierNewFontMap.Add("Microsoft JhengHei", new FontSizeMapping(2.0, 2.0, 2.0));
+ _courierNewFontMap.Add("MS Gothic", new FontSizeMapping(-1.0, 2.0, -3.0));
+ _courierNewFontMap.Add("Meiryo", new FontSizeMapping(2.0, 2.0, 4.0));
+
+ //This is a map of conversion factors intended for use when the same font is used as the base font and in the composition window
+ //but we'll use it whenever the base font isn't Consola or Courier New.
+ _fontMap.Add("MS Gothic", new FontSizeMapping(0.0, 2.0, 0.0));
+ _fontMap.Add("MS PGothic", new FontSizeMapping(0.0, 2.0, 0.0));
+ _fontMap.Add("MS UI Gothic", new FontSizeMapping(0.0, 2.0, 0.0));
+ _fontMap.Add("Meiryo", new FontSizeMapping(0.0, 2.0, 0.0));
+ _fontMap.Add("Arial Unicode MS", new FontSizeMapping(0.0, 2.0, 0.0));
+ _fontMap.Add("MS Mincho", new FontSizeMapping(0.0, 2.0, 0.0));
+ _fontMap.Add("MS PMincho", new FontSizeMapping(0.0, 2.0, 0.0));
+
+ _fontMap.Add("Dotum", new FontSizeMapping(0.0, 2.0, 1.0));
+ _fontMap.Add("DotumChe", new FontSizeMapping(0.0, 2.0, 1.0));
+ _fontMap.Add("Malgun Gothic", new FontSizeMapping(1.0, 2.0, 0.0));
+ _fontMap.Add("Batang", new FontSizeMapping(0.0, 2.0, -1.0));
+ _fontMap.Add("BatangChe", new FontSizeMapping(0.0, 2.0, -1.0));
+ _fontMap.Add("Gulim", new FontSizeMapping(-1.0, 2.0, -1.0));
+ _fontMap.Add("GulimChe", new FontSizeMapping(-1.0, 2.0, -1.0));
+ _fontMap.Add("Gungsuh", new FontSizeMapping(-1.0, 2.0, -1.0));
+ _fontMap.Add("GungsuhChe", new FontSizeMapping(-1.0, 2.0, -1.0));
+
+ _fontMap.Add("SimSun", new FontSizeMapping(-1.0, 2.0, -2.0));
+ _fontMap.Add("SimSun-ExtB", new FontSizeMapping(-1.0, 2.0, -2.0));
+ _fontMap.Add("NSimSun", new FontSizeMapping(-1.0, 2.0, -2.0));
+ _fontMap.Add("Microsoft YaHei", new FontSizeMapping(-1.0, 2.0, 0.0));
+ _fontMap.Add("SimHei", new FontSizeMapping(-1.0, 2.0, -2.0));
+ _fontMap.Add("KaiTi", new FontSizeMapping(-1.0, 2.0, -1.0));
+ _fontMap.Add("FangSong", new FontSizeMapping(-1.0, 2.0, -2.0));
+
+ _fontMap.Add("MingLiU", new FontSizeMapping(-2.0, 1.0, -3.0));
+ _fontMap.Add("PMingLiU", new FontSizeMapping(-2.0, 1.0, -3.0));
+ _fontMap.Add("Microsoft JhengHei", new FontSizeMapping(-1.0, 2.0, 0.0));
+ }
+
+ public static void GetSizeAdjustments(string baseFont, string compositionFont, out double topPadding, out double bottomPadding, out double heightPadding)
+ {
+ IDictionary<string, FontSizeMapping> map;
+ if (string.Equals(baseFont, "Consolas", StringComparison.Ordinal))
+ map = _consolasFontMap;
+ else if (string.Equals(baseFont, "Courier New", StringComparison.Ordinal))
+ map = _courierNewFontMap;
+ else
+ map = _fontMap;
+
+ FontSizeMapping mapping;
+ if (map.TryGetValue(compositionFont, out mapping))
+ {
+ topPadding = mapping.TopPadding;
+ bottomPadding = mapping.BottomPadding;
+ heightPadding = mapping.HeightPadding;
+ }
+ else
+ {
+ topPadding = 0.0;
+ bottomPadding = 2.0;
+ heightPadding = -2.0;
+ }
+ }
+
+ private struct FontSizeMapping
+ {
+ public readonly double TopPadding;
+ public readonly double BottomPadding;
+ public readonly double HeightPadding;
+
+ public FontSizeMapping(double topPadding, double bottomPadding, double unadjustedHeightPadding)
+ {
+ this.TopPadding = topPadding;
+ this.BottomPadding = bottomPadding;
+ this.HeightPadding = unadjustedHeightPadding - (topPadding + bottomPadding);
+ }
+ }
+
+ private class LanguageFontMapping
+ {
+ public readonly string OldFallbackFont;
+ public readonly string NewFallbackFont;
+
+ public LanguageFontMapping(string oldFallbackFont, string newFallbackFont)
+ {
+ this.OldFallbackFont = oldFallbackFont;
+ this.NewFallbackFont = newFallbackFont;
+ }
+
+ public string GetCompositionFont(int majorVersion)
+ {
+ return (majorVersion >= 6) ? this.NewFallbackFont : this.OldFallbackFont;
+ }
+ }
+ }
+
+ public static IntPtr GetDefaultIMEWnd()
+ {
+ return NativeMethods.ImmGetDefaultIMEWnd(IntPtr.Zero);
+ }
+
+ public static IntPtr GetImmContext(IntPtr hwnd)
+ {
+ if (hwnd != IntPtr.Zero)
+ return NativeMethods.ImmGetContext(hwnd);
+ else
+ return IntPtr.Zero;
+ }
+
+ /// <summary>
+ /// Release the IMM Context.
+ /// </summary>
+ public static bool ReleaseContext(IntPtr hwnd, IntPtr immContext)
+ {
+ if ((hwnd != IntPtr.Zero) && (immContext != IntPtr.Zero))
+ return NativeMethods.ImmReleaseContext(hwnd, immContext);
+ else
+ return false;
+ }
+
+ public static void EnableImmComposition()
+ {
+
+ if (!_threadMgrFailed)
+ {
+ // Create a Thread manager if it doesn't exist
+ if (_threadMgr == null)
+ {
+#pragma warning disable CA1806 // Do not ignore method results
+ NativeMethods.TF_CreateThreadMgr(out _threadMgr);
+#pragma warning restore CA1806 // Do not ignore method results
+ if (_threadMgr == null)
+ {
+ _threadMgrFailed = true;
+ return;
+ }
+ }
+
+ _threadMgr.SetFocus(IntPtr.Zero);
+ }
+ }
+
+ public static IntPtr GetKeyboardLayout()
+ {
+ return NativeMethods.GetKeyboardLayout(0);
+ }
+
+ public static bool ImmIsIME(IntPtr hkl)
+ {
+ return NativeMethods.ImmIsIME(hkl);
+ }
+
+ /// <summary>
+ /// Generate a new FileStream with a unique random name.
+ /// </summary>
+ /// <param name="fileDirectory">Directory where the file will live.</param>
+ /// <param name="filePath">Path to the file created.</param>
+ /// <returns>A file stream with a random file name.</returns>
+ private static FileStream GetRandomFileNameStream(string fileDirectory, out string filePath)
+ {
+ int count = 0;
+ filePath = string.Empty;
+ while (count++ < 2)
+ {
+ string fileName = Path.GetRandomFileName();
+ filePath = Path.Combine(fileDirectory, fileName + "~"); //The ~ suffix hides the temporary file from GIT.
+ if (!File.Exists(filePath))
+ {
+ try
+ {
+ return new FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
+ }
+ catch (Exception)
+ {
+ Debug.Fail("Creating random file failed.");
+ }
+ }
+ }
+
+ throw new IOException(filePath + " exists");
+ }
+ }
+
+ /// <summary>
+ /// SafeHandle wrapper for the cursor image
+ /// </summary>
+ internal sealed class SafeCursor : SafeHandle
+ {
+ public SafeCursor()
+ : base(IntPtr.Zero, true)
+ {
+ }
+
+ public SafeCursor(IntPtr hCursor)
+ : base(hCursor, true)
+ {
+ }
+
+ public override bool IsInvalid
+ {
+ get
+ {
+ return this.handle == IntPtr.Zero;
+ }
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ return NativeMethods.DestroyCursor(this.handle);
+ }
+ }
+
+
+ [SuppressUnmanagedCodeSecurity]
+ static class NativeMethods
+ {
+ public const int LOGPIXELSX = 88;
+ public const int LOGPIXELSY = 90;
+
+ #region Win32 Interop
+
+ /// <summary>
+ /// A point structure to match the Win32 POINT
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT
+ {
+ public int x;
+ public int y;
+ };
+
+ /// <summary>
+ /// A rect structure to match the Win32 RECT
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+ };
+
+ /// <summary>
+ /// Win32 MONITORINFO Struct
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MONITORINFO
+ {
+ public int cbSize;
+ public RECT rcMonitor;
+ public RECT rcWork;
+ public int dwFlags;
+ };
+
+ /// <summary>
+ /// Win32 COMPOSITIONFORM struct
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct COMPOSITIONFORM
+ {
+ public int dwStyle;
+ public POINT ptCurrentPos;
+ public RECT rcArea;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECONVERTSTRING
+ {
+ public int dwSize;
+ public int dwVersion;
+ public int dwStrLen;
+ public int dwStrOffset;
+ public int dwCompStrLen;
+ public int dwCompStrOffset;
+ public int dwTargetStrLen;
+ public int dwTargetStrOffset;
+ }
+
+ /// <summary>
+ /// Win32 LOGFONT struct
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public class LOGFONT
+ {
+ public int lfHeight;
+ public int lfWidth;
+ public int lfEscapement;
+ public int lfOrientation;
+ public int lfWeight;
+ public byte lfItalic;
+ public byte lfUnderline;
+ public byte lfStrikeOut;
+ public byte lfCharSet;
+ public byte lfOutPrecision;
+ public byte lfClipPrecision;
+ public byte lfQuality;
+ public byte lfPitchAndFamily;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
+ public string lfFaceName;
+ }
+
+ /// <summary>
+ /// Win32 WINDOWPOS struct
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public class WINDOWPOS
+ {
+ public IntPtr hwnd;
+ public IntPtr hwndInsertAfter;
+ public int x;
+ public int y;
+ public int cx;
+ public int cy;
+ public uint flags;
+ }
+
+ /// <summary></summary>
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("aa80e801-2021-11d2-93e0-0060b067b86e")]
+ internal interface ITfThreadMgr
+ {
+ // <summary></summary>
+ //HRESULT Activate([out] TfClientId *ptid);
+ /// <SecurityNote>
+ /// Critical: This code calls into an unmanaged COM function which is not
+ /// safe since it elevates
+ /// </SecurityNote>
+ [SecurityCritical]
+ [SuppressUnmanagedCodeSecurity]
+ void Activate(out int clientId);
+
+ // <summary></summary>
+ //HRESULT Deactivate();
+ /// <SecurityNote>
+ /// Critical: This code calls into an unmanaged COM function which is not
+ /// safe since it elevates
+ /// </SecurityNote>
+ [SecurityCritical]
+ [SuppressUnmanagedCodeSecurity]
+ void Deactivate();
+
+ // <summary></summary>
+ //HRESULT CreateDocumentMgr([out] ITfDocumentMgr **ppdim);
+ /// <SecurityNote>
+ /// Critical: This code calls into an unmanaged COM function which is not
+ /// safe since it elevates
+ /// </SecurityNote>
+ [SecurityCritical]
+ [SuppressUnmanagedCodeSecurity]
+ void CreateDocumentMgr(out object docMgr);
+
+ /// <summary></summary>
+ //HRESULT EnumDocumentMgrs([out] IEnumTfDocumentMgrs **ppEnum);
+ void EnumDocumentMgrs(out object enumDocMgrs);
+
+ /// <summary></summary>
+ //HRESULT GetFocus([out] ITfDocumentMgr **ppdimFocus);
+ void GetFocus(out IntPtr docMgr);
+
+ // <summary></summary>
+ //HRESULT SetFocus([in] ITfDocumentMgr *pdimFocus);
+ /// <SecurityNote>
+ /// Critical: This code calls into an unmanaged COM function which is not
+ /// safe since it elevates
+ /// </SecurityNote>
+ [SecurityCritical]
+ [SuppressUnmanagedCodeSecurity]
+ void SetFocus(IntPtr docMgr);
+
+ /// <summary></summary>
+ //HRESULT AssociateFocus([in] HWND hwnd,
+ // [in, unique] ITfDocumentMgr *pdimNew,
+ // [out] ITfDocumentMgr **ppdimPrev);
+ void AssociateFocus(IntPtr hwnd, object newDocMgr, out object prevDocMgr);
+
+ /// <summary></summary>
+ //HRESULT IsThreadFocus([out] BOOL *pfThreadFocus);
+ void IsThreadFocus([MarshalAs(UnmanagedType.Bool)] out bool isFocus);
+
+ //HRESULT GetFunctionProvider([in] REFCLSID clsid,
+ // [out] ITfFunctionProvider **ppFuncProv);
+ /// <summary></summary>
+ /// <SecurityNote>
+ /// Critical: This code calls into an unmanaged COM function which is not
+ /// safe since it elevates
+ /// </SecurityNote>
+ [SecurityCritical]
+ [SuppressUnmanagedCodeSecurity]
+ [PreserveSig]
+ int GetFunctionProvider(ref Guid classId, out object funcProvider);
+
+ /// <summary></summary>
+ //HRESULT EnumFunctionProviders([out] IEnumTfFunctionProviders **ppEnum);
+ void EnumFunctionProviders(out object enumProviders);
+
+ //HRESULT GetGlobalCompartment([out] ITfCompartmentMgr **ppCompMgr);
+ /// <summary></summary>
+ /// <SecurityNote>
+ /// Critical: This code calls into an unmanaged COM function which is not
+ /// safe since it elevates
+ /// </SecurityNote>
+ [SecurityCritical]
+ [SuppressUnmanagedCodeSecurity]
+ void GetGlobalCompartment(out object compartmentMgr);
+ }
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DestroyCursor(IntPtr hCursor);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);
+
+ [DllImport("User32.dll")]
+ public static extern IntPtr GetDC(IntPtr hwnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ReleaseDC(IntPtr hWnd, IntPtr hdc);
+
+ [DllImport("Gdi32.dll")]
+ public static extern int GetDeviceCaps(IntPtr hdc, int index);
+
+ [DllImport("user32.dll")]
+ public extern static IntPtr GetKeyboardLayout(int dwThread);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public extern static bool ClientToScreen(IntPtr hWnd, ref POINT point);
+
+ [DllImport("user32.dll")]
+ public extern static IntPtr MonitorFromWindow(IntPtr hwnd, int dwFlags);
+
+ [DllImport("user32.dll")]
+ public extern static IntPtr MonitorFromPoint(POINT pt, int dwFlags);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public extern static bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr LoadImage(IntPtr hinst, string lpszName, IMAGE_TYPE uType, int cxDesired, int cyDesired, IMAGE_FORMAT_REQUEST fuLoad);
+
+ [DllImport("msctf.dll")]
+ internal static extern int TF_CreateThreadMgr(out ITfThreadMgr threadMgr);
+
+ [DllImport("imm32.dll")]
+ internal static extern IntPtr ImmGetDefaultIMEWnd(IntPtr hWnd);
+
+ [DllImport("imm32.dll")]
+ internal static extern IntPtr ImmGetContext(IntPtr hWnd);
+
+ [DllImport("imm32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ImmSetCompositionWindow(IntPtr hIMC, IntPtr ptr);
+
+ [DllImport("imm32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
+
+ [DllImport("imm32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ImmSetCompositionFontW(IntPtr hIMC, IntPtr lplf);
+
+ [DllImport("imm32.dll", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.I4)]
+ internal static extern int ImmGetCompositionStringW(IntPtr hIMC, int dwIndex, StringBuilder lpBuf, int dwBufLen);
+
+ [DllImport("imm32.dll", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.I4)]
+ internal static extern int ImmSetCompositionStringW(IntPtr hIMC, int dwIndex, StringBuilder lpComp, int dwCompLen, StringBuilder lpBuf, int dwBufLen);
+
+ [DllImport("imm32.dll")]
+ internal static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
+
+ [DllImport("imm32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ImmNotifyIME(IntPtr immContext, int dwAction, int dwIndex, int dwValue);
+
+ [DllImport("imm32.dll", CharSet = CharSet.Unicode)]
+ internal static extern IntPtr ImmEscapeW(IntPtr hkl, IntPtr himc, int esc, IntPtr lpBuf);
+
+ [DllImport("imm32.dll", CharSet = CharSet.Unicode)]
+ internal static extern bool ImmIsIME(IntPtr hkl);
+
+ public const int MONITOR_DEFAULTTONEAREST = 0x00000002;
+ public const int CFS_RECT = 0x0001;
+
+ public enum IMAGE_TYPE
+ {
+ IMAGE_BITMAP = 0,
+ IMAGE_ICON = 1,
+ IMAGE_CURSOR = 2,
+ IMAGE_ENHMETAFILE = 3
+ }
+
+ [Flags]
+ public enum IMAGE_FORMAT_REQUEST
+ {
+ LR_DEFAULTCOLOR = 0x0000,
+ LR_MONOCHROME = 0x0001,
+ LR_COPYRETURNORG = 0x0004,
+ LR_COPYDELETEORG = 0x0008,
+ LR_LOADFROMFILE = 0x0010,
+ LR_DEFAULTSIZE = 0x0040,
+ LR_LOADMAP3DCOLORS = 0x1000,
+ LR_CREATEDIBSECTION = 0x2000,
+ LR_COPYFROMRESOURCE = 0x4000,
+ LR_SHARED = 0x8000
+ }
+
+ #endregion // Win32 Interop
+ }
+}