Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial X11 scancode implementation #1400

Closed
wants to merge 33 commits into from

Conversation

eliasdaler
Copy link
Contributor

@eliasdaler eliasdaler commented Mar 29, 2018

SFML Tasks

  • Agree on code structure (see below)
  • Adjust code according to the review comments
  • Test (use this code for it and switch your keyboard layout to non-US for harder cases)
  • Merge into the feature/scancode branch (see Scancode #1235)

Hello everyone! This is my first PR and it was pretty hard to get this working! Keycodes, KeySyms, scancodes, SFML's scancodes - it's all different and sometimes it's hard to convert one to another.
A lot of the code was based on GLFW implementation because it deals with very hard cases.

I've introduced X11InputManager singleton, because someone needs to hold mappings between keycodes and SFML's scancodes. If someone comes up with a better alternative - I'll be happy to remake it. :)


getDescription was pretty hard to implement because there's no easy way to convert keycode or keysym to unicode. One way of doing it is using huge lookup tables like this one. But thankfully, we have Xutf8LookupString now. But we need to create a fake event for it to work... which works, but isn't pretty.
And one more thing: some keys like Tab, Enter and Space produce unwanted results - they return " ", "\n" or "\t", so they have to be accounted for. It's even worse for Delete or Backspace, but it's the same thing.


There'll probably be a lot of things which need to be fixed with my code - I haven't done much X11 programming, so maybe I've made some mistakes - I'll be happy to fix them.

@eliasdaler
Copy link
Contributor Author

eliasdaler commented Mar 29, 2018

Oh, and one more thing - maybe it's worth putting KeySym <-> sf::Keyboard::Key mappings to a separate header? They make X11InputManager.cpp much longer than it could be.

@mantognini
Copy link
Member

Fantastic! Looking forward testers feedback.

Feel free to split files in a meaningful manner. I'll probably end up doing something similar for macOS. ;-)

@binary1248
Copy link
Member

Is the singleton really necessary? We already have a reference counted Display in Display.cpp. You can initialize the stuff in OpenDisplay, deinitialize the stuff in CloseDisplay and convert all those methods to static methods. I would also give the XInputManager its own XIC. Something tells me that sharing it with some random Window (and even changing it whenever new Windows are created) won't work out so well...

@eliasdaler
Copy link
Contributor Author

Fair enough. But where should I store the mapping between the keycodes and scancodes?

@binary1248
Copy link
Member

In an anonymous namespace at the top of XInputManager.cpp like is done in all the other files.

@eliasdaler
Copy link
Contributor Author

eliasdaler commented Mar 31, 2018

So, I did tons of work on this:

  • X11InputManager is now KeyboardImpl as it deals with keyboard input only, and we already have JoysticImpl, so it's similar.
  • We don't need a singleton anymore - everything is static.
  • I've made a script which generated a giant switch-case which maps KeySym to Unicode from this file. Sadly, XLib doesn't provide a way to do it without such mappings. I can share the script I made to generate the function if anyone is interested.

Okay, some of the namings might not be perfect, so feel free to give feedback about how to improve them.
And I'll see if I can make less conversions between KeySyms, Keycodes, sf::Keyboard::Key and sf::Keyboard::Scancode. But right now the implementation looks a lot better!

@eliasdaler
Copy link
Contributor Author

eliasdaler commented Apr 7, 2018

Thanks a lot for testing!

At first I made a commit to change ScanEnter and ScanReturn, but then I realized that I've made a mistake. Right now ScanEnter = keyboard enter and ScanReturn = numpad enter. That's how @mantognini wrote it for now.

As for the naming - getDescription now returns "Enter" and "Enter (Numpad)". The names of scancodes should be discussed in #1235 and it seems like we may agree to have ScanEnter for keyboard "Enter" and ScanNumpadEnter for numpad "Enter". It's still not 100%, so you should probably post your point there!

Also see #1395. We agreed to have sf::Keyboard::Enter, so it should be ScanEnter for main Enter, not ScanReturn, imo.

P. S. "Fn" is keyboard specific and it's impossible to handle it.

@@ -89,6 +89,10 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
${SRCROOT}/Unix/Display.hpp
${SRCROOT}/Unix/InputImpl.cpp
${SRCROOT}/Unix/InputImpl.hpp
${SRCROOT}/Unix/KeyboardImpl.hpp
${SRCROOT}/Unix/KeyboardImpl.cpp
${SRCROOT}/Unix/KeySymToSFKeyMapping.hpp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no name clash, I would just drop the SF.

#include <SFML/System/Err.hpp>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <cstring>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still needed? I don't see any new line of code that would need this included.

////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2017 Laurent Gomila (laurent@sfml-dev.org)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2018

/// \return The corresponding sf::Keyboard::Key
///
////////////////////////////////////////////////////////////
inline Keyboard::Key keySymToSFKey(KeySym symbol)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no name clash, I would just drop the SF.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think any sane compiler is going to actually inline this function. The resulting jump table is going to be so huge that it would completely wreck the instruction cache. I would rather just move the implementation into a .cpp file. It shouldn't make any noticeable difference performance-wise.

/// \return The corresponding X11 KeySym
///
////////////////////////////////////////////////////////////
inline KeySym SFKeyToKeySym(Keyboard::Key key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I would drop SF if I could.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think any sane compiler is going to actually inline this function. The resulting jump table is going to be so huge that it would completely wreck the instruction cache. I would rather just move the implementation into a .cpp file. It shouldn't make any noticeable difference performance-wise.

case Keyboard::ScanRShift: return "Shift (Right)";
case Keyboard::ScanRAlt: return "Meta (Right)";
case Keyboard::ScanRSystem: return "Super (Right)";
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move "Unknown Scancode" into a default case.

if (key != Keyboard::Unknown)
break;
}
return key;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aesthetics, would insert an empty line before this return.

}

} // namespace priv
} // namespace sf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing empty line before this line.

////////////////////////////////////////////////////////////
/// \brief sf::priv::InputImpl helper
///
/// This class manage as a singleton instance the keyboard state.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a singleton any more. 😉

#include <X11/X.h> // Keycode
#include <X11/XKBlib.h>

namespace sf {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namespace curly braces on new lines.

@eliasdaler
Copy link
Contributor Author

That's a lot of feedback, thanks a lot!
And I also found a bug, "Escape" wasn't shown correctly. Fixed it in the same commit.

For now, I don't know what to do with fallthrough cases. Should I just place return statements here?

@binary1248
Copy link
Member

For now, I don't know what to do with fallthrough cases. Should I just place return statements here?

Yes.

@eliasdaler
Copy link
Contributor Author

Done!

Copy link
Member

@binary1248 binary1248 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few more aesthetic touch ups but otherwise this is good with me. 👍

case 0x04b4: return 0x30a8; // kana_E
case 0x04ab: return 0x30a9; // kana_o
case 0x04b5: return 0x30aa; // kana_O
case 0x04b6: return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub says there is no newline at the end of this file.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason, why 'magic numbers' are used instead of constants?
At first glance most of them are defined in X11/keysym.h.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, indeed. I must have only seen X11/keysym.h, but didn't take a look at keysymdef.h, where all these codes are.
Will redo this giant switch later. :)

{

const KeyCode NullKeyCode = 0;
KeyCode scancodeToKeycode[sf::Keyboard::ScanCodeCount]; ///< Mapping of SFML scancode to X11 KeyCode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the space before the comment meant for alignment with the line below? I can't tell what is the intention here.

bool isValidKeycode(KeyCode keycode)
{
// Valid key code range is [8,255], according to the Xlib manual
return keycode >= 8 || keycode <= 255;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might not be necessary, but brackets around the comparisons makes it safer and maybe even a bit more readable.

std::memcpy(name, desc->names->keys[keycode].name, XkbKeyNameLength);
name[XkbKeyNameLength] = '\0';

if (strcmp(name, "TLDE") == 0) sc = sf::Keyboard::ScanGraveAccent;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would align the (strcmp(name, "TLDE") == 0) with the lines below just for that extra touch.

else if (strcmp(name, "AE10") == 0) sc = sf::Keyboard::ScanNum0;
else if (strcmp(name, "AE11") == 0) sc = sf::Keyboard::ScanDash;
else if (strcmp(name, "AE12") == 0) sc = sf::Keyboard::ScanEquals;
else if (strcmp(name, "TAB") == 0) sc = sf::Keyboard::ScanTab;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would align the ) == 0) with the other lines.

@eliasdaler
Copy link
Contributor Author

Agreed with everything. Done! 👍

@eliasdaler
Copy link
Contributor Author

@HiImJulien

Looking back at why I didn't use the mapping already present in <X11/keysym.h> - it doesn't really correspond to correct and actual Unicode code points! See

... So this mapping is really necessary.

@eXpl0it3r eXpl0it3r force-pushed the feature/scancode branch 5 times, most recently from 6c85444 to be8c225 Compare January 28, 2020 15:52
@eXpl0it3r
Copy link
Member

I've rebased, fixed my bad rebase mistakes and merged your branch onto feature/scancode, hope you don't mind. 😉
Let's iron out the rest on one branch, so refactorings are a bit easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants