Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Computer Use Support/Example, PDF Support, Claude 3.5 Haiku Model Constant #60

Merged
merged 9 commits into from
Nov 20, 2024
Merged
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
20 changes: 20 additions & 0 deletions Anthropic.SDK.ComputerUse/Anthropic.SDK.ComputerUse.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SharpHook" Version="5.3.8" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageReference Include="System.Drawing.Common" Version="8.0.11" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Anthropic.SDK\Anthropic.SDK.csproj" />
</ItemGroup>

</Project>
111 changes: 111 additions & 0 deletions Anthropic.SDK.ComputerUse/Inputs/KeyboardSimulator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using SharpHook.Native;
using SharpHook;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Anthropic.SDK.ComputerUse.Inputs
{
public class KeyboardSimulator
{
public static void SimulateTextInput(string text)
{
if (string.IsNullOrWhiteSpace(text))
throw new ArgumentException("Text cannot be null or empty.");

IEventSimulator simulator = new EventSimulator();

simulator.SimulateTextEntry(text);
}
public static void SimulateKeyCombination(string keyCombination)
{
if (string.IsNullOrWhiteSpace(keyCombination))
throw new ArgumentException("Key combination cannot be null or empty.");

// Split the key combination into individual keys
var keys = keyCombination.Split(new[] { '+', ' ' }, StringSplitOptions.RemoveEmptyEntries);

IEventSimulator simulator = new EventSimulator();

// Stack to keep track of keys pressed
Stack<KeyCode> keysDown = new Stack<KeyCode>();
ModifierMask currentMask = ModifierMask.None;

// Map key names to KeyCode enums
var keyMap = new Dictionary<string, KeyCode>(StringComparer.OrdinalIgnoreCase)
{
{ "Shift", KeyCode.VcLeftShift },
{ "Ctrl", KeyCode.VcLeftControl },
{ "Control", KeyCode.VcLeftControl },
{ "Alt", KeyCode.VcLeftAlt },
{ "LWin", KeyCode.VcLeftMeta },
{ "RWin", KeyCode.VcRightMeta },
{ "Enter", KeyCode.VcEnter },
{ "Return", KeyCode.VcEnter },
{ "Super", KeyCode.VcLeftMeta },
{ "Windows", KeyCode.VcLeftMeta },
// Add other keys as needed
};

// Map modifier keys to ModifierMask enums
var modifierMap = new Dictionary<KeyCode, ModifierMask>
{
{ KeyCode.VcLeftShift, ModifierMask.Shift },
{ KeyCode.VcLeftControl, ModifierMask.Ctrl },
{ KeyCode.VcLeftAlt, ModifierMask.Alt },
{ KeyCode.VcLeftMeta, ModifierMask.Meta },
{ KeyCode.VcRightMeta, ModifierMask.Meta }
};

// Press down all keys
foreach (var key in keys)
{
KeyCode keyCode;

// Check if the key is in the keyMap
if (keyMap.TryGetValue(key, out keyCode))
{
simulator.SimulateKeyPress(keyCode);

// Update the modifier mask if it's a modifier key
if (modifierMap.TryGetValue(keyCode, out ModifierMask modifier))
{
currentMask |= modifier;
}

keysDown.Push(keyCode);
}
else if (key.Length == 1)
{
// Handle single character keys
char c = key.ToUpper()[0];
KeyCode charKeyCode = (KeyCode)Enum.Parse(typeof(KeyCode), $"Vc{c}", true);

simulator.SimulateKeyPress(charKeyCode);

keysDown.Push(charKeyCode);
}
else
{
throw new ArgumentException($"Unknown key: {key}");
}
}

// Release keys in reverse order
while (keysDown.Count > 0)
{
KeyCode keyCode = keysDown.Pop();

// Update the modifier mask if it's a modifier key
if (modifierMap.ContainsKey(keyCode))
{
currentMask &= ~modifierMap[keyCode];
}

simulator.SimulateKeyRelease(keyCode);
}
}
}
}
136 changes: 136 additions & 0 deletions Anthropic.SDK.ComputerUse/Inputs/WindowsMouseController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
using SharpHook;
using SharpHook.Native;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Anthropic.SDK.ComputerUse.Inputs
{
public class WindowsMouseController
{
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
}

// Define MONITORINFO structure
[StructLayout(LayoutKind.Sequential)]
public struct MONITORINFO
{
public uint cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
}

// Delegate for monitor enumeration callback
private delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);

// P/Invoke declarations
[DllImport("user32.dll")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip,
MonitorEnumDelegate lpfnEnum, IntPtr dwData);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);

// Class to hold monitor information
public class MonitorInfo
{
public IntPtr MonitorHandle;
public RECT MonitorArea;
}

// Method to get all connected monitors
public static List<MonitorInfo> GetMonitors()
{
var monitors = new List<MonitorInfo>();

bool Callback(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
{
var mi = new MONITORINFO { cbSize = (uint)Marshal.SizeOf(typeof(MONITORINFO)) };
if (GetMonitorInfo(hMonitor, ref mi))
{
monitors.Add(new MonitorInfo
{
MonitorHandle = hMonitor,
MonitorArea = mi.rcMonitor
});
}
return true; // Continue enumeration
}

EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, Callback, IntPtr.Zero);
return monitors;
}

public static (int virtualX, int virtualY) GetVirtualCoordinates(int screenIndex, int x, int y)
{
// Get all screens
var monitors = GetMonitors();

// Validate the screen index
if (screenIndex < 0 || screenIndex >= monitors.Count)
{
throw new ArgumentOutOfRangeException(nameof(screenIndex), "Invalid screen index.");
}

var monitor = monitors[screenIndex];
var monitorBounds = new Rectangle(monitor.MonitorArea.Left, monitor.MonitorArea.Top,
monitor.MonitorArea.Right - monitor.MonitorArea.Left,
monitor.MonitorArea.Bottom - monitor.MonitorArea.Top);


// Validate coordinates
if (x < 0 || x >= monitorBounds.Width || y < 0 || y >= monitorBounds.Height)
{
throw new ArgumentOutOfRangeException("Coordinates are out of bounds for the specified monitor.");
}

// Convert to virtual screen coordinates
int virtualX = (int)(monitorBounds.X + x);
int virtualY = (int)(monitorBounds.Y + y);

return (virtualX, virtualY);
}

// Method to set the cursor position on a specific monitor
public static void SetCursorPositionOnMonitor(int monitorIndex, int x, int y)
{
var (virtualX, virtualY) = GetVirtualCoordinates(monitorIndex, x, y);

IEventSimulator simulator = new EventSimulator();

// Move the cursor to the specified position
simulator.SimulateMouseMovement(Convert.ToInt16(virtualX), Convert.ToInt16(virtualY));
}

// Method to perform a left-click at the current cursor position
public static void LeftClick()
{
IEventSimulator simulator = new EventSimulator();
simulator.SimulateMousePress(MouseButton.Button1);
simulator.SimulateMouseRelease(MouseButton.Button1);

}

public static void RightClick()
{
IEventSimulator simulator = new EventSimulator();
simulator.SimulateMousePress(MouseButton.Button2);
simulator.SimulateMouseRelease(MouseButton.Button2);

}


// Method to move the cursor and perform a left-click at specified coordinates on a specific monitor
public static void ClickAtPositionOnMonitor(int monitorIndex, int x, int y)
{
SetCursorPositionOnMonitor(monitorIndex, x, y);
System.Threading.Thread.Sleep(50); // Optional delay to ensure the cursor has moved
LeftClick();
}


}
}
Loading
Loading