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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions TabletFriend/TabletFriend/Actions/ButtonActionResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public static class ButtonActionResolver
private const string _typeKeyword = "type ";
private const string _toggleKeyword = "toggle ";
private const string _cmdKeyword = "cmd ";
private const string _clickKeyword = "click ";
private const string _waitKeyword = "wait ";
private const string _holdKeyword = "hold ";
private const string _releaseKeyword = "release ";
Expand Down Expand Up @@ -36,6 +37,10 @@ public static ButtonAction Resolve(string actionString)
{
return ResolveCmdAction(actionString.Substring(_cmdKeyword.Length));
}
if (actionString.StartsWith(_clickKeyword))
{
return ResolveClickAction(actionString.Substring(_clickKeyword.Length));
}
if (actionString.StartsWith(_waitKeyword))
{
return ResolveWaitAction(actionString.Substring(_waitKeyword.Length));
Expand Down Expand Up @@ -75,6 +80,9 @@ private static ButtonAction ResolveTypeAction(string actionString) =>
private static ButtonAction ResolveCmdAction(string actionString) =>
new CmdAction(actionString.Trim());

private static ButtonAction ResolveClickAction(string actionString) =>
new ClickAction(actionString.Trim());

private static ButtonAction ResolveWaitAction(string actionString) =>
new WaitAction(int.Parse(actionString));

Expand Down
142 changes: 142 additions & 0 deletions TabletFriend/TabletFriend/Actions/ClickAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using System.Drawing;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using WindowsInput.Events;

namespace TabletFriend.Actions
{
public class ClickAction : ButtonAction
{
private static System.Drawing.Point? _newClickCoordinates = null;
private static Rectangle _dragBoxFromMouseDown;

private bool _initialized = false;
private readonly int _x;
private readonly int _y;

public ClickAction(string cmd)
{
// The regular expression extracts the coordinates from the given cmd string.
// Furthermore it validates the format of the string.
// The string has to consist of two numbers separated by a comma "," (white spaces are ignored) like e.g
// "10,20" or " 10,20 " or "10, 20" or " 10 , 20 "
Regex expression = new Regex(@"^\s*(?<x_coordinate>\d+)\s*,\s*(?<y_coordinate>\d+)\s*$");
Match match = expression.Match(cmd);
if (match.Success)
{
_x = int.Parse(match.Groups["x_coordinate"].Value);
_y = int.Parse(match.Groups["y_coordinate"].Value);
_initialized = true;
}
}

public async override Task Invoke()
{
if (_initialized)
{
var sim = new EventBuilder();
sim.MoveTo(_x, _y).Click(ButtonCode.Left);
await sim.Invoke();
}
}

public static void AddDragAndDropEventHandlers(ButtonBase uiButton, string key)
{
// Add event handlers to the click action button
// to support drag/drop for defining the destination coordinates.
uiButton.Name = key;
uiButton.PreviewMouseLeftButtonUp += MouseUp;
uiButton.PreviewMouseLeftButtonDown += MouseDown;
uiButton.PreviewMouseMove += MouseMove;
uiButton.PreviewQueryContinueDrag += QueryContinueDrag;
uiButton.PreviewGiveFeedback += GiveFeedback;
}

private static void MouseDown(object sender, System.Windows.Input.MouseEventArgs e)
{
// Remember the point where the mouse down occurred. The DragSize indicates
// the size that the mouse can move before a drag event should be started.
System.Drawing.Size dragSize = System.Windows.Forms.SystemInformation.DragSize;
var x = System.Windows.Forms.Cursor.Position.X;
var y = System.Windows.Forms.Cursor.Position.Y;

System.Windows.Point mpos = e.GetPosition(null);
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
_dragBoxFromMouseDown = new Rectangle(
new System.Drawing.Point(
x - (dragSize.Width / 2),
y - (dragSize.Height / 2)),
dragSize);
}

private static void MouseUp(object sender, System.Windows.Input.MouseEventArgs e)
{
// Reset the drag rectangle when the mouse button is raised.
_dragBoxFromMouseDown = Rectangle.Empty;
}

private static void MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
var x = System.Windows.Forms.Cursor.Position.X;
var y = System.Windows.Forms.Cursor.Position.Y;

// If the mouse moves outside the rectangle, start the drag.
if (_dragBoxFromMouseDown != Rectangle.Empty &&
!_dragBoxFromMouseDown.Contains(x, y))
{
_dragBoxFromMouseDown = Rectangle.Empty;
{
DataObject dataObj = new DataObject((sender as Button));
System.Windows.DragDrop.DoDragDrop((sender as Button), dataObj, DragDropEffects.None);
if (_newClickCoordinates.HasValue)
{
var result = MessageBox.Show(
$"Save new click destination {_newClickCoordinates.Value}",
"Mouse Click Action",
MessageBoxButton.OKCancel);

if (result == MessageBoxResult.OK)
{
var key = (sender as Button).Name;
LayoutManager.UpdateClickActionCoordinatesInCurrentLayoutFile(key, _newClickCoordinates.Value);
}

_newClickCoordinates = null;
}
}
}
}
}

private static void GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
System.Windows.Input.Mouse.SetCursor(System.Windows.Input.Cursors.Cross);
e.Handled = true;
}

private static void QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
if (e.KeyStates == DragDropKeyStates.None)
{
var pointOnScreen = System.Windows.Forms.Cursor.Position;
var pointInMainWindow = Application.Current.MainWindow.PointFromScreen(
new System.Windows.Point(pointOnScreen.X, pointOnScreen.Y));
var rs = Application.Current.MainWindow.RenderSize;
var dropDestinationInsideOfMainWindow =
(pointInMainWindow.X > 0 && pointInMainWindow.X < rs.Width) &&
(pointInMainWindow.Y > 0 && pointInMainWindow.Y < rs.Height);

if (!dropDestinationInsideOfMainWindow)
{
_newClickCoordinates = pointOnScreen;
}
}
}
}
}
24 changes: 23 additions & 1 deletion TabletFriend/TabletFriend/LayoutManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Windows;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows;
using WpfAppBar;

namespace TabletFriend
Expand Down Expand Up @@ -57,5 +59,25 @@ public void LoadLayout(string path)
EventBeacon.SendEvent("docking_changed", AppState.Settings.DockingMode);
}

public static void UpdateClickActionCoordinatesInCurrentLayoutFile(
string keyNameInLayoutFile,
System.Drawing.Point newCoordinates)
{
if (AppState.CurrentLayout != null)
{
var layout = AppState.CurrentLayoutPath;
var currentLayoutFileContent = File.ReadAllText(layout);
var pattern = @$"({keyNameInLayoutFile}:.*?action:.*?click)\s+(?<x_coordinate>\d+)\s*,\s*(?<y_coordinate>\d+)";
if (Regex.IsMatch(currentLayoutFileContent, pattern, RegexOptions.Singleline))
{
var updatedLayoutFileContent = Regex.Replace(
currentLayoutFileContent,
pattern,
@$"$1 {newCoordinates.X},{newCoordinates.Y}",
RegexOptions.Singleline);
File.WriteAllText(layout, updatedLayoutFileContent);
}
}
}
}
}
4 changes: 3 additions & 1 deletion TabletFriend/TabletFriend/Models/ButtonModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class ButtonModel : IDisposable
public ButtonAction Action;

public string Text = "";
public string Key = "";
public object Icon;

public Vector2 Position = Vector2.Zero;
Expand All @@ -33,12 +34,13 @@ public class ButtonModel : IDisposable

public ButtonVisibility Visibility;

public ButtonModel(ButtonData data)
public ButtonModel(string key, ButtonData data)
{
if (data == null)
{
return;
}
Key = key;
Text = (data.Text ?? "").Replace("\\n", Environment.NewLine);

if (!string.IsNullOrEmpty(data.Icon))
Expand Down
2 changes: 1 addition & 1 deletion TabletFriend/TabletFriend/Models/LayoutModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public LayoutModel(LayoutData data)

foreach (var button in data.Buttons)
{
Buttons.Add(new ButtonModel(button.Value));
Buttons.Add(new ButtonModel(button.Key, button.Value));
}
}

Expand Down
6 changes: 4 additions & 2 deletions TabletFriend/TabletFriend/UiFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using MaterialDesignThemes.Wpf;
using System;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Windows;
Expand Down Expand Up @@ -265,6 +264,9 @@ Vector2 offset
if (button.Action != null)
{
uiButton.Click += (e, o) => _ = button.Action.Invoke();

if (button.Action is ClickAction)
ClickAction.AddDragAndDropEventHandlers(uiButton, button.Key);
}

Canvas.SetTop(uiButton, theme.CellSize * position.Y + theme.Margin + offset.Y);
Expand Down
13 changes: 13 additions & 0 deletions TabletFriend/TabletFriend/files/layouts/sample_layout.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,19 @@ buttons:
icon: pencil
text: bluetooth button\nhold
size: 2,1

# Left mouse click at a given location
# Drag and drop the button to specify new destination coordinates.
click1:
action: click 0,0
text: Mouse\nClick 1
size: 2,2
style: accent
click2:
action: click 0,0
text: Mouse\nClick 2
size: 2,2
style: accent

docked_spacer:
spacer: true
Expand Down