Mouse and Keyboard Input
Time to make your plugin respond to what players do! This guide covers capturing mouse positions, clicks, and keyboard input.
Mouse Input
Getting Mouse Position
-- InputGetMouseX()
-- Returns the horizontal position of the mouse cursor
local mouseX = InputGetMouseX()
LogPrint("Mouse X: " .. mouseX)
-- InputGetMouseY()
-- Returns the vertical position of the mouse cursor
local mouseY = InputGetMouseY()
LogPrint("Mouse Y: " .. mouseY)
Checking if Mouse is Over an Area
InputCheckMousePos(x, y, w, h)
Parameters:
x, y- Area positionw, h- Area size
Returns: true if mouse is inside the area
local isInside = InputCheckMousePos(100, 100, 200, 50)
if isInside then
LogPrint("Mouse is inside the area!")
end
Example in Render Function
function MyPlugin.renderWindow(window)
UIRenderWindow(window, 0, 0, window.w, window.h, 0)
-- Check if mouse is over a specific button
local buttonX = 20
local buttonY = 50
local buttonW = 100
local buttonH = 30
-- Convert to global coordinates
local globalX = window.x + buttonX
local globalY = window.y + buttonY
if InputCheckMousePos(globalX, globalY, buttonW, buttonH) then
-- Mouse is over the button - highlight it
window:renderColor(buttonX, buttonY, buttonW, buttonH, RGBA(100, 100, 100, 255))
else
-- Mouse is not over the button - normal
window:renderColor(buttonX, buttonY, buttonW, buttonH, RGBA(50, 50, 50, 255))
end
window:renderText("Button", buttonX, buttonY, buttonW, buttonH, 4,
RGBA(255,255,255,255), FontM)
end
Window Hover Check Method
Windows have a convenient method for checking hover with relative coordinates:
window:checkHover(x, y, w, h)
This is the same as InputCheckMousePos but uses coordinates relative to the window.
function MyPlugin.renderWindow(window)
UIRenderWindow(window, 0, 0, window.w, window.h, 0)
-- Check hover more easily
if window:checkHover(20, 50, 100, 30) then
window:renderColor(20, 50, 100, 30, RGBA(100, 100, 100, 255))
else
window:renderColor(20, 50, 100, 30, RGBA(50, 50, 50, 255))
end
end
Keyboard Input
InputCheckKeyPress(index, value)
Parameters:
index- VK code of the key (use VK_* constants)value- Check type:0= Is the key being held down?1= Was the key just pressed this frame?
Returns: true if the condition is met
Examples
-- Check if key is being held
if InputCheckKeyPress(VK_SPACE, 0) then
LogPrint("Space is pressed!")
end
-- Check if key was just pressed (single press)
if InputCheckKeyPress(VK_F1, 1) then
LogPrint("F1 was pressed!")
MyPlugin:toggleWindow()
end
Practical Example - Open Window with Key
function MyPlugin.updateWindow(window)
-- Check F2 key to open/close
if InputCheckKeyPress(VK_F2, 1) then
if window.state == 0 then
window:setState(1)
else
window:setState(0)
end
end
return window.state == 1
end
Virtual Key Constants
Here are all the key codes you can use:
Mouse Buttons
VK_LBUTTON = 1 -- Left mouse button
VK_RBUTTON = 2 -- Right mouse button
VK_MBUTTON = 4 -- Middle mouse button
VK_XBUTTON1 = 5 -- Mouse extra button 1
VK_XBUTTON2 = 6 -- Mouse extra button 2
Special Keys
VK_BACK = 8 -- Backspace
VK_TAB = 9 -- Tab
VK_RETURN = 13 -- Enter
VK_SHIFT = 16 -- Shift
VK_CONTROL = 17 -- Ctrl
VK_MENU = 18 -- Alt
VK_PAUSE = 19 -- Pause
VK_CAPITAL = 20 -- Caps Lock
VK_ESCAPE = 27 -- Esc
VK_SPACE = 32 -- Space
Navigation Keys
VK_PRIOR = 33 -- Page Up
VK_NEXT = 34 -- Page Down
VK_END = 35 -- End
VK_HOME = 36 -- Home
VK_LEFT = 37 -- Left Arrow
VK_UP = 38 -- Up Arrow
VK_RIGHT = 39 -- Right Arrow
VK_DOWN = 40 -- Down Arrow
VK_INSERT = 45 -- Insert
VK_DELETE = 46 -- Delete
Number Keys (Main Keyboard)
VK_0 = 48
VK_1 = 49
VK_2 = 50
VK_3 = 51
VK_4 = 52
VK_5 = 53
VK_6 = 54
VK_7 = 55
VK_8 = 56
VK_9 = 57
Letter Keys (A-Z)
VK_A = 65
VK_B = 66
VK_C = 67
VK_D = 68
VK_E = 69
VK_F = 70
VK_G = 71
VK_H = 72
VK_I = 73
VK_J = 74
VK_K = 75
VK_L = 76
VK_M = 77
VK_N = 78
VK_O = 79
VK_P = 80
VK_Q = 81
VK_R = 82
VK_S = 83
VK_T = 84
VK_U = 85
VK_V = 86
VK_W = 87
VK_X = 88
VK_Y = 89
VK_Z = 90
Windows Keys
VK_LWIN = 91 -- Left Windows key
VK_RWIN = 92 -- Right Windows key
Numpad Keys
VK_NUMPAD0 = 96
VK_NUMPAD1 = 97
VK_NUMPAD2 = 98
VK_NUMPAD3 = 99
VK_NUMPAD4 = 100
VK_NUMPAD5 = 101
VK_NUMPAD6 = 102
VK_NUMPAD7 = 103
VK_NUMPAD8 = 104
VK_NUMPAD9 = 105
VK_MULTIPLY = 106 -- *
VK_ADD = 107 -- +
VK_SUBTRACT = 109 -- -
VK_DECIMAL = 110 -- .
VK_DIVIDE = 111 -- /
Function Keys (F1-F12)
VK_F1 = 112
VK_F2 = 113
VK_F3 = 114
VK_F4 = 115
VK_F5 = 116
VK_F6 = 117
VK_F7 = 118
VK_F8 = 119
VK_F9 = 120
VK_F10 = 121
VK_F11 = 122
VK_F12 = 123
Lock Keys
VK_NUMLOCK = 144 -- Num Lock
VK_SCROLL = 145 -- Scroll Lock
Left/Right Shift
VK_LSHIFT = 160
VK_RSHIFT = 161
Checking if Chat is Open
This is super important! You don't want hotkeys triggering while the player is typing in chat:
InputCheckChatOpen()
Returns: true if chat window is open
function MyPlugin.updateWindow(window)
-- Only process keys if chat is not open
if not InputCheckChatOpen() then
if InputCheckKeyPress(VK_F1, 1) then
window:setState(window.state == 0 and 1 or 0)
end
end
return window.state == 1
end
Complete Example - Hotkey System
Here's a full hotkey manager:
HotkeySystem = {
index = GetWindowIndex(),
group = UI_GROUP_INGAME,
hotkeys = {
{key = VK_F1, name = "Inventory", action = function() LogPrint("Opening inventory") end},
{key = VK_F2, name = "Skills", action = function() LogPrint("Opening skills") end},
{key = VK_F3, name = "Party", action = function() LogPrint("Opening party") end},
{key = VK_F4, name = "Guild", action = function() LogPrint("Opening guild") end},
}
}
function HotkeySystem.renderWindow(window)
UIRenderWindow(window, 0, 0, window.w, window.h, 0)
-- Title
window:renderText("Hotkeys", 0, 10, window.w, 30, 4,
RGBA(255,215,0,255), FontL)
-- List hotkeys
local y = 50
for i, hotkey in ipairs(HotkeySystem.hotkeys) do
-- Key name
local keyName = "F" .. i
window:renderText(keyName, 20, y, 50, 25, 1,
RGBA(255,255,255,255), FontM)
-- Action name
window:renderText(hotkey.name, 80, y, 150, 25, 1,
RGBA(192,192,192,255), FontM)
y = y + 30
end
-- Instructions
window:renderText("Press ESC to close", 0, window.h-30, window.w, 25, 4,
RGBA(150,150,150,255), FontS)
end
function HotkeySystem.updateWindow(window)
-- Don't process input if chat is open
if InputCheckChatOpen() then
return window.state == 1
end
-- Check each hotkey
for i, hotkey in ipairs(HotkeySystem.hotkeys) do
if InputCheckKeyPress(hotkey.key, 1) then
hotkey.action()
end
end
-- ESC to close
if InputCheckKeyPress(VK_ESCAPE, 1) and window.state == 1 then
window:setState(0)
end
-- F12 to open/close hotkey menu
if InputCheckKeyPress(VK_F12, 1) then
window:setState(window.state == 0 and 1 or 0)
end
return window.state == 1
end
Example - Custom Movement Control
MovementDemo = {
index = GetWindowIndex(),
group = UI_GROUP_INGAME,
playerX = 200,
playerY = 200,
speed = 5,
}
function MovementDemo.renderWindow(window)
UIRenderWindow(window, 0, 0, window.w, window.h, 0)
-- Title
window:renderText("Movement Demo", 0, 10, window.w, 30, 4,
RGBA(255,255,255,255), FontL)
-- Game area
window:renderColor(20, 50, window.w-40, window.h-70, RGBA(30,30,30,255))
-- Player (red circle)
window:renderColor(
MovementDemo.playerX - 5,
MovementDemo.playerY - 5,
10, 10,
RGBA(255, 0, 0, 255)
)
-- Instructions
window:renderText("Use WASD to move", 20, window.h-25, window.w-40, 20, 4,
RGBA(200,200,200,255), FontS)
end
function MovementDemo.updateWindow(window)
if window.state == 0 then
return false
end
-- Don't process if chat is open
if InputCheckChatOpen() then
return true
end
-- Movement controls (hold key)
if InputCheckKeyPress(VK_W, 0) then
MovementDemo.playerY = MovementDemo.playerY - MovementDemo.speed
end
if InputCheckKeyPress(VK_S, 0) then
MovementDemo.playerY = MovementDemo.playerY + MovementDemo.speed
end
if InputCheckKeyPress(VK_A, 0) then
MovementDemo.playerX = MovementDemo.playerX - MovementDemo.speed
end
if InputCheckKeyPress(VK_D, 0) then
MovementDemo.playerX = MovementDemo.playerX + MovementDemo.speed
end
-- Limit movement to game area
local minX = 25
local maxX = window.w - 45
local minY = 55
local maxY = window.h - 75
if MovementDemo.playerX < minX then MovementDemo.playerX = minX end
if MovementDemo.playerX > maxX then MovementDemo.playerX = maxX end
if MovementDemo.playerY < minY then MovementDemo.playerY = minY end
if MovementDemo.playerY > maxY then MovementDemo.playerY = maxY end
return true
end
Example - Key Combinations
KeyComboDemo = {
index = GetWindowIndex(),
group = UI_GROUP_INGAME,
}
function KeyComboDemo.updateWindow(window)
if window.state == 0 then
return false
end
if InputCheckChatOpen() then
return true
end
-- Ctrl + S to save
if InputCheckKeyPress(VK_CONTROL, 0) and InputCheckKeyPress(VK_S, 1) then
NoticeSend(1, "Saving...")
end
-- Ctrl + Shift + D for debug
if InputCheckKeyPress(VK_CONTROL, 0) and
InputCheckKeyPress(VK_SHIFT, 0) and
InputCheckKeyPress(VK_D, 1) then
NoticeSend(1, "Debug mode activated!")
end
-- Alt + F4 to close (example, not recommended)
if InputCheckKeyPress(VK_MENU, 0) and InputCheckKeyPress(VK_F4, 1) then
window:setState(0)
NoticeSend(1, "Closing window...")
end
return true
end
Best Practices
-
ALWAYS check InputCheckChatOpen() before processing hotkeys - Prevents keys from triggering while typing in chat
-
Use value=1 for single actions (open menu, activate skill) - Prevents multiple activations while key is held
-
Use value=0 for continuous actions (movement, holding button) - Detects key being held down
-
Check modifiers first when using key combinations - Always check Ctrl, Shift, Alt with value=0, then the action key with value=1
-
Consider game conflicts - Some keys might already be used by the game client - Test your hotkeys
-
Performance matters - InputCheckKeyPress is fast, but don't check hundreds of keys - Only check the keys you actually need
That's input handling! Now you can make plugins that respond to player actions.