Pascal readkey command issue - pascal

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.

Related

Find & Extract hashtags in text

I'm looking for an easy/quick way to identify and extract hashtags from a string, and temporarily store them separately - e.g.:
If I have the following string:
2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure).
Then I want to be able to get this:
#Example
#Date:2017-09-01
#NothingWow
I figured storing it in a TStringList should be sufficient until I'm done. I just need to store them outside of the original string for easier cross referencing, then if the original string changes, add them back at the end.
(but that's easy - its the extracting part I'm having trouble with)
It should start at the # and end/break when it encounters a [space].
The way I initially planned it was to use Boolean flags (defaulted to False), then check for the different hashtags, set them to true if found, and extract anything after a [:] separately.
(but I'm sure there is a better way of doing it)
Any advice will be greatly appreciated.
The following shows a simple console application which you could use as the basis
for a solution. It works because assigning your input string to the DelimitedText property of a StringList causes the StringList to parse the input into a series of space-limited lines. It is then a simple matter to look for the ones which start with a #.
The code is written as a Delphi console application but should be trivial to convert to Lazarus/FPC.
Code:
program HashTags;
{$APPTYPE CONSOLE}
uses
Classes, SysUtils;
procedure TestHashTags;
var
TL : TStringList;
S : String;
i : Integer;
begin
TL := TStringList.Create;
try
S := '2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure)';
TL.DelimitedText := S;
for i := 0 to TL.Count - 1 do begin
if Pos('#', TL[i]) = 1 then
writeln(i, ' ', TL[i]);
end;
finally
TL.Free;
end;
readln;
end;
begin
TestHashTags;
end.

Ada thread to pass auto random generated data to a procedure

How would i go about creating a procedure that is a thread which continuously passes automatic random generated data within a specified range.
I currently would have to manually enter in each bit of data in the console using this procedure below. I want to creatre a procedure that when running is able to pass data to this procedure as if it was being typed into the console itself.
procedure Analyse_Data is
Data : Integer;
begin
DT_Put_Line("Data input by user");
loop
DT_Get(Data,"Data must be taken as a whole number");
exit when (Data >=0) and (Data <= Maximum_Data_Possible);
DT_Put("Please input a value between 0 and ");
DT_Put(Maximum_Data_Possible);
DT_Put_Line("");
end loop;
Status_System.Data_Measured := Data_Range(Data);
end Analyse_Data;
I havent included the specification files (.ads)
I am new to Ada and any help would be appreciated.
Use an instance of Discrete_Random to generate some number of random data values in the desired range:
subtype Valid_Range is Natural range 0 .. Maximum_Data_Possible;
package Some_Value is new Ada.Numerics.Discrete_Random(Valid_Range);
G : Some_Value.Generator;
…
procedure Generate is
N : Valid_Range;
begin
for I in 1 .. Count loop
N := Some_Value.Random(G);
Put(N);
end loop;
end;
Save the values to a file:
./generate > test_data.txt
Feed that file to your program using I/O redirection from the command line:
./analyse_data < test_data.txt
The exact details will depend on you actual program. See this related Q&A regarding empty lines in standard input.

How to capture combination key event?

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').

Free Pascal - Problem solving query (not syntax) - how to approach the next phase of this loop

I have more of a 'problem solving' question than a syntax related problem.
Briefly, I'm creating a program that will read a text file full of words (that may feasibly be a list of passwords), one word per line - I'll be using ReadLn for that bit in a loop. For every word it finds, I want it to add "an amount" of obfuscation in line with how users these days will use '3' instead of 'E' in their passwords, or '1' instead of 'I'. I work in the IT security field and password breaking is often part of it and that's what the program is for.
I have managed to create the program so far that it generates a LEET table full of many different values for each letter of the alphabet and stacks them in a StringGrid that I can access as part of the process (and it is also outputted visually to a table).
type
TLetters = 'A'..'Z';
TLeet = array[TLetters] of TStringList;
var
SourceFileName, str : string;
StartIndexFile : TextFile;
i : TLetters;
leet : TLeet;
s : string;
n, o, ColumnSize : integer;
begin
for i in TLetters do
leet[ i ] := TStringList.Create;
// The next sequence of loops populates the string grid by counting the number of characters for each letter of the alphabet and then inserting them down, column by column and row by row...
//Letter A:
s := '4 # /-\ /\ ^ aye ∂ ci λ Z';
ColumnSize := wordcount(s,[' ']);
o := 0;
for n := 0 to ColumnSize do
leet['A'].Add(ExtractWord(n,s,[' ']));
for o := 0 to ColumnSize do
StringGrid1.Cells[1,o] := Leet['A'][o];
// And so on for B - Z
// ... then an OpenDialog that opens the source text file to read. Got that sorted
// A load of file opening stuff and then the obsfucation
repeat
Readln(StartIndexFile, Str);
LblProgress.Caption := ('Parsing Index File...please wait');
OBSFUCATE THE WORDS HERE TO SOME EXTENT
// but now I have hit a barrier....
until(EOF(StartIndexFile));
My problem is this : given the word 'Edward', for example, how do I decide to what level I should obfuscate it? Just the first letter 'E' to be replaced with a '3', and nothing more perhaps? Or the first two letters 'E' and 'd' to be replaced with ALL the values in the LEET table for both of the letters E and d (meaning dozens of new words would be generated from 'Edward', and so on), or all the values for 'E' but nothing else...the list goes on. Potentially, for every word, I could create thousands of additional one's! A 100Gb source file would soon become terabytes!
In other words, I need to set "a level" for which the program will function, that the user can decide. But I'm not sure how to structure that level?
So I'm not sure how to make it work? I didn't really think it through enough before I started. My initial thoughts were "It would be cool to have a program that would take an index of words from a computer, and then generate variations of every word to account for people who obfuscate characters." but having come to code it, I've realised it's a bigger job than I thought and I am now stuck at the section for actually 'LEETing my input file'!
You could use a level (0-10) as input.
0: replace nothing
10: replace all letters with LEET letters.
Depending on the length of the word, you calculate how many letters to replace and just replace random letters in the word, so that you not always replace the first letter for level 1 etc.

Weird runtime error while implementing a bubble sort in Pascal

This snippet not only causes a runtime error, it makes FPC close if I run it using the debugger.
procedure sortplayersbyscore(var vAux:tplayers);
procedure swap(var a:trplayers;var b:trplayers);
var
rAux:trplayers;
begin
rAux:=a;
a:=b;
b:=rAux;
end;
var
i,j:integer;
sorted:boolean;
begin
vAux:=playersarray;
i:=1;
sorted:=false;
while (i <= MAXPLAYERS -1) and not sorted do
begin
j:=1;
sorted:=true;
while (j <= MAXPLAYERS -i) do
begin
if (vAux[j].score < vAux[j+1].score) then
begin
swap(vAux[j],vAux[j+1]);
sorted:=false;
end;
inc(j);
end;
inc(i);
end;
end;
The code itself is part of a really big source file, I can post the whole thing but the responsible for the error is just that bunch of lines. The debugger terminates at line:
swap(vAux[j],vAux[j+1]);
tplayers is just a type defined as an array of records that contain score (an integer) among a bunch of other variables. trplayers is the type of the aforementioned records. I'm at a total loss; FPC (while not under debugging mode) spits an out-of-range error but under my watches I see that the variables I'm trying to read exist. Any help is really appreciated!
rAux:trplayers; have you typed a wrong symbol or the type here really contains "r" in its name?
It looks valid (other than typos) ... so let's try something simple.
What's the value of "j" when you abort?
If the debugger won't tell you, try adding:
writeln ('j = ', j);
just before the "swap" call.
As Yochai's question implied, your array needs to be dimensioned at least from
1 (or lower) to MAXPLAYERS (or larger). (I.e.: 0..MAXPLAYERS-1 would not work,
but 1..MAXPLAYERS should.)

Resources