├── README.md └── AHKCoordGrid.ahk /README.md: -------------------------------------------------------------------------------- 1 | # AhkCoordGrid 2 | AutoHotkey code for Windows overlay grid allowing you to emulate a mouse left-click at different points on the screen using keyboard shortcuts. 3 | 4 | When you press NumKeyEnter, this script builds then displays a movable 26*26 grid of buttons (actually AHK edit controls), labelled AA-ZZ, overlaying the whole screen. 5 | You can then move the grid using arrow keys, and you can emulate a mouse-click (or a touchscreen 'touch') at any of those 676 locations by entering the coordinates, as displayed on each button, as keyboard shortcuts. 6 | Pressing NumKeyEnter thereafter toggles the grid (it displays much faster after the first time, as it has already been built). 7 | 8 | Inspired by the cVim chrome plugin's 'hints' - shortcut keys to most links / buttons on web pages. 9 | Previously posted on the AutoHotkey forum, and includes code around timing of key presses by the user @scriptor on that forum. 10 | 11 | AhkCoordGrid goes some way towards helping realize WCAG 2.1 Success Criterion 2.1.1, which begins 'All functionality of the content is operable through a keyboard interface ...' 12 | 13 | ## RELEASE HISTORY 14 | 15 | ### 2/2/2019 v1.0 16 | 17 | Initial release. Grid not movable. 18 | 19 | ### 27/11/2019 v2.0 20 | 21 | Grid made movable, thanks to code contributed by SpeedMaster @ www.autohotkey.com/boards -------------------------------------------------------------------------------- /AHKCoordGrid.ahk: -------------------------------------------------------------------------------- 1 | #SingleInstance 2 | DetectHiddenWindows, On 3 | VerticalScale := 1 4 | numberOfRows := 26 5 | numberOfCols := 26 6 | GridHeight := VerticalScale * A_ScreenHeight 7 | GridWidth := A_ScreenWidth 8 | rowSpacing := GridHeight / numberOfRows 9 | colSpacing := 1.025 * GridWidth / numberOfCols 10 | AscA := 97 11 | KeyArray := ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] 12 | 13 | #IfWinNotActive CoordGrid 14 | #IfWinNotExist CoordGrid 15 | global VerticalScale, numberOfRows, numberOfCols, GridHeight, GridWidth, rowSpacing, colSpacing, KeyArray 16 | 17 | NumpadEnter:: 18 | ; Display Coordinates 19 | rowCounter := 0 20 | Loop { 21 | rowYCoord := (numberOfRows - 1 - rowCounter) * rowSpacing ; 22 | rowYCoordAlpha := KeyArray[rowCounter+1] 23 | StringUpper, rowYCoordAlpha, rowYCoordAlpha 24 | colCounter := 0 25 | Loop { 26 | colXCoord := colCounter * colSpacing 27 | colXCoordAlpha := KeyArray[colCounter+1] 28 | StringUpper, colXCoordAlpha, colXCoordAlpha 29 | Gui, Add, Progress, w21 h21 x%colXCoord% y%rowYCoord% BackgroundFFFFFF disabled 30 | gui, add, text, w21 h21 x%colXCoord% y%rowYCoord% border 0x201 readonly backgroundtrans cBlack, %colXCoordAlpha%%rowYCoordAlpha% 31 | colCounter := colCounter + 1 32 | } 33 | Until colCounter = numberOfcols 34 | rowCounter := rowCounter + 1 35 | } 36 | Until rowCounter = numberOfRows 37 | Gui, Color, 000115 38 | Gui, Show, W%GridWidth% H%GridHeight%, CoordGrid 39 | Gui -Caption +AlwaysOnTop 40 | Gui, maximize 41 | WinSet, Transcolor, 000115, CoordGrid 42 | 43 | Return 44 | #IfWinNotExist 45 | #IfWinNotActive 46 | 47 | #IfWinExist CoordGrid 48 | #IfWinNotActive CoordGrid 49 | NumpadEnter:: 50 | winmove , CoordGrid,,0,0 51 | Gui Show 52 | Return 53 | #IfWinNotActive 54 | #IfWinExist 55 | 56 | #IfWinActive CoordGrid 57 | NumpadEnter:: 58 | winmove , CoordGrid,,0,0 59 | Gui Hide 60 | Return 61 | 62 | left:: 63 | WinGetPos , currentposX, currentposY,,, CoordGrid 64 | winmove, CoordGrid,, % currentposX-10 65 | return 66 | right:: 67 | WinGetPos , currentposX, currentposY,,, CoordGrid 68 | winmove, CoordGrid,, % currentposX+10 69 | return 70 | Up:: 71 | WinGetPos , currentposX, currentposY,,, CoordGrid 72 | winmove, CoordGrid,, , % currentposY-10 73 | return 74 | Down:: 75 | WinGetPos , currentposX, currentposY,,, CoordGrid 76 | winmove, CoordGrid,, , % currentposY+10 77 | return 78 | 79 | ~a:: gosub, RunKey 80 | ~b:: gosub, RunKey 81 | ~c:: gosub, RunKey 82 | ~d:: gosub, RunKey 83 | ~e:: gosub, RunKey 84 | ~f:: gosub, RunKey 85 | ~g:: gosub, RunKey 86 | ~h:: gosub, RunKey 87 | ~i:: gosub, RunKey 88 | ~j:: gosub, RunKey 89 | ~k:: gosub, RunKey 90 | ~l:: gosub, RunKey 91 | ~m:: gosub, RunKey 92 | ~n:: gosub, RunKey 93 | ~o:: gosub, RunKey 94 | ~p:: gosub, RunKey 95 | ~q:: gosub, RunKey 96 | ~r:: gosub, RunKey 97 | ~s:: gosub, RunKey 98 | ~t:: gosub, RunKey 99 | ~u:: gosub, RunKey 100 | ~v:: gosub, RunKey 101 | ~w:: gosub, RunKey 102 | ~x:: gosub, RunKey 103 | ~y:: gosub, RunKey 104 | ~z:: gosub, RunKey 105 | 106 | Runkey: 107 | if winc_presses > 0 108 | { 109 | winc_presses += 1 110 | Return 111 | } 112 | winc_presses = 1 113 | SetTimer, TheKey, 1000 114 | Return 115 | 116 | TheKey: 117 | SetTimer, TheKey, off 118 | if winc_presses = 2 119 | { 120 | NavigateToCoord() 121 | } 122 | 123 | winc_presses = 0 124 | Return 125 | 126 | NavigateToCoord() 127 | { 128 | CoordMode, Mouse, Window 129 | global VerticalScale, numberOfRows, numberOfCols, GridHeight, GridWidth, rowSpacing, colSpacing 130 | 131 | XCoordInput := SubStr(A_PriorHotkey,2,1) 132 | YCoordInput := SubStr(A_ThisHotkey,2,1) 133 | XCoordToUse := ConvertInputCoord(XcoordInput, "X") 134 | YCoordToUse := ConvertInputCoord(YcoordInput, "Y") 135 | 136 | XCoord := (XCoordToUse+0.2) * colSpacing 137 | YCoord := (YCoordToUse-0.7) * rowSpacing 138 | 139 | MouseMove, %XCoord%, %YCoord% 140 | sleep, 100 141 | Gui Hide 142 | Click 143 | Return 144 | } 145 | 146 | ConvertInputCoord(coordInput, XorY) 147 | { 148 | global AscA 149 | coordAsc := Asc(coordInput) 150 | if (XorY = "X") { 151 | coordToUse := coordAsc - AscA 152 | } 153 | else { 154 | coordToUse := numberOfRows - (coordAsc - AscA) 155 | } 156 | coordToUse := floor(coordToUse) 157 | Return coordToUse 158 | } 159 | #IfWinActive --------------------------------------------------------------------------------