Keycode not working for a french keyboard ?

Started by Baguettator, Mon 01/04/2024 12:50:36

Previous topic - Next topic

Baguettator

Hi !

I'm using a BlocNotes module to allow writing text in my ags game.

I encounter some problem : with that module, using keycodes to recognize the wanted characters, I can't write things like ( ' " é ù _ - (mostly things that can be found with the numerical keys).

I want (and need !) to be able to have, for these keys :
- when MAJ (or capslock) is off, it returns the symbol (like ' " é ç etc...)
- when MAJ (or capslock) is on, it returns the number (1 2 3 4 etc)

In AGS, it seems to return each time the number, even if MAJ (or capslock) is off...

Also, I don't know if AGS has a keycode for éèâ characters ? And how to find them ?

I've read the help files, but didn't find the answer...

Here is my code :

Code: ags
function on_key_press(int keycode)
{
// Appui sur une touche alphabétique
  if (('A' <= keycode) && (keycode <= 'Z')) {
    char lettre;
    // Si aucun shift n'est pressé et que le capslock n'est pas activé ou s'il l'est et qu'un shift est pressé >> minuscule
    if ((!(IsKeyPressed(403)) && !(IsKeyPressed(404)) && (!System.CapsLock)) || ((System.CapsLock) && (IsKeyPressed(403) || IsKeyPressed(404))))
      lettre = keycode + 32;
    else lettre = keycode;
    SetBlocTexte(BlocTexte.InsertAt(curs, lettre));
    curs++;
  }
  // Appui sur un caractère à afficher
  if (((32 <= keycode) && (keycode <= 64)) || ((91 <= keycode) && (keycode <= 255))) {
    SetBlocTexte(BlocTexte.InsertAt(curs, keycode));
    curs++;
  }
}

EDIT : I can imagine that a workaround is to have a function that "converts" combinations like "MAJ+6" => "-", "AltGr+3" => "#" etc... But perhaps there is a better solution ?
Also, AGS seems to have no keycode for "ù", "*" (both near the enter key) and "²" keys.

eri0o

#1
I have no idea what module is that and how it works, but if it's pre-3.6.x era it may not have some additional stuff to handle these things.

In newer AGS if you want to handle text you probably should use on_text_input handler

https://adventuregamestudio.github.io/ags-manual/Globalfunctions_Event.html#on_text_input

I wouldn't depend on this strongly in-game though, if you ever want to port to systems where a keyboard is not as straightforward (like on consoles), you may need also the option to showing a keyboard in-game.

More meaning like, these characters are fine if they are only used like by the player when naming their own save files or something, but in a puzzle, I would avoid or make it doable with a simpler keyboard I would be comfortable implementing in-game with GUIs.

Ah right, other common issue is the person makes all their scripts correctly but the font used doesn't have the character, this is something else to check. Also, if you are using utf-8 mode in ags too.

Crimson Wizard

#2
eri0o posted a reply while I was typing mine, but I would post anyway, trying to elaborate a little more.

The thing is that Keycodes are not "human" letters, they are  "logical" keys. They cannot be matched to written text directly, unless that's a English language, but that's rather a historical coincidence.
Keycodes also do not depend on whether you press Shift or CapsLock or not.
Some locales have completely unrelated letters per each key, and some languages require several keys to be pressed in a sequence (e.g. Chinese).

Starting with 3.6.0, which has Unicode support, there's a new event function for getting actual text from keypresses which should be used as a solution for this problem. This function is called "on_text_input":
https://adventuregamestudio.github.io/ags-manual/Globalfunctions_Event.html#on_text_input

EDIT: to make this work correctly, you need to have 2 general settings:
1. Text format set to Unicode.
2. Use old-style key handling disabled (so, using new-style key handling).

EDIT2: in case the example from the manual is not enough, here's how it may be used with the above script:
Code: ags
function on_text_input(int ch)
{
  // Appui sur une touche alphabétique
  SetBlocTexte(BlocTexte.InsertAt(curs, ch));
  curs++;
}

I'm not sure what to do with non-letter key presses though, as I could not understand the purpose of the script under "// Appui sur un caractère à afficher". It depends on the goal. But whatever that is, non-letter keycodes should be handled in on_key_press still.

Baguettator

Thanks a lot for answers ! so quick, as usual :)

The module has been made by a french AGSer, long time ago, perhaps pre-3.6. The thing is that it's a full module to write text like in Word or things similar, with possibility to select, copy/paste etc...

As I understand, the new function on_text_input is ONLY for letters, so for this kind of module it can't be only this function that handles text writing as we need also symbols and numbers.

So perhaps I will try to create my own function to "emulate" the keyboard, with all the symbols and MAJ/ALT combinations.

Quote from: Crimson Wizard on Mon 01/04/2024 13:35:18I could not understand the purpose of the script under "// Appui sur un caractère à afficher".
This part of the code is to manage keycodes that are not letters. So if keycode value is not under 32 (because under 32 it's Ctrl+Key keycodes), not between 65 and 91 (it's letters) and not over 255 (certainly because it's not keycodes that mean a character, letter or symbol, like "enter", "space" and things like that).
I think he did it to make a difference for letters when MAJ is on, that he didn't want for other keys. But I will change his code to manage missing characters.

So the thing is that if my keyboard has got keys without keycode (I wrote a "display(%d, keycode)" line in my on_key_press function, and some keys don't display anything, so keycode isn't existing for those), I can't detect them at all for my game ?


Crimson Wizard

#4
Quote from: Baguettator on Mon 01/04/2024 15:01:53As I understand, the new function on_text_input is ONLY for letters, so for this kind of module it can't be only this function that handles text writing as we need also symbols and numbers.

Oh, I was not clear. By "letters" I mean any printable symbols whatsoever.

The very purpose of this is so that users would not have to emulate anything, as everything is done by the engine (or rather libraries it is using).

Quote from: Baguettator on Mon 01/04/2024 15:01:53So the thing is that if my keyboard has got keys without keycode (I wrote a "display(%d, keycode)" line in my on_key_press function, and some keys don't display anything, so keycode isn't existing for those), I can't detect them at all for my game ?

Please tell which keys from keyboard are these, and also, do you have "Old-style key handling" turned on or off in your General Settings?

Baguettator

I will have a look soon if  I have the option on or off.

So the new function on_text_input is called like on_key_press, and works the same ? (the link by erioO is dead, doesn't work).

Does this function works with Ctrl+Key or Alt+Key ? If you could give me an example, it would be very kind :)

Crimson Wizard

#6
Quote from: Baguettator on Mon 01/04/2024 15:44:57So the new function on_text_input is called like on_key_press, and works the same ? (the link by erioO is dead, doesn't work).

There's something wrong with our online manual today. But you have it all in your Editor, if you press F1, or run ags-help.chm from the program files.

EDIT: ah, you can read the wiki that is used to make the manual:
https://github.com/adventuregamestudio/ags-manual/wiki/Globalfunctions_Event#on_text_input


Quote from: Baguettator on Mon 01/04/2024 15:44:57Does this function works with Ctrl+Key or Alt+Key ? If you could give me an example, it would be very kind :)

No, on_text_input is for printable characters, for anything else you should be using on_key_press as usual. So you need both functions.
I added an example of on_text_input in my first reply above. Also, few examples may be found in the manual. If these are not enough, please tell what kind of example specifically do you need.

eri0o

#7
@Baguettator sorry I was messing up with the manual for the new release and it blew up unexpectedly but it should be right in place now.  (roll)

Noticed we also wrote a bit about it here: https://adventuregamestudio.github.io/ags-manual/UpgradeTo36.html#changes-to-key-input-handling

Baguettator

OK, but sorry, now I don't really see the difference between "printable characters" and "others one"...? Why should I need both functions ? In this case, it's better to use one ?

Crimson Wizard

#9
Quote from: Baguettator on Mon 01/04/2024 18:04:40OK, but sorry, now I don't really see the difference between "printable characters" and "others one"...? Why should I need both functions ? In this case, it's better to use one ?

Keycodes are codes of "logical" keys on your keyboard. Such as A, B, C, 1, 2, but also Tab, Shift, F1, Enter and so on. Each key on your keyboard has its code, and also one code which never changes (I think).

Printable characters are symbols that are generated by pressing keys.

Same key may generate different printable character depending on current system language. Some characters are generated by pressing multiple keys.

on_key_press receives logical key codes, for each pressed key, one by one.
on_text_input receives printable characters generated by pressing keys. If a pressed key does not generate printable character, then on_text_input is not called at all. If pressed key is not enough to generate a printable character, then it's not called yet.
When a character is generated by a combination of 2+ keys, there are 2+ calls of on_key_press (for each key), but only one call of on_text_input (for one character).

That is why you need on_text_input to handle printable characters, as something that forms a text, and on_key_press to handle logical keys, as something that triggers actions.

If you expect printed characters, you may skip keys in on_key_press, and handle them in on_text_input.
If you expect logical keys, for example controlling player movement by WASD, you handle that in on_key_press.

If you are handling the text input field, printed characters should be added in on_text_input, but actions like Backspace (Del, etc) or Enter should be handled in on_key_press.

Baguettator

OK I see. As the code of the module uses on_key_press to handle actions and not only the printable characters, I will stay with on_key_press.

Is there any problem to turn options on for the unicode compatibility ? It won't "hurt" my game nor its functions ?

Crimson Wizard

#11
Quote from: Baguettator on Mon 01/04/2024 18:36:01OK I see. As the code of the module uses on_key_press to handle actions and not only the printable characters, I will stay with on_key_press.

I am still not sure if we understand each other, so I will say once more just in case: on_key_press is not meant to reliably handle printable characters for all languages. For the optimal solution you have to use both on_key_press and on_text_input. on_key_press for actions, and on_text_input for printable chars.
If only on_key_press, then you will have to emulate printable characters by manually scripting all possible key combinations resulting in extended chars, depending on current system language.

Quote from: Baguettator on Mon 01/04/2024 18:36:01Is there any problem to turn options on for the unicode compatibility ? It won't "hurt" my game nor its functions ?

Please be more specific, which options are you referring to, how they are set now and how do you intend to change them?

eri0o

You need both because some things aren't simultaneous key presses, like, I can hit an accent key in my language (like "'") and LATER presses a letter (say "E") and then it will output a different text letter than the pressed one (in my example "É"). (This would make the on_key_press return E while on_text_input return É).

Spoiler
There are languages where instead you compose a whole word, so to add support to them in the future we will probably evolve this a bit more - I imagine adding a string in as an additional parameter of on_text_input. Mobile keyboards works like this too, you compose the word with them.
[close]

Baguettator

OK, so I managed to change the code of the module, and now it works with on_text_input ! So nice !

Thanks a lot !

I don't know if there's any Text Writer Module for AGS, but this one is working very well ! There's only 1 minor bug I couldn't fix yet, but nothing important. If needed, I could share the module in this forum (with author autorization of course) ?

eri0o

I know only this one from @Snarky https://www.adventuregamestudio.co.uk/forums/modules-plugins-tools/module-textfield-v1-2-0/

I have also one thing from myself but it's not in a shareable module state.

I would say having more modules is always nice, so it would be nice if you could share, later, with the author's permission. :)

Baguettator

#15
Quote from: eri0o on Mon 01/04/2024 21:46:13I would say having more modules is always nice, so it would be nice if you could share, later, with the author's permission. :)

The module is available at the french forum of AGS : (you need to login to download it)
https://adventuregamestudio.1fr1.net/forum (in "modules" section, "Module Bloc-Notes")

If you want to try it, I could send you the scripts I fixed. the author has not logged in since more than 1 year, so perhaps he won't see my message... :(

EDIT : just saw that the author is Kitai, registered in this forum too, and perhaps you know him, or you have talked with him by the past !

Baguettator

Oh, question... Not really linked to this thread, but...

With this BlocNotes, I can use the "enter" key to go to next line. Like in Word program or similar. Nice. So I can write :

Code: ags
Yes I use the enter key twice.

And here it is.

Then, I create a String that gets the text from my Blocnote (wordpad). How the "jump line" character is "translated" into the String ? Because if I make :

Code: ags
String s=BlocNote.Text; // gives the text I wrote before to s

File *f.Open($SAVEGAMEDIR$/myfile.txt, eFileWrite);
f.WriteRawLine(s);
f.Close();

In the file, I will see :
Code: ags
Yes I use the enter key twice.

And here it is.
(the same as in my BlocNote)

But perhaps it should be better to have :
Code: ags
Yes I use the enter key twice.[[And here it is.

because later I will use File.ReadRawLineBack() functions, and I want to read the full text, not only the first line.

I hope I'm clear, as you have understood english is not my native language :S

Crimson Wizard

#17
You can read whole text by calling File.ReadRawLineBack() in a loop until File.EOF:

Code: ags
String all_text = "";
while (!file.EOF) {
    if (!String.IsNullOrEmpty(all_text)) {
        all_text = all_text.AppendChar('\n');
    }
    all_text = all_text.Append(file.ReadRawLineBack());
}

It's better to use regular linebreaks ("\n"), because "[" is a non-standard solution used only by AGS, and other programs do not understand it.
In AGS 4.0 we deprecated "[", so it's no longer works as a linebreak.

EDIT: Fixed the code, forgot you also need to add linebreak chars between lines.

Baguettator

Thanks I know I will have you switch to the \n solution. Long work again :)

But how backspace is translated in my example below ? \n ?

If I have this String in my BlocNote :

Code: ags
Yo.

It's me.

And I do :

Code: ags
String s=BlocNote.Text;
int p=s.IndexOf("\n");

Is p equal to 3 ?

Crimson Wizard

Quote from: Baguettator on Mon 01/04/2024 22:38:44But how backspace is translated in my example below

Backspace is not translated to a character, when player presses backspace the text input should delete the last character.

Maybe you meant "linebreak"?... In which case probably yes...

Baguettator

Sorry, you are right, I meant "linebreak"...

I checked, effectively, the "linebreaks" in the string are represented with the \n symbol. Obviously it doesn't appear in .txt files.

So I'm going to replace the \n by something like [LINEBREAK] before generating the string in the .txt file, because I need the string to stay in a single line.

eri0o

You can just escape the slash using "\\n". And then on reading you unscape it again.

I am trying to think if there's already some in-ags way to escape things and unscape. Can't quite remember right now, if there isn't it may make sense to think about this to add in the future.

Crimson Wizard

Quote from: Baguettator on Thu 04/04/2024 08:23:01I checked, effectively, the "linebreaks" in the string are represented with the \n symbol. Obviously it doesn't appear in .txt files.

In files it becomes a special symbol which is not printed, but emulated by a text viewer/editor by wrapping the line.
But it is still possible to read it back.

Quote from: Baguettator on Thu 04/04/2024 08:23:01So I'm going to replace the \n by something like [LINEBREAK] before generating the string in the .txt file, because I need the string to stay in a single line.

I'm curious, why do you need whole text to be in exactly one line?

Baguettator

Quote from: Crimson Wizard on Thu 04/04/2024 12:41:08I'm curious, why do you need whole text to be in exactly one line?
Because, for simplicity, I store each parameter one by line. So for the name of a map, it's one line. For its story, another line. At each line's beginning, I have a keyword that tells which parameter it is. Like that : (for title, story, and positions of zombie tokens on the map)

Code: ags
TITLE//My title//
STORY//Mystory//
ZOMBIETOKENS//210//150//200//170//

// is a separator, I have a function that reads things between them.

Crimson Wizard

Quote from: Baguettator on Thu 04/04/2024 14:35:17
Quote from: Crimson Wizard on Thu 04/04/2024 12:41:08I'm curious, why do you need whole text to be in exactly one line?
Because, for simplicity, I store each parameter one by line.


// is a separator, I have a function that reads things between them.

Oh I see.
Well, an alternative to replacing linebreaks would be to support multiline content between separators (or have begin/end tags)

Baguettator

Yeah, already have it. Sometimes I have to separate things inside the line for multiple reasons. I have different separators : // for parameters, [BREAK] for scripts' parts...

Really perfect to let it on one line only, as I won't have to change the whole code too :)

Is the function String.Replace has a .IndexOf(const LookingForText) in it ? I mean, if not, I could add it to my custom function, it could save time for engine, if the text has no \n, instead of verifying each string fully...

Crimson Wizard

Quote from: Baguettator on Fri 05/04/2024 06:06:42Is the function String.Replace has a .IndexOf(const LookingForText) in it ? I mean, if not, I could add it to my custom function, it could save time for engine, if the text has no \n, instead of verifying each string fully...

These functions do exactly same search, there's no way around it but checking the whole string for the given sequence of characters. You will only do duplicate work by calling IndexOf before Replace.

Baguettator

Question about old style keyboard handling :

In my game, I use many things in on_key_press function, like :

Code: ags
function on_key_press(eKeyCode keycode)
{
  if (keycode==eKeyCtrlF)
   // do something
}

If I turn the option "Use old style keyboard handling" false, CtrlF won't do anything anymore... Is it normal ? How can I deal with that ?


SMF spam blocked by CleanTalk