Awesome WM (v3.5.5) keygrabber alternative - lua

I've never liked the default window switching possibilities in Awesome, so I thought I'd implement Alt-Tab behavior that takes history into account (and does fancy opacity effects).
When Alt-Tab is pressed, the entire history is recorded in a table, and appended to that history are the minimized windows (within the same tag). When this table is generated, I instantiate a keygrabber that captures Tab-press events (to switch to the next client in the table) and Alt-release events (to abort entirely).
A flag keeps track of whether the user is in the process of Alt-tabbing, to prevent the table from being generated over and over again.
The code (it's a lot and you probably don't need to see it, but my experience tells me that when I don't post all the code, people will ask for it eventually):
altTabbing = false
altTabIndex = 1
altTabHistory = {}
clientOpacities = {}
function altTabSetOpacities(restore)
for i,c in pairs(altTabHistory) do
if not restore and i ~= altTabIndex then
c.opacity = 0.5
else
c.opacity = clientOpacities[i]
end
end
end
function myAltTab()
-- First check if the user is already alttabbing, in which case the history
-- should NOT be updated. If the user has just pressed alt-tab, generate a new
-- history-table
if not altTabbing then -- generate history-table
-- Clear Tables
for i in pairs(altTabHistory) do altTabHistory[i] = nil end
for i in pairs(clientOpacities) do clientOpacities[i] = nil end
-- Get focus history for current tag
local s = mouse.screen;
local idx = 0
local c = awful.client.focus.history.get(s, idx)
while c do
table.insert(altTabHistory, c)
table.insert(clientOpacities, c.opacity)
idx = idx + 1
c = awful.client.focus.history.get(s, idx)
end
-- Minimized clients will not appear in the focus history
-- Find them by cycling through all clients, and adding them to the list
-- if not already there.
-- This will preserve the history AND enable you to focus on minimized clients
local t = awful.tag.selected(s)
local all = client.get(s)
for i = 1, #all do
local c = all[i]
local ctags = c:tags();
-- check if the client is on the current tag
local isCurrentTag = false
for j = 1, #ctags do
if t == ctags[j] then
isCurrentTag = true
break
end
end
if isCurrentTag then
-- check if client is already in the history
-- if not, add it
local addToHistory = true
for k = 1, #altTabHistory do
if altTabHistory[k] == c then
addToHistory = false
break
end
end
if addToHistory then
table.insert(altTabHistory, c)
table.insert(clientOpacities, c.opacity)
end
end
end
-- reset current index and flag
altTabIndex = 1
altTabbing = true
-- Now that we have collected all windows, we should run a keygrabber
-- as long as the user is alt-tabbing:
keygrabber.run(
function (mod, key, event)
-- Stop alt-tabbing when the alt-key is released
if key == "Alt_L" and event == "release" then
altTabbing = false
altTabSetOpacities(true)
c = altTabHistory[altTabIndex]
client.focus = c
c:raise()
return false -- stop keygrabber
end
-- Move to next client on each Tab-press
if key == "Tab" and event == "press" then
myAltTab()
return true -- keep going
end
return true -- keep going
end
)
end -- if not altTabbing
-- at this point, the user is alt-tabbing, so we should raise
-- the next client in the history-table
if #altTabHistory < 2 then return end
-- Switch to next client
altTabIndex = altTabIndex + 1
if altTabIndex > #altTabHistory then
altTabIndex = 1 -- wrap around
end
-- focus on current client
local c = altTabHistory[altTabIndex]
c.minimized = false
c:raise()
-- make current client stand out
altTabSetOpacities(false)
end
I realize there's a lot of code, but the main thing is the keygrabber. For still unknown reasons, Awesome sometimes crashes while I'm Alt-Tabbing using this approach. I want to replace the keygrabber by connecting signals to the Alt and Tab keys, and disconnecting them as soon as the user is done. However, I'm not able to do this for some reason.
I instantiate a new key-object like this:
local altkey = awful.key({}, "Alt_L")[1]
I found out by trial and error that awful.key() actually returns a table of which I could query the first element for key, keysym etc, hence the [1]. However, when I try to connect a signal to this object, the LUA interpreter complains and tells me it's a nil object. So my question is: am I doing the right thing here? Is it even possible to replace the keygrabber in the way I intend to?

To use the Alt_L key in Awesome you should refer to "Mod1" in your rc.lua file, to make it mor readable I added the following line to the beginning of my configuration so Alt_L can be used.
Alt_L = "Mod1"

Related

Why do keep getting this error, I'm trying to turn a character invisible when the function runs

local camera = workspace.CurrentCamera
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local startergui = game:GetService("StarterGui")
local char = Players.LocalPlayer.Character
local model = workspace.OceanVillagedr201["Wine Cellar"].WineDigitalkeypad
local screen = model.screen
local replicated_storage = game:GetService("ReplicatedStorage")
local CheckCode = Instance.new("RemoteEvent")
CheckCode.Name = "CheckWineCellarCodeEvent"
CheckCode.Parent = replicated_storage
local function Entercode(player)
Players.LocalPlayer.Character.Humanoid.RootPart.Anchored = true
for _,p in pairs(char:GetChildren()) do
p.Transparency = 1
end
game.StarterGui = replicated_storage.EnterWineCellarCode
end
screen.ProximityPrompt.Triggered:Connect(function(player)
Entercode()
end)
Im attempting to create a function that triggers when the proximity prompt is triggered, One piece of this Entercode() function is to toggle the playermodel's Transparency from 0 to 1 and Remove the Characters ability to move.
local function Entercode(player)
print("went")
Players.LocalPlayer.Character.Humanoid.RootPart.Anchored = true
for _,p in pairs(char:GetChildren()) do
p.Transparency = 1
end
But Im having trouble with this Piece. It keeps telling me "attempt to index nil" with anything dealing with trying to reference the Characters model. (FFC(), GetChildren(), Player.LocalPlayer.Character, etc.). I am using a local script because I plan to create a Remote Function for the result of EnterCode()
I believe your problem is that the character either was not spawned at the time of making char or is an old character (player respawned & a new character was made). A quick fix would be to redeclare char inside Entercode:
local function Entercode()
char = player.Character
char.Humanoid.RootPart.Anchored = true
for _, p in pairs(char:GetChildren()) do
if p:IsA("BasePart") then
p.Transparency = 1
end
end
replicated_storage.EnterWineCellarCode.Parent = player.PlayerGui
end
There were also a number of other errors, here are a few changes I made:
local function Entercode()
In the original code, player was a parameter but was not sent as an argument Good thing you set the player variable at the beginning of the code.
if p:IsA("BasePart") then
p.Transparency = 1
end
In the original code, you didn't check to see if p was a part or not.
replicated_storage.EnterWineCellarCode.Parent = player.PlayerGui
In the original code, you tried to set StarterGui to EnterWineCellarCode? I don't know what you were going for but I'm assuming you meant to parent EnterWineCellarCode to PlayerGui
Lastly, you might want to use GetDescendants() instead of GetChildren(). To better understand how the character works I recommend you read the wiki entry for it

Why does my list clear/lose its contents? [ROBLOX]

local sounds = {
877986525;
2734549871;
}
local PrimaryQueue = {} -- Player Chosen Songs.
local SoundObj = workspace.MusicSystem
function PlaySoundAndWait(SoundId)
SoundObj.SoundId = "rbxassetid://"..SoundId
print("Loading Sound...")
repeat wait() until SoundObj.IsLoaded
print("Loaded")
SoundObj:Play()
repeat wait() until not SoundObj.Playing -- Wait till over.
end
local PlaySecondary = sounds
while wait(0.1) do
if #PrimaryQueue ~= 0 then
print("Play primary disregard current")
-- Play primary, disregard current.
PlaySoundAndWait(PrimaryQueue[1])
table.remove(PrimaryQueue,1) -- Remove from queue (played)
else
-- Refill Secondary Queue if empty.
if #PlaySecondary == 0 then
print("REFILL")
PlaySecondary = sounds
print(#sounds)
continue
end
print(PlaySecondary[1])
PlaySoundAndWait(PlaySecondary[1])
table.remove(PlaySecondary,1)
end
end
When I refer to "REFILL" I mean line 26 where the list is refreshed.
This script indefinitely checks if there's anything in the PrimaryQueue, if there is it plays that then removes it. If there's not it checks if the SecondaryQueue is empty, if so it refills it with "sounds". If it's not it plays the first sound then removes it.
As a result all of this should create a music system, but for some reason when refilling, the sound list reads as empty. Even though it shouldn't be and has only been assigned a value once.
Thank you.
You are doing table.remove(PlaySecondary, 1) which is equal to table.remove(sounds, 1) as they both point to the same table due to PlaySecondary = sounds, so it's coming back empty because you yourself removed all its elements previously!
I assume you wanted to create a copy of the table:
PlaySecondary = {unpack(sounds)}

Attemp to call a nil value (field ‘ShowInventory’) [ESX2]

I just installed ESX 2 into my new server, im Really new at lua and i dont really know what i should do with some resources or how to start coding
I wan to work in the inventory system based on es_extended, but, it doesnt work.
I press the Inventory Key informed in the cofig file \server-data\resources\es_extended\config\default\config.lua
“Config.InventoryKey = “REPLAY_START_STOP_RECORDING_SECONDARY” – Key F2 by default”
module.InitESX = function()
module.RegisterControl(module.Groups.MOVE, module.Controls[Config.InventoryKey])
module.On('released', module.Groups.MOVE, module.Controls[Config.InventoryKey], function(lastPressed)
print("Comment before show The Inventory")
ESX.ShowInventory()
-- if Menu.IsOpen ~= nil then
-- if (not ESX.IsDead) and (not Menu.IsOpen('default', 'es_extended', 'inventory')) then
-- ESX.ShowInventory()
-- end
-- end
end)
end
I literally change a little bit the code to directly execute the ShowInventory() Function but i got this error
the original code look like this
module.InitESX = function()
module.RegisterControl(module.Groups.MOVE, module.Controls[Config.InventoryKey])
module.On('released', module.Groups.MOVE, module.Controls[Config.InventoryKey], function(lastPressed)
if Menu.IsOpen ~= nil then
if (not ESX.IsDead) and (not Menu.IsOpen('default', 'es_extended', 'inventory')) then
ESX.ShowInventory()
end
end
end)
end
but when i press the key dont do nothing and doesnt show anything in the console.

How do i make a warn command for my bot using DISCORDIA(LUA)

How can i make a warn command in discordia?
i have tried this but the .json returns as null(no error) in cmd, ive been trying for ages i just cant figure out the problem:
elseif args[1]:lower():sub(3, #".warn") == ".warn" then
local wopen = io.open("warns.json", "r")
local wparse = json.parse(wopen:read("*a"))
wopen:close()
if args[2] then
local mentioned_user = message.mentionedUsers.first
local mentioned_member = message.guild:getMember(mentioned_user)
local mentioned = message.guild:getMember(mentioned_member)
if mentioned ~= nil then
if args[3] then
table.remove(args, 1) --// removes command and mention arguments
local reason = table.concat(args) --// turns remaining contents of the table into one long string value
if wparse[mentioned.id] then --// checks if the mentioned user exists in the database
wparse[mentioned.id] = wparse[mentioned.id] + 1 --// big brain math (if the user already exists, add 1 to their warnings)
message:reply(mentioned.username.." has been warned because: "..reason..". They now have "..wparse[mentioned.id].." warnings.")
else --// if they mentioned user doesn't exist, we should add them to it
wparse[mentioned.id] = 1 --// if they don't exist, add them to the database and set their warnings to 1
message:reply(mentioned.username.." has been warned because: "..reason..". They now have 1 warning.")
end
end
end
else
message:reply("Provide a member to warn.")
end
wopen = io.open("warns.json", "w")
wopen:write(json.stringify(wparse))
wopen:close()
guessing your :sub() command is wrong.
it begins at position three, but then ends at length of ".warn" which is 5
so :sub(3, 5) will never return anything that will never == ".warn"
at best, it might give you ".wa"
you need to add three to the second arg in your sub()
:sub(3, #".warn" +3) == ".warn"

Remote event problems

I'm making a game using ROBLOX about the tank battle system of Dragon Quest Heroes Rocket Slime (although not using 100% GUI's)
Since I didn't know how to make ammo become locked onto a path in normal ROBLOX, I decided to use a gui to show the ammo "firing"
To do this, I have a remote event that fires a function inside the main script of the GUI system when ammo is loaded
cannon.Touched:connect(function(v)
if fireable[v.Name] and v.Parent == workspace then
event:FireAllClients("Left",v.Name)
v:Destroy()
end
end)
Then, the GUI gets the correct sprite for the ammo loaded and fires it out of the right tank (the first argument in the FireAllClients part)
This is one of the two if statements for firing ammo (the other one is literally the same except that it's for the right side tank)
local tank = tankFiring == "Left" and tank1 or tankFiring == "Right" and tank2
if tank == tank1 then
print("yo!")
script.Fire:Play()
local ammoFrame = sp.Ammo:Clone()
ammoFrame.Parent = tank
ammoFrame.Visible = true
ammoFrame.Position = UDim2.new(0,120,0,68)
playAnimation("Cannon Fire",UDim2.new(0,120,0,68-25),tank.Frame)
ammoFrame.Image = ammoTypes[type]["img"]
ammoFrame.Size = ammoTypes[type]["Size"]
repeat
wait(.1)
ammoFrame.Rotation = ammoTypes[type]["Rotatable"] == true and ammoFrame.Rotation + 15 or 0
ammoFrame.Position = ammoFrame.Position + UDim2.new(0,1,0,0)
until
tank2:FindFirstChild("Ammo") and isTouching(ammoFrame,tank2:GetChildren()[3]) or isTouching(ammoFrame,tank2) or ammoFrame == nil
if tank2:FindFirstChild("Ammo") and isTouching(ammoFrame,tank2:GetChildren()[3]) then
script.Collision:Play()
local lastAmmoPos = ammoFrame.Position
playAnimation("Explosion",lastAmmoPos-UDim2.new(0,15,0,25),tank.Frame)
ammoFrame:Destroy()
tank2:GetChildren()[3]:Destroy()
end
if isTouching(ammoFrame,tank2) then
script.Collision:Play()
ammoFrame:Destroy()
workspace["Tank2"].Health.Value = workspace["Tank2"].Health.Value - ammoTypes[type]["dmg"]
end
end
The problem with this, is that if a player joins AFTER the ammo has been shot, they will not see the ammo on the GUI
Is there anyway to fix this? I can't just FireAllClients again, since that'll just fire another piece of ammo for all the players.
Have a service that keeps track of what ammo is in what state. Then all clients first asks the servers of current ammo states when joining, and then subscribes to further changes.

Resources