StrokesPlus.net
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
Anthony  
#1 Posted : Tuesday, October 27, 2020 11:57:20 PM(UTC)
Anthony

Rank: Newbie

Reputation:

Groups: Approved
Joined: 10/27/2020(UTC)
Posts: 6
Germany

Hi,

I just recently moved away from strokeit 0.9.7(~) to Strokesplus.net and am totally flashed by the possibilities.
However, right now I would not even know where to start to sort it out besides learning JavaScript and .NET.
Combined with strokeit I used an AHK based tool called KDE Mover Sizer, quite helpful to move a window or resize it.
However, over time MS Windows updates resulted in a weird behaviour of the button logic (from KDE Mover Sizer).

How did I use it with some tweaking?
-> Right Button + Left Button 'pressed' enabled WindowsMovement for the window underneath the mouse (without actually having to move the mouse to the titlebar...)
-> Right + Middle Button 'pressed' enabled WindowsResizing for the window underneath the mouse (without actually having to move the mouse to the lower right corner)
Yes, laziness ftw in order "not" to move more fingers than necessary and keep other keys on the keyboard available for other shortcuts and actions..

Problems started with an often but not always locked RightButtonClick, either requiring a second press to unlock it or worst case killing the process after using the commands described above.
Worked fine until Windows 7, even Windows 8, but with Windows 10 things started to fall apart.

So, long story short, I am trying to figure out how I can achieve the functionality described above "as part of Strokeplus.net".
Still, I'm not looking for someone who throws everything at me, I would just need some hints which tail to follow.
The existing forum entries are not really helpful on so far (at least not to me) in order to pick something up and fiddle around with it.
To be fair, the first function would be far more helpful than the second, but in combination they come pretty sweet...

Any hint welcome,
regards,...

Anthony

Rob  
#2 Posted : Wednesday, October 28, 2020 7:20:50 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
Hi Anthony and welcome!

So fortunately I just created a similar script a couple days ago for region-based window resizing using the Alt key.

I made some changes for your use case, please read the script comments for button sequence, as it is not exactly the same, but is very close and I feel should be acceptable.

I'll make this post for the resize, and another reply for the mover. Note that these both need to utilize the Mouse Events tab to handle the Left/Middle button release and the Capture Modifiers After setting in the action.
The reason for this is that capturing modifiers after the stroke button is pressed means the Left/Middle button down event is captured and consumed by S+, so the app doesn't see it happen.
In Chrome, it would start doing the middle button page scroll function, for example. So these scripts are designed for the least possible negative impact. It can be done in just the action script only, but you cannot do capture After (which absorbs the down event) and look to see if the button is still down...since S+ consumed it, Windows doesn't report the button as being held down. Hopefully this makes some sense!

Resize Window By Region:

Global Actions > Mouse Events > Middle Click (Script, do not check Consume Click Event)
Code:
//Only do this on middle button release
// ! means NOT, so if the click event is NOT down 
//(can only be Down or NOT Down [Up/Release]
if(!click.Down) 
{
        //Clean up variables and stop the timer script
        sp.DeleteStoredPoint("ResizeLastCursorPos");
        sp.DeleteStoredObject("ResizeStartRegion");
        sp.DeleteStoredObject("ResizeWindow");
        sp.DeleteTimer("ResizeWindowTimer"); 
        sp.DeleteStoredBool("ResizeActive");
}


New Action - No Gesture, Middle Button modifier checked, Capture Modifiers: After
Code:
/*
This resizes the window based on a 3x3 grid, which determines how the window
will be resized based on where the mouse was within the window when the action started

Set action's Modifier as Middle Button, Capture Modifiers: After

You MUST begin holding the Middle button down AFTER pressing the stroke (right) button!

Sequence:
  1. Stroke (right) button down 
  2. Middle button down (hold)
  3. (optional draw gesture)
  4. Stroke (right) button release
  5. Move mouse to resize
  6. Release middle button 

*/

//Don't do anything if the window is maximized
if(!action.Window.Maximized) 
{
    //Get the region (from a 3x3 grid) where the action started and store that for use in the timer script
    sp.StoreObject("ResizeStartRegion", sp.GetRegionFromPoint(action.Window.Rectangle, action.Start, 3, 3));
    //Store the mouse location where the action ended (will be same as action.Start if no gesture)
    sp.StorePoint("ResizeLastCursorPos", action.End);
    //Store the reference to the window below the mouse where the action started
    sp.StoreObject("ResizeWindow", action.Window);

    //Create timer, ticks every 50ms until Middle is not being held down,
    //which is handled in the Global Actions > Mouse Events > Middle Click tab

    //NOTE the end of this line is a backtick, encompassing nearly everything below
    sp.CreateTimer("ResizeWindowTimer", 50, 50, `
    
            //Only do this if there isn't an active timer tick handling a resize
            if(!sp.GetStoredBool("ResizeActive"))
            {
                //Signal so timer doesn't start concurrent resizing
                sp.StoreBool("ResizeActive", true);

                var startRegion = sp.GetStoredObject("ResizeStartRegion"); 
                var lastPoint = sp.GetStoredPoint("ResizeLastCursorPos"); 
                var currentPoint = sp.GetCurrentMousePoint();
                var resizeTarget = sp.GetStoredObject("ResizeWindow");
                var currentRect = resizeTarget.Rectangle;
                var newRect = new Rectangle(currentRect.Location, currentRect.Size)
                var xDiff = lastPoint.X - currentPoint.X;
                var yDiff = lastPoint.Y - currentPoint.Y;

                //Only do this next set of logic if the mouse has moved
                if(xDiff !== 0 || yDiff !== 0)
                {
                    if(startRegion.Row === 1)
                    {
                        //Top row --------------------------------

                        if(startRegion.Column === 1)
                        {
                            //Top left 
                            newRect.Location = new Point(currentRect.X - xDiff, currentRect.Y - yDiff);
                            newRect.Width = currentRect.Width + xDiff;
                            newRect.Height = currentRect.Height + yDiff;
                        }
                        else if(startRegion.Column === 2)
                        {
                            //Top center
                            newRect.Location = new Point(currentRect.X, currentRect.Y - yDiff);
                            newRect.Height = currentRect.Height + yDiff;
                        }
                        else if(startRegion.Column === 3)
                        {
                            //Top right
                            newRect.Location = new Point(currentRect.X, currentRect.Y - yDiff);
                            newRect.Width = currentRect.Width - xDiff;
                            newRect.Height = currentRect.Height + yDiff;
                        }
                    }
                    else if(startRegion.Row === 2)
                    {
                        //Center row --------------------------------

                        if(startRegion.Column === 1)
                        {
                            //Center left 
                            newRect.Location = new Point(currentRect.X - xDiff, currentRect.Y);
                            newRect.Width = currentRect.Width + xDiff;
                        }
                        else if(startRegion.Column === 2)
                        {
                            //Center - Scale? Up/Down & Left/Right
                            newRect.Location = new Point(currentRect.X + parseInt(xDiff / 2), currentRect.Y - parseInt(yDiff / 2));
                            newRect.Width = currentRect.Width - xDiff;
                            newRect.Height = currentRect.Height + yDiff;
                        }
                        else if(startRegion.Column === 3)
                        {
                            //Center right
                            newRect.Width = currentRect.Width - xDiff;
                        }
                    }
                    else if(startRegion.Row === 3)
                    {
                        //Bottom row --------------------------------

                        if(startRegion.Column === 1)
                        {
                            //Bottom left 
                            newRect.Location = new Point(currentRect.X - xDiff, currentRect.Y);
                            newRect.Width = currentRect.Width + xDiff;
                            newRect.Height = currentRect.Height - yDiff;
                        }
                        else if(startRegion.Column === 2)
                        {
                            //Bottom center
                            newRect.Height = currentRect.Height - yDiff;
                        }
                        else if(startRegion.Column === 3)
                        {
                            //Bottom right
                            newRect.Width = currentRect.Width - xDiff;
                            newRect.Height = currentRect.Height - yDiff;
                        }
                    }

                    //Assign window size to new rectangle
                    resizeTarget.Rectangle = newRect;

                    //Store current mouse point as last location
                    sp.StorePoint("ResizeLastCursorPos", currentPoint);
                }
                //Allow next timer tick to process resizing
                sp.StoreBool("ResizeActive", false);
            }

    `);  //End of Timer script parameter
}

Edited by user Wednesday, October 28, 2020 2:34:24 PM(UTC)  | Reason: Not specified

Rob  
#3 Posted : Wednesday, October 28, 2020 7:23:51 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
Move Window

Global Actions > Mouse Events > Left Click (Script, do not check Consume Click Event)
Code:
//Only do this on left button release
// ! means NOT, so if the click event is NOT down 
//(can only be Down or NOT Down [Up/Release]
if(!click.Down) 
{
        //Clean up variables and stop the timer script
        sp.DeleteStoredPoint("MoveLastCursorPos");
        sp.DeleteStoredObject("MoveWindow");
        sp.DeleteTimer("MoveWindowTimer"); 
        sp.DeleteStoredBool("MoveActive");
}


New Action - No Gesture, Left Button modifier checked, Capture Modifiers: After
Code:
/*
Set action's Modifier as Left Button, Capture Modifiers: After

You MUST begin holding the Left button down AFTER pressing the stroke (right) button!

Sequence:
  1. Stroke (right) button down 
  2. Left button down (hold)
  3. (optional draw gesture)
  4. Stroke (right) button release
  5. Move mouse to move window
  6. Release left button 

*/

//Don't do anything if the window is maximized
if(!action.Window.Maximized) 
{
    sp.StorePoint("MoveLastCursorPos", action.End);
    sp.StoreObject("MoveWindow", action.Window);

    //Create timer, ticks every 50ms until Left is not being held down,
    //which is handled in the Global Actions > Mouse Events > Left Click tab

    //NOTE the end of this line is a backtick, encompassing nearly everything below
    sp.CreateTimer("MoveWindowTimer", 50, 50, `
    
            //Only do this if there isn't an active timer tick handling a move sequence
            if(!sp.GetStoredBool("MoveActive"))
            {
                //Signal so timer doesn't start concurrent moving events
                sp.StoreBool("MoveActive", true);

                var lastPoint = sp.GetStoredPoint("MoveLastCursorPos"); 
                var currentPoint = sp.GetCurrentMousePoint();
                var moveTarget = sp.GetStoredObject("MoveWindow");
                var currentLocation = moveTarget.Location;
                var newLocation = new Point(currentLocation.X, currentLocation.Y);
                var xDiff = lastPoint.X - currentPoint.X;
                var yDiff = lastPoint.Y - currentPoint.Y;

                //Only do this next set of logic if the mouse has moved
                if(xDiff !== 0 || yDiff !== 0)
                {
                    //Adjust the new location based on the X/Y difference since last event
                    newLocation.X -= xDiff;
                    newLocation.Y -= yDiff;

                    //Assign window position to new location
                    moveTarget.Location = newLocation;

                    //Store current mouse point as last location
                    sp.StorePoint("MoveLastCursorPos", currentPoint);
                }
                //Allow next timer tick to process moving
                sp.StoreBool("MoveActive", false);
            }

    `);  //End of Timer script parameter
}

Edited by user Wednesday, October 28, 2020 2:32:34 PM(UTC)  | Reason: Not specified

Rob  
#4 Posted : Wednesday, October 28, 2020 7:33:03 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
These also assume you're using the right button as your main stroke button, and that Middle isn't selected as the secondary stroke button.

These can be adjusted to accommodate those scenarios if needed, you would just need to use Global Actions > Mouse Events > Release and check the button being released in the script.

Let me know if you need any help with that, or if you have any other questions!

Quote:
I'm not looking for someone who throws everything at me, I would just need some hints which tail to follow.

I know this is basically "throwing it all at you", but honestly I find it's nice to learn by reading comments and examining logic (with comments as I've added). You get what you need so you're not frustrated, and can understand how the objective was achieved.

Also, feel free to join the Discord server, it's really easy to ask questions in real-time and I can give you tips or snippets. I'm U.S. based (Eastern/New York time zone) and am usually always around M-F 8AM - 5PM - don't ask my why I'm awake at 3:30 AM posting... Blink
Rob  
#5 Posted : Wednesday, October 28, 2020 7:55:00 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
Note that these could be more smooth/fluid by creating a plug-in which utilized more low-level Windows API calls instead of using timer scripts.

But that's a bit more complicated and isn't something I can quickly put together as I can using timer scripts.
Anthony  
#6 Posted : Wednesday, October 28, 2020 11:42:37 AM(UTC)
Anthony

Rank: Newbie

Reputation:

Groups: Approved
Joined: 10/27/2020(UTC)
Posts: 6
Germany

Wow.
A simple "thx" does not even match my gratitude by far!

Being awake at that time ... I'm located in Germany, so I'm ~6 hours ahead, "filed my request" somewhere in the morning and tried fixing the AHK thingy afterwards until 3am whatsoever ;)
Or the other way around, can't recall really =D

I'll sure be having some fun with this!
Awesome!

Edited by user Wednesday, October 28, 2020 11:46:52 AM(UTC)  | Reason: Not specified

Anthony  
#7 Posted : Thursday, October 29, 2020 12:14:46 AM(UTC)
Anthony

Rank: Newbie

Reputation:

Groups: Approved
Joined: 10/27/2020(UTC)
Posts: 6
Germany

Hi there,

played around with it, don't get all the syntax, but I did not expect to get everything within one hour of looking at it :)

I got everything running (reading helps, missed to unpress the right button out of old habit), tweaked the timer for a smoother performance, however, even when narrowing it down only to the move script (with no timer changes), every now and then I received an error after the executed move:

Script execution failed.

TypeError: Cannot read property 'X' of undefined
at Script: 13:61 -> var newLocation = new
Point(currentLocation.X, currentLocation.Y);

No idea if that's racing condition kicking in or something else.

Happened probably somewhere between 15 and 10% off all attempts.
I wasn't able to nail it down to a specific movement or tempo, so no further insights on how to reproduce this.

No other "mouse movement" tools were running, so no intercept from that side.
Using a Logitech wireless mouse, no energy saving active or similar.
So, for now, I'd still go for a rare condition.

Fun fact, one could set up to let the action stick with the mouse by doing a double left click (down, raise, down, raise),
requiring another full "process" cycle to get out of the trap again. Same for the ResizeAction with the MiddleButton - as it behaves the same. Note: I was "not" able to make a similar error appear with the ResizeAction. But can't tell if that's a coincidence.

Ok, so much for the update, open for remarks on what I may be doing wrong to stumble into this error message.
Note: V8Debugging was enabled.

Thx!
Rob  
#8 Posted : Thursday, October 29, 2020 5:16:08 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
Yes, it's a race condition.

The script is executing while you've released the button. In the release script, it's deleting the variables - and the timer script is trying to perform logic against the variables which are now null.

Probably easiest to just wrap the logic in a try/catch to ignore any errors like that (since we know it works).

Code:
/*
Set action's Modifier as Left Button, Capture Modifiers: After

You MUST begin holding the Left button down AFTER pressing the stroke (right) button!

Sequence:
  1. Stroke (right) button down 
  2. Left button down (hold)
  3. (optional draw gesture)
  4. Stroke (right) button release
  5. Move mouse to move window
  6. Release left button 

*/

//Don't do anything if the window is maximized
if(!action.Window.Maximized) 
{
    sp.StorePoint("MoveLastCursorPos", action.End);
    sp.StoreObject("MoveWindow", action.Window);

    //Create timer, ticks every 50ms until Left is not being held down,
    //which is handled in the Global Actions > Mouse Events > Left Click tab

    //NOTE the end of this line is a backtick, encompassing nearly everything below
    sp.CreateTimer("MoveWindowTimer", 50, 50, `
    
            //Only do this if there isn't an active timer tick handling a move sequence
            if(!sp.GetStoredBool("MoveActive"))
            {
                //Signal so timer doesn't start concurrent moving events
                sp.StoreBool("MoveActive", true);

                try
                {
                    var lastPoint = sp.GetStoredPoint("MoveLastCursorPos"); 
                    var currentPoint = sp.GetCurrentMousePoint();
                    var moveTarget = sp.GetStoredObject("MoveWindow");
                    var currentLocation = moveTarget.Location;
                    var newLocation = new Point(currentLocation.X, currentLocation.Y);
                    var xDiff = lastPoint.X - currentPoint.X;
                    var yDiff = lastPoint.Y - currentPoint.Y;

                    //Only do this next set of logic if the mouse has moved
                    if(xDiff !== 0 || yDiff !== 0)
                    {
                        //Adjust the new location based on the X/Y difference since last event
                        newLocation.X -= xDiff;
                        newLocation.Y -= yDiff;

                        //Assign window position to new location
                        moveTarget.Location = newLocation;

                        //Store current mouse point as last location
                        sp.StorePoint("MoveLastCursorPos", currentPoint);
                    }
                } 
                catch (err) 
                { 
                    //Do nothing, but for other scripts, you might want to use the catch
                    //e.g. sp.MessageBox("Error: " + err.message, "Catch"); 
                }
                //Allow next timer tick to process moving
                sp.StoreBool("MoveActive", false);
            }

    `);  //End of Timer script parameter
}

Edited by user Thursday, October 29, 2020 5:28:30 AM(UTC)  | Reason: Not specified

Rob  
#9 Posted : Thursday, October 29, 2020 5:37:01 AM(UTC)
Rob

Rank: Administration

Reputation:

Groups: Translators, Members, Administrators
Joined: 1/11/2018(UTC)
Posts: 1,349
United States
Location: Tampa, FL

Thanks: 28 times
Was thanked: 416 time(s) in 354 post(s)
In the release script, you could do something like this instead to wait for the timer script to finish and prevent it from restarting on the next tick. Just to demonstrate different logic methods - I think the try/catch is better (post above) as I feel like there's still a chance for a race condition, albeit less likely.

Code:
//Only do this on left button release
// ! means NOT, so if the click event is NOT down 
//(can only be Down or NOT Down [Up/Release]
if(!click.Down) 
{
        //Wait for timer tick to finish (empty loop)
        while (sp.GetStoredBool("MoveActive")) {}

        //Signal so timer doesn't start processing
        sp.StoreBool("MoveActive", true);

        //Clean up variables and stop the timer script
        sp.DeleteStoredPoint("MoveLastCursorPos");
        sp.DeleteStoredObject("MoveWindow");
        sp.DeleteTimer("MoveWindowTimer"); 
        sp.DeleteStoredBool("MoveActive");
}

Edited by user Thursday, October 29, 2020 5:57:48 AM(UTC)  | Reason: Not specified

Anthony  
#10 Posted : Friday, October 30, 2020 11:18:36 PM(UTC)
Anthony

Rank: Newbie

Reputation:

Groups: Approved
Joined: 10/27/2020(UTC)
Posts: 6
Germany

... in short, that worked as expected :)
And from a reading point of view I also now get what's happening.
So next step would be to probably learn a bit of the dialect so that besides reading speaking or writing might be an option :)

Edited by user Friday, October 30, 2020 11:25:59 PM(UTC)  | Reason: Not specified

petercncn  
#11 Posted : Saturday, November 21, 2020 4:53:45 PM(UTC)
petercncn

Rank: Member

Reputation:

Groups: Approved
Joined: 11/4/2020(UTC)
Posts: 12
China

I think you can combine the size changer and window mover in only one action. Saying using Right then Left button ( then right button up), move left button to somewhere, then left button up. When the beginning position of left button (also the same of the right button) pressed down is in the middle grid of a window (based on 3x3 grid ), move the windows, and when in the other grids, change the size of the window.
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.