2
\$\begingroup\$

I am starting to learn C programming, though I have a lot of experience using higher-level languages. I want to write a game engine using C and OpenGL. I think I understand the graphics rendering part, but now I'm curious about how to receive and process keyboard, mouse and controller input. How does one implement this sort of thing in C?

\$\endgroup\$
8
  • \$\begingroup\$ If you do not want to use an already made library, you need to interact directly with the OS. So your implementation will be OS dependent. Which OS would you like to build it for? \$\endgroup\$ – Marco Sep 22 '13 at 21:45
  • 1
    \$\begingroup\$ This isn't really a game development specific question, you'll likely find better answers (and it's probably already been asked) on stackoverflow.com. \$\endgroup\$ – MichaelHouse Sep 22 '13 at 21:49
  • \$\begingroup\$ I added an update. Initially I want to be able to run it on Linux, but writing it in C so that it can support multiple platforms. I assumed that C already abstracted the cross-platform implementation, but it sounds like I'm wrong. \$\endgroup\$ – Andrew Sep 22 '13 at 22:17
  • \$\begingroup\$ C becomes platform dependent when you use OS specific library or API in the code. For instance in order to handle inputs in Windows you need to use the Windows API and when you do you loose compatibility with Linux. Cross-platform library in C implement both code specific for windows and code specific for linux with a common interface, so that they provide a cross-platform interface that you can use, without worrying about how the library will manage your request with the OS \$\endgroup\$ – Marco Sep 22 '13 at 22:27
  • 2
    \$\begingroup\$ The base C API is very anemic. It supports some basic file I/O and terminal I/O and that's it. Rendering, windowing, graphical input support, audio, networking, advanced file I/O, etc. are all platform-dependent. Use a library like SDL if you want portability of this stuff. \$\endgroup\$ – Sean Middleditch Sep 22 '13 at 22:51
1
\$\begingroup\$

While you can certainly pick a cross platform library, if you want to write the input functions yourself, you'd need to create some generic code interfacing rules or C++ objects which would cover all platforms to do this neatly. Then you would create implementations that are platform specific, only compiled when the library is being built for that platform.

At least that piece, I can assist with. The following link shows how to use preprocessor directives to detect Windows, and it should work in most cases, although there may be some caveat for 32-bit versions. You would still need to find platform specific APIs to manage the input gathering for each target platform, and perhaps manage the project settings for the compiler / IDE to create multiple build targets, each one for a different target environment. In short, it's the complicated method...

https://stackoverflow.com/questions/3213037/determine-if-linux-or-windows-in-c

If you instead wish to use GLUT, a tutorial is available here that should set you on the right path. I don't think it includes creating Windows, but I hear that GLUT does that as well...

http://www.lighthouse3d.com/tutorials/glut-tutorial/keyboard/

If you have any other questions, I can see what can be done to answer them.

--- EDIT ----

Since it was requested, I can provide a high level idea of how input gathering works, and with some more direction, I can give something more concrete, although I've never used GLUT personally.

There are two methods of gathering input, polling and event based. Polling is preferred for gaming, because you want to be able to get all the input that happened in a frame at once during your update loop. However, in reality, it's all happening in an event based model, even if you go as deep as interrupt handlers in your operating system kernel, interacting with the lowest levels of circuitry. I won't belabor that part, because someone else is probably better licensed to answer that question.

In an event based model, some callback function is fired each time a key is pressed. This happens asynchronously, so some form of multitasking is involved, such as threading, or interrupts, at the lower levels. In this model you hand the input engine a function, which is called each time the event happens, in this case, a key press or a mouse movement. Let's say it looks like this, for a fictitious InputObject API...

void gatherInput(InputObject input)
{
 if(input.isKey())
 {
      doKeyPress(input.getKeyCode());
 }
 else if(input.isMouse())
 {
      doMouseMovement(input.getMousePosition());
 }
}

Obviously, you would want more functionality, like getting modifier keys, or getting mouse button presses and the position, but you get the idea.

The best idea for a video game, though, if it's not already done for you, is to create a polling environment. In this environment, the polling mechanism is basically a queue or some other structure into which our fictitious InputObject entries would be logged. Then all at once, we would call some methods on our input poll, which would allow us to dequeue InputObjects and respond to them, one at a time. This has the obvious advantage that all input since you last ran update in your game loop is collected and responded to at the same time, so that the game logic isn't updating at a different timestep than the input gathering.

An input polling method might look like the following...

void update(Time time)
{
    while(this.inputQueue.hasNext())
    {
     InputObject i = this.inputQueue.dequeue();

     if(i.isKey())
     {
         doKeyPress(i.getKeyCode());
     }
     else if(i.isMouse())
     {
         doMouseMovement(i.getMousePosition());
     }
     // etc...
    }

    simulate(time);
    animate(time);
    draw(time);
    //etc...
}

For some input libraries, you may have to convert events into a polling queue of your own design. In this case, the events simply enqueue the objects containing input into some input queue, and you get them one at a time on each update. This is the preferred method, as previously stated.

Hopefully, that's clear as mud, but if it's ever so slightly clearer, please feel free to offer points:)

\$\endgroup\$
2
  • \$\begingroup\$ Could you provide a high-level overview of the differences in input are handled? Now that I know input is not standardized, I will probably reuse an existing library, but it would still be nice to understand how these are implemented behind the scenes. \$\endgroup\$ – Andrew Sep 23 '13 at 17:25
  • \$\begingroup\$ The example is C++ not C. C is not object oriented. \$\endgroup\$ – Krii May 1 '16 at 2:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.