[Win]+[Shift]+[S]のような範囲選択をC#で

画面の範囲選択をさせたいときに役立つかも．．．？

### 環境
.NetFramework
WinForm

### 完成品
![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376391/1450faa1-72d1-2a22-f89c-b413690817e8.gif)
### コード
```C#
public partial class CaptureForm : Form
{
    /// <summary>
    /// 選択範囲
    /// </summary>
    public Rectangle SelectRegion { get; private set; }

    /// <summary>
    /// 選択の開始位置
    /// </summary>
    private Point startPoint;
    /// <summary>
    /// 選択中の現在位置
    /// </summary>
    private Point currentPoint;
    /// <summary>
    /// 選択前のカーソル状態
    /// </summary>
    private Cursor cursorRestore;

    public CaptureForm()
    {
        InitializeComponent();

        BackColor = Color.Black;
        Opacity = 0.7;
        FormBorderStyle = FormBorderStyle.None;            
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        var screenRectangle = GetSceenRectangle();
        Location = screenRectangle.Location;
        Size = screenRectangle.Size;
    }

    private void CampusForm_MouseDown(object sender, MouseEventArgs e)
    {
        startPoint=e.Location;

        cursorRestore = Cursor;
        Cursor = Cursors.Cross;
    }

    private void CampusForm_MouseMove(object sender, MouseEventArgs e)
    {
        currentPoint = e.Location;
        Invalidate();
    }

    private void CampusForm_MouseUp(object sender, MouseEventArgs e)
    {
        Invalidate();
        Cursor = cursorRestore;

        DialogResult = DialogResult.OK;
        Close();
    }

    private void CampusForm_Paint(object sender, PaintEventArgs e)
    {
        if (MouseButtons != MouseButtons.Left) return;
        SelectRegion = GetSelectRegion();
    }

    /// <summary>
    /// 選択範囲を取得.
    /// </summary>
    private Rectangle GetSelectRegion()
    {
        var region = new Rectangle
        {
            X = Math.Min(startPoint.X, currentPoint.X),
            Y = Math.Min(startPoint.Y, currentPoint.Y),
            Width = Math.Abs(currentPoint.X - startPoint.X),
            Height = Math.Abs(currentPoint.Y - startPoint.Y)
        };

        var regionNew = new Region(ClientRectangle);
        using (var path = new System.Drawing.Drawing2D.GraphicsPath())
        {
            path.AddRectangle(region);
            regionNew.Exclude(region);
        }

        var regionOld = Region;
        Region = regionNew;

        regionOld?.Dispose();
        return region;
    }

    /// <summary>
    /// すべてのスクリーンを合わせた四角形のサイズと位置を表す<see cref="Rectangle"/>を取得.
    /// </summary>
    private Rectangle GetSceenRectangle()
    {
        var screens = Screen.AllScreens;

        // 一番小さいx (左上のx座標)
        var minX = screens.Min(screen => screen.Bounds.X);
        // 一番小さいy (左上のy座標)
        var minY = screens.Min(screen => screen.Bounds.Y);
        // 一番大きいx (右下のx座標)
        var maxX = screens.Max(screen => screen.Bounds.X + screen.Bounds.Width);
        // 一番大きいy (右下のy座標)
        var maxY = screens.Max(screen => screen.Bounds.Y + screen.Bounds.Height);

        return new Rectangle(minX, minY, maxX - minX, maxY - minY);
    }
}
```

MouseUpのタイミングでクリップボードにコピーすると、[Win]+[Shift]+[S]みたいなコピーも可能に。
```C#
/// <summary>
/// 選択範囲をクリップボードにコピーします。
/// </summary>
private void CopyToClipboard()
{
    var bmp = new Bitmap(SelectRegion.Width, SelectRegion.Height);
    using (var graphics = Graphics.FromImage(bmp))
    {
        var screenRectangle = GetSceenRectangle();
        graphics.CopyFromScreen(SelectRegion.X + screenRectangle.X
                                , SelectRegion.Y + screenRectangle.Y, 0, 0, SelectRegion.Size);
        Clipboard.SetImage(bmp);
    };
}
```