-- Garry's Mod Binder - Keybinds Tab (Virtual Keyboard) local PANEL = {} local KEY_LAYOUT = { {"ESC", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"}, {"~", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "BKSP"}, {"TAB", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\"}, {"CAPS", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "ENTER"}, {"SHIFT", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "SHIFT"}, {"CTRL", "WIN", "ALT", "SPACE", "ALT", "WIN", "MENU"} } local KEY_SPECIAL = { {"PRSC", "SCRLK", "PAUSE"}, {"INS", "HOME", "PGUP"}, {"DEL", "END", "PGDN"}, {"↑"}, {"←", "↓", "→"} } local NUM_PAD = { {"NUM", "/", "*", "-"}, {"7", "8", "9", "+"}, {"4", "5", "6"}, {"1", "2", "3", "ENT"}, {"0", "."} } local STRING_TO_KEY = { ["ESC"] = KEY_ESCAPE, ["~"] = KEY_TILDE, ["-"] = KEY_MINUS, ["="] = KEY_EQUAL, ["BKSP"] = KEY_BACKSPACE, ["TAB"] = KEY_TAB, ["["] = KEY_LBRACKET, ["]"] = KEY_RBRACKET, ["\\"] = KEY_BACKSLASH, ["CAPS"] = KEY_CAPSLOCK, [";"] = KEY_SEMICOLON, ["'"] = KEY_APOSTROPHE, ["ENTER"] = KEY_ENTER, ["SHIFT"] = KEY_LSHIFT, [","] = KEY_COMMA, ["."] = KEY_PERIOD, ["/"] = KEY_SLASH, ["CTRL"] = KEY_LCONTROL, ["WIN"] = KEY_LWIN, ["ALT"] = KEY_LALT, ["SPACE"] = KEY_SPACE, ["MENU"] = KEY_APP, ["PRSC"] = KEY_SYSRQ, ["SCRLK"] = KEY_SCROLLLOCK, ["PAUSE"] = KEY_BREAK, ["INS"] = KEY_INSERT, ["HOME"] = KEY_HOME, ["PGUP"] = KEY_PAGEUP, ["DEL"] = KEY_DELETE, ["END"] = KEY_END, ["PGDN"] = KEY_PAGEDOWN, ["↑"] = KEY_UP, ["←"] = KEY_LEFT, ["↓"] = KEY_DOWN, ["→"] = KEY_RIGHT, ["NUM"] = KEY_NUMLOCK, ["/"] = KEY_PAD_DIVIDE, ["*"] = KEY_PAD_MULTIPLY, ["-"] = KEY_PAD_MINUS, ["+"] = KEY_PAD_PLUS, ["ENT"] = KEY_PAD_ENTER, ["."] = KEY_PAD_DECIMAL, ["1"] = KEY_1, ["2"] = KEY_2, ["3"] = KEY_3, ["4"] = KEY_4, ["5"] = KEY_5, ["6"] = KEY_6, ["7"] = KEY_7, ["8"] = KEY_8, ["9"] = KEY_9, ["0"] = KEY_0, } -- Add letters and F-keys for i = 1, 26 do STRING_TO_KEY[string.char(64 + i)] = _G["KEY_" .. string.char(64 + i)] end for i = 1, 12 do STRING_TO_KEY["F" .. i] = _G["KEY_F" .. i] end function PANEL:Init() self:Dock(FILL) self:DockMargin(20, 20, 20, 20) self.Paint = function() end self.InfoBar = vgui.Create("DPanel", self) self.InfoBar:Dock(TOP) self.InfoBar:SetHeight(40) self.InfoBar.Paint = function(s, w, h) draw.RoundedBox(0, 0, 0, w, h, Color(255, 255, 255, 5)) local activeProf = self:GetActiveProfile() local name = activeProf and activeProf.Name or "No Active Profile" local bindCount = activeProf and table.Count(activeProf.Binds or {}) or 0 draw.SimpleText(name, "Binder_Main", 50, h / 2, Color(255, 255, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) draw.SimpleText(Binder.GetPhrase("binds_count", bindCount), "Binder_Small", w - 20, h / 2, Color(255, 255, 255, 100), TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) end self.KeyboardContainer = vgui.Create("DPanel", self) self.KeyboardContainer:Dock(FILL) self.KeyboardContainer:DockMargin(0, 40, 0, 0) self.KeyboardContainer.Paint = function() end self.KeyButtons = {} self:BuildKeyboard() self:Refresh() end function PANEL:GetActiveProfile() for _, p in ipairs(Binder.Profiles or {}) do if p.Active then return p end end return nil end function PANEL:Refresh() local profile = self:GetActiveProfile() local binds = profile and profile.Binds or {} for _, btnData in ipairs(self.KeyButtons) do local isBound = binds[btnData.enum] != nil btnData.btn.IsActiveNode = isBound end end function PANEL:PromptBind(keyStr, keyEnum) local profile = self:GetActiveProfile() if not profile then return end local currentCmd = profile.Binds[keyEnum] or "" Derma_StringRequest( "Bind " .. keyStr, "Enter console command to execute on press (e.g., 'say /raid'):\nLeave blank to unbind.", currentCmd, function(text) if text == "" then profile.Binds[keyEnum] = nil else profile.Binds[keyEnum] = text end Binder.SaveToServer() self:Refresh() end ) end function PANEL:CreateKey(parent, text, x, y, w, h) local btn = vgui.Create("DButton", parent) btn:SetSize(w or 35, h or 35) btn:SetPos(x, y) btn:SetText("") btn.IsActiveNode = false local keyEnum = STRING_TO_KEY[text] btn.Paint = function(s, bw, bh) local bgColor = s.IsActiveNode and Binder.Config.AccentColor or Color(40, 40, 40) if s:IsHovered() then bgColor = Color(bgColor.r + 20, bgColor.g + 20, bgColor.b + 20) end draw.RoundedBox(4, 0, 0, bw, bh, bgColor) draw.SimpleText(text, "Binder_Key", bw / 2, bh / 2, Color(255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end btn.DoClick = function() if keyEnum then self:PromptBind(text, keyEnum) else print("Binder: Unmapped key - " .. text) end end table.insert(self.KeyButtons, {btn = btn, sysName = text, enum = keyEnum}) end function PANEL:BuildKeyboard() local startX, startY = 10, 10 local keySize = 38 local spacing = 4 -- Main Block for r, row in ipairs(KEY_LAYOUT) do local rx = startX local ry = startY + (r - 1) * (keySize + spacing) -- Adjustments if r == 1 then ry = ry - 5 end for k, key in ipairs(row) do local kw = keySize if key == "BKSP" then kw = keySize * 2 + spacing elseif key == "TAB" then kw = keySize * 1.5 elseif key == "CAPS" then kw = keySize * 1.8 elseif key == "ENTER" then kw = keySize * 1.8 elseif key == "SHIFT" then kw = keySize * 2.3 elseif key == "SPACE" then kw = keySize * 5 + spacing * 4 elseif key == "CTRL" or key == "ALT" or key == "WIN" then kw = keySize * 1.2 end self:CreateKey(self.KeyboardContainer, key, rx, ry, kw, keySize) rx = rx + kw + spacing end end -- Special Keys Block local specX = startX + 15 * (keySize + spacing) for r, row in ipairs(KEY_SPECIAL) do local rx = specX local ry = startY + (r - 1) * (keySize + spacing) if r == 4 then rx = rx + keySize + spacing end for k, key in ipairs(row) do self:CreateKey(self.KeyboardContainer, key, rx, ry, keySize, keySize) rx = rx + keySize + spacing end end -- Num Pad local numX = specX + 4 * (keySize + spacing) for r, row in ipairs(NUM_PAD) do local rx = numX local ry = startY + (r - 1) * (keySize + spacing) for k, key in ipairs(row) do local kh = keySize if key == "+" or key == "ENT" then kh = keySize * 2 + spacing end local kw = keySize if key == "0" then kw = keySize * 2 + spacing end self:CreateKey(self.KeyboardContainer, key, rx, ry, kw, kh) rx = rx + kw + spacing end end end vgui.Register("Binder_KeybindsTab", PANEL, "EditablePanel")