AutoHotKey solution for moving the caret using arrow keys

In Rhino 8 for Windows the arrow keys default to adjusting the viewpoint camera. I wanted a way for the arrow keys to instead adjust the caret (text insertion point) when typing in a command or complicated coordinates. I have programmed an AutoHotKey script which utilizes the Ctrl modifier to mouse click at the appropriate coordinates to move the caret position. In order for this to work, you need to have a fixed width font for the command field. I chose Lucida Console which has a character width of 7 and line height of 12.

Below is my code for the AHK script using “Lucida Console” as the command field font.

Enjoy! If you have any questions, feel free to ask.

Looks nice. I suppose this is also dependent on how you have your Rhino on screen and at what resolutions, since you have hard-coded click locations.

So people who want to utilize your AHK script should adjust those values to be in line with their setups.

I checked this and it seems to work the same on different resolutions on my machine. I do believe that if people have a different layout than me, however, adjustments will need to be made.

You can use the code below to find the coordinates on alternative layouts. The hardcoding is fairly easy to understand. If there is interest, I can create a script with variables I can put in the preamble (basically, you need 5 values, the line height and width of the fixed width command font, the y coordinate of the command field, and the x coordinates of the leftmost and rightmost positions of the command field.

F5::
{
if(!CaretGetPos(&OutputVarX, &OutputVarY))
{
MouseClick “left”, 1341, 141
Sleep 100
CaretGetPos(&OutputVarX, &OutputVarY)
}
MsgBox OutputVarX . “,” . OutputVarY

I took your advice. Here is the newest version of the script. I am using F20-F23 instead of the Ctrl-Arrow keys because I have them mapped.

#Requires AutoHotkey v2.0

*F20::
{
if(WinActive(“ahk_exe rhino.exe”))
{
Try ControlGetPos &OutX, &OutY, &OutWidth, &OutHeight, “RICHEDIT50W1”, “A”
if(!isSet(OutX) || !isSet(OutY) || !isSet(OutWidth) || !isSet(OutHeight))
{
Click 0, -12
return
}
EditFieldLBound := OutX+69
EditFieldRBound := OutX+OutWidth-21
EditFieldYPos := OutY+OutHeight+1
MouseGetPos(&MouseX, &MouseY, &MouseWin, &MouseControl)
if(CaretGetPos(&OutputVarX, &OutputVarY))
{
if(OutputVarY=EditFieldYPos)
{
if(OutputVarX>EditFieldLBound)
{
Click OutputVarX-7, OutputVarY
MouseMove MouseX, MouseY
}
}
else
{
Send “{Left}”
}
}
else
{
Click EditFieldRBound, EditFieldYPos
MouseMove MouseX, MouseY
}
}
else
{
Send “{Left}”
}
}

*F21::
{
if(WinActive(“ahk_exe rhino.exe”))
{
Try ControlGetPos &OutX, &OutY, &OutWidth, &OutHeight, “RICHEDIT50W1”, “A”
if(!isSet(OutX) || !isSet(OutY) || !isSet(OutWidth) || !isSet(OutHeight))
{
Click 0, -12
return
}
EditFieldLBound := OutX+69
EditFieldRBound := OutX+OutWidth-21
EditFieldYPos := OutY+OutHeight+1
MouseGetPos &MouseX, &MouseY, &MouseWin, &MouseControl
if(CaretGetPos(&OutputVarX, &OutputVarY))
{
if(OutputVarY=EditFieldYPos)
{
Click OutputVarX+7, OutputVarY
MouseMove MouseX, MouseY
}
else
{
Send “{Right}”
}
}
else
{
Click EditFieldRBound, EditFieldYPos
MouseMove MouseX, MouseY
}
}
else
{
Send “{Right}”
}
}

*F22::
{
if(WinActive(“ahk_exe rhino.exe”))
{
Try ControlGetPos &OutX, &OutY, &OutWidth, &OutHeight, “RICHEDIT50W1”, “A”
if(!isSet(OutX) || !isSet(OutY) || !isSet(OutWidth) || !isSet(OutHeight))
{
Click 0, -12
return
}
EditFieldLBound := OutX+69
EditFieldRBound := OutX+OutWidth-21
EditFieldYPos := OutY+OutHeight+1
MouseGetPos &MouseX, &MouseY, &MouseWin, &MouseControl
if(CaretGetPos(&OutputVarX, &OutputVarY))
{
if(OutputVarY>OutY && OutputVarY<=EditFieldYPos)
{
Click OutputVarX, OutputVarY-12
MouseMove MouseX, MouseY
}
else
{
Send “{Up}”
}
}
else
{
Click EditFieldRBound, EditFieldYPos
MouseMove MouseX, MouseY
}
}
else
{
Send “{Up}”
}
}

*F23::
{
if(WinActive(“ahk_exe rhino.exe”))
{
Try ControlGetPos &OutX, &OutY, &OutWidth, &OutHeight, “RICHEDIT50W1”, “A”
if(!isSet(OutX) || !isSet(OutY) || !isSet(OutWidth) || !isSet(OutHeight))
{
Click 0, -12
return
}
EditFieldLBound := OutX+69
EditFieldRBound := OutX+OutWidth-21
EditFieldYPos := OutY+OutHeight+1
MouseGetPos &MouseX, &MouseY, &MouseWin, &MouseControl
if(CaretGetPos(&OutputVarX, &OutputVarY))
{
if(OutputVarY>=OutY && OutputVarY<EditFieldYPos)
{
Click OutputVarX, OutputVarY+12
Sleep 100
CaretGetPos(&OutputVarX2, &OutputVarY2)
if(OutputVarY2=OutputVarY)
{
if(OutputVarX<EditFieldLBound)
{
Click EditFieldLBound,EditFieldYPos
}
else
{
Click OutputVarX,EditFieldYPos
}
}
MouseMove MouseX, MouseY
}
else if(OutputVarY=EditFieldYPos)
{
}
else
{
Send “{Down}”
}
}
else
{
Click EditFieldRBound, EditFieldYPos
MouseMove MouseX, MouseY
}
}
else
{
Send “{Down}”
}
}