bsl / GLFW-b

Haskell bindings to GLFW
BSD 2-Clause "Simplified" License
71 stars 32 forks source link

Every Key event is Key'UnknownKey #94

Open unclechu opened 2 years ago

unclechu commented 2 years ago

I set a callback using setKeyCallback function but every key press is just Key'UnknownKey. For instance if I press Escape the Key would be Key'UnknownKey and scancode would be 9. Any ideas why the keys are not recognized? Maybe I’m missing some dependencies like Xkb to map some layouts or something?

unclechu commented 2 years ago

GLFW.getKeyScancode GLFW.Key'Escape returns -1 :shrug:

unclechu commented 2 years ago
Prelude Graphics.UI.GLFW> getKeyScancode Key'Q
-1
bsl commented 2 years ago

Hmm, has GLFW been initialized? I have not messed around with this stuff for a long time, but I just saw this in the underlying library that provides all the functionality. https://github.com/glfw/glfw/blob/master/src/input.c#L648

unclechu commented 2 years ago

Yep, GLFW is initialized.

  GLFW.init >>= flip unless (fail "Failed to initialize GLFW!")

If you’d like to see the whole thing:
https://github.com/unclechu/playing-with-shaders/tree/e881105a01e954b2ec384fbd63509a547a4623a6/haskell-version

bsl commented 2 years ago

OK. Could you try to do some stuff with e.g. getError and/or setErrorCallback? Maybe something useful is being returned from GLFW.

unclechu commented 2 years ago

@bsl I have the error callback as well. Nothing is triggered I believe.

bsl commented 2 years ago

I see, maybe we have to look deeper to the platform implementation of getKeyScancode. You're on Linux, right?

bsl commented 2 years ago

I think maybe you were onto something about xkb. In GLFW's x11_init.c I see a createKeyTables that begins by memseting some scan code array to -1, which seems related to your issue. Then, a lot of code is conditioned by if (_glfw.x11.xkb.available). I don't know what that means, but maybe GLFW thinks xkb is not available on your system? Is that some optional component you can install?

unclechu commented 2 years ago

You're on Linux, right?

Yes. I have similar implementation in C++ and this works fine:

  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
    cout
      << "Received escape key press event. "
      << "Marking window as closing…"
      << endl;
    glfwSetWindowShouldClose(window, GLFW_TRUE);
  } else if (on_key_event != nullptr) {
    on_key_event.value()(key, scancode, action, mods);
  }
unclechu commented 2 years ago

@bsl

I don't know what that means, but maybe GLFW thinks xkb is not available on your system? Is that some optional component you can install?

Yeah, I had the same idea, that xkb is not available or something. It is available in my system but it could be, I think, that the source code of libxkb or something was not provided. Will try to look into the project setup in this context.

bsl commented 2 years ago

One more thing that occurs to me is, your C++ program and GLFW-b program may be using different GLFW versions. I don't know if that matters in this case, but it might. GLFW-b depends on bindings-GLFW, which bundles GLFW 3.3.2 (I think). But your C++ program will be linked against whatever version of GLFW was installed by apt (or whatever).

bsl commented 2 years ago

Some other ideas came to me. I was looking at https://github.com/bsl/bindings-GLFW/blob/master/bindings-GLFW.cabal and I see first of all that there are some flags. It could be helpful to build or install with different flags. Secondly, I see that we link in additional libraries via the extra-libraries section. Is there an xkb library we could add there? And/or xkbcommon?

I'm sorry I can't just try these things directly, but these ideas may help the other devs who still have the setup to do the builds.

unclechu commented 2 years ago

One more thing that occurs to me is, your C++ program and GLFW-b program may be using different GLFW versions. I don't know if that matters in this case, but it might. GLFW-b depends on bindings-GLFW, which bundles GLFW 3.3.2 (I think). But your C++ program will be linked against whatever version of GLFW was installed by apt (or whatever).

I was about to say it’s not possible because I use Nix and the same nixpkgs pin for both Haskell and C++ versions. But I looked at bindings-GLFW:

https://github.com/bsl/bindings-GLFW/tree/master/glfw/src

And realized that it has its own copy of the GLFW sources. But still:

But your C++ program will be linked against whatever version of GLFW was installed by apt (or whatever).

In my case it’s a determined version by the nixpkgs pin that I use for the project.

C++ version build:

$ ldd result/bin/app | rg -i glfw
        libglfw.so.3 => /nix/store/a0j4adpnc5z9000lrhil0sv1xcj9y87k-glfw-3.3.4/lib/libglfw.so.3 (0x00007f97e05cc000)
$ nix repl <<< 'with import (import nix/sources.nix).nixpkgs {}; glfw.version'
Welcome to Nix version 2.3.16. Type :? for help.

"3.3.4"
$ jq .nixpkgs < nix/sources.json
{
  "branch": "release-21.05",
  "description": "Nix Packages collection",
  "homepage": "",
  "owner": "NixOS",
  "repo": "nixpkgs",
  "rev": "95eed9b64eee24975b880308065654fd059f22c3",
  "sha256": "1x59xdxh2vrnhh4j29nyq7npq70v178j5acdm2zsgamcagm3qif9",
  "type": "tarball",
  "url": "https://github.com/NixOS/nixpkgs/archive/95eed9b64eee24975b880308065654fd059f22c3.tar.gz",
  "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
unclechu commented 2 years ago

I also realized that even though in ghci REPL I get -1 for letter key they are still recognized in the event handler of the application. But:

  1. Only letter keys are recognized (Escape & Tab keys for instance result in Key'Unknown)
  2. Those letter keys are completely detached from the keyboard layout (if I change it to Finnish layout for instance Ä and Ö keys are recognized as Key'Aphostrophe and Key'Semicolon)
unclechu commented 2 years ago

@bsl Tried to add extra-libraries: xkbcommon to the cabal file. It’s linked by nothing has changed still.

$ ldd result/bin/gl-playground | rg -i xkb
        libxkbcommon.so.0 => /nix/store/9w0vim093yahm7fbml7xr9wgzadpql1s-libxkbcommon-1.3.0/lib/libxkbcommon.so.0 (0x00007f590b67a000)
unclechu commented 2 years ago

I think it should be bindings-GLFW package that is supposed to be patched?

bsl commented 2 years ago

I think it should be bindings-GLFW package that is supposed to be patched?

Right. The situation is, bindings-GLFW is a very raw binding to the C library. Then GLFW-b makes use of bindings-GLFW to make the API much more Haskell-y. That was a common approach back in the day, hopefully still regarded as OK now.

The symptoms you mentioned, my intuition is that GLFW (the C library) judges xkb unavailable, and uses its alternate backup strategy to do that keyboard stuff. The critical code that GLFW uses to decide if xkb is available is this:

    _glfw.x11.xkb.available =
        XkbQueryExtension(_glfw.x11.display,
                          &_glfw.x11.xkb.majorOpcode,
                          &_glfw.x11.xkb.eventBase,
                          &_glfw.x11.xkb.errorBase,
                          &_glfw.x11.xkb.major,
                          &_glfw.x11.xkb.minor);

Could you see if xdpyinfo shows anything about the presence or absence of xkb on your system?

Mokosha commented 2 years ago

If you have a working example in C, it might be useful to recreate it almost verbatim using only bindings-GLFW. That way we can identify if it’s a GLFW-b error or not.

On Nov 15, 2021, at 1:57 AM, brian @.***> wrote:

 I think it should be bindings-GLFW package that is supposed to be patched?

Right. The situation is, bindings-GLFW is a very raw binding to the C library. Then GLFW-b makes use of bindings-GLFW to make the API much more Haskell-y. That was a common approach back in the day, hopefully still regarded as OK now.

The symptoms you mentioned, my intuition is that GLFW (the C library) judges xkb unavailable, and uses its alternate backup strategy to do that keyboard stuff. The critical code that GLFW uses to decide if xkb is available is this:

_glfw.x11.xkb.available =
    XkbQueryExtension(_glfw.x11.display,
                      &_glfw.x11.xkb.majorOpcode,
                      &_glfw.x11.xkb.eventBase,
                      &_glfw.x11.xkb.errorBase,
                      &_glfw.x11.xkb.major,
                      &_glfw.x11.xkb.minor);

Could you see if xdpyinfo shows anything about the presence or absence of xkb on your system?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android.