user1526124
user1526124

Reputation: 247

TStringList always doing line break

I'm developing a hook for keyboard and using SetWindowsHookEx and I add every keystroke inside a TStringList. To manipulate the keystrokes inside the TStringList I'm always using the '.Text' property. To add the typed keystrokes for example I use:

KeyStrokes.Text:= KeyStrokes.Text + AChr;

If I detect a [backspace] then I try to delete the last character in the StringList using:

KeyStrokes.Text := Copy(KeyStrokes.Text, 1, length(KeyStrokes.Text) - 1);

All this was working while I added inside a TMemo using the same '.Text' property. But since when I put in TStringList, in the saved Log.txt file (using .SaveToFile property) I'm getting the logs like this:

H

E

L

L

O

Instead of 'Hello'. I tried '.Append', '.Add' properties and always the same. And of course, the backspace deleting the last letter doesn't work anymore... How to put keystrokes correctly? Is that even possible to do in TStringList?

Upvotes: 1

Views: 6750

Answers (3)

Disillusioned
Disillusioned

Reputation: 14842

It really seems far more practical to use a normal string. In a comment you were concerned about losing some functionality, saying: "I was doing a line break when detect [enter]". You can easily support this with normal strings by appending sLineBreak a constant for the End-Of-Line (EOL) marker. On Windows, this equals #13#10 (a carriage return and line feed). The only thing you'd need to watch out for is that when you use backspace to delete the EOL, you need to delete the correct number of characters: 2 for Windows, 1 for Linux/MAC. Length(sLineBreak) would tell you how many.

Another option you may want to consider is the TStringBuilder class. It is designed to build up strings piece-meal, so may suite your purposes.

Finally, if you really want to use TStringList, you can manipulate the strings individually (i.e. not using the Text property):

FInputData: TStrings;
FInputData := TStringList.Create;
FInputData.Add(''); { Important to always have at least 1 string }

{ When adding a character "Ch" }
FInputData[FInputData.Count-1] := FInputData[FInputData.Count-1] + Ch;

{ When detecting the Enter Key }
FInputData.Add('');

{ When detecting Backspace }
S := FInputData[FInputData.Count-1];
if (S <> '') then
begin
  { Delete last character on current line }
  Delete(S, Length(S), 1);
  FInputData[FInputData.Count-1] := S;
end
else if (S = '') and (FInputData.Count > 1) then
begin
  { Go back to previous line if current is empty, but don't delete if 
    there's nothing left. (Remember: always have at least 1 string) }
  FInputData.Delete(FInputData.Count-1);
end;

{ To write the current data }
Writeln(FInputData.Text);

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 597961

The only way the TStringList could be saving line breaks to the file is if the TStringList has multiple strings in it when you call SaveToFile(). The reason is because reading the Text property inserts an implicit line break at the end, which are not stripping off before writing back to the Text. So each keystroke ends up as a new string in the list.

Like everyone else said, TStringList is the wrong tool for this job in the first place. Use a simple String instead:

KeyStrokes: String;
...
KeyStrokes := KeyStrokes + AChr;
...
Delete(KeyStrokes, Length(KeyStrokes), 1);

Upvotes: 2

Rob Kennedy
Rob Kennedy

Reputation: 163357

TStringList doesn't appear to be the right tool for the job, at least not if you're going to use the Text property. As you know from the documentation, reading the Text property joins all the items in the list with line breaks. Writing to that property splits the new value at each line break and creates a separate entry in the list for each item.

If you're trying to keep track of keystrokes, you don't want your data structure to silently munge your data by inserting and removing things that look like keystrokes but that don't represent real keystrokes. (In particular, note that reading the Text property will append a line break at the end of the result. That affects your backspace logic.)

Use a plain old string to keep track of the current state of the string input.

Upvotes: 2

Related Questions