Esempio n. 1
0
Bool
XkbComputeRowBounds(XkbGeometryPtr geom, XkbSectionPtr section, XkbRowPtr row)
{
    register int k, pos;
    XkbKeyPtr key;
    XkbBoundsPtr bounds, sbounds;

    if ((!geom) || (!section) || (!row))
        return False;
    bounds = &row->bounds;
    bzero(bounds, sizeof(XkbBoundsRec));
    for (key = row->keys, pos = k = 0; k < row->num_keys; k++, key++) {
        sbounds = &XkbKeyShape(geom, key)->bounds;
        _XkbCheckBounds(bounds, pos, 0);
        if (!row->vertical) {
            if (key->gap != 0) {
                pos += key->gap;
                _XkbCheckBounds(bounds, pos, 0);
            }
            _XkbCheckBounds(bounds, pos + sbounds->x1, sbounds->y1);
            _XkbCheckBounds(bounds, pos + sbounds->x2, sbounds->y2);
            pos += sbounds->x2;
        }
        else {
            if (key->gap != 0) {
                pos += key->gap;
                _XkbCheckBounds(bounds, 0, pos);
            }
            _XkbCheckBounds(bounds, pos + sbounds->x1, sbounds->y1);
            _XkbCheckBounds(bounds, pos + sbounds->x2, sbounds->y2);
            pos += sbounds->y2;
        }
    }
    return True;
}
Esempio n. 2
0
static guint
compute_above_tab_keycode (Display *xdisplay)
{
  XkbDescPtr keyboard;
  XkbGeometryPtr geometry;
  int i, j, k;
  int tab_keycode;
  char *tab_name;
  XkbSectionPtr tab_section;
  XkbBoundsRec tab_bounds;
  XkbKeyPtr best_key = NULL;
  guint best_keycode = (guint)-1;
  int best_x_dist = G_MAXINT;
  int best_y_dist = G_MAXINT;

  /* We need only the Names and the Geometry, but asking for these results
   * in the Keyboard information retrieval failing for unknown reasons.
   * (Testing with xorg-1.9.1.) So we ask for a part that we don't need
   * as well.
   */
  keyboard = XkbGetKeyboard (xdisplay,
                             XkbGBN_ClientSymbolsMask | XkbGBN_KeyNamesMask | XkbGBN_GeometryMask,
                             XkbUseCoreKbd);
  if (!keyboard)
    return best_keycode;

  geometry = keyboard->geom;

  /* There could potentially be multiple keys with the Tab keysym on the keyboard;
   * but XKeysymToKeycode() returns us the one that the alt-Tab binding will
   * use which is good enough
   */
  tab_keycode = XKeysymToKeycode (xdisplay, XK_Tab);
  if (tab_keycode == 0 || tab_keycode < keyboard->min_key_code || tab_keycode > keyboard->max_key_code)
    goto out;

  /* The keyboard geometry is stored by key "name" rather than keycode.
   * (Key names are 4-character strings like like TAB or AE01.) We use the
   * 'names' part of the keyboard description to map keycode to key name.
   *
   * XKB has a "key aliases" feature where a single keyboard key can have
   * multiple names (with separate sets of aliases in the 'names' part and
   * in the 'geometry' part), but I don't really understand it or how it is used,
   * so I'm ignoring it here.
   */

  tab_name = keyboard->names->keys[tab_keycode].name; /* Not NULL terminated! */

  /* First, iterate through the keyboard geometry to find the tab key; the keyboard
   * geometry has a three-level heirarchy of section > row > key
   */
  for (i = 0; i < geometry->num_sections; i++)
    {
      XkbSectionPtr section = &geometry->sections[i];
      for (j = 0; j < section->num_rows; j++)
        {
          int x = 0;
          int y = 0;

          XkbRowPtr row = &section->rows[j];
          for (k = 0; k < row->num_keys; k++)
            {
              XkbKeyPtr key = &row->keys[k];
              XkbShapePtr shape = XkbKeyShape (geometry, key);

              if (row->vertical)
                y += key->gap;
              else
                x += key->gap;

              if (strncmp (key->name.name, tab_name, XkbKeyNameLength) == 0)
                {
                  tab_section = section;
                  tab_bounds = shape->bounds;
                  tab_bounds.x1 += row->left + x;
                  tab_bounds.x2 += row->left + x;
                  tab_bounds.y1 += row->top + y;
                  tab_bounds.y2 += row->top + y;

                  goto found_tab;
                }

              if (row->vertical)
                y += (shape->bounds.y2 - shape->bounds.y1);
              else
                x += (shape->bounds.x2 - shape->bounds.x1);
            }
        }
    }

  /* No tab key found */
  goto out;

 found_tab:

  /* Now find the key that:
   *  - Is in the same section as the Tab key
   *  - Has a horizontal center in the Tab key's horizonal bounds
   *  - Is above the Tab key at a distance closer than any other key
   *  - In case of ties, has its horizontal center as close as possible
   *    to the Tab key's horizontal center
   */
  for (j = 0; j < tab_section->num_rows; j++)
    {
      int x = 0;
      int y = 0;

      XkbRowPtr row = &tab_section->rows[j];
      for (k = 0; k < row->num_keys; k++)
        {
          XkbKeyPtr key = &row->keys[k];
          XkbShapePtr shape = XkbKeyShape(geometry, key);
          XkbBoundsRec bounds = shape->bounds;
          int x_center;
          int x_dist, y_dist;

          if (row->vertical)
            y += key->gap;
          else
            x += key->gap;

          bounds.x1 += row->left + x;
          bounds.x2 += row->left + x;
          bounds.y1 += row->top + y;
          bounds.y2 += row->top + y;

          y_dist = tab_bounds.y1 - bounds.y2;
          if (y_dist < 0)
            continue;

          x_center = (bounds.x1 + bounds.x2) / 2;
          if (x_center < tab_bounds.x1 || x_center > tab_bounds.x2)
            continue;

          x_dist = ABS (x_center - (tab_bounds.x1 + tab_bounds.x2) / 2);

          if (y_dist < best_y_dist ||
              (y_dist == best_y_dist && x_dist < best_x_dist))
            {
              best_key = key;
              best_x_dist = x_dist;
              best_y_dist = y_dist;
             }

          if (row->vertical)
            y += (shape->bounds.y2 - shape->bounds.y1);
          else
            x += (shape->bounds.x2 - shape->bounds.x1);
        }
    }

  if (best_key == NULL)
    goto out;

  /* Now we need to resolve the name of the best key back to a keycode */
  for (i = keyboard->min_key_code; i < keyboard->max_key_code; i++)
    {
      if (strncmp (best_key->name.name, keyboard->names->keys[i].name, XkbKeyNameLength) == 0)
        {
          best_keycode = i;
          break;
        }
    }

 out:
  XkbFreeKeyboard (keyboard, 0, True);

  return best_keycode;
}