I have Microsoft Quick BASIC 4.5 running on a DOS 5.0 computer.
I have been able to PEEK the memory to see when special keyboard keys like Num Lock, Caps Lock, Insert, and others are pressed:
DEF SEG = 0
x = PEEK(&H418)
Print x
When I print x I get the following values for the following keys:
Right Shift = 1
Left Shift = 2
Ctrl = 4
Alt = 8
Scroll Lock = 16
Num Lock = 32
Caps Lock = 64
Insert = 128
But what memory segment (DEF SEG) and memory address PEEK(?) do I use to "see" when the A key, or B key, or number key, or any other key is pressed?
I'm not sure there is a location to check for those keys. You might be able to use inkey$ for that. Together with Peek($h418) you should be able to get the current keypresses.
Related
I am trying to collect the participants' responses (i.e., the first key they press on the keyboard) and their reaction time (i.e., the time elapsed since the presentation of a picture and the response). I am using the KbQueueXXX functions in Psychtoolbox, but I am not sure if I am using them properly.
Thanks for your help.
Dear Psychtoolbox users,
I wrote a script to run a 2AFC task where participants must respond within a fixed deadline of 2 seconds. If participants respond earlier, then they move to the subsequent trial straight away. To collect their responses (i.e., the first key they pressed and their RT), I coded a custom function that incorporates KbQueueCheck(). I am now reviewing and debugging my script but I have some doubts about the KbQueueXXX functions. I would be grateful if you could give me some feedback.
Task script
In a mixture of code and pseudocode, here is what I am doing.
KbQueueCreate(KEYBOARD, KEYS_OF_INTEREST);
KbQueueStart(KEYBOARD);
% TRIALS' LOOP STARTS
for iTrial = 1:nTrials
KbQueueFlush(KEYBOARD);
% show stimulus and record its onset and offset times
respDeadline = stimulusOffset + 2;
collectResponse(KEYBOARD, respDeadline, stimulusOnset); % <- KbQueueCheck() here!
end
% TRIALS' LOOP ENDS
KbQueueStop(KEYBOARD);
KbQueueRelease(KEYBOARD);
Custom function
Below is my custom function collectResponse() where I embedded KbQueueCheck().
function [choice, rt, choiceTime, firstPress, keyCodes, pressed] = collectResponse(deviceIndex, untilTime, targetOnset)
%% LOOK FOR KEYPRESSES
pressed = false;
while pressed == false && GetSecs <= untilTime
[pressed, firstPress] = KbQueueCheck(deviceIndex);
end
%% PROCESS KEYPRESSES
if pressed == false % NO KEYS WERE PRESSED
keyCodes = NaN;
firstPress = NaN;
choiceTime = NaN;
choice = NaN;
rt = NaN;
else % ONE OR MORE KEYS WERE PRESSED
keyCodes = find(firstPress > 0); % all keypresses
choiceTime = min(firstPress(keyCodes)); % ts of first keypress
choice = find(firstPress == choiceTime); % first keypress
if length(choice) > 1
% handle simultaneous keypresses
choice = -999;
end
rt = choiceTime - targetOnset; % reaction time
end
end
My questions
I am not sure whether I am calling KbQueueXXX functions correctly and whether they are in the expected position.
Shall I keep KbQueueCreate()/KbQueueStart() and KbQueueStop()/KbQueueRelease() respectively before and after the trials’ loop?
Shall I rather just KbQueueStart(), KbQueueCheck(), and KbQueueStop() at each trial iteratively?
Is it OK to KbQueueFlush() at the beginning of each trial, before the presentation of a new stimulus?
Is my custom function collectResponse() fit for the purpose I described at the top of this post?
Thank you very much for your time, I look forward to knowing your thoughts.
Kind regards,
Valerio
OS: Windows 10
MATLAB: 9.10.0.1851785 (R2021a) Update 6
PTB: 3.0.18 - Flavor: beta - Corresponds to SVN Revision 13009
The original post can be found in the Psychtoolbox forum.
KbQueueXXX functions: which to use and where do they go in relation to the trials' loop?
I use readkey command twice.
It works fine on the first time but refuses to work in the second one.
I'd like that program waits for my key press but the program ends itself.
code:
program window1;
uses crt;
var x,y:integer;
begin
clrscr;
window(1,1,80,25);
readkey;
//writting just window borders
for x:=1 to 80 do
for y:=1 to 25 do
begin
if (x >= 2) and (x <= 79) and
(y >= 2) and (y <= 24) then
continue
else
begin
gotoxy(x,y);
write('*');
end;
end;
gotoxy(2,23);
write('inside window press any key to exit...');
readkey;
//readln;
end.
I've pressed the up arrow key.
I've pressed the up arrow key
Some keys on a keyboard generates what is called extended keys. The arrow keys (among others) are such keys. They return two characters, not one. The first character is ASCII 0 and the second is the scan code of the pressed key.
For ReadKey it is documented:
ReadKey reads 1 key from the keyboard buffer, and returns this. If an extended or function key has been pressed, then the zero ASCII code is returned. You can then read the scan code of the key with a second ReadKey call.
I could add to that, that ReadKey waits for input if the keyboard buffer is empty (but only if it is empty).
Therefore, when your program calls ReadKey for the first time, and you hit the "up arrow key", two bytes are put into the buffer, $00 and $48. The first one ($00) is returned to your code, and the scan code for the up arrow remains in the input buffer. When you then later call ReadKey a second time it receives the scan code from the buffer and continues immediately without stopping for input.
You can deal with this in one of two ways:
1.Write a procedure, say WaitForAnyKey that deals with the extended keys:
procedure WaitForAnyKey;
var
c: char;
begin
c:=ReadKey;
if c=#0 then
c:=ReadKey;
end;
and you call it instead of calling ReadKey directly.
2.Write a procedure that waits for, and accepts a specific key only:
procedure WaitForCR; // wait for CR, Carriage Return (Enter)
const
CR=#13;
var
c: Char;
begin
repeat
c:=ReadKey;
until c=CR;
end
and you call it instead of calling ReadKey directly.
In C#, it was written like this:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.Shift && e.KeyCode == Keys.P)
{
MessageBox.Show("Hello");
}
}
Capturing Ctrl + Shift + P key stroke in a C# Windows Forms application [duplicate]
I tried to emulate the way they wrote it in C# to Delphi XE8 but it doesn't seemed to work:
procedure TForm12.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if (GetKeyState(VK_CONTROL) < 0) and (Key = 53) then
ShowMessage('You pressed "ctrl + s"');
end;
Note: The TForm.KeyPreview Troperty is set to true
How can I capture that combination key event?
The key you are looking for, S, has code $53. The key you specified has code 53 and is the number 5. The difference is the $ which signifies hexadecimal.
You'd avoid such silly mistakes, and make the code much clearer, if you let the compiler do the work:
Key = ord('S')
You really don't want to use magic constants in your program. That is very important.
Note that Key is a virtual key code and the convention is that for the 26 keys of the Latin alphabet, they are represented by the ordinal value of the uppercase letter.
The message already passes the state of the modifier keys in the Shift argument, so it is idiomatic to write the test as follows:
if (ssCtrl in Shift) and (Key = ord('S')) then
Your test using GetKeyState does work well, but it's just not idiomatic.
Note that this test, which matches that in the question will, ignores the state of the other modifier keys. Indeed, the C# code in the question also ignores the state of the ALT modifier.
So you may want a true test for CTRL + S you must also check that the other modifiers are up:
if ([ssCtrl] = Shift*[ssCtrl, ssShift, ssAlt]) and (Key = ord('S')) then
All this said, it's usually much easier to manage your shortcuts using actions. This will allow you to specify shortcuts directly, and let the framework detect the low level key events that make up a shortcut. What's more actions allow you to centralise handling of the actions behind buttons and menus without you repeating yourself.
You can use actions to automate shortcuts. Drop in a TActionManager and add a TAction to it. On that action, assign a Name, Caption, and an OnExecute event handler, and most importantly a value for ShortCut. This can be a string representing the keystrokes, in your case Ctrl+Shift+P. Then, you can either assign that action to various controls, or call it like MyAction.Execute.
In Delphi you use the Shift: TShiftState to check which 'shift'-keys are pressed.
As pointed out in comments your error is that the key value for letter s is not decimal 53, but hexadecimal 53, iow $53in Delphi syntax.
I first thought you also wanted to check for the shift key as in the referenced source of your inspiration, in which case you can test for the exclusive combination as follows:
procedure TForm15.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Key = $53) and ([ssCtrl, ssShift] = Shift) then
begin
ShowMessage('You pressed "ctrl + shift + s"');
Key := 0; // optional
end;
end;
You may or may not want to clear the Key parameter to prevent further action by the control with focus.
Rereading your question after another comment, you seem to want to detect only the Ctrl + s combination, in which case the exclusive condition test becomes
if (Key = $53) and ([ssCtrl] = Shift) then
I recommed to be precise (exclusive) in the shift state test, because the shift state includes not only the Shift, Ctrland Alt keys but also mouse buttons and some gestures.
The documentation on TShiftState provides other possible values of Shift to check for.
Finally, as #David Heffernan points out in his answer, instead of a magic constant ($53) for the key test, use Ord('S').
I am receiving some data which is parsed in a Ruby script, a sample of the parsed data looks like this;
{"address":"00","data":"FF"}
{"address":"01","data":"00"}
That data relates to the status (on/off) of plant items (Fans, coolers, heaters etc.) the address is a HEX number to tell you which set of bits the data refers to. So in the example above the lookup table would be; Both of these values are received as HEX as in this example.
Bit1 Bit2 Bit3 Bit4 Bit5 Bit6 Bit7 Bit8
Address 00: Fan1 Fan2 Fan3 Fan4 Cool1 Cool2 Cool3 Heat1
Address 01: Hum1 Hum2 Fan5 Fan6 Heat2 Heat3 Cool4 Cool5
16 Addresses per block (This example is 00-0F)
Data: FF tells me that all items in Address 00 are set on (high/1) I then need to output the result of the lookup for each individual bit e.g
{"element":"FAN1","data":{"type":"STAT","state":"1"}}
{"element":"FAN2","data":{"type":"STAT","state":"1"}}
{"element":"FAN3","data":{"type":"STAT","state":"1"}}
{"element":"FAN4","data":{"type":"STAT","state":"1"}}
{"element":"COOL1","data":{"type":"STAT","state":"1"}}
{"element":"COOL2","data":{"type":"STAT","state":"1"}}
{"element":"COOL3","data":{"type":"STAT","state":"1"}}
{"element":"HEAT1","data":{"type":"STAT","state":"1"}}
A lookup table could be anything up to 2048 bits (though I don't have anything that size in use at the moment - this is maximum I'd need to scale to)
The data field is the status of the all 8 bits per address, some may be on some may be off and this updates every time my source pushes new data at me.
I'm looking for a way to do this in code ideally for the lay-person as I'm still very new to doing much with Ruby. There was a code example here, but it was not used in the end and has been removed from the question so as not to confuse.
Based on the example below I've used the following code to make some progress. (note this integrates with an existing script all of which is not shown here. Nor is the lookup table shown as its quite big now.)
data = [feeder]
data.each do |str|
hash = JSON.parse(str)
address = hash["address"]
number = hash["data"].to_i(16)
binary_str = sprintf("%0.8b", number)
binary_str.reverse.each_char.with_index do |char, i|
break if i+1 > max_binary_digits
mouse = {"element"=>+table[address][i], "data"=>{"type"=>'STAT', "state"=>char}}
mousetrap = JSON.generate(mouse)
puts mousetrap
end
end
This gives me an output of {"element":"COOL1","data":{"type":"STAT","state":"0"}} etc... which in turn gives the correct output via my node.js script.
I have a new problem/query having got this to work and captured a whole bunch of data from last night & this morning. It appears that now I've built my lookup table I need some of the results to be modified based on the result of the lookup. I have other sensors which need to generate a different output to feed my SVG for example;
FAN objects need to output {"element":"FAN1","data":{"type":"STAT","state":"1"}}
DOOR objects need to output {"element":"DOOR1","data":{"type":"LAT","state":"1"}}
SWIPE objects need to output {"element":"SWIPE6","data":{"type":"ROUTE","state":"1"}}
ALARM objects need to output {"element":"PIR1","data":{"type":"PIR","state":"0"}}
This is due to the way the SVG deals with updating - I'm not in a position to modify the DOM stuff so would need to fix this in my Ruby script.
So to address this what I ended up doing was making an exact copy of my existing lookup table and rather than listing the devices I listed the type of output like so;
Address 00: STAT STAT STAT ROUTE ROUTE LAT LAT PIR
Address 01: PIR PIR STAT ROUTE ROUTE LAT LAT PIR
This might be very dirty (and it also means I have to duplicate my lookup table, but it actually might be better for my specific needs as devices within the dataset could have any name (I have no control over the received data) Having built a new lookup table I modified the code I had been provided with below and already used for the original lookup but I had to remove these 2 lines. Without removing them I was getting the result of the lookup output 8 times!
binary_str.reverse.each_char.with_index do |char, i|
break if i+1 > max_binary_digits
The final array was built using the following;
mouse = {"element"=>+table[address][i], "data"=>{"type"=>typetable[address][i], "state"=>char}}
mousetrap = JSON.generate(mouse)
puts mousetrap
This gave me exactly the output I require and was able to integrate with both the existing script, node.js websocket & mongodb 'state' database (which is read on initial load)
There is one last thing I'd like to try and do with this code, when certain element states are set to 1 I'd like to be able to look something else up (and then use that result) I'm thinking this may be best done with a find query to my MongoDB and then just use the result. Doing that would hit the db for every query, but there would only ever be a handful or results so most things would return null which is fine. Am I along the right method of thinking?
require 'json'
table = {
"00" => ["Fan1", "Fan2", "Fan3"],
"01" => ["Hum1", "Hum2", "Fan5"],
}
max_binary_digits = table.first[1].size
data = [
%Q[{"address": "00","data":"FF"}],
%Q[{"address": "01","data":"00"}],
%Q[{"address": "01","data":"03"}],
]
data.each do |str|
hash = JSON.parse(str)
address = hash["address"]
number = hash["data"].to_i(16)
binary_str = sprintf("%0.8b", number)
p binary_str
binary_str.reverse.each_char.with_index do |char, i|
break if i+1 > max_binary_digits
puts %Q[{"element":#{table[address][i]},"data":{"type":"STAT","state":"#{char}"}}}]
end
puts "-" * 20
end
--output:--
"11111111"
{"element":Fan1,"data":{"type":"STAT","state":"1"}}}
{"element":Fan2,"data":{"type":"STAT","state":"1"}}}
{"element":Fan3,"data":{"type":"STAT","state":"1"}}}
--------------------
"00000000"
{"element":Hum1,"data":{"type":"STAT","state":"0"}}}
{"element":Hum2,"data":{"type":"STAT","state":"0"}}}
{"element":Fan5,"data":{"type":"STAT","state":"0"}}}
--------------------
"00000011"
{"element":Hum1,"data":{"type":"STAT","state":"1"}}}
{"element":Hum2,"data":{"type":"STAT","state":"1"}}}
{"element":Fan5,"data":{"type":"STAT","state":"0"}}}
--------------------
My answer assumes Bit1 in your table is the least significant bit, if that is not the case remove .reverse in the code.
You can ask me anything you want about the code.
The "how to sort a table in Lua" question isn't new, but the answers I found can't help me out, maybe you can.
I got this Table:
table = {} -- some kind of database
table[1] = {table.containing.table.with.even.more.tables.inside}
table[9] = {table.containing.table.with.even.more.tables.inside}
table[13] = {table.containing.table.with.even.more.tables.inside}
table[15] = {table.containing.table.with.even.more.tables.inside}
table[45] = {table.containing.table.with.even.more.tables.inside}
table[3254] = {table.containing.table.with.even.more.tables.inside}
Now I want to iterate through "table", check for an specified boolean it contains and if so, run a method with parameters from some subtabels.
for key, value in pairs(table) do
print(key)
end
Is something like:
9 13 1 3254 45 15
As far as I know, that's because Lua iterates through hashvalues(right?).
My Idea was:
sorted_table = {} -- shall point to table, with sorted keys
for i = 0, #table do -- from 0 to the last key of table (some write #table is the last key, some write it's the number of contained keys, I don't know. If you do, please tell me.)
if table[i] then -- for runs every number from i to #table, if i is a key, bingo.
table.insert(sorted_table,(table[i])) -- first key found -> sorted_table[1], second -> sorted_table[2]....
end
end
for k,v in pairs(sorted_table) do
print(key)
end
I got no error, it just jumps over the function and nothing happens. When I print #table, it prints 0. #table is in another file but it's not local but used at other location in the functionfile, so,.. this is weird.
EDIT
Mh strange. I threw some debugs, #table is nil, but in a pairs(table) just under the code, everything works fine.
**SOLUTION-EDIT**
local sorted_table = {}
for k, v in pairs(original_table) do
table.insert(sorted_table, k)
end
table.sort(sorted_table)
for k, v in ipairs(sorted_table) do
print(original_table[v])
end
A little try of explanation:
#table does not necessarily return the length of a table. A table element gets a default key if added in a table without a special key. These keys start from 1 and go up to n. If there is a gap between two keys, when you give your own key, #table will return the key right before that gap.
Example:
t = {'one', 'two', 'three'} -- would be a table like 1 - one, 2 - two, 3 - three
print(#t) -- the last key -> 3, here it works
t2 = {'one', 'two', [4] = 'four'} -- would be a table like 1 - one, 2 - two, 4 - four
print(#t2) -- the last key without a gap -> 2, does not work
Same with pairs(table) and ipairs(table). ipairs iterates from key 1 to n without a gap, pairs iterates over all keys. That's why the solution works.
You can set an own metamethod for the table (__len) to use # for the right length.
And remember that your table keys start at 1 by default.
Hope it helped a bit to unterstand the problem here.
SOLUTION
local sorted_table = {}
for k, v in pairs(original_table) do
table.insert(sorted_table, k)
end
table.sort(sorted_table)
for k, v in ipairs(sorted_table) do
print(original_table[v])
end