KDGKBENT returns wrong keysym values? - c

Example code:
#include <stdio.h>
#include <stdlib.h>
#include <linux/keyboard.h>
#include <sys/ioctl.h>
#include <sys/kd.h>
int
main(int argc, char **argv) {
struct kbentry ke;
ke.kb_table = (unsigned char)atoi(argv[1]);
ke.kb_index = (unsigned char)atoi(argv[2]);
ioclt(0, KDGKBENT, &ke);
printf("keycode %u = %04x\n", ke.kb_index, ke.kb_value);
return 0;
}
When I try to get the value of a keycode using e.g. the code above, KDGKBENT returns strange values. It adds a '0B' to ASCII characters: 0x0B61 for 'a' instead of 0x0061, 0x0B41 for 'A' instead of 0x0041.
I cannot find any answer regarding to what this happens on the internet.
I only found the same question, without any answer there:
https://www.unix.com/unix-for-advanced-and-expert-users/178627-questions-about-linux-console-keyboard-driver-translation-tables.html
Those values in 0x0Bxx do not appear when running dumpkeys -l (alphabet has normal ASCII values), nor in this list:
https://wiki.linuxquestions.org/wiki/List_of_keysyms
Why does this happen? And how am I supposed to get a proper conversion?
Actually, looking carefully at dumpkeys tables, the alphabet keys symbols are '+a', '+A' etc. i.e. they are Caps Lock conditioned to change their case. Could be the explanation behind '0x0B' but I need to find a confirmation about this theory.

Related

How can you get a random number on GBDK?

I'm new to C and to GBDK and I want to code a random number generator that decides between 0 and 1.
Like a 'hacker' simulator.
I have tried a lot of examples from the Internet. But none worked.
Screenshot from the output of the last attempt I made: https://i.ibb.co/f8G39vX/bgberrors.png
Last attempt code:
#include <gb/gb.h>
#include <stdio.h>
#include <rand.h>
void init();
void main()
{
init();
while(1)
{
UINT8 r = ((UINT8)rand()) % (UINT8)4;
printf(r);
}
}
void init()
{
DISPLAY_ON;
}
How can I accomplish it?
#include <gb/gb.h>
#include <stdint.h>
#include <stdio.h>
#include <rand.h>
void init();
void main()
{
init();
printf(" \n\n\n\n\n\n\n\n PRESS START!\n");
// abuse user input for seed generation
waitpad(J_START);
uint16_t seed = LY_REG;
seed |= (uint16_t)DIV_REG << 8;
initrand(seed);
while(1)
{
UINT8 r = ((UINT8)rand()) % (UINT8)2;
printf("%d", r);
}
}
void init()
{
DISPLAY_ON;
}
Tested with GBDK-2020 4.0.3
Also check the "rand" example in GBDK-2020.
Regarding the comments:
Yes, GBDK has it's own lib (including stdlib). It's probably a fork of SDCC's lib 20 years ago. Current SDCC has rand() in stdlib.h, but GBDK-2020 doesn't. Max is 0xFF, I don't know of a define for that.
Float should be avoided as much as possible, it's completely done in software, there is no hardware support for this. Double isn't really supported by the compiler and falls back to float.
There are no man pages, documentation is available here: https://gbdk-2020.github.io/gbdk-2020/docs/api/rand_8h.html or read the gbdk_manual.pdf comming with gbdk-2020

Check only last 3 digits of sensor output

I have a library from WiringPi for DHT11 sensor and I need to modify condition which checks if the value read from sensor is good.
Sometimes the library reads bad values which are 255.255,255.255 or 55,255.255 etc.
sample output
There is the condition in the library:
if(counter==255)
break;
But it doesn't work if the value is e.g. 55,255.255
How can I modify this condition the check last 3 digits of output?
If the output is wrong, there are always "255" at the end of value.
I tried to add conditions like
if(counter==255)
break;
else if(counter==255.255)
break;
But it doesn't solve all possible situations and I realy don't know anything about C/C++
Here is the whole library:
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define MAX_TIME 85
#define DHT11PIN 7
#define ATTEMPTS 5
int dht11_val[5]={0,0,0,0,0};
int dht11_read_val()
{
uint8_t lststate=HIGH;
uint8_t counter=0;
uint8_t j=0,i;
for(i=0;i<5;i++)
dht11_val[i]=0;
pinMode(DHT11PIN,OUTPUT);
digitalWrite(DHT11PIN,LOW);
delay(18);
digitalWrite(DHT11PIN,HIGH);
delayMicroseconds(40);
pinMode(DHT11PIN,INPUT);
for(i=0;i<MAX_TIME;i++)
{
counter=0;
while(digitalRead(DHT11PIN)==lststate){
counter++;
delayMicroseconds(1);
if(counter==255)
break;
}
lststate=digitalRead(DHT11PIN);
if(counter==255)
break;
// top 3 transistions are ignored
if((i>=4)&&(i%2==0)){
dht11_val[j/8]<<=1;
if(counter>16)
dht11_val[j/8]|=1;
j++;
}
}
// verify checksum and print the verified data
if((j>=40)&&(dht11_val[4]==((dht11_val[0]+dht11_val[1]+dht11_val[2]+dht11_val[3])& 0xFF)))
{
printf("%d.%d,%d.%d\n",dht11_val[0],dht11_val[1],dht11_val[2],dht11_val[3]);
return 1;
}
else
return 0;
}
int main(void)
{
int attempts=ATTEMPTS;
if(wiringPiSetup()==-1)
exit(1);
while(attempts)
{
int success = dht11_read_val();
if (success) {
break;
}
attempts--;
delay(500);
}
return 0;
}
No single variable in your code can hold "255.255", that would require a string or a float. You are obviously referring to the output of
printf("%d.%d,%d.%d\n",dht11_val[0],dht11_val[1],dht11_val[2],dht11_val[3]);.
This printf can never produce a three-value output like 55,255.255.
I assume that your output would be 55.255,255.255.
This in turn means that in case of error you will find the "last three digits" in dht11_val[3].
If my assumption is not correct please provide much more detail on the error circumstances.
On the other hand, I suspect that looking for that value is not the solution for your problem either. The function is more complicated. The value of 255 seems the result of an endless loop which is detected by breaking early at counter = 255. So I am pretty sure that checking "the last three digits" is a LESS precise check than what is already implemented.

Strange output when using system("clear") command in C program

I have the following code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#define dimensions 5
int RandomNumInRange(int M, int N)
{
return M + rand() / (RAND_MAX / (N - M + 1) + 1);
}
char ** CreateWorld(int dim)
{
int i,j;
char **world = malloc(dim *sizeof(char*));
for(i=0;i<dim;i++)
world[i]=malloc(dim*sizeof(char));
for(i=0;i<dim;i++)
for(j=0;j<dim;j++)
world[i][j]=42;
return world;
}
void CreateCastle(char **world)
{
//assuming world is big enough
//to hold a match of 2
int randRow,randCol;
//1 to dimension -2 so we can spawn a 3x3 castle
randRow = RandomNumInRange(1,dimensions-2);
randCol = RandomNumInRange(1,dimensions-2);
printf("position: %d %d\n", randRow, randCol);
world[randRow][randCol]='c';
//fill the rest so castle is 3x3
//assuming there is enough space for that
world[randRow-1][randCol-1]=35;
world[randRow-1][randCol]=35;
world[randRow-1][randCol+1]=35;
world[randRow][randCol-1]=35;
world[randRow][randCol+1]=35;
world[randRow+1][randCol-1]=35;
world[randRow+1][randCol]=35;
world[randRow+1][randCol+1]=35;
}
void DisplayWorld(char** world)
{
int i,j;
for(i=0;i<dimensions;i++)
{
for(j=0;j<dimensions;j++)
{
printf("%c",world[i][j]);
}
printf("\n");
}
}
int main(void){
system("clear");
int i,j;
srand (time(NULL));
char **world = CreateWorld(dimensions);
DisplayWorld(world);
CreateCastle(world);
printf("Castle Positions:\n");
DisplayWorld(world);
//free allocated memory
free(world);
//3 star strats
char ***world1 = malloc(3 *sizeof(char**));
for(i=0;i<3;i++)
world1[i]=malloc(3*sizeof(char*));
for(i=0;i<3;i++)
for(j=0;j<3;j++)
world1[i][j]="\u254B";
for(i=0;i<3;i++){
for(j=0;j<3;j++)
printf("%s",world1[i][j]);
puts("");
}
free(world1);
//end
return 0 ;
}
If I use the system("clear") command, I get a line consisting of "[3;J"
followed by an expected output. If I run the program again, I get the same gibberish, then many blank newlines, then the expected output. If I put the system("clear") command in comments then both the "[3;J" and the blank newlines don't show and the output is expected.
Edit: it seems the error is not in the code, but rather in the way the terminal on my system is (not) set. Thank you all for your input, I definitely have a lot of interesting stuff to read and learn now.
The codes being sent by your clear command from don't seem to be compatible with the Gnome terminal emulator, which I believe is what you would be using.
The normal control codes to clear a console are CSI H CSI J. (CSI is the Control Sequence Initializer: an escape character \033 followed by a [). CSI H sends the cursor to the home position, and CSI J clears from the cursor position to the end of the screen. You could also use CSI 2 J which clears the entire screen.
On Linux consoles and some terminal emulators, you can use CSI 3 J to clear both the entire screen and the scrollback. I would consider it unfriendly to do this (and the clear command installed on my system doesn't.)
CSI sequences can typically contain semicolons to separate numeric arguments. However, the J command doesn't accept more than one numeric argument and the semicolon seems to cause Gnome terminal to fail to recognize the control sequence. In any event, I don't believe Gnome terminal supports CSI 3 J.
The clear command normally uses the terminfo database to find the correct control sequences for the terminal. It identifies the terminal by using the value of the TERM environment variable, which suggests that you have to wrong value for that variable. Try setting export TERM=xterm and see if you get different results. If that works, you'll have to figure out where Linux Mint configures environment variables and fix it.
On the whole, you shouldn't need to use system("clear") to clear your screen; it's entirely too much overhead for such a simple task. You would be better off using tputs from the ncurses package. However, that also uses the terminfo database, so you will have to fix your TERM setting in any case.

Why is XKeysymToKeycode() making all of my keys lowercase?

I'm currently having a problem with Xlib where whenever I call XKeysymToKeycode() and pass in an uppercase KeySym, it returns a lowercase KeyCode. Google doesn't really seem to have an answer to this question, or too much documentation at all on the functions I'm using, for that matter.
Here's the code I am using:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
int main(void) {
Display *display;
char *ptr;
char c[2] = {0, 0};
KeySym ksym;
KeyCode kcode;
display = XOpenDisplay(0);
ptr = "Test";
while (*ptr) {
c[0] = *ptr;
ksym = XStringToKeysym(c);
printf("Before XKeysymToKeycode(): %s\n", XKeysymToString(ksym));
kcode = XKeysymToKeycode(display, ksym);
printf("Key code after XKeysymToKeycode(): %s\n", XKeysymToString(XKeycodeToKeysym(display, kcode, 0)));
ptr++;
}
XCloseDisplay(display);
return 0;
}
It can be compiled with gcc -o sendkeys sendkeys_min.c -lX11 -lXtst -g -Wall -Wextra -pedantic -ansi (Assuming it has been saved as sendkeys_min.c.)
The current output is the following:
Before XKeysymToKeycode(): T
Key code after XKeysymToKeycode(): t
Before XKeysymToKeycode(): e
Key code after XKeysymToKeycode(): e
Before XKeysymToKeycode(): s
Key code after XKeysymToKeycode(): s
Before XKeysymToKeycode(): t
Key code after XKeysymToKeycode(): t
The expected output, is, of course, that the first T in "Test" is still uppercase after being ran through XKeysymToKeycode(). (Note that this is not my actual program, but a simplified version for posting here. In the actual program, I am sending key events with the resulting keycode, and the keys sent still have the problem exhibited here (They all become lowercase))
KeySyms and KeyCodes are semantically different, and there is not a 1-1 relationship between them.
A KeyCode is an arbitrary small integer representing a key on the keyboard. (Not a character. A key.) Xlib requires that key codes be in the range [8, 255], but fortunately most keyboards have only a bit more than 100 keys.
A KeySym is a representation of some actual character associated with a key. There will almost always be several of these: lower- and upper-case letters correspond to the same key on most terminal layouts.
So there is no such thing as an "upper-case" or "lower-case" KeyCode. When you get the KeyCode corresponding to a Keysym, you are actually losing information.
In Xlib, a given key has at least four corresponding KeySyms (lower-case, upper-case, alternate lower-case, alternate upper-case), although some might be unassigned. When you ask for the KeySym corresponding to a KeyCode, you need to supply an index; index 0 (as in your code) will get the unshifted unmodified character.
For a given keypress, the translation to a KeySym will take into account the state of the modifier keys. There are eight of these, including the Shift and Lock modifiers. Ignoring Lock, which complicates the situation, the shift modifier key would normally turn lower-case letters into their upper-case equivalents (for alphabetic keys).
Keyboard handling is much more complicated than that brief summary, but it's a start.
For your task, you probably should take a look at XkbKeysymToModifiers.

How can I format currency with commas in C?

I'm looking to format a Long Float as currency in C. I would like to place a dollar sign at the beginning, commas iterating every third digit before decimal, and a dot immediately before decimal. So far, I have been printing numbers like so:
printf("You are owed $%.2Lf!\n", money);
which returns something like
You are owed $123456789.00!
Numbers should look like this
$123,456,789.00
$1,234.56
$123.45
Any answers need not be in actual code. You don't have to spoon feed. If there are C-related specifics which would be of help, please mention. Else pseudo-code is fine.
Your printf might already be able to do that by itself with the ' flag. You probably need to set your locale, though. Here's an example from my machine:
#include <stdio.h>
#include <locale.h>
int main(void)
{
setlocale(LC_NUMERIC, "");
printf("$%'.2Lf\n", 123456789.00L);
printf("$%'.2Lf\n", 1234.56L);
printf("$%'.2Lf\n", 123.45L);
return 0;
}
And running it:
> make example
clang -Wall -Wextra -Werror example.c -o example
> ./example
$123,456,789.00
$1,234.56
$123.45
This program works the way you want it to both on my Mac (10.6.8) and on a Linux machine (Ubuntu 10.10) I just tried.
I know this is a way-old post, but I disappeared down the man rabbit hole today, so I thought I'd document my travels:
There's a function called strfmon() that you can include with monetary.h that will do this, and do it according to local or international standards.
Note that it works like printf(), and will take as many double arguments as there are % formats specified in the string.
There's a lot more to it than what I have here, and I found this page to be the most helpful: https://www.gnu.org/software/libc/manual/html_node/Formatting-Numbers.html
#include <monetary.h>
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
// need to setlocal(), "" sets locale to the system locale
setlocale(LC_ALL, "");
double money_amt = 1234.5678;
int buf_len = 16;
char simple_local[buf_len];
char international[buf_len];
char parenthesis_for_neg[buf_len];
char specified_width[buf_len];
char fill_6_stars[buf_len];
char fill_9_stars[buf_len];
char suppress_thousands[buf_len];
strfmon(simple_local, buf_len-1, "%n", money_amt);
strfmon(international, buf_len-1, "%i", money_amt);
strfmon(parenthesis_for_neg, buf_len-1, "%(n", money_amt);
strfmon(specified_width, buf_len-1, "%#6n", money_amt);
strfmon(fill_6_stars, buf_len-1, "%=*#6n", money_amt);
strfmon(fill_9_stars, buf_len-1, "%=*#8n", money_amt);
strfmon(suppress_thousands, buf_len-1, "%^=*#8n", money_amt);
printf( "===================== Output ===================\n"\
"Simple, local: %s\n"\
"International: %s\n"\
"parenthesis for negatives: %s\n"\
"fixed width (6 digits): %s\n"\
"fill character '*': %s\n"\
"-- note fill characters don't\n"\
"-- count where the thousdands\n"\
"-- separator would go:\n"\
"filling with 9 characters: %s\n"\
"Suppress thousands separators: %s\n"\
"================================================\n",
simple_local, international, parenthesis_for_neg,
specified_width, fill_6_stars, fill_9_stars,
suppress_thousands);
/** free(money_string); */
return 0;
}
===================== Output ===================
Simple, local: $1,234.57
International: USD1,234.57
parenthesis for negatives: $1,234.57
fixed width (6 digits): $ 1,234.57
fill character '*': $**1,234.57
-- note fill characters don't
-- count where the thousdands
-- separator would go:
filling with 9 characters: $*****1,234.57
Suppress thousands separators: $****1234.57
================================================
I don't think there's a C function to do that, but you could just write your own? Say float price = 23234.45. First print (int)price with commas, print a decimal point; then for the decimal part, do printf("%d", (int)(price*100)%100);
int anio, base = 1e4;
double cantidad, rata = 0.5;
int din_buf = 16;
char dinero[din_buf];
printf("%3s%23s\n", "Año", "Cantidad a depositar");
setlocale(LC_ALL, "en_US");
for ( anio = 1; anio < 11; anio++) {
cantidad = base * pow(rata + 1, anio);
strfmon(dinero, din_buf, "%#6n", cantidad);
printf("%3d\t%s\n", anio, dinero);
}
Windows users (with MSVC)
You cannot use:
the POSIX printf() formatting extras in Cal Norum’s answer.
the GNU strfmon() function in rreagan3’s and Edgar Fernando Dagar’s answers.
You are kind of stuck using the Win32 API:
GetCurrencyFormatEx() for locale-dependent currency formatting
(GetNumberFormatEx() for locale-dependent general-purpose number formatting)
Example:
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
int main(void)
{
double money = 1234567.89;
wchar_t s[20], money_s[20];
swprintf( s, sizeof s, L"%.2f", money );
GetCurrencyFormatEx( L"en_US", 0, s, NULL, money_s, (int)sizeof money_s );
printf( "You are owed %S!\n", money_s );
}
You are owed $1,234,567.89!
As always, watch your rounding errors with swprintf() if you are counting currency with more precision than 100ths. (You may not want to round up if you owe money.)

Resources