Linux joystick 游戏手柄编程 (获取输入数据)


啥也不说了,先上代码:

由于linux中的list.h不能直接用,所以单独提取了出来使用:

//listop.h   

  1. /*it is from linux list */  
  2. #ifndef LISTOP_H   
  3. #define LISTOP_H   
  4.   
  5. struct list_head {  
  6.     struct list_head *next, *prev;  
  7. };  
  8.   
  9. typedef struct list_head list_t;  
  10.   
  11. #define LIST_HEAD_INIT(name) { &(name), &(name) }   
  12.   
  13. #define LIST_HEAD(name) \   
  14.     struct list_head name = LIST_HEAD_INIT(name)  
  15.   
  16. #define INIT_LIST_HEAD(ptr) do { \   
  17.     (ptr)->next = (ptr); (ptr)->prev = (ptr); \  
  18. while (0)  
  19.   
  20. /** 
  21.  * list_add - add a new entry 
  22.  * @new: new entry to be added 
  23.  * @head: list head to add it after 
  24.  * 
  25.  * Insert a new entry after the specified head. 
  26.  * This is good for implementing stacks. 
  27.  */  
  28. void list_add(struct list_head *newstruct list_head *head);  
  29.   
  30. /** 
  31.  * list_add_tail - add a new entry 
  32.  * @new: new entry to be added 
  33.  * @head: list head to add it before 
  34.  * 
  35.  * Insert a new entry before the specified head. 
  36.  * This is useful for implementing queues. 
  37.  */  
  38. void list_add_tail(struct list_head *newstruct list_head *head);  
  39.   
  40.   
  41. /** 
  42.  * list_del - deletes entry from list. 
  43.  * @entry: the element to delete from the list. 
  44.  * Note: list_empty on entry does not return true after this, the entry is in an undefined state. 
  45.  */  
  46. void list_del(struct list_head *entry);  
  47.   
  48. /** 
  49.  * list_del_init - deletes entry from list and reinitialize it. 
  50.  * @entry: the element to delete from the list. 
  51.  */  
  52. void list_del_init(struct list_head *entry);  
  53.   
  54.   
  55. /** 
  56.  * list_move - delete from one list and add as another's head 
  57.  * @list: the entry to move 
  58.  * @head: the head that will precede our entry 
  59.  */  
  60. void list_move(struct list_head *list, struct list_head *head);  
  61.   
  62.   
  63. /** 
  64.  * list_move_tail - delete from one list and add as another's tail 
  65.  * @list: the entry to move 
  66.  * @head: the head that will follow our entry 
  67.  */  
  68. void list_move_tail(struct list_head *list,  
  69.                   struct list_head *head);  
  70.   
  71. /** 
  72.  * list_splice - join two lists 
  73.  * @list: the new list to add. 
  74.  * @head: the place to add it in the first list. 
  75.  */  
  76. void list_splice(struct list_head *list, struct list_head *head);  
  77.   
  78. /** 
  79.  * list_empty - tests whether a list is empty 
  80.  * @head: the list to test. 
  81.  */  
  82. static int list_empty(struct list_head *head)  
  83. {  
  84.     return head->next == head;  
  85. }  
  86.   
  87. /** 
  88.  * list_dequeue - dequeue the head of the list if there are more than one entry 
  89.  * @list: the list to dequeue 
  90.  */  
  91. struct list_head * list_dequeue( struct list_head *list );  
  92.   
  93. /** 
  94.  * list_entry - get the struct for this entry 
  95.  * @ptr:    the &struct list_head pointer. 
  96.  * @type:   the type of the struct this is embedded in. 
  97.  * @member: the name of the list_struct within the struct. 
  98.  */  
  99. #define list_entry(ptr, type, member) \   
  100.     ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))  
  101.   
  102. /** 
  103.  * list_for_each    -   iterate over a list 
  104.  * @pos:    the &struct list_head to use as a loop counter. 
  105.  * @head:   the head for your list. 
  106.  */  
  107. #define list_for_each(pos, head) \   
  108.     for (pos = (head)->next; pos != (head); \  
  109.             pos = pos->next)  
  110.               
  111. /** 
  112.  * list_for_each_safe   -   iterate over a list safe against removal of list entry 
  113.  * @pos:    the &struct list_head to use as a loop counter. 
  114.  * @n:      another &struct list_head to use as temporary storage 
  115.  * @head:   the head for your list. 
  116.  */  
  117. #define list_for_each_safe(pos, n, head) \   
  118.     for (pos = (head)->next, n = pos->next; pos != (head); \  
  119.         pos = n, n = pos->next)  
  120.   
  121. /** 
  122.  * list_for_each_prev   -   iterate over a list in reverse order 
  123.  * @pos:    the &struct list_head to use as a loop counter. 
  124.  * @head:   the head for your list. 
  125.  */  
  126. #define list_for_each_prev(pos, head) \   
  127.     for (pos = (head)->prev; pos != (head); \  
  128.             pos = pos->prev)  
  129.               
  130. /** 
  131.  * list_for_each_entry  -   iterate over list of given type 
  132.  * @pos:    the type * to use as a loop counter. 
  133.  * @head:   the head for your list. 
  134.  * @member: the name of the list_struct within the struct. 
  135.  */  
  136. #define list_for_each_entry(pos, head, member)              \   
  137.     for (pos = list_entry((head)->next, typeof(*pos), member);   \  
  138.          &pos->member != (head);     \  
  139.          pos = list_entry(pos->member.next, typeof(*pos), member))  
  140.   
  141. #endif  
// listop.c  
  1. #include "listop.h"   
  2.   
  3.   
  4. static  void __check_head(struct list_head* head)  
  5. {  
  6.     if ((head->next == 0) && (head->prev == 0)) {  
  7.         INIT_LIST_HEAD(head);  
  8.     }  
  9. }  
  10.   
  11. /* 
  12.  * Insert a new entry between two known consecutive entries. 
  13.  * 
  14.  * This is only for internal list manipulation where we know 
  15.  * the prev/next entries already! 
  16.  */  
  17. static  void __list_add(struct list_head* new,  
  18.                         struct list_head* prev,  
  19.                         struct list_head* next)  
  20. {  
  21.   
  22.     next->prev = new;  
  23.     new->next = next;  
  24.     new->prev = prev;  
  25.     prev->next = new;  
  26.   
  27. }  
  28.   
  29.   
  30. /* 
  31.  * Delete a list entry by making the prev/next entries 
  32.  * point to each other. 
  33.  * 
  34.  * This is only for internal list manipulation where we know 
  35.  * the prev/next entries already! 
  36.  */  
  37. static  void __list_del(struct list_head* prev,  
  38.                         struct list_head* next)  
  39. {  
  40.   
  41.     next->prev = prev;  
  42.     prev->next = next;  
  43. }  
  44.   
  45.   
  46.   
  47. /** 
  48.  * list_add - add a new entry 
  49.  * @new: new entry to be added 
  50.  * @head: list head to add it after 
  51.  * 
  52.  * Insert a new entry after the specified head. 
  53.  * This is good for implementing stacks. 
  54.  */  
  55. void list_add(struct list_head* newstruct list_head* head)  
  56. {  
  57.     __check_head(head);  
  58.     __list_add(new, head, head->next);  
  59. }  
  60.   
  61. /** 
  62.  * list_add_tail - add a new entry 
  63.  * @new: new entry to be added 
  64.  * @head: list head to add it before 
  65.  * 
  66.  * Insert a new entry before the specified head. 
  67.  * This is useful for implementing queues. 
  68.  */  
  69. void list_add_tail(struct list_head* newstruct list_head* head)  
  70. {  
  71.     __check_head(head);  
  72.     __list_add(new, head->prev, head);  
  73. }  
  74.   
  75.   
  76. /** 
  77.  * list_del - deletes entry from list. 
  78.  * @entry: the element to delete from the list. 
  79.  * Note: list_empty on entry does not return true after this, the entry is in an undefined state. 
  80.  */  
  81. void list_del(struct list_head* entry)  
  82. {  
  83.     __list_del(entry->prev, entry->next);  
  84. }  
  85.   
  86. /** 
  87.  * list_del_init - deletes entry from list and reinitialize it. 
  88.  * @entry: the element to delete from the list. 
  89.  */  
  90. void list_del_init(struct list_head* entry)  
  91. {  
  92.     __list_del(entry->prev, entry->next);  
  93.     INIT_LIST_HEAD(entry);  
  94. }  
  95.   
  96. /** 
  97.  * list_move - delete from one list and add as another's head 
  98.  * @list: the entry to move 
  99.  * @head: the head that will precede our entry 
  100.  */  
  101. void list_move(struct list_head* list, struct list_head* head)  
  102. {  
  103.     __check_head(head);  
  104.     __list_del(list->prev, list->next);  
  105.     list_add(list, head);  
  106. }  
  107.   
  108. /** 
  109.  * list_move_tail - delete from one list and add as another's tail 
  110.  * @list: the entry to move 
  111.  * @head: the head that will follow our entry 
  112.  */  
  113. void list_move_tail(struct list_head* list,  
  114.                     struct list_head* head)  
  115. {  
  116.     __check_head(head);  
  117.     __list_del(list->prev, list->next);  
  118.     list_add_tail(list, head);  
  119. }  
  120.   
  121.   
  122. /** 
  123.  * list_splice - join two lists 
  124.  * @list: the new list to add. 
  125.  * @head: the place to add it in the first list. 
  126.  */  
  127. void list_splice(struct list_head* list, struct list_head* head)  
  128. {  
  129.     struct list_head* first = list;  
  130.     struct list_head* last  = list->prev;  
  131.     struct list_head* at    = head->next;  
  132.   
  133.     first->prev = head;  
  134.     head->next  = first;  
  135.   
  136.     last->next = at;  
  137.     at->prev   = last;  
  138. }  
  139.   
  140. struct list_head* list_dequeue( struct list_head* list ) {  
  141.     struct list_head* next, *prev, *result = ((void*)0);  
  142.   
  143.     prev = list;  
  144.     next = prev->next;  
  145.   
  146.     if ( next != prev ) {  
  147.         result = next;  
  148.         next = next->next;  
  149.         next->prev = prev;  
  150.         prev->next = next;  
  151.         result->prev = result->next = result;  
  152.     }  
  153.   
  154.     return result;  
  155. }  

主要的文件在这里:
//my_joystick.c

  1. #include <stdio.h>   
  2. #include <sys/types.h>   
  3. #include <sys/time.h>   
  4. #include <sys/stat.h>   
  5. #include <fcntl.h>   
  6. #include <unistd.h>   
  7. #include <errno.h>   
  8. #include <stdlib.h>   
  9. #include <string.h>   
  10. #include <linux/joystick.h>   
  11. //#include <linux/list.h> /*郁闷,不能直接使用linux自带的list链表,需要单独提取出来,见前面的code*/   
  12. #include "listop.h"   
  13.   
  14. #if 1   
  15. #define LOG_DBG(fmt, ...)  fprintf(stdout, fmt, ##__VA_ARGS__)   
  16. #else   
  17. #define LOG_DBG(fmt, ...)   
  18. #endif   
  19.   
  20. #define LOG_ERR(fmt, ...)  fprintf(stderr, fmt, ##__VA_ARGS__)   
  21.   
  22.   
  23. typedef struct _joy_stick_ctx {  
  24.     struct list_head list;  
  25.     int i4_js_fd;  
  26.     unsigned int i4_op_block;  
  27. } JOYSTICK_CTX_T;  
  28.   
  29. LIST_HEAD(_t_js_ctx_head);  
  30. /*==>  struct list_head _t_js_ctx_head = {&_t_js_ctx_head, &_t_js_ctx_head};*/  
  31.   
  32. int joystick_open(char* cp_js_dev_name, int i4_block)  
  33. {  
  34.     int i4_open_flags = O_RDONLY;  
  35.     JOYSTICK_CTX_T*  pt_joystick_ctx = NULL;  
  36.   
  37.     if (!cp_js_dev_name) {  
  38.         LOG_ERR("[%s] js device name is NULL\n", __func__);  
  39.         return -1;  
  40.     }  
  41.   
  42.     pt_joystick_ctx = (JOYSTICK_CTX_T*)calloc(sizeof(JOYSTICK_CTX_T), 1);  
  43.     if (!pt_joystick_ctx) {  
  44.         LOG_ERR("[%s] no memory!!\n", __func__);  
  45.         return -1;  
  46.     }  
  47.   
  48.     pt_joystick_ctx->i4_op_block = i4_block ? 1 : 0;  
  49.   
  50.     if (pt_joystick_ctx->i4_op_block == 0) {  
  51.         i4_open_flags |= O_NONBLOCK;  
  52.     }  
  53.   
  54.     pt_joystick_ctx->i4_js_fd = open(cp_js_dev_name, i4_open_flags);  
  55.     if (pt_joystick_ctx->i4_js_fd < 0) {  
  56.         LOG_ERR("[%s] open device %s error\n", __func__, cp_js_dev_name);  
  57.         free(pt_joystick_ctx);  
  58.         return -1;  
  59.     }  
  60.   
  61.     list_add_tail(&pt_joystick_ctx->list, &_t_js_ctx_head);  
  62.   
  63.     return pt_joystick_ctx->i4_js_fd;  
  64. }  
  65.   
  66. int joystick_close(int i4_fd)  
  67. {  
  68.     struct list_head* pt_entry;  
  69.     struct list_head* pt_next;  
  70.     JOYSTICK_CTX_T* pt_node;  
  71.   
  72.     if (list_empty(&_t_js_ctx_head)) {  
  73.         LOG_ERR("[%s] device not opened\n", __func__);  
  74.         return -1;  
  75.     }  
  76.   
  77.     list_for_each_safe(pt_entry, pt_next, &_t_js_ctx_head) {  
  78.         pt_node = list_entry(pt_entry, JOYSTICK_CTX_T, list);  
  79.         if (pt_node->i4_js_fd == i4_fd) {  
  80.             list_del_init(&pt_node->list);  
  81.             free(pt_node);  
  82.             return close(i4_fd);  
  83.         }  
  84.     }  
  85.   
  86.     LOG_ERR("[%s] i4_fd=%d invalid\n", __func__, i4_fd);  
  87.     return -1;  
  88. }  
  89.   
  90. int joystick_read_one_event(int i4_fd, struct js_event* tp_jse)  
  91. {  
  92.     int i4_rd_bytes;  
  93.   
  94.     /*do not check i4_fd again*/  
  95.   
  96.     i4_rd_bytes = read(i4_fd, tp_jse, sizeof(struct js_event));  
  97.   
  98.     if (i4_rd_bytes == -1) {  
  99.         if (errno == EAGAIN) { /*when no block, it is not error*/  
  100.             return 0;  
  101.         }  
  102.         else {  
  103.             return -1;  
  104.         }  
  105.     }  
  106.   
  107.     return i4_rd_bytes;  
  108. }  
  109.   
  110. int joystick_read_ready(int i4_fd)  
  111. {  
  112.     int i4_block = 2;  
  113.     struct list_head* pt_entry;  
  114.     JOYSTICK_CTX_T* pt_node;  
  115.   
  116.     if (list_empty(&_t_js_ctx_head)) {  
  117.         LOG_ERR("[%s] device not opened\n", __func__);  
  118.         return -1;  
  119.     }  
  120.   
  121.     list_for_each(pt_entry, &_t_js_ctx_head) {  
  122.         pt_node = list_entry(pt_entry, JOYSTICK_CTX_T, list);  
  123.         if (pt_node->i4_js_fd == i4_fd) {  
  124.             i4_block = pt_node->i4_op_block;  
  125.             break;  
  126.         }  
  127.     }  
  128.   
  129.     if (i4_block == 2) {  
  130.         LOG_ERR("[%s] i4_fd=%d invalid\n", __func__, i4_fd);  
  131.         return 0;  
  132.     }  
  133.     else if (i4_block == 1) {  
  134.         fd_set readfd;  
  135.         int i4_ret = 0;  
  136.         struct timeval timeout = {0, 0};  
  137.         FD_ZERO(&readfd);  
  138.         FD_SET(i4_fd, &readfd);  
  139.   
  140.         i4_ret = select(i4_fd + 1, &readfd, NULL, NULL, &timeout);  
  141.   
  142.         if (i4_ret > 0 && FD_ISSET(i4_fd, &readfd)) {  
  143.             return 1;  
  144.         }  
  145.         else {  
  146.             return 0;  
  147.         }  
  148.   
  149.     }  
  150.   
  151.     return 1; /*noblock read, aways ready*/  
  152. }  
  153.   
  154.   
  155. void debug_list(void)  
  156. {  
  157.     if (! list_empty(&_t_js_ctx_head)) {  
  158.         struct list_head* pt_entry;  
  159.         JOYSTICK_CTX_T* pt_node;  
  160.   
  161.         list_for_each(pt_entry, &_t_js_ctx_head) {  
  162.             pt_node = list_entry(pt_entry, JOYSTICK_CTX_T, list);  
  163.             LOG_DBG("fd:%d--block:%d\n", pt_node->i4_js_fd, pt_node->i4_op_block);  
  164.         }  
  165.     }  
  166.     else {  
  167.         LOG_DBG("-----------> EMPTY NOW\n");  
  168.     }  
  169. }  
  170.   
  171. #if 1   
  172. typedef struct _axes_t {  
  173.     int x;  
  174.     int y;  
  175. } AXES_T;  
  176.   
  177. int main(int argc, char* argv[])  
  178. {  
  179.     int fd, rc;  
  180.     int op_times = 0;  
  181.     char number_of_axes = 0;  
  182.     char number_of_btns = 0;  
  183.     char js_name_str[128];  
  184.     unsigned int buttons_state = 0;  
  185.     AXES_T* tp_axes = NULL;  
  186.     int i, print_init_stat = 0;  
  187.   
  188.     struct js_event jse;  
  189.   
  190.     fd = joystick_open("/dev/input/js0", 1);  
  191.     if (fd < 0) {  
  192.         LOG_ERR("open failed.\n");  
  193.         exit(1);  
  194.     }  
  195.   
  196.     rc = ioctl(fd, JSIOCGAXES, &number_of_axes);  
  197.     if (rc != -1) {  
  198.         LOG_DBG("number_of_axes:%d\n", number_of_axes);  
  199.         if (number_of_axes > 0) {  
  200.             tp_axes = (AXES_T*)calloc(sizeof(AXES_T), 1);  
  201.         }  
  202.     }  
  203.   
  204.     rc = ioctl(fd, JSIOCGBUTTONS, &number_of_btns);  
  205.     if (rc != -1) {  
  206.         LOG_DBG("number_of_btns:%d\n", number_of_btns);  
  207.     }  
  208.   
  209.     if (ioctl(fd, JSIOCGNAME(sizeof(js_name_str)), js_name_str) < 0) {  
  210.         LOG_DBG(js_name_str, "Unknown"sizeof(js_name_str));  
  211.     }  
  212.   
  213.     LOG_DBG("joystick Name: %s\n", js_name_str);  
  214.   
  215.     for (;;) {  
  216.         if (joystick_read_ready(fd)) {  
  217.             rc = joystick_read_one_event(fd, &jse);  
  218.             if (rc > 0) {  
  219.                 if ((jse.type & JS_EVENT_INIT) == JS_EVENT_INIT) {  
  220.                     if ((jse.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {  
  221.                         if (jse.value) {  
  222.                             buttons_state |= (1 << jse.number);  
  223.                         }  
  224.                         else {  
  225.                             buttons_state &= ~(1 << jse.number);  
  226.                         }  
  227.                     }  
  228.                     else if ((jse.type & ~JS_EVENT_INIT) == JS_EVENT_AXIS) {  
  229.                         if (tp_axes) {  
  230.                             if ((jse.number & 1) == 0) {  
  231.                                 tp_axes[jse.number / 2].x = jse.value;  
  232.                             }  
  233.                             else {  
  234.                                 tp_axes[jse.number / 2].y = jse.value;  
  235.                             }  
  236.                         }  
  237.   
  238.                     }  
  239.                 }  
  240.                 else {  
  241.                     op_times++;  
  242.                     if (print_init_stat == 0) {  
  243.                         for (i = 0; i < number_of_btns; i++) {  
  244.                             LOG_DBG("joystick init state: button %d is %s.\n", i, ((buttons_state & (1 << i)) == (1 << i)) ? "DOWN" : "UP");  
  245.                         }  
  246.   
  247.                         if (tp_axes)  
  248.                             for (i = 0; i < number_of_axes; i++) {  
  249.                                 LOG_DBG("joystick init state: axes %d is x=%d  y=%d.\n", i, tp_axes[i].x, tp_axes[i].y);  
  250.                             }  
  251.                         print_init_stat = 1;  
  252.                     }  
  253.   
  254.                     if (jse.type  == JS_EVENT_BUTTON) {  
  255.                         if (jse.value) {  
  256.                             buttons_state |= (1 << jse.number);  
  257.                         }  
  258.                         else {  
  259.                             buttons_state &= ~(1 << jse.number);  
  260.                         }  
  261.   
  262.                         LOG_DBG("joystick state: button %d is %s.\n", jse.number, ((buttons_state & (1 << jse.number)) == (1 << jse.number)) ? "DOWN" : "UP");  
  263.                     }  
  264.                     else if (jse.type == JS_EVENT_AXIS) {  
  265.                         if (tp_axes) {  
  266.                             if ((jse.number & 1) == 0) {  
  267.                                 tp_axes[jse.number / 2].x = jse.value;  
  268.                             }  
  269.                             else {  
  270.                                 tp_axes[jse.number / 2].y = jse.value;  
  271.                             }  
  272.                             LOG_DBG("joystick state: axes %d is x=%d  y=%d.\n", jse.number / 2, tp_axes[jse.number / 2].x, tp_axes[jse.number / 2].y);  
  273.                         }  
  274.                         else {  
  275.                             LOG_DBG("joystick state: axes %d is %s=%d.\n", jse.number / 2, ((jse.number & 1) == 0) ? "x" : "y", jse.value);  
  276.                         }  
  277.                     }  
  278.                 }  
  279.   
  280.                 if (op_times >= 18) {  
  281.                     break;  
  282.                 }  
  283.             }  
  284.         }  
  285.   
  286.         usleep(1000);  
  287.     }  
  288.   
  289.     joystick_close(fd);  
  290.   
  291.     if (tp_axes) {  
  292.         free(tp_axes);  
  293.     }  
  294.   
  295.     return 0;  
  296. }  
  297. #endif  

编译:   gcc -o my_joystick my_joystick.c listop.c

运行:   

mayer@mayer-Ubuntu:hid$ ./my_joystick
number_of_axes:2
number_of_btns:10
joystick Name: BETOP GAMEPAD
joystick init state: button 0 is UP.
joystick init state: button 1 is UP.
joystick init state: button 2 is UP.
joystick init state: button 3 is UP.
joystick init state: button 4 is UP.
joystick init state: button 5 is UP.
joystick init state: button 6 is UP.
joystick init state: button 7 is UP.
joystick init state: button 8 is UP.
joystick init state: button 9 is UP.
joystick init state: axes 0 is x=0 y=0.
joystick init state: axes 1 is x=0 y=135129.
joystick state: button 0 is DOWN.
joystick state: button 0 is UP.
joystick state: button 1 is DOWN.
joystick state: button 1 is UP.
joystick state: button 3 is DOWN.
joystick state: button 3 is UP.
joystick state: button 2 is DOWN.
joystick state: button 2 is UP.
joystick state: button 7 is DOWN.
joystick state: button 7 is UP.
joystick state: button 5 is DOWN.
joystick state: button 5 is UP.
joystick state: button 6 is DOWN.
joystick state: button 6 is UP.
joystick state: button 4 is DOWN.
joystick state: button 4 is UP.
joystick state: button 5 is DOWN.
joystick state: button 5 is UP.


不明白的地方可以参考linux kernel中的说明文件:Documentation/input/joystick-api.txt

相关内容