Difference between revisions of "User:Crond/sandbox/openglSpecialKeyboardExample"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
(Created page with "{{VersionBadge|0.7}} {{VersionAtLeast|0.7.5}} <br /><br /><br /><br /> == Introduction == This is a simple modification of the basic OpenGL application, as found [[User:Crond/sa...")
 
m (Requirements: superfluous)
 
(3 intermediate revisions by the same user not shown)
Line 3: Line 3:
  
 
== Introduction ==
 
== Introduction ==
This is a simple modification of the basic OpenGL application, as found [[User:Crond/sandbox/openglExample|here]]. The goal is to present the basics of keyboard processing, via OpenGL and PyCEGUI.
+
This is a simple modification of the basic keyboard processing OpenGL application, as found [[User:Crond/sandbox/openglKeyboardExample|here]]. The goal is to present a further refinement of keyboard processing, specifically the handling of "special" keys, via OpenGL and PyCEGUI.
  
 
== Requirements ==
 
== Requirements ==
* Python 2.6 (untested on Python 3.+)
+
* Python 2.6
 
* PyCEGUI
 
* PyCEGUI
* PyOpenGL (GLU and GLUT, as well)
+
* PyOpenGL
  
 
== Notes ==
 
== Notes ==
Line 52: Line 52:
 
class Application(object):
 
class Application(object):
  
  # Constructor
+
    # Constructor
  def __init__(self):
+
    def __init__(self):
    super(Application, self).__init__()
+
        super(Application, self).__init__()
    self.lastFrameTime = 0
+
        self.lastFrameTime = 0
    self.updateFPS = 0
+
        self.updateFPS = 0
    return
+
        return
  
  # Initialize: OpenGL
+
    # Initialize: OpenGL
  # - A full list of values for `glutInitDisplayMode` can be found in the GLUT
+
    # - A full list of values for `glutInitDisplayMode` can be found in the GLUT
  #  documentation.
+
    #  documentation.
  def initializeOpenGL(self):
+
    def initializeOpenGL(self):
    glutInit()
+
        glutInit()
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
+
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
    glutInitWindowSize(1024, 768)
+
        glutInitWindowSize(1024, 768)
    glutInitWindowPosition(-1, -1) # Let the windowing system figure it out
+
        glutInitWindowPosition(-1, -1) # Let the windowing system figure it out
    glutCreateWindow("Crazy Eddie's GUI Mk-2 - glut Base Application")
+
        glutCreateWindow("Crazy Eddie's GUI Mk-2 - glut Base Application")
    glutSetCursor(GLUT_CURSOR_NONE)
+
        glutSetCursor(GLUT_CURSOR_NONE)
    return
+
        return
  
  # Initialize: Handlers
+
    # Initialize: Handlers
  # - Setup the methods which will be called when events happen.
+
    # - Setup the methods which will be called when events happen.
  def initializeHandlers(self):
+
    def initializeHandlers(self):
    glutDisplayFunc(self.handlerDisplay)
+
        glutDisplayFunc(self.handlerDisplay)
    glutReshapeFunc(self.handlerResize)
+
        glutReshapeFunc(self.handlerResize)
    glutKeyboardFunc(self.handlerKeyboard)
+
        glutKeyboardFunc(self.handlerKeyboard)
    glutSpecialFunc(self.handlerKeyboardSpecial)
+
        glutSpecialFunc(self.handlerKeyboardSpecial)
    glutMouseFunc(self.handlerMouse)
+
        glutMouseFunc(self.handlerMouse)
    glutMotionFunc(self.handlerMouseMotion)
+
        glutMotionFunc(self.handlerMouseMotion)
    glutPassiveMotionFunc(self.handlerMouseMotion)
+
        glutPassiveMotionFunc(self.handlerMouseMotion)
    return
+
        return
  
  # Initialize: PyCEGUI
+
    # Initialize: PyCEGUI
  # - Store some components; saves a lot of typing.
+
    # - Store some components; saves a lot of typing.
  def initializePyCEGUI(self):
+
    def initializePyCEGUI(self):
    Renderer.bootstrapSystem()
+
        Renderer.bootstrapSystem()
    self.sys = PyCEGUI.System.getSingleton()
+
        self.sys = PyCEGUI.System.getSingleton()
    self.rp = self.sys.getResourceProvider()
+
        self.rp = self.sys.getResourceProvider()
    self.scheme = PyCEGUI.SchemeManager.getSingleton()
+
        self.scheme = PyCEGUI.SchemeManager.getSingleton()
    self.wm = PyCEGUI.WindowManager.getSingleton()
+
        self.wm = PyCEGUI.WindowManager.getSingleton()
    return
+
        return
  
  # Initialize: Defaults
+
    # Initialize: Defaults
  # - Resource locations.
+
    # - Resource locations.
  def initializeDefaults(self):
+
    def initializeDefaults(self):
    self.rp.setResourceGroupDirectory('schemes', os.path.join(PATH_RESOURCES, 'datafiles/schemes'))
+
        self.rp.setResourceGroupDirectory('schemes', os.path.join(PATH_RESOURCES, 'datafiles/schemes'))
    self.rp.setResourceGroupDirectory('imagesets', os.path.join(PATH_RESOURCES, 'datafiles/imagesets'))
+
        self.rp.setResourceGroupDirectory('imagesets', os.path.join(PATH_RESOURCES, 'datafiles/imagesets'))
    self.rp.setResourceGroupDirectory('fonts', os.path.join(PATH_RESOURCES, 'datafiles/fonts'))
+
        self.rp.setResourceGroupDirectory('fonts', os.path.join(PATH_RESOURCES, 'datafiles/fonts'))
    self.rp.setResourceGroupDirectory('layouts', os.path.join(PATH_RESOURCES, 'datafiles/layouts'))
+
        self.rp.setResourceGroupDirectory('layouts', os.path.join(PATH_RESOURCES, 'datafiles/layouts'))
    self.rp.setResourceGroupDirectory('looknfeels', os.path.join(PATH_RESOURCES, 'datafiles/looknfeel'))
+
        self.rp.setResourceGroupDirectory('looknfeels', os.path.join(PATH_RESOURCES, 'datafiles/looknfeel'))
    self.rp.setResourceGroupDirectory('schemas', os.path.join(PATH_RESOURCES, 'datafiles/xml_schemas'))
+
        self.rp.setResourceGroupDirectory('schemas', os.path.join(PATH_RESOURCES, 'datafiles/xml_schemas'))
    PyCEGUI.Imageset.setDefaultResourceGroup('imagesets')
+
        PyCEGUI.Imageset.setDefaultResourceGroup('imagesets')
    PyCEGUI.Font.setDefaultResourceGroup('fonts')
+
        PyCEGUI.Font.setDefaultResourceGroup('fonts')
    PyCEGUI.Scheme.setDefaultResourceGroup('schemes')
+
        PyCEGUI.Scheme.setDefaultResourceGroup('schemes')
    PyCEGUI.WidgetLookManager.setDefaultResourceGroup('looknfeels')
+
        PyCEGUI.WidgetLookManager.setDefaultResourceGroup('looknfeels')
    PyCEGUI.WindowManager.setDefaultResourceGroup('layouts')
+
        PyCEGUI.WindowManager.setDefaultResourceGroup('layouts')
    parser = self.sys.getXMLParser()
+
        parser = self.sys.getXMLParser()
    if parser.isPropertyPresent('SchemaDefaultResourceGroup'):
+
        if parser.isPropertyPresent('SchemaDefaultResourceGroup'):
      parser.setProperty('SchemaDefaultResourceGroup', 'schemas')
+
            parser.setProperty('SchemaDefaultResourceGroup', 'schemas')
    return
+
        return
  
  # Initialize: GUI
+
    # Initialize: GUI
  # - This is where we are actually setting up the windows we will see.
+
    # - This is where we are actually setting up the windows we will see.
  def initializeGUI(self):
+
    def initializeGUI(self):
    self.scheme.create('VanillaSkin.scheme')
+
        self.scheme.create('VanillaSkin.scheme')
    self.scheme.create('TaharezLook.scheme')
+
        self.scheme.create('TaharezLook.scheme')
  
    # GUISheet
+
        # GUISheet
    self.rootWindow = self.wm.loadWindowLayout('VanillaWindows.layout')
+
        self.rootWindow = self.wm.loadWindowLayout('VanillaWindows.layout')
    self.sys.setGUISheet(self.rootWindow)
+
        self.sys.setGUISheet(self.rootWindow)
  
    # Cursor
+
        # Cursor
    self.sys.setDefaultMouseCursor('Vanilla-Images', 'MouseArrow')
+
        self.sys.setDefaultMouseCursor('Vanilla-Images', 'MouseArrow')
  
    # An extra window
+
        # An extra window
    w = self.wm.createWindow('TaharezLook/FrameWindow', 'Demo window')
+
        w = self.wm.createWindow('TaharezLook/FrameWindow', 'Demo window')
    self.rootWindow.addChildWindow(w)
+
        self.rootWindow.addChildWindow(w)
    return
+
        return
  
  # Initialize
+
    # Initialize
  def Initialize(self):
+
    def Initialize(self):
    self.initializeOpenGL()
+
        self.initializeOpenGL()
    self.initializeHandlers()
+
        self.initializeHandlers()
    self.initializePyCEGUI()
+
        self.initializePyCEGUI()
    self.initializeDefaults()
+
        self.initializeDefaults()
    self.initializeGUI()
+
        self.initializeGUI()
    return
+
        return
  
  # Handler: Display
+
    # Handler: Display
  def handlerDisplay(self):
+
    def handlerDisplay(self):
  
    # Injecting the time allows CEGUI to know how much time has passed, and
+
        # Injecting the time allows CEGUI to know how much time has passed, and
    # use that to coordinate certain activities - fading, animation, tooltips,
+
        # use that to coordinate certain activities - fading, animation, tooltips,
    # etc.
+
        # etc.
    now = glutGet(GLUT_ELAPSED_TIME)
+
        now = glutGet(GLUT_ELAPSED_TIME)
    elapsed = (now - self.lastFrameTime) / 1000.0
+
        elapsed = (now - self.lastFrameTime) / 1000.0
    self.lastFrameTime = now
+
        self.lastFrameTime = now
    self.updateFPS = self.updateFPS - elapsed
+
        self.updateFPS = self.updateFPS - elapsed
    self.sys.injectTimePulse(elapsed)
+
        self.sys.injectTimePulse(elapsed)
  
    # Actual rendering
+
        # Actual rendering
    # - `renderGUI` updates CEGUI's picture of the GUI.
+
        # - `renderGUI` updates CEGUI's picture of the GUI.
    # - `glutPostRedisplay` is what actually marks the window as needing to
+
        # - `glutPostRedisplay` is what actually marks the window as needing to
    #  be redrawn by OpenGL.
+
        #  be redrawn by OpenGL.
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    self.sys.renderGUI()
+
        self.sys.renderGUI()
    glutPostRedisplay()
+
        glutPostRedisplay()
    glutSwapBuffers()
+
        glutSwapBuffers()
    return
+
        return
  
  # Handler: Resize
+
    # Handler: Resize
  # - `glViewport` modifies the OpenGL viewport to whatever the window size is.
+
    # - `glViewport` modifies the OpenGL viewport to whatever the window size is.
  def handlerResize(self, width, height):
+
    def handlerResize(self, width, height):
    glViewport(0, 0, width, height)
+
        glViewport(0, 0, width, height)
    self.sys.notifyDisplaySizeChanged(PyCEGUI.Size(width, height))
+
        self.sys.notifyDisplaySizeChanged(PyCEGUI.Size(width, height))
    return
+
        return
  
  # Handler: Assist keyboard
+
    # Handler: Assist keyboard
  def handlerAssistKeyboard(self, key):
+
    def handlerAssistKeyboard(self, key):
    try:
+
        try:
      self.sys.injectKeyDown(KEYMAP_ASCII[key])
+
            self.sys.injectKeyDown(KEYMAP_ASCII[key])
    except KeyError:
+
        except KeyError:
      return False
+
            return False
  return True
+
        return True
  
  # Handler: Keyboard
+
    # Handler: Keyboard
  def handlerKeyboard(self, key, x, y):
+
    def handlerKeyboard(self, key, x, y):
    k = ord(key)
+
        k = ord(key)
    if not self.handlerAssistKeyboard(k):
+
        if not self.handlerAssistKeyboard(k):
      self.sys.injectChar(ord(key))
+
            self.sys.injectChar(ord(key))
  return
+
        return
  
  # Handler: Keyboard special
+
    # Handler: Keyboard special
  def handlerKeyboardSpecial(self, key, x, y):
+
    def handlerKeyboardSpecial(self, key, x, y):
    try:
+
        try:
      self.sys.injectKeyDown(KEYMAP_GLUT[key])
+
            self.sys.injectKeyDown(KEYMAP_GLUT[key])
    except KeyError:
+
        except KeyError:
      # Ignore it.
+
            # Ignore it.
      pass
+
            pass
  return
+
        return
  
  # Handler: Mouse buttons
+
    # Handler: Mouse buttons
  def handlerMouse(self, button, state, x, y):
+
    def handlerMouse(self, button, state, x, y):
    if button == GLUT_LEFT_BUTTON:
+
        if button == GLUT_LEFT_BUTTON:
      if state == GLUT_UP:
+
            if state == GLUT_UP:
        self.sys.injectMouseButtonUp(PyCEGUI.LeftButton)
+
                self.sys.injectMouseButtonUp(PyCEGUI.LeftButton)
      else:
+
            else:
        self.sys.injectMouseButtonDown(PyCEGUI.LeftButton)
+
                self.sys.injectMouseButtonDown(PyCEGUI.LeftButton)
    elif button == GLUT_RIGHT_BUTTON:
+
        elif button == GLUT_RIGHT_BUTTON:
      if state == GLUT_UP:
+
            if state == GLUT_UP:
        self.sys.injectMouseButtonUp(PyCEGUI.RightButton)
+
                self.sys.injectMouseButtonUp(PyCEGUI.RightButton)
      else:
+
            else:
        self.sys.injectMouseButtonDown(PyCEGUI.RightButton)
+
                self.sys.injectMouseButtonDown(PyCEGUI.RightButton)
    return
+
        return
  
  # Handler: Mouse motion
+
    # Handler: Mouse motion
  def handlerMouseMotion(self, x, y):
+
    def handlerMouseMotion(self, x, y):
    self.sys.injectMousePosition(x, y)
+
        self.sys.injectMousePosition(x, y)
     return
+
        return
 +
 
 +
     # Run
 +
    def Run(self):
 +
        self.lastFrameTime = glutGet(GLUT_ELAPSED_TIME)
 +
        glutMainLoop()
 +
        return
  
  # Run
 
  def Run(self):
 
    self.lastFrameTime = glutGet(GLUT_ELAPSED_TIME)
 
    glutMainLoop()
 
    return
 
  
 
# Main
 
# Main
 
def main():
 
def main():
  app = Application()
+
    app = Application()
  app.Initialize()
+
    app.Initialize()
  app.Run()
+
    app.Run()
  return 0
+
    return 0
  
  
 
# Guard
 
# Guard
 
if __name__ == '__main__':
 
if __name__ == '__main__':
  sys.exit(main())
+
    sys.exit(main())
 
</source>
 
</source>
  
Line 238: Line 239:
 
=== GLUT, ASCII, PyCEGUI ===
 
=== GLUT, ASCII, PyCEGUI ===
 
It can be a little tricky, at times, to separate them all. A good rule of thumb is that using the `ord` function on any input received via GLUT will produce the ASCII value, which can then be handled in whatever way the application desires - e.g. mapping it to a PyCEGUI value.
 
It can be a little tricky, at times, to separate them all. A good rule of thumb is that using the `ord` function on any input received via GLUT will produce the ASCII value, which can then be handled in whatever way the application desires - e.g. mapping it to a PyCEGUI value.
 +
 +
An additional note is that what GLUT considers to be a "special" key is not exactly what PyCEGUI (or any other library, for that matter) considers to be special. For this reason, the `KEYMAP_ASCII` exists and helps define additional keys that are special, whatever that may mean in a particular context.

Latest revision as of 15:51, 20 June 2011

Written for CEGUI 0.7


Works with versions 0.7.x (obsolete)

Requires at least version
0.7.5





Introduction

This is a simple modification of the basic keyboard processing OpenGL application, as found here. The goal is to present a further refinement of keyboard processing, specifically the handling of "special" keys, via OpenGL and PyCEGUI.

Requirements

  • Python 2.6
  • PyCEGUI
  • PyOpenGL

Notes

This example assumes you have the CEGUI resources located in the same directory as the script; change `PATH_RESOURCES` if they are elsewhere.

Source

#!/usr/bin/env python
#
#
# example.py
 
 
# Import: std
import sys, os
 
# Import: PyOpenGL
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
 
# Import: PyCEGUI
import PyCEGUI
from PyCEGUIOpenGLRenderer import OpenGLRenderer as Renderer
 
# Constants
PATH_RESOURCES = './'
 
# Keymap: ASCII
KEYMAP_ASCII = {8 : PyCEGUI.Key.Scan.Backspace,
                13 : PyCEGUI.Key.Scan.Return,
                27 : PyCEGUI.Key.Scan.Escape,
                127 : PyCEGUI.Key.Scan.Delete}
 
# Keymap: GLUT
KEYMAP_GLUT = {GLUT_KEY_LEFT : PyCEGUI.Key.Scan.ArrowLeft,
               GLUT_KEY_RIGHT : PyCEGUI.Key.Scan.ArrowRight,
               GLUT_KEY_HOME : PyCEGUI.Key.Scan.Home,
               GLUT_KEY_END : PyCEGUI.Key.Scan.End}
 
 
# Application
class Application(object):
 
    # Constructor
    def __init__(self):
        super(Application, self).__init__()
        self.lastFrameTime = 0
        self.updateFPS = 0
        return
 
    # Initialize: OpenGL
    # - A full list of values for `glutInitDisplayMode` can be found in the GLUT
    #   documentation.
    def initializeOpenGL(self):
        glutInit()
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
        glutInitWindowSize(1024, 768)
        glutInitWindowPosition(-1, -1) # Let the windowing system figure it out
        glutCreateWindow("Crazy Eddie's GUI Mk-2 - glut Base Application")
        glutSetCursor(GLUT_CURSOR_NONE)
        return
 
    # Initialize: Handlers
    # - Setup the methods which will be called when events happen.
    def initializeHandlers(self):
        glutDisplayFunc(self.handlerDisplay)
        glutReshapeFunc(self.handlerResize)
        glutKeyboardFunc(self.handlerKeyboard)
        glutSpecialFunc(self.handlerKeyboardSpecial)
        glutMouseFunc(self.handlerMouse)
        glutMotionFunc(self.handlerMouseMotion)
        glutPassiveMotionFunc(self.handlerMouseMotion)
        return
 
    # Initialize: PyCEGUI
    # - Store some components; saves a lot of typing.
    def initializePyCEGUI(self):
        Renderer.bootstrapSystem()
        self.sys = PyCEGUI.System.getSingleton()
        self.rp = self.sys.getResourceProvider()
        self.scheme = PyCEGUI.SchemeManager.getSingleton()
        self.wm = PyCEGUI.WindowManager.getSingleton()
        return
 
    # Initialize: Defaults
    # - Resource locations.
    def initializeDefaults(self):
        self.rp.setResourceGroupDirectory('schemes', os.path.join(PATH_RESOURCES, 'datafiles/schemes'))
        self.rp.setResourceGroupDirectory('imagesets', os.path.join(PATH_RESOURCES, 'datafiles/imagesets'))
        self.rp.setResourceGroupDirectory('fonts', os.path.join(PATH_RESOURCES, 'datafiles/fonts'))
        self.rp.setResourceGroupDirectory('layouts', os.path.join(PATH_RESOURCES, 'datafiles/layouts'))
        self.rp.setResourceGroupDirectory('looknfeels', os.path.join(PATH_RESOURCES, 'datafiles/looknfeel'))
        self.rp.setResourceGroupDirectory('schemas', os.path.join(PATH_RESOURCES, 'datafiles/xml_schemas'))
        PyCEGUI.Imageset.setDefaultResourceGroup('imagesets')
        PyCEGUI.Font.setDefaultResourceGroup('fonts')
        PyCEGUI.Scheme.setDefaultResourceGroup('schemes')
        PyCEGUI.WidgetLookManager.setDefaultResourceGroup('looknfeels')
        PyCEGUI.WindowManager.setDefaultResourceGroup('layouts')
        parser = self.sys.getXMLParser()
        if parser.isPropertyPresent('SchemaDefaultResourceGroup'):
            parser.setProperty('SchemaDefaultResourceGroup', 'schemas')
        return
 
    # Initialize: GUI
    # - This is where we are actually setting up the windows we will see.
    def initializeGUI(self):
        self.scheme.create('VanillaSkin.scheme')
        self.scheme.create('TaharezLook.scheme')
 
        # GUISheet
        self.rootWindow = self.wm.loadWindowLayout('VanillaWindows.layout')
        self.sys.setGUISheet(self.rootWindow)
 
        # Cursor
        self.sys.setDefaultMouseCursor('Vanilla-Images', 'MouseArrow')
 
        # An extra window
        w = self.wm.createWindow('TaharezLook/FrameWindow', 'Demo window')
        self.rootWindow.addChildWindow(w)
        return
 
    # Initialize
    def Initialize(self):
        self.initializeOpenGL()
        self.initializeHandlers()
        self.initializePyCEGUI()
        self.initializeDefaults()
        self.initializeGUI()
        return
 
    # Handler: Display
    def handlerDisplay(self):
 
        # Injecting the time allows CEGUI to know how much time has passed, and
        # use that to coordinate certain activities - fading, animation, tooltips,
        # etc.
        now = glutGet(GLUT_ELAPSED_TIME)
        elapsed = (now - self.lastFrameTime) / 1000.0
        self.lastFrameTime = now
        self.updateFPS = self.updateFPS - elapsed
        self.sys.injectTimePulse(elapsed)
 
        # Actual rendering
        # - `renderGUI` updates CEGUI's picture of the GUI.
        # - `glutPostRedisplay` is what actually marks the window as needing to
        #   be redrawn by OpenGL.
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        self.sys.renderGUI()
        glutPostRedisplay()
        glutSwapBuffers()
        return
 
    # Handler: Resize
    # - `glViewport` modifies the OpenGL viewport to whatever the window size is.
    def handlerResize(self, width, height):
        glViewport(0, 0, width, height)
        self.sys.notifyDisplaySizeChanged(PyCEGUI.Size(width, height))
        return
 
    # Handler: Assist keyboard
    def handlerAssistKeyboard(self, key):
        try:
            self.sys.injectKeyDown(KEYMAP_ASCII[key])
        except KeyError:
            return False
        return True
 
    # Handler: Keyboard
    def handlerKeyboard(self, key, x, y):
        k = ord(key)
        if not self.handlerAssistKeyboard(k):
            self.sys.injectChar(ord(key))
        return
 
    # Handler: Keyboard special
    def handlerKeyboardSpecial(self, key, x, y):
        try:
            self.sys.injectKeyDown(KEYMAP_GLUT[key])
        except KeyError:
            # Ignore it.
            pass
        return
 
    # Handler: Mouse buttons
    def handlerMouse(self, button, state, x, y):
        if button == GLUT_LEFT_BUTTON:
            if state == GLUT_UP:
                self.sys.injectMouseButtonUp(PyCEGUI.LeftButton)
            else:
                self.sys.injectMouseButtonDown(PyCEGUI.LeftButton)
        elif button == GLUT_RIGHT_BUTTON:
            if state == GLUT_UP:
                self.sys.injectMouseButtonUp(PyCEGUI.RightButton)
            else:
                self.sys.injectMouseButtonDown(PyCEGUI.RightButton)
        return
 
    # Handler: Mouse motion
    def handlerMouseMotion(self, x, y):
        self.sys.injectMousePosition(x, y)
        return
 
    # Run
    def Run(self):
        self.lastFrameTime = glutGet(GLUT_ELAPSED_TIME)
        glutMainLoop()
        return
 
 
# Main
def main():
    app = Application()
    app.Initialize()
    app.Run()
    return 0
 
 
# Guard
if __name__ == '__main__':
    sys.exit(main())

Demonstration

As before, we can see that this works by running the application, typing into the Editbox, and pressing the arrow keys, or any of the other keys.

Several keys, such as Escape and Return, are not readily testable (i.e. produce no discernible effects on the application), although they do work. It is left as an exercise to the reader to prove it.

Examination

GLUT, ASCII, PyCEGUI

It can be a little tricky, at times, to separate them all. A good rule of thumb is that using the `ord` function on any input received via GLUT will produce the ASCII value, which can then be handled in whatever way the application desires - e.g. mapping it to a PyCEGUI value.

An additional note is that what GLUT considers to be a "special" key is not exactly what PyCEGUI (or any other library, for that matter) considers to be special. For this reason, the `KEYMAP_ASCII` exists and helps define additional keys that are special, whatever that may mean in a particular context.