-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Add mouse click effect capability for screen recording #7622
Closed
Closed
Changes from 1 commit
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
bc48eac
add mouse click effect capability for screen recording
Vertygo dd383c8
review: switch to full circle
Vertygo b206d5e
review: switch to layered window
Vertygo 95c9174
run effect outside Task.Run
Vertygo 30cb81d
adhere to coding guidelines - removing underscore from fields
Vertygo 582d793
implement right click effect
Vertygo 57b1be0
fix checkbox position in settings form
Vertygo e45f45d
fix formatting
Vertygo 28c4c56
add space in control flow statement option in .editorconfig
Vertygo 5ac1d29
removing empty lines
Vertygo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
using System; | ||
using System.Drawing; | ||
using System.Windows.Forms; | ||
|
||
namespace ShareX.HelpersLib | ||
{ | ||
// transparent form where mouse effect will be drawn | ||
public class MouseClickEffectForm : Form | ||
{ | ||
private bool _drawEffect = false; | ||
public MouseClickEffectForm() | ||
{ | ||
Size = new Size(40, 40); | ||
FormBorderStyle = FormBorderStyle.None; | ||
ShowIcon = false; | ||
ShowInTaskbar = false; | ||
TopMost = true; | ||
AllowTransparency = true; | ||
BackColor = Color.White; // Set a key color for transparency | ||
TransparencyKey = Color.White; // Make that color transparent | ||
} | ||
|
||
/// <summary> | ||
/// Draw mouse effect on given mouse position | ||
/// </summary> | ||
public void DrawMouseEffect(Point cursorPosition) | ||
{ | ||
_drawEffect = true; | ||
CenterFormToCursorPosition(cursorPosition); | ||
Invalidate(); // redraw form | ||
} | ||
|
||
/// <summary> | ||
/// Clear mouse effect | ||
/// </summary> | ||
public void ClearMouseEffect() | ||
{ | ||
_drawEffect = false; | ||
Invalidate(); // redraw form | ||
} | ||
|
||
/// <summary> | ||
/// Draw a hollow circle as an mouse effect | ||
/// </summary> | ||
protected override void OnPaint(PaintEventArgs e) | ||
{ | ||
if (_drawEffect) | ||
{ | ||
Graphics g = e.Graphics; | ||
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; | ||
// Define a pen to draw hollow circle | ||
Pen pen = new Pen(Color.Red, 3); | ||
int diameter = 10; | ||
|
||
// Calculate the top-left corner to center the circle | ||
int x = (ClientSize.Width - diameter) / 2; | ||
int y = (ClientSize.Height - diameter) / 2; | ||
|
||
// .NET GDI+ is not precise when drawign circles this would be better off with WPF/vector-based drawing | ||
g.DrawEllipse(pen, x, y, diameter, diameter); | ||
} | ||
|
||
base.OnPaint(e); | ||
} | ||
|
||
private void CenterFormToCursorPosition(Point cursorPosition) | ||
{ | ||
var x = cursorPosition.X - (Width / 2); | ||
var y = cursorPosition.Y - (Height / 2); | ||
var flags = SetWindowPosFlags.SWP_NOSIZE | | ||
SetWindowPosFlags.SWP_NOOWNERZORDER | | ||
SetWindowPosFlags.SWP_NOACTIVATE; | ||
|
||
// Center the form/circle at the current mouse cursor position | ||
NativeMethods.SetWindowPos(Handle, (IntPtr)NativeConstants.HWND_TOPMOST, x, y, 0, 0, flags); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
using System; | ||
using System.Windows.Forms; | ||
|
||
namespace ShareX.HelpersLib | ||
{ | ||
public class MouseClickEffectManager : IDisposable | ||
{ | ||
private MouseHook mouseHook; | ||
private MouseClickEffectForm clickEffectForm; | ||
private bool _disposed; | ||
|
||
// start click mouse effects | ||
public void Start() | ||
{ | ||
var action = new Action(() => | ||
{ | ||
clickEffectForm = new MouseClickEffectForm(); | ||
mouseHook = new MouseHook(); | ||
mouseHook.OnMouseEvent += OnMouseEvent; | ||
clickEffectForm.Show(); | ||
}); | ||
|
||
// form needs to be running on main UI thread otherwise it will not show up | ||
if (Application.OpenForms[0].InvokeRequired) | ||
{ | ||
Application.OpenForms[0].Invoke(action); | ||
} | ||
else | ||
{ | ||
action(); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Mouse event handler | ||
/// </summary> | ||
private void OnMouseEvent(MouseEventInfo eventInfo) | ||
{ | ||
switch (eventInfo.ButtonState) | ||
{ | ||
case ButtonState.LeftButtonDown: | ||
clickEffectForm.DrawMouseEffect(eventInfo.CursorPosition); | ||
break; | ||
default: | ||
clickEffectForm.ClearMouseEffect(); | ||
break; | ||
} | ||
} | ||
|
||
public void Stop() | ||
{ | ||
Dispose(); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
Dispose(true); | ||
} | ||
|
||
protected virtual void Dispose(bool disposing) | ||
{ | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
|
||
if (disposing) | ||
{ | ||
mouseHook.OnMouseEvent -= OnMouseEvent; | ||
mouseHook.Dispose(); | ||
clickEffectForm.Close(); | ||
clickEffectForm.Dispose(); | ||
} | ||
|
||
mouseHook = null; | ||
clickEffectForm = null; | ||
|
||
_disposed = true; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
| ||
|
||
using System.Drawing; | ||
|
||
namespace ShareX.HelpersLib | ||
{ | ||
public class MouseEventInfo | ||
{ | ||
public ButtonState ButtonState { get; set; } | ||
public Point CursorPosition { get; set; } | ||
} | ||
|
||
public enum ButtonState | ||
{ | ||
LeftButtonDown, | ||
RightButtonDown, | ||
ButtonUp | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System; | ||
|
||
namespace ShareX.HelpersLib | ||
{ | ||
public class MouseHook : IDisposable | ||
{ | ||
private HookProc _proc; | ||
private static IntPtr _hookID = IntPtr.Zero; | ||
|
||
public delegate void MouseEventHandler(MouseEventInfo eventInfo); | ||
public event MouseEventHandler OnMouseEvent; | ||
|
||
public MouseHook() | ||
{ | ||
_proc = HookCallback; | ||
_hookID = SetHook(_proc); // Set up global mouse hook | ||
} | ||
|
||
~MouseHook() | ||
{ | ||
Dispose(); | ||
} | ||
|
||
private static IntPtr SetHook(HookProc proc) | ||
{ | ||
using (var curProcess = System.Diagnostics.Process.GetCurrentProcess()) | ||
using (var curModule = curProcess.MainModule) | ||
{ | ||
return NativeMethods.SetWindowsHookEx(NativeConstants.WH_MOUSE_LL, proc, NativeMethods.GetModuleHandle(curModule.ModuleName), 0); | ||
} | ||
} | ||
|
||
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) | ||
{ | ||
if (nCode >= 0) | ||
{ | ||
switch ((WindowsMessages)wParam) | ||
{ | ||
case WindowsMessages.LBUTTONDOWN: | ||
OnMouseEvent(new MouseEventInfo | ||
{ | ||
ButtonState = ButtonState.LeftButtonDown, | ||
CursorPosition = CaptureHelpers.GetCursorPosition() | ||
}); | ||
break; | ||
|
||
case WindowsMessages.LBUTTONUP: | ||
OnMouseEvent(new MouseEventInfo | ||
{ | ||
ButtonState = ButtonState.ButtonUp, | ||
CursorPosition = CaptureHelpers.GetCursorPosition() | ||
}); | ||
break; | ||
} | ||
} | ||
|
||
return NativeMethods.CallNextHookEx(_hookID, nCode, wParam, lParam); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
NativeMethods.UnhookWindowsHookEx(_hookID); // Clean up hook on exit | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might not be best solution due to GDI+ poor precision.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't add that much to this, I just wanted to say that rn I'm using this tool https://github.com/Phaiax/Key-n-Stroke to achieve the same and as it is open-source already you guys can probably get inspiration from there and/or took over some of the code to not reinvent the wheel here :) (altho I dunno if the poor precision thing is really better with keynstroke --> at least from a enduser-experience I've never had simliar problems)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point @saintcore. I do get inspired by projects like this. I like keyboard capturing capability it has and I might take a stab at it after I'm done with mouse effect.
I don't know how things work regarding "taking over" some code in the open-source world. I guess some collaboration with the owner (@Phaiax) is needed.
Regarding the small issue I mentioned here, I think that might be solved with help from @Jaex but keynstroke uses WPF so it is slightly different than ShareX which uses Windows Forms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well according to the provided license, it shouldn't be a problem (see https://github.com/Phaiax/Key-n-Stroke?tab=Apache-2.0-1-ov-file#readme ). A good summary of what apache 2.0 license allows us to do with and not is available over at snyk: https://snyk.io/learn/apache-license/
With that said, ofc it would be nice to hear from the original author of keynstroke and his desires beside license thoughts :)