Index: /trunk/nv/base/common.hh
===================================================================
--- /trunk/nv/base/common.hh	(revision 449)
+++ /trunk/nv/base/common.hh	(revision 450)
@@ -253,7 +253,7 @@
 
 	template <typename OBJ, typename T>
-	inline size_t offset_of( T OBJ::*ptr )
-	{
-		return static_cast<size_t>( &( ( static_cast<OBJ*>(0) )->*ptr ) );
+	inline ptrdiff_t offset_of( T OBJ::*ptr )
+	{
+		return reinterpret_cast<ptrdiff_t>( &reinterpret_cast<const volatile char&>( ( static_cast<OBJ*>(0) )->*ptr ) );
 	}
 
Index: /trunk/nv/core/types.hh
===================================================================
--- /trunk/nv/core/types.hh	(revision 449)
+++ /trunk/nv/core/types.hh	(revision 450)
@@ -33,8 +33,9 @@
 		// TODO: enforce exact type?
 		constexpr thash64() : inherited_type() {}
-		template < typename T >
-		constexpr thash64() : inherited_type( rtti_type_hash< T >::hash() ) {}
 		constexpr explicit thash64( hash_type value ) : inherited_type( value ) {}
 		constexpr thash64( const thash64& value ) = default;
+
+		template < typename T >
+		static thash64 create() { return thash64( rtti_type_hash< T >::hash() ); }
 	};
 
@@ -78,4 +79,6 @@
 		uint32      flags;    //!< flags 
 		uint32      offset;   //!< offset into parent
+		type_field* control;  //!< pointer to field control (in unions)
+		sint32      enumidx;  //!< field index (in unions)
 	};
 
@@ -115,4 +118,10 @@
 		type_creator field( const string_view& aname, TFIELD TOBJECT::*field, typename enable_if< !is_container<TFIELD>::value, void* >::type = nullptr );
 
+		template< typename TOBJECT, typename TFIELD, typename ENUM_VALUE >
+		type_creator union_field( const string_view& aname, TFIELD TOBJECT::*field, const string_view& control_name, ENUM_VALUE control_value, typename enable_if< is_container<TFIELD>::value, void* >::type = nullptr );
+
+		template< typename TOBJECT, typename TFIELD, typename ENUM_VALUE >
+		type_creator union_field( const string_view& aname, TFIELD TOBJECT::*field, const string_view& control_name, ENUM_VALUE control_value, typename enable_if< !is_container<TFIELD>::value, void* >::type = nullptr );
+
 		type_creator value( const string_view& aname, sint32 value );
 	private:
@@ -129,5 +138,5 @@
 		type_creator create_type()
 		{
-			return create_type<TYPE>( rtti_type_hash< TYPE >.name() );
+			return create_type<TYPE>( rtti_type_hash< TYPE >::name() );
 		}
 
@@ -143,5 +152,5 @@
 			i_type->constructor = raw_construct_object < TYPE >;
 			i_type->destructor  = raw_destroy_object < TYPE >;
-			m_index_by_type[ thash64< TYPE >() ] = i_type;
+			m_index_by_type[ thash64::create< TYPE >() ] = i_type;
 			m_index_by_name[ i_type->name ] = i_type;
 			m_type_list.push_back( i_type );
@@ -164,5 +173,5 @@
 		type_entry* get_type()
 		{
-			auto it = m_index_by_type.find( thash64< T >() );
+			auto it = m_index_by_type.find( thash64::create< T >() );
 			return it != m_index_by_type.end() ? it->second : nullptr;
 		}
@@ -197,11 +206,14 @@
 		NV_ASSERT( m_entry->enum_list.empty(), "Type cannot have both enums and fields!" );
 		type_field f;
-		f.name = m_database->m_names.insert( name );
-		f.type = type_db->get_type< remove_pointer_t<TFIELD> >();
+		f.name = m_database->m_names.insert( aname );
+		f.type = m_database->get_type< remove_pointer_t<TFIELD> >();
 		f.flags = TF_CONTAINER |
 			( is_pointer<field_type>::value ? TF_POINTER : 0 ) |
 			( is_pod<field_type>::value ? TF_SIMPLETYPE : 0 );
 		f.offset = offset_of( field );
-		m_entry->field_list.push_back( f );
+		f.control = nullptr;
+		f.enumidx = 0;
+		m_entry->field_list.push_back( f );
+		m_entry->field_names[f.name] = &m_entry->field_list.back();
 		return *this;
 	}
@@ -212,11 +224,51 @@
 		NV_ASSERT( m_entry->enum_list.empty(), "Type cannot have both enums and fields!" );
 		type_field f;
-		f.name = m_database->m_names.insert( name );
-		f.type = type_db->get_type< remove_pointer_t<TFIELD> >();
+		f.name = m_database->m_names.insert( aname );
+		f.type = m_database->get_type< remove_pointer_t<TFIELD> >();
 		f.flags =
 			( is_pointer<TFIELD>::value ? TF_POINTER : 0 ) |
 			( is_pod<TFIELD>::value ? TF_SIMPLETYPE : 0 );
 		f.offset = offset_of( field );
-		m_entry->field_list.push_back( f );
+		f.control = nullptr;
+		f.enumidx = 0;
+		m_entry->field_list.push_back( f );
+		m_entry->field_names[f.name] = &m_entry->field_list.back();
+		return *this;
+	}
+
+	template< typename TOBJECT, typename TFIELD, typename ENUM_VALUE >
+	type_creator type_creator::union_field( const string_view& aname, TFIELD TOBJECT::*field, const string_view& control_name, ENUM_VALUE control_value, typename enable_if< is_container<TFIELD>::value, void* >::type )
+	{
+		typedef typename TFIELD::value_type field_type;
+		NV_ASSERT( m_entry->enum_list.empty(), "Type cannot have both enums and fields!" );
+		type_field f;
+		f.name = m_database->m_names.insert( aname );
+		f.type = m_database->get_type< remove_pointer_t<TFIELD> >();
+		f.flags = TF_CONTAINER |
+			( is_pointer<field_type>::value ? TF_POINTER : 0 ) |
+			( is_pod<field_type>::value ? TF_SIMPLETYPE : 0 );
+		f.offset = offset_of( field );
+		f.control = m_entry->field_names[ control_name ];
+		f.enumidx = static_cast< sint32 >( control_value );
+		m_entry->field_list.push_back( f );
+		m_entry->field_names[f.name] = &m_entry->field_list.back();
+		return *this;
+	}
+
+	template< typename TOBJECT, typename TFIELD, typename ENUM_VALUE >
+	type_creator type_creator::union_field( const string_view& aname, TFIELD TOBJECT::*field, const string_view& control_name, ENUM_VALUE control_value, typename enable_if< !is_container<TFIELD>::value, void* >::type )
+	{
+		NV_ASSERT( m_entry->enum_list.empty(), "Type cannot have both enums and fields!" );
+		type_field f;
+		f.name = m_database->m_names.insert( aname );
+		f.type = m_database->get_type< remove_pointer_t<TFIELD> >();
+		f.flags =
+			( is_pointer<TFIELD>::value ? TF_POINTER : 0 ) |
+			( is_pod<TFIELD>::value ? TF_SIMPLETYPE : 0 );
+		f.offset = offset_of( field );
+		f.control = m_entry->field_names[control_name];
+		f.enumidx = static_cast<sint32>( control_value );
+		m_entry->field_list.push_back( f );
+		m_entry->field_names[f.name] = &m_entry->field_list.back();
 		return *this;
 	}
@@ -229,4 +281,5 @@
 		e.value = value;
 		m_entry->enum_list.push_back( e );
+		m_entry->enum_names[e.name] = &m_entry->enum_list.back();
 		return *this;
 	}
Index: /trunk/src/core/io_event.cc
===================================================================
--- /trunk/src/core/io_event.cc	(revision 449)
+++ /trunk/src/core/io_event.cc	(revision 450)
@@ -141,4 +141,19 @@
 		.field( "param2",   &system_event::param2 );
 
-	// TODO: io_event
+	db->create_type<io_event>()
+		.field( "type", &io_event::type )
+		.union_field( "key",     &io_event::key,    "type", EV_KEY )
+		.union_field( "mbutton", &io_event::mbutton,"type", EV_MOUSE_BUTTON )
+		.union_field( "mmove",   &io_event::mmove,  "type", EV_MOUSE_MOVE )
+		.union_field( "mwheel",  &io_event::mwheel, "type", EV_MOUSE_WHEEL )
+		.union_field( "pbutton", &io_event::pbutton,"type", EV_PAD_BUTTON )
+		.union_field( "paxis",   &io_event::paxis,  "type", EV_PAD_AXIS )
+		.union_field( "jbutton", &io_event::jbutton,"type", EV_JOY_BUTTON )
+		.union_field( "jaxis",   &io_event::jaxis,  "type", EV_JOY_AXIS )
+		.union_field( "jhat",    &io_event::jhat,   "type", EV_JOY_HAT )
+		.union_field( "jball",   &io_event::jball,  "type", EV_JOY_BALL )
+		.union_field( "resize",  &io_event::resize, "type", EV_ACTIVE )
+		.union_field( "active",  &io_event::active, "type", EV_RESIZE )
+		.union_field( "system",  &io_event::system, "type", EV_SYSTEM );
+
 }
