<commit_before>/* bzflag
 * Copyright (c) 1993 - 2006 <NAME>
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* common headers */
#include "common.h"

/* interface headers */
#include "EvdevJoystick.h"

#ifdef HAVE_LINUX_INPUT_H

/* system headers */
#include <vector>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

/* implementation headers */
#include "ErrorHandler.h"
#include "bzfio.h"

static inline int test_bit (int nr, const volatile void *addr)
{
  return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31));
}

bool	     EvdevJoystick::isEvdevAvailable()
{
  /* Test whether this driver should be used without actually
   * loading it. Will return false if no event devices can be
   * located, or if it has been specifically disabled by setting
   * the environment variable BZFLAG_ENABLE_EVDEV=0
   */

  char *envvar = getenv("BZFLAG_ENABLE_EVDEV");
  if (envvar)
    return atoi(envvar) != 0;

  std::map<std::string,EvdevJoystickInfo> joysticks;
  scanForJoysticks(joysticks);
  return !joysticks.empty();
}


EvdevJoystick::EvdevJoystick()
{
  joystickfd = 0;
  currentJoystick = NULL;
  ff_rumble = new struct ff_effect;
  scanForJoysticks(joysticks);
}

EvdevJoystick::~EvdevJoystick()
{
  initJoystick("");
  delete ff_rumble;
}

void	     EvdevJoystick::scanForJoysticks(std::map<std::string,
							EvdevJoystickInfo> &joysticks)
{
  joysticks.clear();

  const std::string inputdirName = "/dev/input";
  DIR* inputdir = opendir(inputdirName.c_str());
  if (!inputdir)
    return;

  struct dirent *dent;
  while ((dent = readdir(inputdir))) {
    EvdevJoystickInfo info;

    /* Does it look like an event device? */
    if (strncmp(dent->d_name, "event", 5))
      continue;

    /* Can we open it for r/w? */
    info.filename = inputdirName + "/" + dent->d_name;
    int fd = open(info.filename.c_str(), O_RDWR);
    /* if we can't open read/write, try just read...if it's not ff it'll work anyhow */
    if (!fd) {
      fd = open(info.filename.c_str(), O_RDONLY);
      if (fd) logDebugMessage(4,"Opened event device %s as read-only.\n", info.filename.c_str());
    } else {
      logDebugMessage(4,"Opened event device %s as read-write.\n", info.filename.c_str());
    }
    /* no good, can't open it */
    if (!fd) {
      logDebugMessage(4,"Can't open event device %s.  Check permissions.\n", info.filename.c_str());
      continue;
    }

    /* Does it look like a joystick? */
    if (!(collectJoystickBits(fd, info) && isJoystick(info))) {
      logDebugMessage(4,"Device %s doesn't seem to be a joystick.  Skipping.\n", info.filename.c_str());
      close(fd);
      continue;
    }

    /* Can we get its name? */
    char jsname[128];
    if (ioctl(fd, EVIOCGNAME(sizeof(jsname)-1), jsname) < 0) {
      close(fd);
      continue;
    }
    jsname[sizeof(jsname)-1] = '\0';

    close(fd);

    /* Yay, add it to our map.
     *
     * FIXME: we can't handle multiple joysticks with the same name yet.
     *	This could be fixed by disambiguating jsname if it already
     *	exists in 'joysticks', but the user would still have a hard
     *	time knowing which device to pick.
     */
    joysticks[jsname] = info;
  }

  closedir(inputdir);
}

bool		    EvdevJoystick::collectJoystickBits(int fd, struct EvdevJoystickInfo &info)
{
  /* Collect all the bitfields we're interested in from an event device
   * at the given file descriptor.
   */
  if (ioctl(fd, EVIOCGBIT(0, sizeof(info.evbit)), info.evbit) < 0)
    return false;
  if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(info.keybit)), info.keybit) < 0)
    return false;
  if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(info.absbit)), info.absbit) < 0)
    return false;
  if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(info.ffbit)), info.ffbit) < 0)
    return false;

  /* Collect information about our absolute axes */<commit_msg>allow EvdevJoystick to compile on old kernels that do support evdev but don't support FF.  14760, 14777, 14779 from trunk.<commit_after>/* bzflag
 * Copyright (c) 1993 - 2006 <NAME>
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* common headers */
#include "common.h"

/* interface headers */
#include "EvdevJoystick.h"

#ifdef HAVE_LINUX_INPUT_H

/* system headers */
#include <vector>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

/* implementation headers */
#include "ErrorHandler.h"
#include "bzfio.h"

static inline int test_bit (int nr, const volatile void *addr)
{
  return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31));
}

bool	     EvdevJoystick::isEvdevAvailable()
{
  /* Test whether this driver should be used without actually
   * loading it. Will return false if no event devices can be
   * located, or if it has been specifically disabled by setting
   * the environment variable BZFLAG_ENABLE_EVDEV=0
   */

  char *envvar = getenv("BZFLAG_ENABLE_EVDEV");
  if (envvar)
    return atoi(envvar) != 0;

  std::map<std::string,EvdevJoystickInfo> joysticks;
  scanForJoysticks(joysticks);
  return !joysticks.empty();
}


EvdevJoystick::EvdevJoystick()
{
  joystickfd = 0;
  currentJoystick = NULL;
#if defined(HAVE_FF_EFFECT_DIRECTIONAL || HAVE_FF_EFFECT_RUMBLE)
  ff_rumble = new struct ff_effect;
#else
  ff_rumble = NULL;
#endif
  scanForJoysticks(joysticks);
}

EvdevJoystick::~EvdevJoystick()
{
  initJoystick("");
  delete ff_rumble;
}

void	     EvdevJoystick::scanForJoysticks(std::map<std::string,
							EvdevJoystickInfo> &joysticks)
{
  joysticks.clear();

  const std::string inputdirName = "/dev/input";
  DIR* inputdir = opendir(inputdirName.c_str());
  if (!inputdir)
    return;

  struct dirent *dent;
  while ((dent = readdir(inputdir))) {
    EvdevJoystickInfo info;

    /* Does it look like an event device? */
    if (strncmp(dent->d_name, "event", 5))
      continue;

    /* Can we open it for r/w? */
    info.filename = inputdirName + "/" + dent->d_name;
    int fd = open(info.filename.c_str(), O_RDWR);
    /* if we can't open read/write, try just read...if it's not ff it'll work anyhow */
    if (!fd) {
      fd = open(info.filename.c_str(), O_RDONLY);
      if (fd) logDebugMessage(4,"Opened event device %s as read-only.\n", info.filename.c_str());
    } else {
      logDebugMessage(4,"Opened event device %s as read-write.\n", info.filename.c_str());
    }
    /* no good, can't open it */
    if (!fd) {
      logDebugMessage(4,"Can't open event device %s.  Check permissions.\n", info.filename.c_str());
      continue;
    }

    /* Does it look like a joystick? */
    if (!(collectJoystickBits(fd, info) && isJoystick(info))) {
      logDebugMessage(4,"Device %s doesn't seem to be a joystick.  Skipping.\n", info.filename.c_str());
      close(fd);
      continue;
    }

    /* Can we get its name? */
    char jsname[128];
    if (ioctl(fd, EVIOCGNAME(sizeof(jsname)-1), jsname) < 0) {
      close(fd);
      continue;
    }
    jsname[sizeof(jsname)-1] = '\0';

    close(fd);

    /* Yay, add it to our map.
     *
     * FIXME: we can't handle multiple joysticks with the same name yet.
     *	This could be fixed by disambiguating jsname if it already
     *	exists in 'joysticks', but the user would still have a hard
     *	time knowing which device to pick.
     */
    joysticks[jsname] = info;
  }

  closedir(inputdir);
}

bool		    EvdevJoystick::collectJoystickBits(int fd, struct EvdevJoystickInfo &info)
{
  /* Collect all the bitfields we're interested in from an event device
   * at the given file descriptor.
   */
  if (ioctl(fd, EVIOCGBIT(0, sizeof(info.evbit)), info.evbit) < 0)
    return false;
  if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(info.keybit)), info.keybit) < 0)
    return false;
  if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(info.absbit)), info.absbit) < 0)
    return false;
#if defined(HAVE_FF_EFFECT_DIRECTIONAL) || defined(HAVE_FF_EFFECT_RUMBLE)
  if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(info.ffbit)), info.ffbit) < 0)
    return false;
#endif

  /* Collect information about our absolute axes */
{'fraction_non_alphanumeric': 0.12913385826771653, 'fraction_numerical': 0.009336332958380203, 'mean_word_length': 3.4655951783023604, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4867880', 'n_tokens_mistral': 3177, 'n_tokens_neox': 3012, 'n_words': 890}