KeyPress event in Lua? - events

is it possible to get users keypress on lua?
fe.
while true do
if keyPress(27)==true then
print("You just pressed ESC")
end
end

Lua is predicated on extreme portability. As such it's based on supplying, essentially, only that which is available in ANSI C in terms of capabilities. (I think the sole exception to that is dynamic linking which is a non-ANSI feature not available on all platforms, but is so useful that they've put it in for many.)
ANSI C doesn't provide keypress functionality so the default Lua library doesn't either.
That being said, the LuaRocks repository might lead you to a library with this capability. For example it could be that ltermbox, found on the LuaRocks page there, has the functionality you need. (You'll probably have to remove the bits you don't want, mind.) There may be other libraries available. Go digging.
Failing that, the whole point of Lua is extensibility. It's an extensible extension language. It's not actually all that hard to hand-roll your own extension that provides the functionality you want.

Not in stock Lua. Probably with an additional library.

There is a binding to getkey() in the NTLua project. You can get some sources from there.
(it just wraps getch())

It seems like you are trying to make a game. For 2D games you might want to consider love2d. It looks a little weird, but it works and it's relatively easy compared to other languages such as C.

First thing's first: if you're using my method of doing this, you need to put the script(s) you use in a LocalScript. Not doing this will cause the key(s) to not show up in the console (F9 to see console).
Alright, now that we know it's in a LocalScript, here's the script:
local player = game.Players.LocalPlayer -- Gets the LocalPlayer
local mouse = player:GetMouse() -- Gets the player's mouse
mouse.KeyDown:connect(function(key) -- Gets mouse, then gets the keyboard
if key:lower() == "e" or key:upper() == "E" then -- Checks for selected key (key:lower = lowercase keys, key:upper = uppercase keys)
print('You pressed e') -- Prints the key pressed
end -- Ends if statement
end) -- Ends function
If you're wanting to signal only one key (lowercase only, or uppercase only) check below.
Lowercase only:
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
mouse.KeyDown:connect(function(key)
if key == "e" then
print('You pressed e')
end
end)
Uppercase only:
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
mouse.KeyDown:connect(function(key)
if key == "E" then
print('You pressed E')
end
end)
Or, if you want to just signal any key in general, you can also do this:
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
mouse.KeyDown:connect(function(key)
print('You pressed '..key)
end)
I hope I helped answer your question.

if keypress=(29)==true then
print("hello")
end

Related

Use datastore more efficiently

I am coding my fist a game with lua on the Roblox Stuido ide. The game works -- sort of--, although I know the code is not great. It's a game for small children in which a number shows on a sign and the player has to go to the platform that matches the number. One of the issues that I have is that I want there to be a GUI that displays the points in big numbers as the leader stats on the top corner are not easy to see. What I want is not just for the player to see their own points this would be somewhat easier, just add a textLabel on the starter player gui with a script like so:
while true do
wait(.1)
script.Parent.Text = game.Players.LocalPlayer.leaderstats.Platforms.Value
end
with the following code too:
game.Players.PlayerAdded:connect(function(player)
local playerKey = "Player_" .. player.UserId
local leaderstats = Instance.new("Folder",player)
leaderstats.Name = "leaderstats"
local Platforms = Instance.new("IntValue", leaderstats)
Platforms.Name = "Platforms"
Platforms.Value = 0
platformCount:SetAsync(player.UserId, 0)
StartGui:FireAllClients(player)
end)
Please take note of the last couple of lines of that block, those are what I came up with. I am not sure how to do it better but I sense they are a botch.
My objective is that each player can see not only their scores updated in real time, but also every other player's. This is what is not fully working. My method is as follows. When a player steps on the desired platform I have this code on a local script
allPlats[k].Eliminated = true
player:WaitForChild("leaderstats"):FindFirstChild("Platforms").Value = player:WaitForChild("leaderstats"):FindFirstChild("Platforms").Value + 1 --increase leaderstats
points = points + 1
numIfScored:InvokeServer(column, row, teamColorReady, points, team)
PlatformDeleted.OnClientEvent:Connect(platformTransparency)
Ignore the lines that don't apply to the question. The important part for this question is that I access the intValue created in the leaderstats and increase it's value by one. I also send a call to the server with a remote function that passes where the platform was, the color of the team etc...
The serverside script then uses these values to perform a number of tasks related to setting the next target and updating the way the platforms look and, crucially, sends the data to a datastore:
function numIfScored.OnServerInvoke(plr, col, row, orignalTeamColor, points, team)
game.Workspace.TargetNumber.Value = getAnddisplayTarget(col, row)
PlatformDeleted:FireAllClients(col, row)
for k, v in pairs(allPlats) do
if v.Column == col and v.Row == row then
v.Part.Transparency = 0
v.Part.Material = "Neon"
v.Part.BrickColor = BrickColor.new(orignalTeamColor)
end
end
platformCount:SetAsync(plr.UserId, points)
end
I then run a separate block of code in the same scrip that is constantly updating the gui by grabbing the points from the datastore:
while wait(.1) do
for _, player in pairs(Players:GetPlayers()) do
local points = platformCount:GetAsync(player.UserId)
UpdateGUI:FireAllClients(player.UserId,points, player.Team)
end
end
I have a localscript that is a child of the text label that displays the scores with the following code:
local function UpdateLabel(plrId, points, team)
if team.Name == "Really red Team" then
game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeam.Text = points
elseif team.Name == "Really blue Team" then
game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeam.Text = points
end
end
StartGui.OnClientEvent:Connect(StartLabel)
This works but is buggy. I play at home with my son an it sort of works, with a bit of lag, but as soon as I try to play with other players, like my friend and his son, the system stops working well. One thing that I know is not good is that if you start playing before another player joins, then that player can't see your progress before they came in. Another problem is that the first player that joins will be seen by players that join later, but as players join that can't see the labels of players that joined before.
Is there a much simpler way to create a gui that updates all the players scores in all the players gui's? Thanks.
I can post full code if needed.
No need for full code. I just needed the sentence "It's in a LocalScript". Even if you're changing the text of the labels in a server script, you're adding the points on a local script which means it'll only change the points for you and not any other player. Instead if you use a RemoteFunction and call on the server to change the points, I'm more than certain it should work.

VB6, Adding an integer to a control name in a for loop

I am currently trying you learn VB6 and came across this issue.
I wanted to loop through a for loop and adding a number to a control name.
Dim I As Integer
For I = 1 To 5
S = CStr(I)
If TextS.Text = "" Then
LabelS.ForeColor = &HFF&
Else
LabelS.ForeColor = &H80000012
End If
Next I
This S needs to be added to Text and Label so the colour will be changed without needing to use 5 If Else statements
I hope you can help me with this.
From your comment below:
What i mean is this: If Text1.text = "" Then I need this 1 to be replaced with the variable I, so the for loop can loop through my 5 textboxes and the same for my Labels.
You can't do that (look up a variable using an expression to create its name) in VB6. (Edit: While that statement is true, it's not true that you can't look up form controls using a name from an expression. See "alternative" below.)
What you can do is make an array of your textboxes, and then index into that array. The dev env even helps you do that: Open your form in the dev env and click the first textbox. Change its name to the name you want the array to have (perhaps TextBoxes). Then click the next textbox and change its name to the same thing (TextBoxes). The dev env will ask you:
(Don't ask me why I have a VM lying around with VB6 on it...)
Click Yes, and then you can rename your other textboxes TextBoxes to add them to the array. Then do the same for your labels.
Then your code should look like this:
For I = TextBoxes.LBound To TextBoxes.UBound
If TextBoxes(I).Text = "" Then
Labels(I).ForeColor = &HFF&
Else
Labels(I).ForeColor = &H80000012
End If
Next
LBound is the lowest index of the control array, UBound is the highest. (You can't use the standard LBound and Ubound that take the array as an argument, because control arrays aren't quite normal arrays.) Note also that there's no need to put I on the Next line, that hasn't been required since VB4 or VB5. You can, though, if you like being explicit.
Just make sure that you have exactly the same number of TextBoxes as Labels. Alternately, you could create a user control that consisted of a label and a textbox, and then have a control array of your user control.
Alternative: : You can use the Controls array to look up a control using a name resulting from an expression, like this:
For I = 1 To 5
If Me.Controls("Text" & I).Text = "" Then
Me.Controls("Label" & I).ForeColor = &HFF&
Else
Me.Controls("Label" & I).ForeColor = &H80000012
End If
Next
This has the advantage of mapping over to a very similar construct in VB.Net, should you migrate at some point.
Side note:
I am currently trying you learn VB6...
(tl;dr - I'd recommend learning something else instead, VB6 is outdated and the dev env hasn't been supported in years.)
VB6's development environment has been discontinued and unsupported for years (since 2008). The runtime is still (I believe) supported because of the sheer number of apps that use it, although the most recent patch seems to be from 2012. But FWIW, you'd get a better return on your study time learning VB.net or C#.Net (or any of several non-Microsoft languages), rather than VB6...

How to program faster, (generate code from a pattern?)

I frequently run into problems that could be solved with automating code writing, but aren't long enough to justify it as tediously entering each piece is faster.
Here is an example:
Putting lists into dictionaries and things like this. Converting A into B.
A
hotdog HD
hamburger HB
hat H
B
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
end
Sure I could come up with something to do this automatically, but it would only make sense if the list was 100+ items long. For a list of 10-20 items, is there a better solution than tediously typing? This is a Ruby example, but I typically run into cases like this all the time. Instead of a case statement, maybe it's a dictionary, maybe it's a list, etc.
My current solution is a python template with the streaming input and output already in place, and I just have to write the parsing and output code. This is pretty good, but is there better? I feel like this would be something VIM macro would excel at, but I'm that experienced with VIM. Can VIM do this easily?
For vim, it'd be a macro running over a list of space separated pairs of words, inserting the first 'when "' bit, the long form word 'hotdog', the ending quote, a newline and 'return "', and then the abbreviation and then final quote, then going back to the list and repeating.
Starting with a register w of:
when "
register r of:
return "
an initial list of:
hotdog HD
hamburger HB
hat H
and a starting file of:
def symbolizeType
case self.type
"newline here"
you can use the following macro at the start of the initial list:
^"ayeeeb"byeo"wp"apa"^Mrb"j
where ^M is a newline.
I do this frequently, and I use a single register and a macro, so I'll share.
Simply pick a register, record your keystrokes, and then replay your keystrokes from the register.
This is a long explanation, but the process is extremely simple and intuitive.
Here are the steps that I would take:
A. The starting text
hotdog HD
hamburger HB
hat H
B. Insert the initial, non-repetitive lines preceding the text to transform
def symbolizeType
case self.type
hotdog HD
hamburger HB
hat H
C. Transform the first line, while recording your keystrokes in a macro
This step I'll write out in detailed sub-steps.
Place the cursor on the first line to transform ("hotdog") and type qa to begin recording your keystrokes as a macro into register a.
Type ^ to move the cursor to the start of the line
Type like you normally would to transform the line to what you want, which for me comes out looking like the following macro
^i^Iwhen "^[ea"^[ldwi^M^Ireturn "^[ea"^[j
Where ^I is Tab, ^[ is Esc, and ^M is Enter.
After the line is transformed to your liking, move your cursor to the next line that you want to transform. You can see this in the macro above with the final j at the end.
This will allow you to automatically repeat the macro while it cycles through each repetitive line.
Stop recording the macro by typing q again.
You can then replay the macro from register a as many times as you like using a standard vim count prefix, in this case two consecutive times starting from the next line to transform.
2#a
This gives the following text
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
D. Finally, insert the ending non-repetitive text
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
end
Final Comments
This works very quick for any random, repetitive text, and I find it very fluent.
Simply pick a register, record your keystrokes, and then replay your keystrokes from the register.
For things like this I have a few ways of making it easier. One is to use an editor like Sublime Text that allows you to multi-edit a number of things at once, so you can throw in markup with a few keystrokes and convert that into a Hash like:
NAME_TO_CODE = {
hotdog: 'HD',
hamburger: 'HB',
hat: 'H'
}
Not really a whole lot changed there. Your function looks like:
def symbolize_type(type)
NAME_TO_CODE[type.to_sym]
end
Defining this as a data structure has the bonus of being able to manipulate it:
CODE_TO_NAME = NAME_TO_CODE.invert
Now you can do this:
def unsymbolize_type(symbol)
CODE_TO_NAME[symbol.to_s]
end
You can also get super lazy and just parse it on the fly:
NAME_TO_CODE = Hash[%w[
hotdog HD
hamburger HB
hat H
].each_slice(2).to_a]
snippets are like the built-in :abbreviate on steroids, usually with parameter insertions, mirroring, and multiple stops inside them. One of the first, very famous (and still widely used) Vim plugins is snipMate (inspired by the TextMate editor); unfortunately, it's not maintained any more; though there is a fork. A modern alternative (that requires Python though) is UltiSnips. There are more, see this list on the Vim Tips Wiki.
There are three things to evaluate: First, the features of the snippet engine itself, second, the quality and breadth of snippets provided by the author or others; third, how easy it is to add new snippets.

What is the best way to get keyboard events (input without press 'enter') in a Ruby console application?

I've been looking for this answer in the internet for a while and have found other people asking the same thing, even here. So this post will be a presentation of my case and a response to the "solutions" that I have found.
I am such new in Ruby, but for learning purposes I decided to create a gem, here.
I am trying to implement a keyboard navigation to this program, that will allow the user use short-cuts to select what kind of request he want to see. And in the future, arrow navigations, etc.
My problem: I can't find a consistent way to get the keyboard events from the user's console with Ruby.
Solutions that I have tried:
Highline gem: Seems do not support this feature anymore. Anyway it uses the STDIN, keep reading.
STDIN.getch: I need to run it in a parallel loop, because at the same time that the user can use a short-cut, more data can be created and the program needs to show it. And well, I display formated text in the console, (Rails log). When this loop is running, my text lost the all the format.
Curses: Cool but I need to set position(x,y) to display my text every time? It will get confusing.
Here is where I am trying to do it.
You may note that I am using "stty -raw echo" (turns raw off) before show my text and "stty raw -echo" (turns raw on) after. That keeps my text formated.
But my key listener loop is not working. I mean, It works in sometimes but is not consistent. If a press a key twice it don't work anymore and sometimes it stops alone too.
Let me put one part of the code here:
def run
# Two loops run in parallel using Threads.
# stream_log loops like a normal stream in the file, but it also parser the text.
# break it into requests and store in #requests_queue.
# stream_parsed_log stream inside the #requests_queue and shows it in the screen.
#requests_queue = Queue.new
#all_requests = Array.new
# It's not working yet.
Thread.new { listen_keyboard }
Thread.new { stream_log }
stream_parsed_log
end
def listen_keyboard
# not finished
loop do
char = STDIN.getch
case char
when 'q'
puts "Exiting."
exit
when 'a'
#types_to_show = ['GET', 'POST', 'PUT', 'DELETE', 'ASSET']
requests_to_show = filter_to_show(#all_requests)
command = true
when 'p'
#types_to_show = ['POST']
requests_to_show = filter_to_show(#all_requests)
command = true
end
clear_screen if command
#requests_queue += requests_to_show if command
command = false
end
end
I need a light in my path, what should I do?
That one was my mistake.
It's just a logic error in another part of code that was running in another thread so the ruby don't shows the error by default. I used ruby -d and realized what was wrong. This mistake was messing my keyboard input.
So now it's fixed and I am using STDIN.getch with no problem.
I just turn the raw mode off before show any string. And everything is ok.
You can check here, or in the gem itself.
That's it.

Remap Capslock Key in Keymando?

Can you remap the CapsLock key in Keymando?
CapsLock is listed as an available key but when I try a test like:
map "<CapsLock-j>" { alert("CapsLock-j") }
... and hit Reload Config in the Keymando menu, I get an error dialog that says:
Error Parsing Keymando Config File
undefined method `ctrl' for nil:NilClass
Is there perhaps an abbreviation of CapsLock? For example, in the available keys, the Control key is just listed as Control but in the example code it is ctrl. Is there a similar abbreviation for CapsLock?
If possible, I would like to use the CapsLock key as a mode key to implement logic like:
if <CapsLock>
map <j>, <Down>
map <k>, <Up>
# ...etc
end
Sorry, that's a mistake on our part listing Capslock on the website. Currently it can only be remapped to Control, Option, or Command via the Keyboard.prefPane under "Modifer Keys.." and there's no way for us right now to detect if it's been pressed.
We'll keep our eyes open for a solution but as of right now it's not going to do what you're wanting. Sorry.
The website has been fixed to avoid any more confusion, as well.
While you can't remap capslock, you can achieve almost the same functionality by adding some basic state to your keymandorc file. I couldn't figure out how to map something to the option key alone, but apart from that, this should do what you are aiming for:
At the top of your keymandorc put:
#caps = false
Then down wherever you define your bindings put something like the following
map "j" do
if #caps then
send("<Down>")
else
send("j")
end
end
map "<Option-v>" do
#caps = !#caps;
alert("Vim Mode: " + #caps.to_s)
end
You could then also bind escape to exit the mode if #caps is true, and so forth.

Resources