{.experimental: "codeReordering".}

import xcb
#, bitops

type
 xkb_mod_index_t* = uint32
 xkb_mod_mask_t* = uint32
 xkb_led_mask_t* = uint32
 xkb_keycode_t* = uint32
 xkb_layout_index_t* = uint32
 xkb_level_index_t* = uint32
 xkb_keysym_t* = uint32
 xkb_layout_mask_t* = uint32

const
 XKB_MAX_GROUPS* = 4

 #Don't allow more modifiers than we can hold in xkb_mod_mask_t.
 XKB_MAX_MODS* = sizeof(uint32) * 8

 # Don't allow more leds than we can hold in xkb_led_mask_t.
 XKB_MAX_LEDS* = sizeof(uint32) * 8

 MOD_REAL_MASK_ALL* = uint32 0x000000ff

type
 xkb_explicit_components* = enum
  EXPLICIT_INTERP = (1 shl 0)

 xkb_range_exceed_type* = enum
  RANGE_WRAP = 0

 mod_type* = enum
  MOD_REAL = (1 shl 0),
  MOD_VIRT = (1 shl 1),
  MOD_BOTH = (MOD_REAL.ord or MOD_VIRT.ord)

 xkb_x11_setup_xkb_extension_flags* = enum XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS
 xkb_keymap_format* = enum
  # The current/classic XKB text format, as generated by xkbcomp -xkb.
  XKB_KEYMAP_FORMAT_TEXT_V1 = 1

 xkb_action_type* = enum
  ACTION_TYPE_NONE = 0,
  ACTION_TYPE_MOD_SET,
  ACTION_TYPE_MOD_LATCH,
  ACTION_TYPE_MOD_LOCK,
  ACTION_TYPE_GROUP_SET,
  ACTION_TYPE_GROUP_LATCH,
  ACTION_TYPE_GROUP_LOCK,
  ACTION_TYPE_PTR_MOVE,
  ACTION_TYPE_PTR_BUTTON,
  ACTION_TYPE_PTR_LOCK,
  ACTION_TYPE_PTR_DEFAULT,
  ACTION_TYPE_TERMINATE,
  ACTION_TYPE_SWITCH_VT,
  ACTION_TYPE_CTRL_SET,
  ACTION_TYPE_CTRL_LOCK,
  ACTION_TYPE_PRIVATE,
  ACTION_TYPE_NUM_ENTRIES

 xkb_action_controls* = enum
  CONTROL_REPEAT = (1 shl 0),
  CONTROL_SLOW = (1 shl 1),
  CONTROL_DEBOUNCE = (1 shl 2),
  CONTROL_STICKY = (1 shl 3),
  CONTROL_MOUSEKEYS = (1 shl 4),
  CONTROL_MOUSEKEYS_ACCEL = (1 shl 5),
  CONTROL_AX = (1 shl 6),
  CONTROL_AX_TIMEOUT = (1 shl 7),
  CONTROL_AX_FEEDBACK = (1 shl 8),
  CONTROL_BELL = (1 shl 9),
  CONTROL_IGNORE_GROUP_LOCK = (1 shl 10),
  CONTROL_ALL = CONTROL_REPEAT.ord            or
                CONTROL_SLOW.ord              or
                CONTROL_DEBOUNCE.ord          or
                CONTROL_STICKY.ord            or
                CONTROL_MOUSEKEYS.ord         or
                CONTROL_MOUSEKEYS_ACCEL.ord   or
                CONTROL_AX.ord                or
                CONTROL_AX_TIMEOUT.ord        or
                CONTROL_AX_FEEDBACK.ord       or
                CONTROL_BELL.ord              or
                CONTROL_IGNORE_GROUP_LOCK.ord

 xkb_rule_names* {.bycopy.} = object
  str0*: cstring
  str1*: cstring
  str2*: cstring
  str3*: cstring
  str4*: cstring

 AtomTable* {.bycopy.} = object
 xkb_atom_t* = uint32

 DArr*[T] {.bycopy.} = object
  item*: ptr T
  size*: cuint
  alloc*: cuint

 xkb_keymap_compile_flags* = enum
  # Do not apply any flags.
  XKB_KEYMAP_COMPILE_NO_FLAGS = 0

 xkb_context_flags* = enum
  XKB_CONTEXT_NO_FLAGS = 0, # Do not apply any context flags.
  XKB_CONTEXT_NO_DEFAULT_INCLUDES = (1 shl 0), # Create this context with an empty include path.
  # Don't take RMLVO names from the environment. @since 0.3.0
  XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 shl 1)

 # Modifier and layout types for state objects.  This enum is bitmaskable,
 # e.g. (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED) is valid to
 # exclude locked modifiers.
 # In XKB, the DEPRESSED components are also known as 'base'.

 xkb_state_component* = enum
  # Depressed modifiers, i.e. a key is physically holding them.
  XKB_STATE_MODS_DEPRESSED = (1 shl 0),
  # Latched modifiers, i.e. will be unset after the next non-modifier key press.
  XKB_STATE_MODS_LATCHED = (1 shl 1),
  # Locked modifiers, i.e. will be unset after the key provoking the  lock has been pressed again.
  XKB_STATE_MODS_LOCKED = (1 shl 2),
  # Effective modifiers, i.e. currently active and affect key
  # processing (derived from the other state components).
  # Use this unless you explicitly care how the state came about.
  XKB_STATE_MODS_EFFECTIVE = (1 shl 3),
  # Depressed layout, i.e. a key is physically holding it.
  XKB_STATE_LAYOUT_DEPRESSED = (1 shl 4),
  # Latched layout, i.e. will be unset after the next non-modifier key press.
  XKB_STATE_LAYOUT_LATCHED = (1 shl 5),
  # Locked layout, i.e. will be unset after the key provoking the lock has been pressed again.
  XKB_STATE_LAYOUT_LOCKED = (1 shl 6),
  # Effective layout, i.e. currently active and affects key processing
  # (derived from the other state components).
  # Use this unless you explicitly care how the state came about.
  XKB_STATE_LAYOUT_EFFECTIVE = (1 shl 7),
  # LEDs (derived from the other state components).
  XKB_STATE_LEDS = (1 shl 8)

 xkb_log_level* = enum
  XKB_LOG_LEVEL_CRITICAL = 10, # Log critical internal errors only.
  XKB_LOG_LEVEL_ERROR = 20,    # Log all errors.
  XKB_LOG_LEVEL_WARNING = 30,  # Log warnings and errors.
  XKB_LOG_LEVEL_INFO = 40,     # Log information, warnings, and errors.
  XKB_LOG_LEVEL_DEBUG = 50     # Log everything.

 xkb_group* {.bycopy.} = object
  out_of_range_group_number*: xkb_layout_index_t
  num_groups*: xkb_layout_index_t
  groups*: ptr xkb_group

 xkb_key* {.bycopy.} = object
  keycode*: xkb_keycode_t
  name*: xkb_atom_t
  explicit*: xkb_explicit_components
  modmap*: xkb_mod_mask_t
  vmodmap*: xkb_mod_mask_t
  repeats*: bool
  out_of_range_group_action*: xkb_range_exceed_type
  out_of_range_group_number*: xkb_layout_index_t
  num_groups*: xkb_layout_index_t
  groups*: ptr xkb_group

 xkb_context* {.bycopy.} = object
  refcnt*: int
  log_verbosity*: int
  logLevel*: xkb_log_level
  userData*: pointer
  x11_atom_cache*: pointer # Used and allocated by xkbcommon-x11, free()d with the context.
  text_next*: csize_t
  use_environment_names*: uint # 1
  text_buffer*: cstring #$[2048, char]
  names_dflt*: xkb_rule_names
  includes*: DArr[ptr char]
  failedIncludes*: DArr[ptr char]
  atom_table*: ptr AtomTable
  ## Buffer for the *Text() functions.

  # ATTR_PRINTF(3, 0) void (*log_fn)(struct xkb_context *ctx,
  #                                      enum xkb_log_level level,
  #                                  const char *fmt, va_list args);

 xkb_key_alias* {.bycopy.} = object
  real: xkb_atom_t
  alias: xkb_atom_t

 xkb_action_flags* {.bycopy.} = enum
  ACTION_LOCK_CLEAR = (1 shl 0)
  ACTION_LATCH_TO_LOCK = (1 shl 1),
  ACTION_LOCK_NO_LOCK = (1 shl 2),
  ACTION_LOCK_NO_UNLOCK = (1 shl 3),
  ACTION_MODS_LOOKUP_MODMAP = (1 shl 4),
  ACTION_ABSOLUTE_SWITCH = (1 shl 5),
  ACTION_ABSOLUTE_X = (1 shl 6),
  ACTION_ABSOLUTE_Y = (1 shl 7),
  ACTION_ACCEL = (1 shl 8),
  ACTION_SAME_SCREEN = (1 shl 9)

 xkb_compose_state_flags* = enum
    XKB_COMPOSE_STATE_NO_FLAGS = 0

 xkb_mods* {.bycopy.} = object
  # original real+virtual mods in definition
  modMask*: xkb_mod_mask_t
  actType*: xkb_action_type
  flags*: xkb_action_flags
  #mods: xkb_mods

 xkb_key_type_entry* {.bycopy.} = object
  level*: xkb_level_index_t
  mods*: xkb_mods
  preserve*: xkb_mods
  num_entries*: cuint
  entries*: ptr xkb_key_type_entry

 xkb_key_type* {.bycopy.} = object
  name*: xkb_atom_t
  mods*: xkb_mods
  num_levels*: xkb_level_index_t
  num_level_names*: cuint
  level_names*: ptr xkb_atom_t
  num_entries*: cuint
  entries*: ptr xkb_key_type_entry

 xkb_match_operation* = enum
  MATCH_NONE
  MATCH_ANY_OR_NONE
  MATCH_ANY
  MATCH_ALL
  MATCH_EXACTLY

 xkb_key_direction* = enum XKB_KEY_UP XKB_KEY_DOWN

 xkb_compose_compile_flags* = enum
  XKB_COMPOSE_COMPILE_NO_FLAGS = 0

 xkb_mod_action* {.bycopy.} = object
  actType*: xkb_action_type
  flags*: xkb_action_flags
  mods*: xkb_mods

 xkb_group_action* {.bycopy.} = object
  actType*: xkb_action_type
  flags8: xkb_action_flags
  group*: int32

 xkb_controls_action* {.bycopy.} = object
  actType*: xkb_action_type
  flags*: xkb_action_flags
  ctrls*: xkb_action_controls

 xkb_pointer_default_action* {.bycopy.} = object
  actType*: xkb_action_type
  flags*: xkb_action_flags
  value*: int8

 xkb_switch_screen_action* {.bycopy.} = object
  actType*: xkb_action_type
  flags*: xkb_action_flags
  screen*: int8

 xkb_pointer_action* {.bycopy.} = object
  actType: xkb_action_type
  flags: xkb_action_flags
  x: int16
  y: int16

 xkb_pointer_button_action* {.bycopy.} = object
  actType*: xkb_action_type
  flags*: xkb_action_flags
  count*: uint8
  button*: uint8

 xkb_private_action* {.bycopy.} = object
  actType: xkb_action_type
  data: array[7,uint8]

 xkb_action* {.bycopy, union.} = object
  actType: xkb_action_type
  mods: xkb_mod_action
  group: xkb_group_action
  ctrls: xkb_controls_action
  dflt: xkb_pointer_default_action
  screen: xkb_switch_screen_action
  ptrAction: xkb_pointer_action
  btn: xkb_pointer_button_action
  priv: xkb_private_action

 xkb_sym_interpret* {.bycopy.} = object
  sym*: xkb_keysym_t
  match*: xkb_match_operation
  mods*: xkb_mod_mask_t
  virtual_mod*: xkb_mod_index_t
  action*: xkb_action # union:
  level_one_only*: bool
  repeat*: bool

 xkb_mod* {.bycopy.} = object
  name*: xkb_atom_t
  modType*: mod_type
  mapping*: xkb_mod_mask_t

 xkb_mod_set* {.bycopy.} = object
  mods: array[XKB_MAX_MODS, xkb_mod]
  num_mods: cuint

 xkb_led* {.bycopy.} = object
  name*: xkb_atom_t
  which_groups*: xkb_state_component
  groups*: xkb_layout_mask_t
  which_mods*: xkb_state_component
  mods*: xkb_mods
  ctrls*: xkb_action_controls

 xkb_keymap* {.bycopy.} = object
  ctx*: ptr xkb_context
  refcnt*: cint
  flags*: xkb_keymap_compile_flags
  format*: xkb_keymap_format
  enabled_ctrls*: xkb_action_controls
  min_key_code*: xkb_keycode_t
  max_key_code*: xkb_keycode_t
  keys*: ptr xkb_key
  # aliases in no particular order
  num_key_aliases: cuint
  key_aliases: ptr xkb_key_alias
  types: ptr xkb_key_type
  num_types: cuint
  num_sym_interprets: cuint
  sym_interprets: ptr xkb_sym_interpret
  mods: xkb_mod_set
  # Number of groups in the key with the most groups.
  num_groups: xkb_layout_index_t
  # Not all groups must have names.
  num_group_names: xkb_layout_index_t
  group_names: ptr xkb_atom_t
  leds: array[XKB_MAX_LEDS, xkb_led]
  num_leds*: cuint
  keycodes_section_name: ptr char
  symbols_section_name: ptr char
  types_section_name: ptr char
  compat_section_name: ptr char

 xkb_filter* {.bycopy.} = object
  action*: xkb_action # union in C
  key*: ptr xkb_key # declared const struct xkb_key * key in C
  priv*: uint32
  #[
     bool (*func)(struct xkb_state *state,
                 struct xkb_filter *filter,
                 const struct xkb_key *key,
                 enum xkb_key_direction direction);
  ]#
  fnptr: proc( state: ptr xkb_state
             , filter: ptr xkb_filter
             , key: ptr xkb_key
             , direction: xkb_key_direction
             ): ptr bool
  refcnt*: cint

 state_components* {.bycopy.} = object
  # These may be negative, because of -1 group actions. */
  base_group*: int32 # depressed
  latched_group*: int32
  locked_group*: int32
  group*: xkb_layout_index_t # effective
  base_mods*: xkb_mod_mask_t # depressed
  latched_mods*: xkb_mod_mask_t
  locked_mods*: xkb_mod_mask_t
  mods*: xkb_mod_mask_t # effective
  leds*: xkb_led_mask_t

 xkb_state* {.bycopy.} = object
  # Before updating the state, we keep a copy of just this struct. This
  # allows us to report which components of the state have changed.
  components*: state_components

  # At each event, we accumulate all the needed modifications to the base
  # modifiers, and apply them at the end. These keep track of this state.
  set_mods*: xkb_mod_mask_t
  clear_mods*: xkb_mod_mask_t

  # We mustn't clear a base modifier if there's another depressed key
  # which affects it, e.g. given this sequence
  # < Left Shift down, Right Shift down, Left Shift Up >
  # the modifier should still be set. This keeps the count.
  mod_key_count*: array[XKB_MAX_MODS, int16]
  refcnt*: cint
  filters*: DArr[xkb_filter]
  keymap*: ptr xkb_keymap

 # Opaque Compose table object.
 # The compose table holds the definitions of the Compose sequences, as
 # gathered from Compose files. It is immutable.
 xkb_compose_table* {.bycopy.} = object

 xkb_compose_state* {.bycopy.} = object
  refcnt: cint
  flags: xkb_compose_state_flags
  table: ptr xkb_compose_table
  # Offsets into xkb_compose_table::nodes.
  # They maintain the current and previous position in the trie; see
  # xkb_compose_state_feed().
  # This is also sufficient for inferring the current status; see
  # xkb_compose_state_get_status().
  prev_context: uint16
  context: uint16

proc xkb_x11_setup_xkb_extension*( connection: ptr xcb_connection_t
                                 , major_xkb_version: uint16
                                 , minor_xkb_version: uint16
                                 , flags: xkb_x11_setup_xkb_extension_flags
                                 , major_xkb_version_out: ptr uint16
                                 , minor_xkb_version_out: ptr uint16
                                 , base_event_out: ptr uint8
                                 , base_error_out: ptr uint8
                                 ): int {.importc, cdecl.}

proc atom_table_free*(table: ptr AtomTable): void {.importc, cdecl.}

proc atom_intern*( table: ptr AtomTable
                , str: ptr cstring
                , len: csize_t
                , add: bool
                ): xkb_atom_t {.importc, cdecl.}

proc atom_text*( table: ptr AtomTable
               , atom: xkb_atom_t
               ): ptr cstring {.importc, cdecl.}

proc xkb_context_new*(flags: xkb_context_flags): ptr xkb_context {.importc, cdecl.}
proc xkb_keymap_unref*(keymap: ptr xkb_keymap): void {.importc, cdecl.}

proc xkb_x11_get_core_keyboard_device_id*(connection: ptr xcb_connection_t): int32 {.importc, cdecl.}

proc xkb_x11_keymap_new_from_device*( context: ptr xkb_context
                                    , connection: ptr xcb_connection_t
                                    , device_id: int32
                                    , flags: xkb_keymap_compile_flags
                                    ): ptr xkb_keymap {.importc, cdecl.}

proc xkb_x11_state_new_from_device*( keymap: ptr xkb_keymap
                                  , connection: ptr xcb_connection_t
                                  , device_id: int32
                                  ): ptr xkb_state {.importc, cdecl.}

#[ Release a reference on a keybaord state object, and possibly free it.
   @param state The state.  If it is NULL, this function does nothing.
   @memberof xkb_state
 ]#
proc xkb_state_unref*( state: ptr xkb_state ): void {.importc, cdecl.}
proc xkb_compose_state_unref*( state: ptr xkb_compose_state ): void {.importc, cdecl.}

proc xkb_compose_table_unref*( table: ptr xkb_compose_table ): void {.importc, cdecl.}

proc xkb_compose_table_new_from_locale*( ctx: ptr xkb_context
                                       , locale: cstring
                                       , flags: xkb_compose_compile_flags
                                       ): ptr xkb_compose_table {.importc, cdecl.}

proc xkb_compose_state_new*( table: ptr xkb_compose_table
                           , flags: xkb_compose_state_flags
                           ): ptr xkb_compose_state {.importc, cdecl.}

proc xkb_state_key_get_one_sym*( state: ptr xkb_state
                               , kc: xkb_keycode_t
                               ): xkb_keysym_t {.importc, cdecl.}

proc xkb_keymap_layout_get_name*( keymap: ptr xkb_keymap
                                , idx: xkb_layout_index_t
                                ): cstring {.importc, cdecl.}

proc xkb_state_get_keymap*(state: ptr xkb_state): ptr xkb_keymap {.importc, cdecl.}

proc xkb_state_layout_index_is_active*( state: ptr xkb_state
                                      , idx: xkb_layout_index_t
                                      , stateType: xkb_state_component
                                      ): int {.importc, cdecl.}

proc xkb_keymap_num_layouts*( keymap: ptr xkb_keymap ): xkb_layout_index_t {.importc, cdecl.}

proc xkb_state_serialize_layout*( state: ptr xkb_state
                               , stateType: xkb_state_component
                               ): xkb_layout_index_t {.importc, cdecl.}