How to read a single character in D language?

2021-11-19 Thread BoQsc via Digitalmars-d-learn
Let's say I want to write a simple program that asks for an input 
of a single character.
After pressing a single key on a keyboard, the character is 
printed out and the program  should stop.


Re: How to read a single character in D language?

2021-11-19 Thread Adam D Ruppe via Digitalmars-d-learn

On Friday, 19 November 2021 at 17:36:55 UTC, BoQsc wrote:
Let's say I want to write a simple program that asks for an 
input of a single character.
After pressing a single key on a keyboard, the character is 
printed out and the program  should stop.


This is platform specific. About 10 lines of code for a minimum 
implementation per OS, but if you don't wanna do it that way my 
library has a function for it with a prepackaged sample:


http://arsd-official.dpldocs.info/arsd.terminal.html#single-key

that's arsd-official:terminal on dub or you can grab the file 
from my github repo.


I guess you could view my source to see the impl but I don't feel 
like pulling it out right now.


Re: How to read a single character in D language?

2021-11-19 Thread BoQsc via Digitalmars-d-learn

On Friday, 19 November 2021 at 18:01:57 UTC, Adam D Ruppe wrote:

On Friday, 19 November 2021 at 17:36:55 UTC, BoQsc wrote:
Let's say I want to write a simple program that asks for an 
input of a single character.
After pressing a single key on a keyboard, the character is 
printed out and the program  should stop.


This is platform specific. About 10 lines of code for a minimum 
implementation per OS, but if you don't wanna do it that way my 
library has a function for it with a prepackaged sample:


http://arsd-official.dpldocs.info/arsd.terminal.html#single-key

that's arsd-official:terminal on dub or you can grab the file 
from my github repo.


I guess you could view my source to see the impl but I don't 
feel like pulling it out right now.


Thanks Adam.
I've tested and it does work on Windows 10.


mkdir "read_character_project"
cd "read_character_project"
dub init
dub add arsd-official:terminal
notepad ./source/app.d


import arsd.terminal;

void main() {
auto terminal = Terminal(ConsoleOutputType.linear);
	auto input = RealTimeConsoleInput(&terminal, 
ConsoleInputFlags.raw);


terminal.writeln("Press any key to continue...");
auto ch = input.getch();
terminal.writeln("You pressed ", ch);
}



dub run


Performing "debug" build using C:\Program Files\LDC 
1.28\bin\ldc2.exe for x86_64.
arsd-official:terminal 10.3.10: target for configuration "normal" 
is up to date.
arsd ~master: target for configuration "application" is up to 
date.

To force a rebuild of up-to-date targets, run again with --force.
Running arsd.exe
Press any key to continue...
You pressed u

___

Of interest, I also tried to look up getch() inside
http://arsd-official.dpldocs.info/source/arsd.terminal.d.html#L2867

But the source file overwhelmed me by its size.

For now I'm still interested in a more simple standalone 
implementation that would be more learning friendly, or at least 
with little explanation of basic things behind the code and how 
it is interfacing with the operating system, the native library.




Re: How to read a single character in D language?

2021-11-19 Thread Adam Ruppe via Digitalmars-d-learn

On Friday, 19 November 2021 at 20:51:09 UTC, BoQsc wrote:

But the source file overwhelmed me by its size.


Yeah, the getch function in there builds on the rest of the 
events the library offers, so it won't be that useful outside.



The OS functions for getch alone though are actually pretty 
simple:


1) change the terminal to "raw" mode. the default is to buffer 
lines, which means your application doesn't get anything until a 
line is complete. You need to turn that off.


The RealTimeConsoleInput constructor does this in the lib:
http://arsd-official.dpldocs.info/v10.3.8/source/arsd.terminal.d.html#L2487

On Windows, you basically just call `SetConsoleMode`, but since 
the console is a shared resource, you also need to save the old 
mode to set it back later (that's what I do in the destructor of 
the struct).


On Linux, you call `tcsetattr`. The function for mine is here:
http://arsd-official.dpldocs.info/v10.3.8/source/arsd.terminal.d.html#L2620

Again, the terminal is a shared resource (this is actually even 
more true on linux systems!) so it is important to save the old 
one and set it back when you're done. There's a lot of ways this 
can happen so you should handle them all - that's why there's a 
bunch of signal handler blocks there.


Other things the library initialize is if you want echo, mouse 
input, paste events, resize notifications, etc. But if you only 
care about getch you can ignore most that stuff.


2) Read the terminal's event stream. On Windows, you call 
`ReadConsoleInput` and process the struct it sends you for a 
keyevent. See: 
http://arsd-official.dpldocs.info/v10.3.8/source/arsd.terminal.d.html#L3122


On Linux, you call the system `read` function on the stdin stream 
(file number 0). Basic keys will come as a single byte read on 
there. Others get extremely complicated.

http://arsd-official.dpldocs.info/v10.3.8/source/arsd.terminal.d.html#L3369

And it goes on for about 400 lines! And it depends on some of 
that other initialization we skipped over before and uses a 
database of terminal quirks found elsewhere in the file.


Windows' API is far, far easier to use.


But the Linux one isn't bad if you only want basic alphanumeric 
and enter keys. You can read those as a single ascii byte off the 
read function, so for that you can do it in just a few lines.


3) Again, remember to set it back how you found it before you 
exit by callling the SetConsoleMode/tcsetattr again before you 
exit.


Re: How to read a single character in D language?

2021-11-19 Thread Imperatorn via Digitalmars-d-learn

On Friday, 19 November 2021 at 17:36:55 UTC, BoQsc wrote:
Let's say I want to write a simple program that asks for an 
input of a single character.
After pressing a single key on a keyboard, the character is 
printed out and the program  should stop.


If you want to test on Windows you can do this:

```d
// conio.h
extern (C) int _getch();
```

Like for demonstration purposes:
```d
writeln("Press a button...");
int a = _getch();
writeln("You pressed ", a);
```

That should be unbuffered.


Re: How to read a single character in D language?

2021-11-19 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Nov 19, 2021 at 10:21:42PM +, Adam Ruppe via Digitalmars-d-learn 
wrote:
[...]
> The OS functions for getch alone though are actually pretty simple:
> 
> 1) change the terminal to "raw" mode. the default is to buffer lines,
> which means your application doesn't get anything until a line is
> complete. You need to turn that off.
[...]
> 2) Read the terminal's event stream.
[...]
> 3) Again, remember to set it back how you found it before you exit by
> callling the SetConsoleMode/tcsetattr again before you exit.

And *this* is why you want to use a library for this.  Doing this by
hand is certainly possible, but very tedious, error-prone, and requires
a lot of knowledge about OS system calls.  Why bother when you could
just drop arsd.terminal into your workspace and call it a day?  :-)

(Of course, learning how things work under the hood for the sake of
educating yourself is definitely worthwhile. Just don't do that when you
need to get stuff done.)


T

-- 
Let's not fight disease by killing the patient. -- Sean 'Shaleh' Perry


Re: How to read a single character in D language?

2021-11-23 Thread Alexey via Digitalmars-d-learn

On Friday, 19 November 2021 at 17:36:55 UTC, BoQsc wrote:
Let's say I want to write a simple program that asks for an 
input of a single character.
After pressing a single key on a keyboard, the character is 
printed out and the program  should stop.


```D
import std.stdio;

void main()
{
while (true)
{
char c;
scanf("%c", &c);

writefln(0x"%c (%1$x %1$d) is inputed", c);
}
}
```


Re: How to read a single character in D language?

2021-11-23 Thread Alexey via Digitalmars-d-learn

On Wednesday, 24 November 2021 at 04:48:46 UTC, Alexey wrote:

writefln(0x"%c (%1$x %1$d) is inputed", c);

sorry:
```diff
10c10


Re: How to read a single character in D language?

2021-11-23 Thread Alexey via Digitalmars-d-learn

On Wednesday, 24 November 2021 at 04:51:03 UTC, Alexey wrote:

On Wednesday, 24 November 2021 at 04:48:46 UTC, Alexey wrote:


oh, also I completely missed what you need it to work without 
Enter key presses. so here is fixed version


```D
import std.stdio;

import core.sys.posix.termios;

void main()
{
termios input_settings;

tcgetattr(stdin.fileno, &input_settings);
input_settings.c_lflag &= ~ICANON;
tcsetattr(stdin.fileno, TCSANOW, &input_settings);

while (true)
{
char c;
stdin.readf("%c", &c);

writefln("\n%c (0x%1$x %1$d) is inputed", c);
}
}
```


Re: How to read a single character in D language?

2021-11-24 Thread forkit via Digitalmars-d-learn

On Friday, 19 November 2021 at 17:36:55 UTC, BoQsc wrote:
Let's say I want to write a simple program that asks for an 
input of a single character.
After pressing a single key on a keyboard, the character is 
printed out and the program  should stop.


module test;

void main()
{
import core.stdc.stdio : getchar, puts, putchar;
puts("Enter a character:");
putchar(getchar());
}