diff --git a/generator/Data/XCB/Python/Parse.hs b/generator/Data/XCB/Python/Parse.hs
--- a/generator/Data/XCB/Python/Parse.hs
+++ b/generator/Data/XCB/Python/Parse.hs
@@ -708,7 +708,7 @@
       eventsUpd = mkDictUpdate "_events" opcode cname
       isxge = fromMaybe False xge
       -- xgeexp = mkAssign "xge" (if fromMaybe False xge then (mkName "True") else (mkName "False"))
-  return [Declaration [ mkXClass cname "xcffib.Event" isxge statements (pack : synthetic)
+  return [Declaration [ mkXEventClass cname isxge opcode statements (pack : synthetic)
                        , eventsUpd
                        ]]
 processXDecl ext (XError name opcode _ membs) = do
diff --git a/generator/Data/XCB/Python/PyHelpers.hs b/generator/Data/XCB/Python/PyHelpers.hs
--- a/generator/Data/XCB/Python/PyHelpers.hs
+++ b/generator/Data/XCB/Python/PyHelpers.hs
@@ -26,6 +26,7 @@
   mkClass,
   mkEmptyClass,
   mkXClass,
+  mkXEventClass,
   mkStr,
   mkUnpackFrom,
   mkDict,
@@ -72,12 +73,20 @@
 mkXClass :: String -> String -> Bool -> Suite -> Suite -> Statement
 mkXClass clazz superclazz False [] [] = mkEmptyClass clazz superclazz
 mkXClass clazz superclazz xge constructor methods =
+  mkXClassWithAttrs clazz superclazz [mkXgeAttr xge] constructor methods
+
+mkXEventClass :: String -> Bool -> Int -> Suite -> Suite -> Statement
+mkXEventClass clazz xge eventNumber =
+  mkXClassWithAttrs clazz "xcffib.Event" [mkXgeAttr xge, mkAssign "event_number" (Int eventNumber)]
+
+mkXClassWithAttrs :: String -> String -> Suite -> Suite -> Suite -> Statement
+mkXClassWithAttrs clazz superclazz [] [] [] = mkEmptyClass clazz superclazz
+mkXClassWithAttrs clazz superclazz classAttrs constructor methods =
   let args = [ "self", "unpacker" ]
       super = mkCall (superclazz ++ ".__init__") $ map mkName args
       body = eventToUnpacker : (StmtExpr super) : constructor
-      xgeexp = mkAssign "xge" (if xge then (mkName "True") else (mkName "False"))
       initMethod = Fun "__init__" args body
-  in mkClass clazz superclazz $ xgeexp : initMethod : methods
+  in mkClass clazz superclazz $ classAttrs ++ [initMethod] ++ methods
 
     where
 
@@ -90,6 +99,9 @@
                                                               [mkCall "unpacker.pack" []])
                             cond = mkCall "isinstance" [mkName "unpacker", mkName "xcffib.Protobj"]
                         in mkIf cond [newUnpacker]
+
+mkXgeAttr :: Bool -> Statement
+mkXgeAttr xge = mkAssign "xge" (Bool xge)
 
 
 mkEmptyClass :: String -> String -> Statement
diff --git a/generator/xcffibgen.hs b/generator/xcffibgen.hs
--- a/generator/xcffibgen.hs
+++ b/generator/xcffibgen.hs
@@ -22,6 +22,52 @@
 import System.Directory
 import System.FilePath
 
+import Control.Monad (mfilter)
+import Data.Char (isAlphaNum, isHexDigit)
+import Data.List (isPrefixOf, sort, stripPrefix)
+import Data.Maybe (fromMaybe, mapMaybe)
+import System.Environment (lookupEnv)
+import System.Process (readProcess)
+
+keysymSections :: [String]
+keysymSections =
+  [ "MISCELLANY", "XKB_KEYS", "3270", "LATIN1", "LATIN2", "LATIN3"
+  , "LATIN4", "LATIN8", "LATIN9", "KATAKANA", "ARABIC", "CYRILLIC"
+  , "GREEK", "TECHNICAL", "SPECIAL", "PUBLISHING", "APL", "HEBREW"
+  , "THAI", "KOREAN", "ARMENIAN", "GEORGIAN", "CAUCASUS", "VIETNAMESE"
+  , "CURRENCY", "MATHEMATICAL", "BRAILLE", "SINHALA"
+  ]
+
+generateKeysyms :: FilePath -> IO ()
+generateKeysyms out = do
+  cpp <- fromMaybe "cpp" <$> lookupEnv "CPP"
+  let generate outputName headerFile extraArgs shouldKeep = do
+        defines <- lines <$> readProcess cpp
+          (["-dM"] ++ extraArgs ++ ["-include", headerFile, "-"]) ""
+        writeFile (out </> outputName) . unlines . sort $
+          mapMaybe (fmap formatDefine . mfilter (shouldKeep . fst) . parseDefine) defines
+  generate "keysymdef.py" "X11/keysymdef.h" (map ("-DXK_" ++) keysymSections) $
+    maybe False (`notElem` keysymSections) . stripPrefix "XK_"
+  generate "xf86keysym.py" "X11/XF86keysym.h" [] $ isPrefixOf "XF86XK_"
+  where
+    parseDefine line = case words line of
+      ("#define" : name : vals)
+        | validName name -> Just (name, unwords vals)
+      _ -> Nothing
+
+    validName name = not (null name) && all (\c -> isAlphaNum c || c == '_') name
+
+    formatDefine (name, val) = name ++ " = " ++ renderValue val
+
+    renderValue val = case val of
+      '0' : 'x' : digits
+        | not (null digits) && all isHexDigit digits -> val
+      _ -> case stripPrefix "_EVDEVK(0x" val >>= (fmap reverse . stripPrefix ")" . reverse) of
+        Just digits
+          | not (null digits) && all isHexDigit digits ->
+              "0x10081000 + 0x" ++ digits
+        _ -> error $ "invalid keysym value: " ++ val
+
 data Xcffibgen = Xcffibgen { input :: String
                            , output :: String
                            }
@@ -42,6 +88,7 @@
   headers <- parseXHeaders inp
   createDirectoryIfMissing True out
   sequence_ $ map processFile $ xform headers
+  generateKeysyms out
   where
     processFile (fname, suite) = do
       putStrLn fname
diff --git a/test/generator/event.py b/test/generator/event.py
--- a/test/generator/event.py
+++ b/test/generator/event.py
@@ -8,6 +8,7 @@
 _errors = {}
 class ScreenChangeNotifyEvent(xcffib.Event):
     xge = False
+    event_number = 0
     def __init__(self, unpacker):
         if isinstance(unpacker, xcffib.Protobj):
             unpacker = xcffib.MemoryUnpacker(unpacker.pack())
diff --git a/test/generator/no_sequence.py b/test/generator/no_sequence.py
--- a/test/generator/no_sequence.py
+++ b/test/generator/no_sequence.py
@@ -5,6 +5,7 @@
 _errors = {}
 class KeymapNotifyEvent(xcffib.Event):
     xge = False
+    event_number = 11
     def __init__(self, unpacker):
         if isinstance(unpacker, xcffib.Protobj):
             unpacker = xcffib.MemoryUnpacker(unpacker.pack())
diff --git a/xcffib.cabal b/xcffib.cabal
--- a/xcffib.cabal
+++ b/xcffib.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.4
 name:                xcffib
-version:             1.12.0
+version:             1.13.0
 synopsis:            A cffi-based python binding for X
 homepage:            http://github.com/tych0/xcffib
 license:             Apache-2.0
@@ -26,13 +26,13 @@
 library
   build-depends: base ==4.*,
                  xcb-types >= 0.15.0 && < 0.16,
-                 filepath >= 1.4.2 && < 1.5,
+                 filepath >= 1.4.2 && < 1.6,
                  filemanip >= 0.3.6 && < 0.4,
                  split >= 0.2.3 && < 0.3,
-                 containers >= 0.6.5 && < 0.7,
+                 containers >= 0.6.5 && < 0.9,
                  mtl >= 2.2.2 && < 2.4,
                  attoparsec >= 0.14.4 && < 0.15,
-                 bytestring >= 0.11.3 && < 0.12,
+                 bytestring >= 0.11.3 && < 0.13,
                  either >= 5.0.2 && < 5.1,
                  pretty >= 1.1 && < 1.2
   hs-source-dirs: generator
@@ -48,17 +48,18 @@
   build-depends: base ==4.*,
                  xcffib,
                  xcb-types >= 0.15.0 && < 0.16,
-                 filepath >= 1.4.2 && < 1.5,
+                 filepath >= 1.4.2 && < 1.6,
                  filemanip >= 0.3.6 && < 0.4,
                  split >= 0.2.3 && < 0.3,
-                 containers >= 0.6.5 && < 0.7,
+                 containers >= 0.6.5 && < 0.9,
                  mtl >= 2.2.2 && < 2.4,
                  attoparsec >= 0.14.4 && < 0.15,
-                 bytestring >= 0.11.3 && < 0.12,
+                 bytestring >= 0.11.3 && < 0.13,
                  either >= 5.0.2 && < 5.1,
                  pretty >= 1.1 && < 1.2,
                  directory >= 1.3.6 && < 1.4,
-                 optparse-applicative >= 0.18.1 && < 0.19
+                 process >= 1.6.13 && < 1.7,
+                 optparse-applicative >= 0.18.1 && < 0.20
   other-modules: Data.XCB.Python.Parse,
                  Data.XCB.Python.PyHelpers
                  Data.XCB.Python.AST
@@ -83,7 +84,7 @@
   build-depends: base ==4.*,
                  xcffib,
                  xcb-types >= 0.15.0 && < 0.16,
-                 filepath >= 1.4.2 && < 1.5,
+                 filepath >= 1.4.2 && < 1.6,
                  HUnit >= 1.6.2 && < 1.7,
                  test-framework >= 0.8.2 && < 0.9,
                  test-framework-hunit >= 0.3.0 && < 0.4
