D programming language - input without pressing enter - windows

I'm playing around with the D programming language and am wondering how I
can grab a character without requiring the user to press enter.
Pseudocode example of what I want:
while(true){
if(userHasPressedChar()){
writeln(getChar());
}
}
In C++ I can use conio.h's "getch()", but i have yet to find anything similar here.
Edit: I am using Windows 7.
Edit 2: I found a solution at this forum, which I could alter for my own use.
module main;
import std.stdio;
import core.sys.windows.windows;
void main() {
auto hCon = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hCon);
for(;;) { // in default console mode, ctrl-C will terminate
INPUT_RECORD inrec;
DWORD numread;
while(inrec.EventType != KEY_EVENT) {
WaitForSingleObject(hCon, INFINITE);
ReadConsoleInputW(hCon, &inrec, 1, &numread);
}
auto keyEvent = inrec.KeyEvent;
writefln("VK: %x \tChar: %x \tState: %x",
keyEvent.wVirtualKeyCode,
keyEvent.UnicodeChar,
keyEvent.dwControlKeyState);
}
}

You can also use various libraries. For example, my terminal.d can do this https://github.com/adamdruppe/arsd/blob/master/terminal.d for windows and linux.
Here's an example file from my book (see my SO profile if you're interested) that demonstrates the usage http://arsdnet.net/dcode/book/chapter_12/07/input.d
import terminal;
void main() {
auto terminal = Terminal(ConsoleOutputType.linear);
auto input = RealTimeConsoleInput(&terminal, ConsoleInputFlags.raw);
terminal.writeln("Press any key to exit");
auto ch = input.getch();
terminal.writeln("Bye!");
}
The input object does the necessary conversions to the console mode to turn off line buffering and cleans up after itself. Once you create one, you have methods like input.getch() and input.kbhit() similarly to conio.
My terminal library also offers other event types for things like mouse input if you want to get into more advanced usages.
To compile, just download terminal.d and add it to your command, e.g. dmd yourfile.d terminal.d.

Related

No relevant answers on the actual behavior of kbhit() on characters such as ", %, ~ in Windows 10 when keyboard and locale are US (not international)

Windows 10 with latest updates installed on a Dell XPS13. US keyboard layout and US locale selected (not international). Still a call to kbhit() or _kbhit() with specific characters such as ", ~, % does not return the key hit, at least mot until a certain amount of time (~1second) and a second character has been hit.
I try to use kbhit() because I need a non-waiting function. How can I detect correctly a keyboard hit on " or % with a single keystroke?
In Linux using a timed-out select() on stdin works great, but doesn't seem to be OK with Windows.
Thanks,
-Patrick
I finally found a solution that fits my needs and fixes the issues I have with kbhit(); code below; I hope it helps others too.
– Patrick
int getkey();
//
// int getkey(): returns the typed character at keyboard or NO_CHAR if no keyboard key was pressed.
// This is done in non-blocking mode; i.e. NO_CHAR is returned if no keyboard event is read from the
// console event queue.
// This works a lot better for me than the standard call to kbhit() which is generally used as kbhit()
// keeps some characters such as ", `, %, and tries to deal with them before returning them. Not easy
// the to follow-up what's really been typed in.
//
int getkey() {
INPUT_RECORD buf; // interested in bKeyDown event
DWORD len; // seem necessary
int ch;
ch = NO_CHAR; // default return value;
PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &buf, 1, &len);
if (len > 0) {
if (buf.EventType == KEY_EVENT && buf.Event.KeyEvent.bKeyDown) {
ch = _getche(); // set ch to input char only under right conditions
} // _getche() returns char and echoes it to console out
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); // remove consumed events
} else {
Sleep(5); // avoids too High a CPU usage when no input
}
return ch;
}
It is also possible to call ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &buf, 1, &len); rather than FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); in the code above, but for some unknown reason, it doesn't seem to reply/react as quickly and some character are missed when typing at the keyboard.

How do I enable editable user input for a Rust terminal application?

I am writing a minimal Lisp with a classic terminal-based REPL environment project in Rust.
How do I read in user input from the arrow keys, allowing them to move back and forth on their current line of input at least before they have pressed enter? Ideally, I will be able to extend functionality to include moving "back" to retrieve old inputs like you would in any terminal or any REPL. Here's an image of the behavior for clarity:
I have played around with the standard library's io module and the termion crate but have not figured this functionality out.
Here is my current working code. It effectively takes input and immediately prints it back to the user in addition to quitting as expected with quit().
use std::io::prelude::*;
use std::io;
fn main() {
println!("Rispy Version 0.0.1");
println!("Enter `quit()` to Exit");
let mut input: String;
// continuous input til ctrl-c or quit()
loop {
print!("rispy>> ");
io::stdout().flush().unwrap();
input = String::new();
io::stdin().read_line(&mut input)
.expect("Error reading line");
print!("input: {}", input);
match input.as_ref() {
"quit()\n" => {
println!("\nGoodbye");
break;
},
_ => continue,
}
}
}
It's funny how some basic/fundamental crates are not suggested elsewhere more readily for problems like this but thankfully #kazemakase answered the question by suggesting a crate I had not found up to this point: rustyline
A slight edit to the example code on the readme yields the results I want, with history, the ability to navigate left/right with the arrow keys, and even the use of key strokes like ctrl-d, ctrl-c, home, etcetera. Here it is to couple with the question as asked:
extern crate rustyline;
use rustyline::Editor;
use rustyline::error::ReadlineError;
fn main() {
println!("Rispy Version 0.0.1");
println!("Enter `quit()` to Exit");
let mut reader = Editor::<()>::new();
if let Err(_) = reader.load_history("rispy_history.txt") {
println!("No previous history.");
}
// continuous input
loop {
let readline = reader.readline("rispy>> ");
match readline {
Ok(line) => {
reader.add_history_entry(&line);
println!("input: {}", line);
},
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
println!("Goodbye");
break
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
println!("Goodbye");
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
}
reader.save_history("rispy_history.txt").unwrap();
}
As an out-of-the-box answer, I occasionally use rlwrap, a small wrapper around any command line program that adds basic readline capabilities.
Running rlwrap cargo run, your original program now has editing like you asked, as well as command history and history searching, and probably a lot of other things.

Add breakpoints and install handlers

My high-level goal is something like this:
void print_backtrace() {
void *callstack[128];
int framesC = backtrace(callstack, sizeof(callstack));
printf("backtrace() returned %d addresses\n", framesC);
char** strs = backtrace_symbols(callstack, framesC);
for(int i = 0; i < framesC; ++i) {
if(strs[i])
printf("%s\n", strs[i]);
else
break;
}
free(strs);
}
install_breakpoint_handler("__NSAutoreleaseNoPool", print_backtrace);
So, each time the __NSAutoreleaseNoPool function breakpoint is catched, print_backtrace should be called. (All within the same binary. I'm not trying to catch the breakpoint of separate processes.)
I guess I can somehow do this via ptrace. Is there some easy-to-use and lightweight library?
Currently I'm searching for a MacOSX solution, but cross-platform would be nice of course.
I just found one lib (I even had used it a few years ago...): mach_override
I also found this debuglib but didn't tried.
See here for a demonstration for __NSAutoreleaseNoPool: It automatically executes print_backtrace.

FreeBSD newbus driver loading succesfully but cant create /dev/** file and debugging

I am installing a new newbuf driver on FreeBSD 10.0 . After compiling with make the driver.ko file has been created and than kldload can load successfully. kldload returns 0 and I can see the device at the kldstat output. When attempt to use the driver opening the /dev/** file, the file is not exist.
I think that this /dev/** file should be created by make_dev function which is located in device_attach member method. To test if the kldload reaches this attaching function; when write printf and uprintf to debug the driver, I can not see any output at console nor dmesg output.
But the problem is after writing printf at beginnings (after local variable definitions) of device_identify and device_probe functions, I can't see any output again at console nor dmesg.
My question is that even if the physical driver has problem (not located etc.), should I see the ouput of printf at the device_identify member function which is called by kldload at starting course (I think)?
Do I have a mistake when debugging newbuf driver with printf (I also tried a hello_world device driver and at this driver I can take output of printf at dmesg)?
Mainly how can I test/debug this driver's kldload processes?
Below some parts of my driver code (I think at least I should see MSG1, but I can not see):
struct mydrv_softc
{
device_t dev;
};
static devclass_t mydrv_devclass;
static struct cdevsw mydrv_cdevsw = {
.d_version = D_VERSION,
.d_name = "mydrv",
.d_flags = D_NEEDGIANT,
.d_open = mydrv_open,
.d_close = mydrv_close,
.d_ioctl = mydrv_ioctl,
.d_write = mydrv_write,
.d_read = mydrv_read
};
static void mydrv_identify (driver_t *driver, device_t parent) {
devclass_t dc;
device_t child;
printf("MSG1: The process inside the identfy function.");
dc = devclass_find("mydrv");
if (devclass_get_device(dc, 0) == NULL) {
child = BUS_ADD_CHILD(parent, 0, "mydrv", -1);
}
}
static int mydrv_probe(device_t dev) {
printf("MSG2: The process inside the probe function.");
mydrv_init();
if (device_get_unit(dev) != 0)
return (ENXIO);
device_set_desc(dev, "FreeBSD Device Driver");
return (0);
}
static int mydrv_attach(device_t dev) {
struct mydrv_softc *sc;
device_printf(dev, "MSG3: The process will make attachment.");
sc = (struct mydrv_softc *) device_get_softc(dev);
sc->dev = (device_t)make_dev(&mydrv_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, "mydrv_drv");
return 0;
}
static int mydrv_detach(device_t dev) {
struct mydrv_softc *sc;
sc = (struct mydrv_softc *) device_get_softc(dev);
destroy_dev((struct cdev*)(sc->dev));
bus_generic_detach(dev);
return 0;
}
static device_method_t mydrv_methods[] = {
DEVMETHOD(device_identify, mydrv_identify),
DEVMETHOD(device_probe, mydrv_probe),
DEVMETHOD(device_attach, mydrv_attach),
DEVMETHOD(device_detach, mydrv_detach),
{ 0, 0 }
};
static driver_t mydrv_driver = {
"mydrv",
mydrv_methods,
sizeof(struct mydrv_softc),
};
DRIVER_MODULE(mydrv, ppbus, mydrv_driver, mydrv_devclass, 0, 0);
If you don't see your printf's output on your console then your device functions will probably not be called. Can you show us your module's code?
Have you used DRIVER_MODULE() or DEV_MODULE()?
What parent bus are you using?
I guess printf works fine, but I prefer to use device_printf as it also prints the device name, and will be easier when looking through logs or dmesg output. Also leave multiple debug prints and check the log files on your system. Most logs for the device drivers are logged in /var/log/messages. But check other log files too.
Are you running your code on a virtual machine? Some device drivers don't show up their device files in /dev if the OS is running on a virtual machine. You should probably run your OS on actual hardware for the device file to show up.
As far as I know, you can't see the output in dmesg if you cannot find the corresponding device file in /dev but you may have luck with logs as I mentioned.
The easiest way to debug is of course using the printf statements. Other than this, you can debug the kernel using gdb running on another system. I am not familiar with the exact process but I know you can do this. Google it.

Setting process name on Mac OS X at runtime

I'm trying to change my process' name as it appears in ps and Activity Monitor at runtime. I found several notes that there is no portable way to do this (which I don't care about).
Here's what I tried. None of these approaches worked for me.
Changing argv[0] (seems to be the way to go on some Unix systems)
Calling [[NSProcessInfo processInfo] setProcessName:#"someName"]
Calling setprogname (calling getprogname returns the name I set, but that is irrelevant)
I also read about a function called setproctitle which should be defined in stdlib.h if it is available, but it's not there.
There must be a way to accomplish this because QTKitServer - the faceless decoder for QuickTime Player X - has its corresponding QuickTime Player's PID in its process name.
Does anybody have a clue about how to accomplish this? I'd very much prefer a Core Foundation or POSIXy way over an Objective-C method to do this.
Thanks,
Marco
Edit: If it is in any way relevant, I'm using Mac OS X 10.6.5 and Xcode 3.2.5
There are good reasons to change the process name. Java software should change process names because when running different java tools I want to see which java process is for which tool.
Chromium does it: http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm.
Node.js uses same code to implement Process.title = 'newtitle': https://github.com/joyent/node/blob/master/src/platform_darwin_proctitle.cc
Note: This fails if someone does su to a different not logged-in user: https://github.com/joyent/node/issues/1727
Here the source code in its full complex glory. By the way, someone told me it also works for Mac OS X Lion and also fails with su.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
void SetProcessName(CFStringRef process_name) {
if (!process_name || CFStringGetLength(process_name) == 0) {
NOTREACHED() << "SetProcessName given bad name.";
return;
}
if (![NSThread isMainThread]) {
NOTREACHED() << "Should only set process name from main thread.";
return;
}
// Warning: here be dragons! This is SPI reverse-engineered from WebKit's
// plugin host, and could break at any time (although realistically it's only
// likely to break in a new major release).
// When 10.7 is available, check that this still works, and update this
// comment for 10.8.
// Private CFType used in these LaunchServices calls.
typedef CFTypeRef PrivateLSASN;
typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
CFStringRef,
CFStringRef,
CFDictionaryRef*);
static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
NULL;
static LSSetApplicationInformationItemType
ls_set_application_information_item_func = NULL;
static CFStringRef ls_display_name_key = NULL;
static bool did_symbol_lookup = false;
if (!did_symbol_lookup) {
did_symbol_lookup = true;
CFBundleRef launch_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
if (!launch_services_bundle) {
LOG(ERROR) << "Failed to look up LaunchServices bundle";
return;
}
ls_get_current_application_asn_func =
reinterpret_cast<LSGetCurrentApplicationASNType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
if (!ls_get_current_application_asn_func)
LOG(ERROR) << "Could not find _LSGetCurrentApplicationASN";
ls_set_application_information_item_func =
reinterpret_cast<LSSetApplicationInformationItemType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSSetApplicationInformationItem")));
if (!ls_set_application_information_item_func)
LOG(ERROR) << "Could not find _LSSetApplicationInformationItem";
CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
CFBundleGetDataPointerForName(launch_services_bundle,
CFSTR("_kLSDisplayNameKey")));
ls_display_name_key = key_pointer ? *key_pointer : NULL;
if (!ls_display_name_key)
LOG(ERROR) << "Could not find _kLSDisplayNameKey";
// Internally, this call relies on the Mach ports that are started up by the
// Carbon Process Manager. In debug builds this usually happens due to how
// the logging layers are started up; but in release, it isn't started in as
// much of a defined order. So if the symbols had to be loaded, go ahead
// and force a call to make sure the manager has been initialized and hence
// the ports are opened.
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
}
if (!ls_get_current_application_asn_func ||
!ls_set_application_information_item_func ||
!ls_display_name_key) {
return;
}
PrivateLSASN asn = ls_get_current_application_asn_func();
// Constant used by WebKit; what exactly it means is unknown.
const int magic_session_constant = -2;
OSErr err =
ls_set_application_information_item_func(magic_session_constant, asn,
ls_display_name_key,
process_name,
NULL /* optional out param */);
LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
}
Edit: It's a complex and confusing problem.
On OS X there is no setproctitle(3). One has to write into the argv array (ugly
and a bit dangerous because it is possible to overwrite some environment variables with bogus stuff). Done correctly it works very well.
Additionally Apple has the ActivityMonitor application, something like the Task Manager under Windows. The code above manipulates ActivityMonitor but this manipulation doesn't seem to be encouraged by Apple (hence the use of undocumented functions).
Important: ps and ActivityMonitor don't show the same information.
Also important: ActivityMonitor is not available if you don't have GUI. This can happen if you ssh in to a remote Apple box and there is nobody logged in by GUI. Sadly there is a bug by Apple IMO. Just querying if there is a GUI sends an annoying warning message to stderr.
Summary: If you need to change ActivityMonitor, use the code above. If you have GUI-less situations and and dislike warnings on stderr, redirect stderr temporarily to /dev/null during the call of SetProcessName. If you need to change ps information, write into argv.
You can use the lsappinfo tool which comes with macOS since at least 10.6 and up to present day (10.13.2):
Shell:
lsappinfo setinfo <PID> --name <NAME>
C++:
#include <sstream>
#include <string>
#include <stdlib.h>
void setProcessName (pid_t pid, std::string name)
{
std::ostringstream cmd;
cmd << "/usr/bin/lsappinfo setinfo " << pid;
cmd << " --name \"" << name << "\"";
system (cmd.str().c_str());
}

Resources