Permalink
Cannot retrieve contributors at this time
4035 lines (3623 sloc)
97.9 KB
| #include <stdio.h> | |
| #include <fcntl.h> | |
| #include <unistd.h> | |
| #include <signal.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/inotify.h> | |
| #include <sys/poll.h> | |
| #include <sys/sysinfo.h> | |
| #include <dirent.h> | |
| #include <errno.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <linux/input.h> | |
| #include <linux/uinput.h> | |
| #include <sys/time.h> | |
| #include <sys/types.h> | |
| #include <stdarg.h> | |
| #include "input.h" | |
| #include "user_io.h" | |
| #include "menu.h" | |
| #include "hardware.h" | |
| #include "cfg.h" | |
| #include "fpga_io.h" | |
| #include "osd.h" | |
| #include "video.h" | |
| #include "joymapping.h" | |
| #include "support.h" | |
| #define NUMDEV 30 | |
| #define NUMPLAYERS 6 | |
| #define UINPUT_NAME "MiSTer virtual input" | |
| char joy_bnames[NUMBUTTONS][32] = {}; | |
| int joy_bcount = 0; | |
| static int ev2amiga[] = | |
| { | |
| NONE, //0 KEY_RESERVED | |
| 0x45, //1 KEY_ESC | |
| 0x01, //2 KEY_1 | |
| 0x02, //3 KEY_2 | |
| 0x03, //4 KEY_3 | |
| 0x04, //5 KEY_4 | |
| 0x05, //6 KEY_5 | |
| 0x06, //7 KEY_6 | |
| 0x07, //8 KEY_7 | |
| 0x08, //9 KEY_8 | |
| 0x09, //10 KEY_9 | |
| 0x0a, //11 KEY_0 | |
| 0x0b, //12 KEY_MINUS | |
| 0x0c, //13 KEY_EQUAL | |
| 0x41, //14 KEY_BACKSPACE | |
| 0x42, //15 KEY_TAB | |
| 0x10, //16 KEY_Q | |
| 0x11, //17 KEY_W | |
| 0x12, //18 KEY_E | |
| 0x13, //19 KEY_R | |
| 0x14, //20 KEY_T | |
| 0x15, //21 KEY_Y | |
| 0x16, //22 KEY_U | |
| 0x17, //23 KEY_I | |
| 0x18, //24 KEY_O | |
| 0x19, //25 KEY_P | |
| 0x1a, //26 KEY_LEFTBRACE | |
| 0x1b, //27 KEY_RIGHTBRACE | |
| 0x44, //28 KEY_ENTER | |
| 0x63, //29 KEY_LEFTCTRL | |
| 0x20, //30 KEY_A | |
| 0x21, //31 KEY_S | |
| 0x22, //32 KEY_D | |
| 0x23, //33 KEY_F | |
| 0x24, //34 KEY_G | |
| 0x25, //35 KEY_H | |
| 0x26, //36 KEY_J | |
| 0x27, //37 KEY_K | |
| 0x28, //38 KEY_L | |
| 0x29, //39 KEY_SEMICOLON | |
| 0x2a, //40 KEY_APOSTROPHE | |
| 0x00, //41 KEY_GRAVE | |
| 0x60, //42 KEY_LEFTSHIFT | |
| 0x0d, //43 KEY_BACKSLASH | |
| 0x31, //44 KEY_Z | |
| 0x32, //45 KEY_X | |
| 0x33, //46 KEY_C | |
| 0x34, //47 KEY_V | |
| 0x35, //48 KEY_B | |
| 0x36, //49 KEY_N | |
| 0x37, //50 KEY_M | |
| 0x38, //51 KEY_COMMA | |
| 0x39, //52 KEY_DOT | |
| 0x3a, //53 KEY_SLASH | |
| 0x61, //54 KEY_RIGHTSHIFT | |
| 0x5d, //55 KEY_KPASTERISK | |
| 0x64, //56 KEY_LEFTALT | |
| 0x40, //57 KEY_SPACE | |
| 0x62 | CAPS_TOGGLE, //58 KEY_CAPSLOCK | |
| 0x50, //59 KEY_F1 | |
| 0x51, //60 KEY_F2 | |
| 0x52, //61 KEY_F3 | |
| 0x53, //62 KEY_F4 | |
| 0x54, //63 KEY_F5 | |
| 0x55, //64 KEY_F6 | |
| 0x56, //65 KEY_F7 | |
| 0x57, //66 KEY_F8 | |
| 0x58, //67 KEY_F9 | |
| 0x59, //68 KEY_F10 | |
| NONE, //69 KEY_NUMLOCK | |
| NONE, //70 KEY_SCROLLLOCK | |
| 0x3d, //71 KEY_KP7 | |
| 0x3e, //72 KEY_KP8 | |
| 0x3f, //73 KEY_KP9 | |
| 0x4a, //74 KEY_KPMINUS | |
| 0x2d, //75 KEY_KP4 | |
| 0x2e, //76 KEY_KP5 | |
| 0x2f, //77 KEY_KP6 | |
| 0x5e, //78 KEY_KPPLUS | |
| 0x1d, //79 KEY_KP1 | |
| 0x1e, //80 KEY_KP2 | |
| 0x1f, //81 KEY_KP3 | |
| 0x0f, //82 KEY_KP0 | |
| 0x3c, //83 KEY_KPDOT | |
| NONE, //84 ??? | |
| NONE, //85 KEY_ZENKAKU | |
| 0x30, //86 KEY_102ND, '<' on most keyboards | |
| 0x5f, //87 KEY_F11 | |
| NONE, //88 KEY_F12 | |
| NONE, //89 KEY_RO | |
| NONE, //90 KEY_KATAKANA | |
| NONE, //91 KEY_HIRAGANA | |
| NONE, //92 KEY_HENKAN | |
| NONE, //93 KEY_KATAKANA | |
| NONE, //94 KEY_MUHENKAN | |
| NONE, //95 KEY_KPJPCOMMA | |
| 0x43, //96 KEY_KPENTER | |
| 0x63, //97 KEY_RIGHTCTRL | |
| 0x5c, //98 KEY_KPSLASH | |
| NONE, //99 KEY_SYSRQ | |
| 0x65, //100 KEY_RIGHTALT | |
| NONE, //101 KEY_LINEFEED | |
| 0x6a, //102 KEY_HOME | |
| 0x4c, //103 KEY_UP | |
| 0x5b, //104 KEY_PAGEUP | |
| 0x4f, //105 KEY_LEFT | |
| 0x4e, //106 KEY_RIGHT | |
| NONE, //107 KEY_END | |
| 0x4d, //108 KEY_DOWN | |
| 0x5a, //109 KEY_PAGEDOWN | |
| 0x0d, //110 KEY_INSERT | |
| 0x46, //111 KEY_DELETE | |
| NONE, //112 KEY_MACRO | |
| NONE, //113 KEY_MUTE | |
| NONE, //114 KEY_VOLUMEDOWN | |
| NONE, //115 KEY_VOLUMEUP | |
| NONE, //116 KEY_POWER | |
| NONE, //117 KEY_KPEQUAL | |
| NONE, //118 KEY_KPPLUSMINUS | |
| NONE, //119 KEY_PAUSE | |
| NONE, //120 KEY_SCALE | |
| NONE, //121 KEY_KPCOMMA | |
| NONE, //122 KEY_HANGEUL | |
| NONE, //123 KEY_HANJA | |
| NONE, //124 KEY_YEN | |
| 0x66, //125 KEY_LEFTMETA | |
| 0x67, //126 KEY_RIGHTMETA | |
| NONE, //127 KEY_COMPOSE | |
| NONE, //128 KEY_STOP | |
| NONE, //129 KEY_AGAIN | |
| NONE, //130 KEY_PROPS | |
| NONE, //131 KEY_UNDO | |
| NONE, //132 KEY_FRONT | |
| NONE, //133 KEY_COPY | |
| NONE, //134 KEY_OPEN | |
| NONE, //135 KEY_PASTE | |
| NONE, //136 KEY_FIND | |
| NONE, //137 KEY_CUT | |
| NONE, //138 KEY_HELP | |
| NONE, //139 KEY_MENU | |
| NONE, //140 KEY_CALC | |
| NONE, //141 KEY_SETUP | |
| NONE, //142 KEY_SLEEP | |
| NONE, //143 KEY_WAKEUP | |
| NONE, //144 KEY_FILE | |
| NONE, //145 KEY_SENDFILE | |
| NONE, //146 KEY_DELETEFILE | |
| NONE, //147 KEY_XFER | |
| NONE, //148 KEY_PROG1 | |
| NONE, //149 KEY_PROG2 | |
| NONE, //150 KEY_WWW | |
| NONE, //151 KEY_MSDOS | |
| NONE, //152 KEY_SCREENLOCK | |
| NONE, //153 KEY_DIRECTION | |
| NONE, //154 KEY_CYCLEWINDOWS | |
| NONE, //155 KEY_MAIL | |
| NONE, //156 KEY_BOOKMARKS | |
| NONE, //157 KEY_COMPUTER | |
| NONE, //158 KEY_BACK | |
| NONE, //159 KEY_FORWARD | |
| NONE, //160 KEY_CLOSECD | |
| NONE, //161 KEY_EJECTCD | |
| NONE, //162 KEY_EJECTCLOSECD | |
| NONE, //163 KEY_NEXTSONG | |
| NONE, //164 KEY_PLAYPAUSE | |
| NONE, //165 KEY_PREVIOUSSONG | |
| NONE, //166 KEY_STOPCD | |
| NONE, //167 KEY_RECORD | |
| NONE, //168 KEY_REWIND | |
| NONE, //169 KEY_PHONE | |
| NONE, //170 KEY_ISO | |
| NONE, //171 KEY_CONFIG | |
| NONE, //172 KEY_HOMEPAGE | |
| NONE, //173 KEY_REFRESH | |
| NONE, //174 KEY_EXIT | |
| NONE, //175 KEY_MOVE | |
| NONE, //176 KEY_EDIT | |
| NONE, //177 KEY_SCROLLUP | |
| NONE, //178 KEY_SCROLLDOWN | |
| NONE, //179 KEY_KPLEFTPAREN | |
| NONE, //180 KEY_KPRIGHTPAREN | |
| NONE, //181 KEY_NEW | |
| NONE, //182 KEY_REDO | |
| 0x5a, //183 KEY_F13 | |
| 0x5b, //184 KEY_F14 | |
| NONE, //185 KEY_F15 | |
| 0x5f, //186 KEY_F16 | |
| NONE, //187 KEY_F17 | |
| NONE, //188 KEY_F18 | |
| NONE, //189 KEY_F19 | |
| NONE, //190 KEY_F20 | |
| NONE, //191 KEY_F21 | |
| NONE, //192 KEY_F22 | |
| NONE, //193 KEY_F23 | |
| 0x2b, //194 # on German keyboard, was 0x63 (CTRL on Amiga), 194 KEY_F24 | |
| NONE, //195 ??? | |
| NONE, //196 ??? | |
| NONE, //197 ??? | |
| NONE, //198 ??? | |
| NONE, //199 ??? | |
| NONE, //200 KEY_PLAYCD | |
| NONE, //201 KEY_PAUSECD | |
| NONE, //202 KEY_PROG3 | |
| NONE, //203 KEY_PROG4 | |
| NONE, //204 KEY_DASHBOARD | |
| NONE, //205 KEY_SUSPEND | |
| NONE, //206 KEY_CLOSE | |
| NONE, //207 KEY_PLAY | |
| NONE, //208 KEY_FASTFORWARD | |
| NONE, //209 KEY_BASSBOOST | |
| NONE, //210 KEY_PRINT | |
| NONE, //211 KEY_HP | |
| NONE, //212 KEY_CAMERA | |
| NONE, //213 KEY_SOUND | |
| NONE, //214 KEY_QUESTION | |
| NONE, //215 KEY_EMAIL | |
| NONE, //216 KEY_CHAT | |
| NONE, //217 KEY_SEARCH | |
| NONE, //218 KEY_CONNECT | |
| NONE, //219 KEY_FINANCE | |
| NONE, //220 KEY_SPORT | |
| NONE, //221 KEY_SHOP | |
| NONE, //222 KEY_ALTERASE | |
| NONE, //223 KEY_CANCEL | |
| NONE, //224 KEY_BRIGHT_DOWN | |
| NONE, //225 KEY_BRIGHT_UP | |
| NONE, //226 KEY_MEDIA | |
| NONE, //227 KEY_SWITCHVIDEO | |
| NONE, //228 KEY_DILLUMTOGGLE | |
| NONE, //229 KEY_DILLUMDOWN | |
| NONE, //230 KEY_DILLUMUP | |
| NONE, //231 KEY_SEND | |
| NONE, //232 KEY_REPLY | |
| NONE, //233 KEY_FORWARDMAIL | |
| NONE, //234 KEY_SAVE | |
| NONE, //235 KEY_DOCUMENTS | |
| NONE, //236 KEY_BATTERY | |
| NONE, //237 KEY_BLUETOOTH | |
| NONE, //238 KEY_WLAN | |
| NONE, //239 KEY_UWB | |
| NONE, //240 KEY_UNKNOWN | |
| NONE, //241 KEY_VIDEO_NEXT | |
| NONE, //242 KEY_VIDEO_PREV | |
| NONE, //243 KEY_BRIGHT_CYCLE | |
| NONE, //244 KEY_BRIGHT_AUTO | |
| NONE, //245 KEY_DISPLAY_OFF | |
| NONE, //246 KEY_WWAN | |
| NONE, //247 KEY_RFKILL | |
| NONE, //248 KEY_MICMUTE | |
| NONE, //249 ??? | |
| NONE, //250 ??? | |
| NONE, //251 ??? | |
| NONE, //252 ??? | |
| NONE, //253 ??? | |
| NONE, //254 ??? | |
| NONE //255 ??? | |
| }; | |
| static const int ev2ps2[] = | |
| { | |
| NONE, //0 KEY_RESERVED | |
| 0x76, //1 KEY_ESC | |
| 0x16, //2 KEY_1 | |
| 0x1e, //3 KEY_2 | |
| 0x26, //4 KEY_3 | |
| 0x25, //5 KEY_4 | |
| 0x2e, //6 KEY_5 | |
| 0x36, //7 KEY_6 | |
| 0x3d, //8 KEY_7 | |
| 0x3e, //9 KEY_8 | |
| 0x46, //10 KEY_9 | |
| 0x45, //11 KEY_0 | |
| 0x4e, //12 KEY_MINUS | |
| 0x55, //13 KEY_EQUAL | |
| 0x66, //14 KEY_BACKSPACE | |
| 0x0d, //15 KEY_TAB | |
| 0x15, //16 KEY_Q | |
| 0x1d, //17 KEY_W | |
| 0x24, //18 KEY_E | |
| 0x2d, //19 KEY_R | |
| 0x2c, //20 KEY_T | |
| 0x35, //21 KEY_Y | |
| 0x3c, //22 KEY_U | |
| 0x43, //23 KEY_I | |
| 0x44, //24 KEY_O | |
| 0x4d, //25 KEY_P | |
| 0x54, //26 KEY_LEFTBRACE | |
| 0x5b, //27 KEY_RIGHTBRACE | |
| 0x5a, //28 KEY_ENTER | |
| LCTRL | 0x14, //29 KEY_LEFTCTRL | |
| 0x1c, //30 KEY_A | |
| 0x1b, //31 KEY_S | |
| 0x23, //32 KEY_D | |
| 0x2b, //33 KEY_F | |
| 0x34, //34 KEY_G | |
| 0x33, //35 KEY_H | |
| 0x3b, //36 KEY_J | |
| 0x42, //37 KEY_K | |
| 0x4b, //38 KEY_L | |
| 0x4c, //39 KEY_SEMICOLON | |
| 0x52, //40 KEY_APOSTROPHE | |
| 0x0e, //41 KEY_GRAVE | |
| LSHIFT | 0x12, //42 KEY_LEFTSHIFT | |
| 0x5d, //43 KEY_BACKSLASH | |
| 0x1a, //44 KEY_Z | |
| 0x22, //45 KEY_X | |
| 0x21, //46 KEY_C | |
| 0x2a, //47 KEY_V | |
| 0x32, //48 KEY_B | |
| 0x31, //49 KEY_N | |
| 0x3a, //50 KEY_M | |
| 0x41, //51 KEY_COMMA | |
| 0x49, //52 KEY_DOT | |
| 0x4a, //53 KEY_SLASH | |
| RSHIFT | 0x59, //54 KEY_RIGHTSHIFT | |
| 0x7c, //55 KEY_KPASTERISK | |
| LALT | 0x11, //56 KEY_LEFTALT | |
| 0x29, //57 KEY_SPACE | |
| 0x58, //58 KEY_CAPSLOCK | |
| 0x05, //59 KEY_F1 | |
| 0x06, //60 KEY_F2 | |
| 0x04, //61 KEY_F3 | |
| 0x0c, //62 KEY_F4 | |
| 0x03, //63 KEY_F5 | |
| 0x0b, //64 KEY_F6 | |
| 0x83, //65 KEY_F7 | |
| 0x0a, //66 KEY_F8 | |
| 0x01, //67 KEY_F9 | |
| 0x09, //68 KEY_F10 | |
| EMU_SWITCH_2 | 0x77, //69 KEY_NUMLOCK | |
| EMU_SWITCH_1 | 0x7E, //70 KEY_SCROLLLOCK | |
| 0x6c, //71 KEY_KP7 | |
| 0x75, //72 KEY_KP8 | |
| 0x7d, //73 KEY_KP9 | |
| 0x7b, //74 KEY_KPMINUS | |
| 0x6b, //75 KEY_KP4 | |
| 0x73, //76 KEY_KP5 | |
| 0x74, //77 KEY_KP6 | |
| 0x79, //78 KEY_KPPLUS | |
| 0x69, //79 KEY_KP1 | |
| 0x72, //80 KEY_KP2 | |
| 0x7a, //81 KEY_KP3 | |
| 0x70, //82 KEY_KP0 | |
| 0x71, //83 KEY_KPDOT | |
| NONE, //84 ??? | |
| NONE, //85 KEY_ZENKAKU | |
| 0x61, //86 KEY_102ND | |
| 0x78, //87 KEY_F11 | |
| 0x07, //88 KEY_F12 | |
| NONE, //89 KEY_RO | |
| NONE, //90 KEY_KATAKANA | |
| NONE, //91 KEY_HIRAGANA | |
| NONE, //92 KEY_HENKAN | |
| NONE, //93 KEY_KATAKANA | |
| NONE, //94 KEY_MUHENKAN | |
| NONE, //95 KEY_KPJPCOMMA | |
| EXT | 0x5a, //96 KEY_KPENTER | |
| RCTRL | EXT | 0x14, //97 KEY_RIGHTCTRL | |
| EXT | 0x4a, //98 KEY_KPSLASH | |
| 0xE2, //99 KEY_SYSRQ | |
| RALT | EXT | 0x11, //100 KEY_RIGHTALT | |
| NONE, //101 KEY_LINEFEED | |
| EXT | 0x6c, //102 KEY_HOME | |
| EXT | 0x75, //103 KEY_UP | |
| EXT | 0x7d, //104 KEY_PAGEUP | |
| EXT | 0x6b, //105 KEY_LEFT | |
| EXT | 0x74, //106 KEY_RIGHT | |
| EXT | 0x69, //107 KEY_END | |
| EXT | 0x72, //108 KEY_DOWN | |
| EXT | 0x7a, //109 KEY_PAGEDOWN | |
| EXT | 0x70, //110 KEY_INSERT | |
| EXT | 0x71, //111 KEY_DELETE | |
| NONE, //112 KEY_MACRO | |
| NONE, //113 KEY_MUTE | |
| NONE, //114 KEY_VOLUMEDOWN | |
| NONE, //115 KEY_VOLUMEUP | |
| NONE, //116 KEY_POWER | |
| NONE, //117 KEY_KPEQUAL | |
| NONE, //118 KEY_KPPLUSMINUS | |
| 0xE1, //119 KEY_PAUSE | |
| NONE, //120 KEY_SCALE | |
| NONE, //121 KEY_KPCOMMA | |
| NONE, //122 KEY_HANGEUL | |
| NONE, //123 KEY_HANJA | |
| NONE, //124 KEY_YEN | |
| LGUI | EXT | 0x1f, //125 KEY_LEFTMETA | |
| RGUI | EXT | 0x27, //126 KEY_RIGHTMETA | |
| NONE, //127 KEY_COMPOSE | |
| NONE, //128 KEY_STOP | |
| NONE, //129 KEY_AGAIN | |
| NONE, //130 KEY_PROPS | |
| NONE, //131 KEY_UNDO | |
| NONE, //132 KEY_FRONT | |
| NONE, //133 KEY_COPY | |
| NONE, //134 KEY_OPEN | |
| NONE, //135 KEY_PASTE | |
| NONE, //136 KEY_FIND | |
| NONE, //137 KEY_CUT | |
| NONE, //138 KEY_HELP | |
| NONE, //139 KEY_MENU | |
| NONE, //140 KEY_CALC | |
| NONE, //141 KEY_SETUP | |
| NONE, //142 KEY_SLEEP | |
| NONE, //143 KEY_WAKEUP | |
| NONE, //144 KEY_FILE | |
| NONE, //145 KEY_SENDFILE | |
| NONE, //146 KEY_DELETEFILE | |
| NONE, //147 KEY_XFER | |
| NONE, //148 KEY_PROG1 | |
| NONE, //149 KEY_PROG2 | |
| NONE, //150 KEY_WWW | |
| NONE, //151 KEY_MSDOS | |
| NONE, //152 KEY_SCREENLOCK | |
| NONE, //153 KEY_DIRECTION | |
| NONE, //154 KEY_CYCLEWINDOWS | |
| NONE, //155 KEY_MAIL | |
| NONE, //156 KEY_BOOKMARKS | |
| NONE, //157 KEY_COMPUTER | |
| NONE, //158 KEY_BACK | |
| NONE, //159 KEY_FORWARD | |
| NONE, //160 KEY_CLOSECD | |
| NONE, //161 KEY_EJECTCD | |
| NONE, //162 KEY_EJECTCLOSECD | |
| NONE, //163 KEY_NEXTSONG | |
| NONE, //164 KEY_PLAYPAUSE | |
| NONE, //165 KEY_PREVIOUSSONG | |
| NONE, //166 KEY_STOPCD | |
| NONE, //167 KEY_RECORD | |
| NONE, //168 KEY_REWIND | |
| NONE, //169 KEY_PHONE | |
| NONE, //170 KEY_ISO | |
| NONE, //171 KEY_CONFIG | |
| NONE, //172 KEY_HOMEPAGE | |
| NONE, //173 KEY_REFRESH | |
| NONE, //174 KEY_EXIT | |
| NONE, //175 KEY_MOVE | |
| NONE, //176 KEY_EDIT | |
| NONE, //177 KEY_SCROLLUP | |
| NONE, //178 KEY_SCROLLDOWN | |
| NONE, //179 KEY_KPLEFTPAREN | |
| NONE, //180 KEY_KPRIGHTPAREN | |
| NONE, //181 KEY_NEW | |
| NONE, //182 KEY_REDO | |
| NONE, //183 KEY_F13 | |
| NONE, //184 KEY_F14 | |
| NONE, //185 KEY_F15 | |
| NONE, //186 KEY_F16 | |
| EMU_SWITCH_1 | 1, //187 KEY_F17 | |
| EMU_SWITCH_1 | 2, //188 KEY_F18 | |
| EMU_SWITCH_1 | 3, //189 KEY_F19 | |
| EMU_SWITCH_1 | 4, //190 KEY_F20 | |
| NONE, //191 KEY_F21 | |
| NONE, //192 KEY_F22 | |
| NONE, //193 KEY_F23 | |
| 0x5D, //194 U-mlaut on DE mapped to backslash | |
| NONE, //195 ??? | |
| NONE, //196 ??? | |
| NONE, //197 ??? | |
| NONE, //198 ??? | |
| NONE, //199 ??? | |
| NONE, //200 KEY_PLAYCD | |
| NONE, //201 KEY_PAUSECD | |
| NONE, //202 KEY_PROG3 | |
| NONE, //203 KEY_PROG4 | |
| NONE, //204 KEY_DASHBOARD | |
| NONE, //205 KEY_SUSPEND | |
| NONE, //206 KEY_CLOSE | |
| NONE, //207 KEY_PLAY | |
| NONE, //208 KEY_FASTFORWARD | |
| NONE, //209 KEY_BASSBOOST | |
| NONE, //210 KEY_PRINT | |
| NONE, //211 KEY_HP | |
| NONE, //212 KEY_CAMERA | |
| NONE, //213 KEY_SOUND | |
| NONE, //214 KEY_QUESTION | |
| NONE, //215 KEY_EMAIL | |
| NONE, //216 KEY_CHAT | |
| NONE, //217 KEY_SEARCH | |
| NONE, //218 KEY_CONNECT | |
| NONE, //219 KEY_FINANCE | |
| NONE, //220 KEY_SPORT | |
| NONE, //221 KEY_SHOP | |
| NONE, //222 KEY_ALTERASE | |
| NONE, //223 KEY_CANCEL | |
| NONE, //224 KEY_BRIGHT_DOWN | |
| NONE, //225 KEY_BRIGHT_UP | |
| NONE, //226 KEY_MEDIA | |
| NONE, //227 KEY_SWITCHVIDEO | |
| NONE, //228 KEY_DILLUMTOGGLE | |
| NONE, //229 KEY_DILLUMDOWN | |
| NONE, //230 KEY_DILLUMUP | |
| NONE, //231 KEY_SEND | |
| NONE, //232 KEY_REPLY | |
| NONE, //233 KEY_FORWARDMAIL | |
| NONE, //234 KEY_SAVE | |
| NONE, //235 KEY_DOCUMENTS | |
| NONE, //236 KEY_BATTERY | |
| NONE, //237 KEY_BLUETOOTH | |
| NONE, //238 KEY_WLAN | |
| NONE, //239 KEY_UWB | |
| NONE, //240 KEY_UNKNOWN | |
| NONE, //241 KEY_VIDEO_NEXT | |
| NONE, //242 KEY_VIDEO_PREV | |
| NONE, //243 KEY_BRIGHT_CYCLE | |
| NONE, //244 KEY_BRIGHT_AUTO | |
| NONE, //245 KEY_DISPLAY_OFF | |
| NONE, //246 KEY_WWAN | |
| NONE, //247 KEY_RFKILL | |
| NONE, //248 KEY_MICMUTE | |
| NONE, //249 ??? | |
| NONE, //250 ??? | |
| NONE, //251 ??? | |
| NONE, //252 ??? | |
| NONE, //253 ??? | |
| NONE, //254 ??? | |
| NONE //255 ??? | |
| }; | |
| static int ev2archie[] = | |
| { | |
| NONE, //0 KEY_RESERVED | |
| 0x00, //1 KEY_ESC | |
| 0x11, //2 KEY_1 | |
| 0x12, //3 KEY_2 | |
| 0x13, //4 KEY_3 | |
| 0x14, //5 KEY_4 | |
| 0x15, //6 KEY_5 | |
| 0x16, //7 KEY_6 | |
| 0x17, //8 KEY_7 | |
| 0x18, //9 KEY_8 | |
| 0x19, //10 KEY_9 | |
| 0x1a, //11 KEY_0 | |
| 0x1b, //12 KEY_MINUS | |
| 0x1c, //13 KEY_EQUAL | |
| 0x1e, //14 KEY_BACKSPACE | |
| 0x26, //15 KEY_TAB | |
| 0x27, //16 KEY_Q | |
| 0x28, //17 KEY_W | |
| 0x29, //18 KEY_E | |
| 0x2a, //19 KEY_R | |
| 0x2b, //20 KEY_T | |
| 0x2c, //21 KEY_Y | |
| 0x2d, //22 KEY_U | |
| 0x2e, //23 KEY_I | |
| 0x2f, //24 KEY_O | |
| 0x30, //25 KEY_P | |
| 0x31, //26 KEY_LEFTBRACE | |
| 0x32, //27 KEY_RIGHTBRACE | |
| 0x47, //28 KEY_ENTER | |
| 0x3b, //29 KEY_LEFTCTRL | |
| 0x3c, //30 KEY_A | |
| 0x3d, //31 KEY_S | |
| 0x3e, //32 KEY_D | |
| 0x3f, //33 KEY_F | |
| 0x40, //34 KEY_G | |
| 0x41, //35 KEY_H | |
| 0x42, //36 KEY_J | |
| 0x43, //37 KEY_K | |
| 0x44, //38 KEY_L | |
| 0x45, //39 KEY_SEMICOLON | |
| 0x46, //40 KEY_APOSTROPHE | |
| 0x10, //41 KEY_GRAVE | |
| 0x4c, //42 KEY_LEFTSHIFT | |
| 0x33, //43 KEY_BACKSLASH | |
| 0x4e, //44 KEY_Z | |
| 0x4f, //45 KEY_X | |
| 0x50, //46 KEY_C | |
| 0x51, //47 KEY_V | |
| 0x52, //48 KEY_B | |
| 0x53, //49 KEY_N | |
| 0x54, //50 KEY_M | |
| 0x55, //51 KEY_COMMA | |
| 0x56, //52 KEY_DOT | |
| 0x57, //53 KEY_SLASH | |
| 0x58, //54 KEY_RIGHTSHIFT | |
| 0x24, //55 KEY_KPASTERISK | |
| 0x5e, //56 KEY_LEFTALT | |
| 0x5f, //57 KEY_SPACE | |
| 0x5d, //58 KEY_CAPSLOCK | |
| 0x01, //59 KEY_F1 | |
| 0x02, //60 KEY_F2 | |
| 0x03, //61 KEY_F3 | |
| 0x04, //62 KEY_F4 | |
| 0x05, //63 KEY_F5 | |
| 0x06, //64 KEY_F6 | |
| 0x07, //65 KEY_F7 | |
| 0x08, //66 KEY_F8 | |
| 0x09, //67 KEY_F9 | |
| 0x0a, //68 KEY_F10 | |
| 0x22, //69 KEY_NUMLOCK | |
| NONE, //70 KEY_SCROLLLOCK | |
| 0x37, //71 KEY_KP7 | |
| 0x38, //72 KEY_KP8 | |
| 0x39, //73 KEY_KP9 | |
| 0x3a, //74 KEY_KPMINUS | |
| 0x48, //75 KEY_KP4 | |
| 0x49, //76 KEY_KP5 | |
| 0x4a, //77 KEY_KP6 | |
| 0x4b, //78 KEY_KPPLUS | |
| 0x5a, //79 KEY_KP1 | |
| 0x5b, //80 KEY_KP2 | |
| 0x5c, //81 KEY_KP3 | |
| 0x65, //82 KEY_KP0 | |
| 0x66, //83 KEY_KPDOT | |
| NONE, //84 ??? | |
| NONE, //85 KEY_ZENKAKU | |
| NONE, //86 KEY_102ND | |
| 0x0b, //87 KEY_F11 | |
| 0x0c, //88 KEY_F12 | |
| NONE, //89 KEY_RO | |
| NONE, //90 KEY_KATAKANA | |
| NONE, //91 KEY_HIRAGANA | |
| NONE, //92 KEY_HENKAN | |
| NONE, //93 KEY_KATAKANA | |
| NONE, //94 KEY_MUHENKAN | |
| NONE, //95 KEY_KPJPCOMMA | |
| 0x67, //96 KEY_KPENTER | |
| 0x61, //97 KEY_RIGHTCTRL | |
| 0x23, //98 KEY_KPSLASH | |
| 0x0D, //99 KEY_SYSRQ | |
| 0x60, //100 KEY_RIGHTALT | |
| NONE, //101 KEY_LINEFEED | |
| 0x20, //102 KEY_HOME | |
| 0x59, //103 KEY_UP | |
| 0x21, //104 KEY_PAGEUP | |
| 0x62, //105 KEY_LEFT | |
| 0x64, //106 KEY_RIGHT | |
| 0x35, //107 KEY_END | |
| 0x63, //108 KEY_DOWN | |
| 0x36, //109 KEY_PAGEDOWN | |
| 0x1f, //110 KEY_INSERT | |
| 0x34, //111 KEY_DELETE | |
| NONE, //112 KEY_MACRO | |
| NONE, //113 KEY_MUTE | |
| NONE, //114 KEY_VOLUMEDOWN | |
| NONE, //115 KEY_VOLUMEUP | |
| NONE, //116 KEY_POWER | |
| NONE, //117 KEY_KPEQUAL | |
| NONE, //118 KEY_KPPLUSMINUS | |
| 0x0f, //119 KEY_PAUSE | |
| NONE, //120 KEY_SCALE | |
| NONE, //121 KEY_KPCOMMA | |
| NONE, //122 KEY_HANGEUL | |
| NONE, //123 KEY_HANJA | |
| NONE, //124 KEY_YEN | |
| NONE, //125 KEY_LEFTMETA | |
| NONE, //126 KEY_RIGHTMETA | |
| 0x71, //127 KEY_COMPOSE | |
| NONE, //128 KEY_STOP | |
| NONE, //129 KEY_AGAIN | |
| NONE, //130 KEY_PROPS | |
| NONE, //131 KEY_UNDO | |
| NONE, //132 KEY_FRONT | |
| NONE, //133 KEY_COPY | |
| NONE, //134 KEY_OPEN | |
| NONE, //135 KEY_PASTE | |
| NONE, //136 KEY_FIND | |
| NONE, //137 KEY_CUT | |
| NONE, //138 KEY_HELP | |
| NONE, //139 KEY_MENU | |
| NONE, //140 KEY_CALC | |
| NONE, //141 KEY_SETUP | |
| NONE, //142 KEY_SLEEP | |
| NONE, //143 KEY_WAKEUP | |
| NONE, //144 KEY_FILE | |
| NONE, //145 KEY_SENDFILE | |
| NONE, //146 KEY_DELETEFILE | |
| NONE, //147 KEY_XFER | |
| NONE, //148 KEY_PROG1 | |
| NONE, //149 KEY_PROG2 | |
| NONE, //150 KEY_WWW | |
| NONE, //151 KEY_MSDOS | |
| NONE, //152 KEY_SCREENLOCK | |
| NONE, //153 KEY_DIRECTION | |
| NONE, //154 KEY_CYCLEWINDOWS | |
| NONE, //155 KEY_MAIL | |
| NONE, //156 KEY_BOOKMARKS | |
| NONE, //157 KEY_COMPUTER | |
| NONE, //158 KEY_BACK | |
| NONE, //159 KEY_FORWARD | |
| NONE, //160 KEY_CLOSECD | |
| NONE, //161 KEY_EJECTCD | |
| NONE, //162 KEY_EJECTCLOSECD | |
| NONE, //163 KEY_NEXTSONG | |
| NONE, //164 KEY_PLAYPAUSE | |
| NONE, //165 KEY_PREVIOUSSONG | |
| NONE, //166 KEY_STOPCD | |
| NONE, //167 KEY_RECORD | |
| NONE, //168 KEY_REWIND | |
| NONE, //169 KEY_PHONE | |
| NONE, //170 KEY_ISO | |
| NONE, //171 KEY_CONFIG | |
| NONE, //172 KEY_HOMEPAGE | |
| NONE, //173 KEY_REFRESH | |
| NONE, //174 KEY_EXIT | |
| NONE, //175 KEY_MOVE | |
| NONE, //176 KEY_EDIT | |
| NONE, //177 KEY_SCROLLUP | |
| NONE, //178 KEY_SCROLLDOWN | |
| NONE, //179 KEY_KPLEFTPAREN | |
| NONE, //180 KEY_KPRIGHTPAREN | |
| NONE, //181 KEY_NEW | |
| NONE, //182 KEY_REDO | |
| NONE, //183 KEY_F13 | |
| NONE, //184 KEY_F14 | |
| NONE, //185 KEY_F15 | |
| NONE, //186 KEY_F16 | |
| NONE, //187 KEY_F17 | |
| NONE, //188 KEY_F18 | |
| NONE, //189 KEY_F19 | |
| NONE, //190 KEY_F20 | |
| NONE, //191 KEY_F21 | |
| NONE, //192 KEY_F22 | |
| NONE, //193 KEY_F23 | |
| NONE, //194 KEY_F24 | |
| NONE, //195 ??? | |
| NONE, //196 ??? | |
| NONE, //197 ??? | |
| NONE, //198 ??? | |
| NONE, //199 ??? | |
| NONE, //200 KEY_PLAYCD | |
| NONE, //201 KEY_PAUSECD | |
| NONE, //202 KEY_PROG3 | |
| NONE, //203 KEY_PROG4 | |
| NONE, //204 KEY_DASHBOARD | |
| NONE, //205 KEY_SUSPEND | |
| NONE, //206 KEY_CLOSE | |
| NONE, //207 KEY_PLAY | |
| NONE, //208 KEY_FASTFORWARD | |
| NONE, //209 KEY_BASSBOOST | |
| NONE, //210 KEY_PRINT | |
| NONE, //211 KEY_HP | |
| NONE, //212 KEY_CAMERA | |
| NONE, //213 KEY_SOUND | |
| NONE, //214 KEY_QUESTION | |
| NONE, //215 KEY_EMAIL | |
| NONE, //216 KEY_CHAT | |
| NONE, //217 KEY_SEARCH | |
| NONE, //218 KEY_CONNECT | |
| NONE, //219 KEY_FINANCE | |
| NONE, //220 KEY_SPORT | |
| NONE, //221 KEY_SHOP | |
| NONE, //222 KEY_ALTERASE | |
| NONE, //223 KEY_CANCEL | |
| NONE, //224 KEY_BRIGHT_DOWN | |
| NONE, //225 KEY_BRIGHT_UP | |
| NONE, //226 KEY_MEDIA | |
| NONE, //227 KEY_SWITCHVIDEO | |
| NONE, //228 KEY_DILLUMTOGGLE | |
| NONE, //229 KEY_DILLUMDOWN | |
| NONE, //230 KEY_DILLUMUP | |
| NONE, //231 KEY_SEND | |
| NONE, //232 KEY_REPLY | |
| NONE, //233 KEY_FORWARDMAIL | |
| NONE, //234 KEY_SAVE | |
| NONE, //235 KEY_DOCUMENTS | |
| NONE, //236 KEY_BATTERY | |
| NONE, //237 KEY_BLUETOOTH | |
| NONE, //238 KEY_WLAN | |
| NONE, //239 KEY_UWB | |
| NONE, //240 KEY_UNKNOWN | |
| NONE, //241 KEY_VIDEO_NEXT | |
| NONE, //242 KEY_VIDEO_PREV | |
| NONE, //243 KEY_BRIGHT_CYCLE | |
| NONE, //244 KEY_BRIGHT_AUTO | |
| NONE, //245 KEY_DISPLAY_OFF | |
| NONE, //246 KEY_WWAN | |
| NONE, //247 KEY_RFKILL | |
| NONE, //248 KEY_MICMUTE | |
| NONE, //249 ??? | |
| NONE, //250 ??? | |
| NONE, //251 ??? | |
| NONE, //252 ??? | |
| NONE, //253 ??? | |
| NONE, //254 ??? | |
| NONE //255 ??? | |
| }; | |
| uint32_t get_ps2_code(uint16_t key) | |
| { | |
| if (key > 255) return NONE; | |
| return ev2ps2[key]; | |
| } | |
| uint32_t get_amiga_code(uint16_t key) | |
| { | |
| if (key > 255) return NONE; | |
| return ev2amiga[key]; | |
| } | |
| uint32_t get_archie_code(uint16_t key) | |
| { | |
| if (key > 255) return NONE; | |
| return ev2archie[key]; | |
| } | |
| static uint32_t modifier = 0; | |
| uint32_t get_key_mod() | |
| { | |
| return modifier & MODMASK; | |
| } | |
| enum QUIRK | |
| { | |
| QUIRK_NONE = 0, | |
| QUIRK_CWIID, | |
| QUIRK_WIIMOTE, | |
| QUIRK_DS3, | |
| QUIRK_DS4, | |
| QUIRK_DS4TOUCH, | |
| QUIRK_MADCATZ360, | |
| QUIRK_PDSP, | |
| QUIRK_PDSP_ARCADE, | |
| QUIRK_JAMMA, | |
| QUIRK_MSSP, | |
| QUIRK_TOUCHGUN, | |
| }; | |
| typedef struct | |
| { | |
| uint16_t vid, pid; | |
| char idstr[256]; | |
| uint8_t led; | |
| uint8_t mouse; | |
| uint8_t axis_edge[256]; | |
| int8_t axis_pos[256]; | |
| uint8_t num; | |
| uint8_t has_map; | |
| uint32_t map[NUMBUTTONS]; | |
| int map_shown; | |
| uint8_t osd_combo; | |
| uint8_t has_mmap; | |
| uint32_t mmap[NUMBUTTONS]; | |
| uint16_t jkmap[1024]; | |
| uint8_t has_kbdmap; | |
| uint8_t kbdmap[256]; | |
| uint16_t guncal[4]; | |
| int accx, accy; | |
| int startx, starty; | |
| int lastx, lasty; | |
| int quirk; | |
| int misc_flags; | |
| int paddle_val; | |
| int spinner_acc; | |
| int spinner_prediv; | |
| int old_btn; | |
| int ds_mouse_emu; | |
| int lightgun_req; | |
| int lightgun; | |
| int bind; | |
| char devname[32]; | |
| char id[80]; | |
| char name[128]; | |
| } devInput; | |
| static devInput input[NUMDEV] = {}; | |
| static devInput player_pad[NUMPLAYERS] = {}; | |
| static devInput player_pdsp[NUMPLAYERS] = {}; | |
| #define BTN_NUM (sizeof(devInput::map) / sizeof(devInput::map[0])) | |
| int mfd = -1; | |
| int mwd = -1; | |
| static int set_watch() | |
| { | |
| mwd = -1; | |
| mfd = inotify_init(); | |
| if (mfd < 0) | |
| { | |
| printf("ERR: inotify_init"); | |
| return -1; | |
| } | |
| mwd = inotify_add_watch(mfd, "/dev/input", IN_MODIFY | IN_CREATE | IN_DELETE); | |
| if (mwd < 0) | |
| { | |
| printf("ERR: inotify_add_watch"); | |
| return -1; | |
| } | |
| return mfd; | |
| } | |
| #define EVENT_SIZE ( sizeof (struct inotify_event) ) | |
| #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) | |
| static int check_devs() | |
| { | |
| int result = 0; | |
| int length, i = 0; | |
| char buffer[BUF_LEN]; | |
| length = read(mfd, buffer, BUF_LEN); | |
| if (length < 0) | |
| { | |
| printf("ERR: read\n"); | |
| return 0; | |
| } | |
| while (i<length) | |
| { | |
| struct inotify_event *event = (struct inotify_event *) &buffer[i]; | |
| if (event->len) | |
| { | |
| if (event->mask & IN_CREATE) | |
| { | |
| result = 1; | |
| if (event->mask & IN_ISDIR) | |
| { | |
| printf("The directory %s was created.\n", event->name); | |
| } | |
| else | |
| { | |
| printf("The file %s was created.\n", event->name); | |
| } | |
| } | |
| else if (event->mask & IN_DELETE) | |
| { | |
| result = 1; | |
| if (event->mask & IN_ISDIR) | |
| { | |
| printf("The directory %s was deleted.\n", event->name); | |
| } | |
| else | |
| { | |
| printf("The file %s was deleted.\n", event->name); | |
| } | |
| } | |
| /* | |
| else if ( event->mask & IN_MODIFY ) | |
| { | |
| result = 1; | |
| if ( event->mask & IN_ISDIR ) | |
| { | |
| printf( "The directory %s was modified.\n", event->name ); | |
| } | |
| else | |
| { | |
| printf( "The file %s was modified.\n", event->name ); | |
| } | |
| } | |
| */ | |
| } | |
| i += EVENT_SIZE + event->len; | |
| } | |
| return result; | |
| } | |
| static void INThandler(int code) | |
| { | |
| (void)code; | |
| printf("\nExiting...\n"); | |
| if (mwd >= 0) inotify_rm_watch(mfd, mwd); | |
| if (mfd >= 0) close(mfd); | |
| exit(0); | |
| } | |
| #define test_bit(bit, array) (array [bit / 8] & (1 << (bit % 8))) | |
| static char has_led(int fd) | |
| { | |
| unsigned char evtype_b[(EV_MAX + 7) / 8]; | |
| if (fd<0) return 0; | |
| memset(&evtype_b, 0, sizeof(evtype_b)); | |
| if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype_b)), evtype_b) < 0) | |
| { | |
| printf("ERR: evdev ioctl.\n"); | |
| return 0; | |
| } | |
| return test_bit(EV_LED, evtype_b) ? 1 : 0; | |
| } | |
| static char leds_state = 0; | |
| void set_kbdled(int mask, int state) | |
| { | |
| leds_state = state ? leds_state | (mask&HID_LED_MASK) : leds_state & ~(mask&HID_LED_MASK); | |
| } | |
| int get_kbdled(int mask) | |
| { | |
| return (leds_state & (mask&HID_LED_MASK)) ? 1 : 0; | |
| } | |
| int toggle_kbdled(int mask) | |
| { | |
| int state = !get_kbdled(mask); | |
| set_kbdled(mask, state); | |
| return state; | |
| } | |
| #define JOYMAP_DIR "inputs/" | |
| static int load_map(const char *name, void *pBuffer, int size) | |
| { | |
| char path[256] = { JOYMAP_DIR }; | |
| strcat(path, name); | |
| int ret = FileLoadConfig(path, pBuffer, size); | |
| if (!ret) return FileLoadConfig(name, pBuffer, size); | |
| return ret; | |
| } | |
| static void delete_map(const char *name) | |
| { | |
| char path[256] = { JOYMAP_DIR }; | |
| FileCreatePath(path); | |
| strcat(path, name); | |
| FileDeleteConfig(name); | |
| FileDeleteConfig(path); | |
| } | |
| static int save_map(const char *name, void *pBuffer, int size) | |
| { | |
| char path[256] = { JOYMAP_DIR }; | |
| FileCreatePath(path); | |
| strcat(path, name); | |
| FileDeleteConfig(name); | |
| return FileSaveConfig(path, pBuffer, size); | |
| } | |
| static int mapping = 0; | |
| static int mapping_button; | |
| static int mapping_dev = -1; | |
| static int mapping_type; | |
| static int mapping_count; | |
| static int mapping_clear; | |
| static int mapping_set; | |
| static uint32_t tmp_axis[4]; | |
| static int tmp_axis_n = 0; | |
| static int grabbed = 1; | |
| void start_map_setting(int cnt, int set) | |
| { | |
| mapping_button = 0; | |
| mapping = 1; | |
| mapping_set = set; | |
| if (!mapping_set) | |
| { | |
| mapping_dev = -1; | |
| mapping_type = (cnt < 0) ? 3 : cnt ? 1 : 2; | |
| } | |
| mapping_count = cnt; | |
| mapping_clear = 0; | |
| tmp_axis_n = 0; | |
| if (mapping_type <= 1 && is_menu()) mapping_button = -6; | |
| memset(tmp_axis, 0, sizeof(tmp_axis)); | |
| //un-stick the enter key | |
| user_io_kbd(KEY_ENTER, 0); | |
| } | |
| int get_map_button() | |
| { | |
| return mapping_button; | |
| } | |
| int get_map_type() | |
| { | |
| return mapping_type; | |
| } | |
| int get_map_clear() | |
| { | |
| return mapping_clear; | |
| } | |
| static uint32_t osd_timer = 0; | |
| int get_map_cancel() | |
| { | |
| return (mapping && !is_menu() && osd_timer && CheckTimer(osd_timer)); | |
| } | |
| static char *get_map_name(int dev, int def) | |
| { | |
| static char name[128]; | |
| if (def || is_menu()) sprintf(name, "input_%s_v3.map", input[dev].idstr); | |
| else sprintf(name, "%s_input_%s_v3.map", user_io_get_core_name_ex(), input[dev].idstr); | |
| return name; | |
| } | |
| static char *get_kbdmap_name(int dev) | |
| { | |
| static char name[128]; | |
| sprintf(name, "kbd_%s.map", input[dev].idstr); | |
| return name; | |
| } | |
| void finish_map_setting(int dismiss) | |
| { | |
| mapping = 0; | |
| if (mapping_dev<0) return; | |
| if (mapping_type == 2) | |
| { | |
| if (dismiss) input[mapping_dev].has_kbdmap = 0; | |
| else if (dismiss == 2) FileDeleteConfig(get_kbdmap_name(mapping_dev)); | |
| else FileSaveConfig(get_kbdmap_name(mapping_dev), &input[mapping_dev].kbdmap, sizeof(input[mapping_dev].kbdmap)); | |
| } | |
| else if (mapping_type == 3) | |
| { | |
| if (dismiss) memset(input[mapping_dev].jkmap, 0, sizeof(input[mapping_dev].jkmap)); | |
| } | |
| else | |
| { | |
| for (int i = 0; i < NUMDEV; i++) input[i].has_map = 0; | |
| if (!dismiss) save_map(get_map_name(mapping_dev, 0), &input[mapping_dev].map, sizeof(input[mapping_dev].map)); | |
| if (dismiss == 2) delete_map(get_map_name(mapping_dev, 0)); | |
| if (is_menu()) input[mapping_dev].has_mmap = 0; | |
| } | |
| } | |
| void input_lightgun_save(int idx, uint16_t *cal) | |
| { | |
| static char name[128]; | |
| sprintf(name, "%s_gun_cal_%04x_%04x.cfg", user_io_get_core_name_ex(), input[idx].vid, input[idx].pid); | |
| FileSaveConfig(name, cal, 4 * sizeof(uint16_t)); | |
| memcpy(input[idx].guncal, cal, sizeof(input[idx].guncal)); | |
| } | |
| static void input_lightgun_load(int idx) | |
| { | |
| static char name[128]; | |
| sprintf(name, "%s_gun_cal_%04x_%04x.cfg", user_io_get_core_name_ex(), input[idx].vid, input[idx].pid); | |
| FileLoadConfig(name, input[idx].guncal, 4 * sizeof(uint16_t)); | |
| } | |
| int input_has_lightgun() | |
| { | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if (input[i].quirk == QUIRK_WIIMOTE) return 1; | |
| if (input[i].quirk == QUIRK_TOUCHGUN) return 1; | |
| } | |
| return 0; | |
| } | |
| uint16_t get_map_vid() | |
| { | |
| return (mapping && mapping_dev >= 0) ? input[mapping_dev].vid : 0; | |
| } | |
| uint16_t get_map_pid() | |
| { | |
| return (mapping && mapping_dev >= 0) ? input[mapping_dev].pid : 0; | |
| } | |
| int has_default_map() | |
| { | |
| return (mapping_dev >= 0) ? (input[mapping_dev].has_mmap == 1) : 0; | |
| } | |
| static char kr_fn_table[] = | |
| { | |
| KEY_KPSLASH, KEY_PAUSE, | |
| KEY_KPASTERISK, KEY_PRINT, | |
| KEY_LEFT, KEY_HOME, | |
| KEY_RIGHT, KEY_END, | |
| KEY_UP, KEY_PAGEUP, | |
| KEY_DOWN, KEY_PAGEDOWN, | |
| KEY_F1, KEY_F11, | |
| KEY_F2, KEY_F12, | |
| KEY_F3, KEY_F17, // EMU_MOUSE | |
| KEY_F4, KEY_F18, // EMU_JOY0 | |
| KEY_F5, KEY_F19, // EMU_JOY1 | |
| KEY_F6, KEY_F20, // EMU_NONE | |
| //Emulate keypad for A600 | |
| KEY_1, KEY_KP1, | |
| KEY_2, KEY_KP2, | |
| KEY_3, KEY_KP3, | |
| KEY_4, KEY_KP4, | |
| KEY_5, KEY_KP5, | |
| KEY_6, KEY_KP6, | |
| KEY_7, KEY_KP7, | |
| KEY_8, KEY_KP8, | |
| KEY_9, KEY_KP9, | |
| KEY_0, KEY_KP0, | |
| KEY_MINUS, KEY_KPMINUS, | |
| KEY_EQUAL, KEY_KPPLUS, | |
| KEY_BACKSLASH, KEY_KPASTERISK, | |
| KEY_LEFTBRACE, KEY_F13, //KP( | |
| KEY_RIGHTBRACE, KEY_F14, //KP) | |
| KEY_DOT, KEY_KPDOT, | |
| KEY_ENTER, KEY_KPENTER | |
| }; | |
| static int keyrah_trans(int key, int press) | |
| { | |
| static int fn = 0; | |
| if (key == KEY_NUMLOCK) return KEY_F13; // numlock -> f13 | |
| if (key == KEY_SCROLLLOCK) return KEY_F14; // scrlock -> f14 | |
| if (key == KEY_INSERT) return KEY_F16; // insert -> f16. workaround! | |
| if (key == KEY_102ND) | |
| { | |
| if (!press && fn == 1) menu_key_set(KEY_MENU); | |
| fn = press ? 1 : 0; | |
| return 0; | |
| } | |
| else if (fn) | |
| { | |
| fn |= 2; | |
| for (uint32_t n = 0; n<(sizeof(kr_fn_table) / (2 * sizeof(kr_fn_table[0]))); n++) | |
| { | |
| if ((key&255) == kr_fn_table[n * 2]) return kr_fn_table[(n * 2) + 1]; | |
| } | |
| } | |
| return key; | |
| } | |
| static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int dev); | |
| static int kbd_toggle = 0; | |
| static uint32_t joy[NUMPLAYERS] = {}; | |
| static uint32_t autofire[NUMPLAYERS] = {}; | |
| static uint32_t autofirecodes[NUMPLAYERS][BTN_NUM] = {}; | |
| static int af_delay[NUMPLAYERS] = {}; | |
| static unsigned char mouse_btn = 0; | |
| static unsigned char mice_btn = 0; | |
| static int mouse_emu = 0; | |
| static int kbd_mouse_emu = 0; | |
| static int mouse_sniper = 0; | |
| static int mouse_emu_x = 0; | |
| static int mouse_emu_y = 0; | |
| static uint32_t mouse_timer = 0; | |
| #define BTN_TGL 100 | |
| #define BTN_OSD 101 | |
| #define AF_MIN 16 | |
| #define AF_MAX 512 | |
| #define AF_STEP 8 | |
| static int uinp_fd = -1; | |
| static int input_uinp_setup() | |
| { | |
| if (uinp_fd <= 0) | |
| { | |
| struct uinput_user_dev uinp; | |
| if (!(uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY))) | |
| { | |
| printf("Unable to open /dev/uinput\n"); | |
| uinp_fd = -1; | |
| return 0; | |
| } | |
| memset(&uinp, 0, sizeof(uinp)); | |
| strncpy(uinp.name, UINPUT_NAME, UINPUT_MAX_NAME_SIZE); | |
| uinp.id.version = 4; | |
| uinp.id.bustype = BUS_USB; | |
| ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY); | |
| for (int i = 0; i < 256; i++) ioctl(uinp_fd, UI_SET_KEYBIT, i); | |
| write(uinp_fd, &uinp, sizeof(uinp)); | |
| if (ioctl(uinp_fd, UI_DEV_CREATE)) | |
| { | |
| printf("Unable to create UINPUT device."); | |
| close(uinp_fd); | |
| uinp_fd = -1; | |
| return 0; | |
| } | |
| } | |
| return 1; | |
| } | |
| void input_uinp_destroy() | |
| { | |
| if (uinp_fd > 0) | |
| { | |
| ioctl(uinp_fd, UI_DEV_DESTROY); | |
| close(uinp_fd); | |
| uinp_fd = -1; | |
| } | |
| } | |
| static unsigned long uinp_repeat = 0; | |
| static struct input_event uinp_ev; | |
| static void uinp_send_key(uint16_t key, int press) | |
| { | |
| if (uinp_fd > 0) | |
| { | |
| if (!uinp_ev.value && press) | |
| { | |
| uinp_repeat = GetTimer(REPEATDELAY); | |
| } | |
| memset(&uinp_ev, 0, sizeof(uinp_ev)); | |
| gettimeofday(&uinp_ev.time, NULL); | |
| uinp_ev.type = EV_KEY; | |
| uinp_ev.code = key; | |
| uinp_ev.value = press; | |
| write(uinp_fd, &uinp_ev, sizeof(uinp_ev)); | |
| static struct input_event ev; | |
| ev.time = uinp_ev.time; | |
| ev.type = EV_SYN; | |
| ev.code = SYN_REPORT; | |
| ev.value = 0; | |
| write(uinp_fd, &ev, sizeof(ev)); | |
| } | |
| } | |
| static void uinp_check_key() | |
| { | |
| if (uinp_fd > 0) | |
| { | |
| if (!grabbed) | |
| { | |
| if (uinp_ev.value && CheckTimer(uinp_repeat)) | |
| { | |
| uinp_repeat = GetTimer(REPEATRATE); | |
| uinp_send_key(uinp_ev.code, 2); | |
| } | |
| } | |
| else | |
| { | |
| if (uinp_ev.value) | |
| { | |
| uinp_send_key(uinp_ev.code, 0); | |
| } | |
| } | |
| } | |
| } | |
| static void mouse_cb(unsigned char b, int16_t x = 0, int16_t y = 0, int16_t w = 0) | |
| { | |
| if (grabbed) user_io_mouse(b, x, y, w); | |
| } | |
| static void joy_digital(int jnum, uint32_t mask, uint32_t code, char press, int bnum, int dont_save = 0) | |
| { | |
| static uint32_t osdbtn = 0; | |
| static char str[128]; | |
| static uint32_t lastcode[NUMPLAYERS], lastmask[NUMPLAYERS]; | |
| int num = jnum - 1; | |
| if (num < NUMPLAYERS) | |
| { | |
| if (jnum) | |
| { | |
| if (bnum != BTN_OSD && bnum != BTN_TGL) | |
| { | |
| if (!dont_save) | |
| { | |
| if (press) | |
| { | |
| lastcode[num] = code; | |
| lastmask[num] = mask; | |
| } | |
| else | |
| { | |
| lastcode[num] = 0; | |
| lastmask[num] = 0; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if (!user_io_osd_is_visible() && press) | |
| { | |
| if (lastcode[num] && lastmask[num]) | |
| { | |
| int found = 0; | |
| int zero = -1; | |
| for (uint i = 0; i < BTN_NUM; i++) | |
| { | |
| if (!autofirecodes[num][i]) zero = i; | |
| if (autofirecodes[num][i] == lastcode[num]) | |
| { | |
| found = 1; | |
| autofirecodes[num][i] = 0; | |
| break; | |
| } | |
| } | |
| if (!found && zero >= 0) autofirecodes[num][zero] = lastcode[num]; | |
| autofire[num] = !found ? autofire[num] | lastmask[num] : autofire[num] & ~lastmask[num]; | |
| if (hasAPI1_5()) | |
| { | |
| if (!found) sprintf(str, "Auto fire: %dms", af_delay[num] * 2); | |
| else sprintf(str, "Auto fire: OFF"); | |
| Info(str); | |
| } | |
| else InfoMessage((!found) ? "\n\n Auto fire\n ON" : | |
| "\n\n Auto fire\n OFF"); | |
| return; | |
| } | |
| else if (lastmask[num] & 0xF) | |
| { | |
| if (lastmask[num] & 9) | |
| { | |
| af_delay[num] += AF_STEP << ((lastmask[num] & 1) ? 1 : 0); | |
| if (af_delay[num] > AF_MAX) af_delay[num] = AF_MAX; | |
| } | |
| else | |
| { | |
| af_delay[num] -= AF_STEP << ((lastmask[num] & 2) ? 1 : 0); | |
| if (af_delay[num] < AF_MIN) af_delay[num] = AF_MIN; | |
| } | |
| static char str[256]; | |
| if (hasAPI1_5()) | |
| { | |
| sprintf(str, "Auto fire period: %dms", af_delay[num] * 2); | |
| Info(str); | |
| } | |
| else | |
| { | |
| sprintf(str, "\n\n Auto fire period\n %dms", af_delay[num] * 2); | |
| InfoMessage(str); | |
| } | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| if (bnum == BTN_TGL) | |
| { | |
| if(press) kbd_toggle = !kbd_toggle; | |
| return; | |
| } | |
| if (!user_io_osd_is_visible() && (bnum == BTN_OSD) && (mouse_emu & 1)) | |
| { | |
| if (press) | |
| { | |
| mouse_sniper = 0; | |
| mouse_timer = 0; | |
| mouse_btn = 0; | |
| mouse_emu_x = 0; | |
| mouse_emu_y = 0; | |
| mouse_cb(mice_btn); | |
| mouse_emu ^= 2; | |
| if (hasAPI1_5()) Info((mouse_emu & 2) ? "Mouse mode ON" : "Mouse mode OFF"); | |
| else InfoMessage((mouse_emu & 2) ? "\n\n Mouse mode lock\n ON" : | |
| "\n\n Mouse mode lock\n OFF"); | |
| } | |
| return; | |
| } | |
| // clear OSD button state if not in the OSD. this avoids problems where buttons are still held | |
| // on OSD exit and causes combinations to match when partial buttons are pressed. | |
| if (!user_io_osd_is_visible()) osdbtn = 0; | |
| if (user_io_osd_is_visible() || (bnum == BTN_OSD)) | |
| { | |
| if (press) | |
| { | |
| osdbtn |= mask; | |
| if (mask & (JOY_BTN1 | JOY_BTN2)) { | |
| if ((osdbtn & (JOY_BTN1 | JOY_BTN2)) == (JOY_BTN1 | JOY_BTN2)) | |
| { | |
| osdbtn |= JOY_BTN3; | |
| mask = JOY_BTN3; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| int old_osdbtn = osdbtn; | |
| osdbtn &= ~mask; | |
| if (mask & (JOY_BTN1 | JOY_BTN2)) { | |
| if ((old_osdbtn & (JOY_BTN1 | JOY_BTN2 | JOY_BTN3)) == (JOY_BTN1 | JOY_BTN2 | JOY_BTN3)) | |
| { | |
| mask = JOY_BTN3; | |
| } | |
| else if (old_osdbtn & JOY_BTN3) | |
| { | |
| if (!(osdbtn & (JOY_BTN1 | JOY_BTN2))) osdbtn &= ~JOY_BTN3; | |
| mask = 0; | |
| } | |
| } | |
| if((mask & JOY_BTN2) && !(old_osdbtn & JOY_BTN2)) mask = 0; | |
| } | |
| memset(joy, 0, sizeof(joy)); | |
| struct input_event ev; | |
| ev.type = EV_KEY; | |
| ev.value = press; | |
| int cfg_switch = menu_allow_cfg_switch() && (osdbtn & JOY_BTN2) && press; | |
| switch (mask) | |
| { | |
| case JOY_RIGHT: | |
| if (cfg_switch) | |
| { | |
| user_io_set_ini(0); | |
| osdbtn = 0; | |
| return; | |
| } | |
| ev.code = KEY_RIGHT; | |
| break; | |
| case JOY_LEFT: | |
| if (cfg_switch) | |
| { | |
| user_io_set_ini(1); | |
| osdbtn = 0; | |
| return; | |
| } | |
| ev.code = KEY_LEFT; | |
| break; | |
| case JOY_UP: | |
| if (cfg_switch) | |
| { | |
| user_io_set_ini(2); | |
| osdbtn = 0; | |
| return; | |
| } | |
| ev.code = KEY_UP; | |
| break; | |
| case JOY_DOWN: | |
| if (cfg_switch) | |
| { | |
| user_io_set_ini(3); | |
| osdbtn = 0; | |
| return; | |
| } | |
| ev.code = KEY_DOWN; | |
| break; | |
| case JOY_BTN1: | |
| ev.code = KEY_ENTER; | |
| break; | |
| case JOY_BTN2: | |
| ev.code = KEY_BACK; | |
| break; | |
| case JOY_BTN3: | |
| ev.code = KEY_BACKSPACE; | |
| break; | |
| case JOY_L: | |
| ev.code = KEY_MINUS; | |
| break; | |
| case JOY_R: | |
| ev.code = KEY_EQUAL; | |
| break; | |
| default: | |
| ev.code = (bnum == BTN_OSD) ? KEY_MENU : 0; | |
| } | |
| input_cb(&ev, 0, 0); | |
| } | |
| else if (video_fb_state()) | |
| { | |
| switch (mask) | |
| { | |
| case JOY_RIGHT: | |
| uinp_send_key(KEY_RIGHT, press); | |
| break; | |
| case JOY_LEFT: | |
| uinp_send_key(KEY_LEFT, press); | |
| break; | |
| case JOY_UP: | |
| uinp_send_key(KEY_UP, press); | |
| break; | |
| case JOY_DOWN: | |
| uinp_send_key(KEY_DOWN, press); | |
| break; | |
| case JOY_BTN1: | |
| uinp_send_key(KEY_ENTER, press); | |
| break; | |
| case JOY_BTN2: | |
| uinp_send_key(KEY_ESC, press); | |
| break; | |
| case JOY_BTN3: | |
| uinp_send_key(KEY_SPACE, press); | |
| break; | |
| case JOY_BTN4: | |
| uinp_send_key(KEY_TAB, press); | |
| break; | |
| } | |
| } | |
| else if(jnum) | |
| { | |
| if (press) joy[num] |= mask; | |
| else joy[num] &= ~mask; | |
| //user_io_digital_joystick(num, joy[num]); | |
| if (code) | |
| { | |
| int found = 0; | |
| for (uint i = 0; i < BTN_NUM; i++) if (autofirecodes[num][i] == code) found = 1; | |
| if (found) autofire[num] = press ? autofire[num] | mask : autofire[num] & ~mask; | |
| } | |
| } | |
| } | |
| } | |
| static void joy_analog(int num, int axis, int offset) | |
| { | |
| static int pos[NUMPLAYERS][2] = {}; | |
| if (grabbed && num > 0 && num < NUMPLAYERS+1) | |
| { | |
| num--; | |
| pos[num][axis] = offset; | |
| user_io_analog_joystick(num, (char)(pos[num][0]), (char)(pos[num][1])); | |
| } | |
| } | |
| void reset_players() | |
| { | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| input[i].num = 0; | |
| input[i].map_shown = 0; | |
| } | |
| memset(player_pad, 0, sizeof(player_pad)); | |
| memset(player_pdsp, 0, sizeof(player_pdsp)); | |
| } | |
| void store_player(int num, int dev) | |
| { | |
| devInput *player = (input[dev].quirk == QUIRK_PDSP || input[dev].quirk == QUIRK_MSSP) ? player_pdsp : player_pad; | |
| // remove possible old assignment | |
| for (int i = 1; i < NUMPLAYERS; i++) if (!strcmp(player[i].id, input[dev].id)) player[i].id[0] = 0; | |
| if(num && num < NUMPLAYERS) memcpy(&player[num], &input[dev], sizeof(devInput)); | |
| } | |
| void restore_player(int dev) | |
| { | |
| // do not restore bound devices | |
| if (dev != input[dev].bind) return; | |
| devInput *player = (input[dev].quirk == QUIRK_PDSP || input[dev].quirk == QUIRK_MSSP) ? player_pdsp : player_pad; | |
| for (int k = 1; k < NUMPLAYERS; k++) | |
| { | |
| if (strlen(player[k].id) && !strcmp(player[k].id, input[dev].id)) | |
| { | |
| printf("restore player %d to %s (%s)\n", k, input[dev].devname, input[dev].id); | |
| input[dev].num = k; | |
| input[dev].map_shown = player[k].map_shown; | |
| memcpy(input[dev].jkmap, player[k].jkmap, sizeof(input[dev].jkmap)); | |
| input[dev].lightgun = player[k].lightgun; | |
| break; | |
| } | |
| } | |
| } | |
| void unflag_players() | |
| { | |
| for (int k = 1; k < NUMPLAYERS; k++) | |
| { | |
| int found = 0; | |
| for (int i = 0; i < NUMDEV; i++) if (strlen(player_pad[k].id) && !strcmp(player_pad[k].id, input[i].id)) found = 1; | |
| if (!found) player_pad[k].map_shown = 0; | |
| } | |
| for (int k = 1; k < NUMPLAYERS; k++) | |
| { | |
| int found = 0; | |
| for (int i = 0; i < NUMDEV; i++) if (strlen(player_pdsp[k].id) && !strcmp(player_pdsp[k].id, input[i].id)) found = 1; | |
| if (!found) player_pdsp[k].map_shown = 0; | |
| } | |
| } | |
| static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int dev) | |
| { | |
| if (ev->type != EV_KEY && ev->type != EV_ABS && ev->type != EV_REL) return; | |
| if (ev->type == EV_KEY && (!ev->code || ev->code == KEY_UNKNOWN)) return; | |
| static uint16_t last_axis = 0; | |
| int sub_dev = dev; | |
| //check if device is a part of multifunctional device | |
| if (input[dev].bind >= 0) dev = input[dev].bind; | |
| //mouse | |
| if (ev->type == EV_KEY && ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) | |
| { | |
| //skip it. we use /dev/input/mice | |
| return; | |
| } | |
| static int key_mapped = 0; | |
| if (ev->type == EV_KEY && mapping && mapping_type == 3 && ev->code == input[dev].mmap[SYS_BTN_OSD_KTGL + 1]) ev->code = KEY_ENTER; | |
| int map_skip = (ev->type == EV_KEY && ((ev->code == KEY_SPACE && mapping_type == 1) || ev->code == KEY_ALTERASE) && (mapping_dev >= 0 || mapping_button<0)); | |
| int cancel = (ev->type == EV_KEY && ev->code == KEY_ESC); | |
| int enter = (ev->type == EV_KEY && ev->code == KEY_ENTER); | |
| int origcode = ev->code; | |
| if (!input[dev].has_mmap) | |
| { | |
| if (input[dev].quirk == QUIRK_TOUCHGUN) | |
| { | |
| memset(input[dev].mmap, 0, sizeof(input[dev].mmap)); | |
| input[dev].mmap[SYS_AXIS_MX] = -1; | |
| input[dev].mmap[SYS_AXIS_MY] = -1; | |
| input[dev].mmap[SYS_AXIS_X] = -1; | |
| input[dev].mmap[SYS_AXIS_Y] = -1; | |
| } | |
| else if (input[dev].quirk != QUIRK_PDSP && input[dev].quirk != QUIRK_MSSP) | |
| { | |
| if (!load_map(get_map_name(dev, 1), &input[dev].mmap, sizeof(input[dev].mmap))) | |
| { | |
| memset(input[dev].mmap, 0, sizeof(input[dev].mmap)); | |
| input[dev].has_mmap++; | |
| } | |
| if (!input[dev].mmap[SYS_BTN_OSD_KTGL + 2]) input[dev].mmap[SYS_BTN_OSD_KTGL + 2] = input[dev].mmap[SYS_BTN_OSD_KTGL + 1]; | |
| } | |
| input[dev].has_mmap++; | |
| } | |
| if (!input[dev].has_map) | |
| { | |
| if (input[dev].quirk == QUIRK_PDSP || input[dev].quirk == QUIRK_MSSP) | |
| { | |
| memset(input[dev].map, 0, sizeof(input[dev].map)); | |
| input[dev].map[map_paddle_btn()] = 0x120; | |
| } | |
| else if (!load_map(get_map_name(dev, 0), &input[dev].map, sizeof(input[dev].map))) | |
| { | |
| memset(input[dev].map, 0, sizeof(input[dev].map)); | |
| if (!is_menu()) | |
| { | |
| if (input[dev].has_mmap == 1) | |
| { | |
| // not defined try to guess the mapping | |
| map_joystick(input[dev].map, input[dev].mmap); | |
| } | |
| else | |
| { | |
| input[dev].has_map++; | |
| } | |
| } | |
| input[dev].has_map++; | |
| } | |
| input[dev].has_map++; | |
| } | |
| if (!input[dev].num) | |
| { | |
| int assign_btn = ((input[dev].quirk == QUIRK_PDSP || input[dev].quirk == QUIRK_MSSP) && (ev->type == EV_REL || ev->type == EV_KEY)); | |
| if (!assign_btn && ev->type == EV_KEY && ev->value >= 1 && ev->code >= 256) | |
| { | |
| for (int i = SYS_BTN_RIGHT; i <= SYS_BTN_START; i++) if (ev->code == input[dev].mmap[i]) assign_btn = 1; | |
| } | |
| if (assign_btn) | |
| { | |
| for (uint8_t num = 1; num < NUMDEV + 1; num++) | |
| { | |
| int found = 0; | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if (input[i].quirk != QUIRK_TOUCHGUN) | |
| { | |
| // paddles/spinners overlay on top of other gamepad | |
| if (!((input[dev].quirk == QUIRK_PDSP || input[dev].quirk == QUIRK_MSSP) ^ (input[i].quirk == QUIRK_PDSP || input[i].quirk == QUIRK_MSSP))) | |
| { | |
| found = (input[i].num == num); | |
| if (found) break; | |
| } | |
| } | |
| } | |
| if (!found) | |
| { | |
| input[dev].num = num; | |
| store_player(num, dev); | |
| printf("Device %s assigned to player %d\n", input[dev].id, input[dev].num); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (!input[dev].map_shown && input[dev].num) | |
| { | |
| input[dev].map_shown = 1; | |
| store_player(input[dev].num, dev); | |
| if (cfg.controller_info) | |
| { | |
| if (input[dev].quirk == QUIRK_PDSP || input[dev].quirk == QUIRK_MSSP) | |
| { | |
| char str[32]; | |
| sprintf(str, "P%d paddle/spinner", input[dev].num); | |
| Info(str, cfg.controller_info * 1000); | |
| } | |
| else | |
| { | |
| map_joystick_show(input[dev].map, input[dev].mmap, input[dev].num); | |
| } | |
| } | |
| } | |
| int old_combo = input[dev].osd_combo; | |
| if (ev->type == EV_KEY) | |
| { | |
| if (ev->code == input[dev].mmap[SYS_BTN_OSD_KTGL + 2]) | |
| { | |
| if (ev->value) input[dev].osd_combo |= 2; | |
| else input[dev].osd_combo &= ~2; | |
| } | |
| if (ev->code == input[dev].mmap[SYS_BTN_OSD_KTGL + 1]) | |
| { | |
| if (ev->value) input[dev].osd_combo |= 1; | |
| else input[dev].osd_combo &= ~1; | |
| } | |
| } | |
| int osd_event = 0; | |
| if (old_combo != 3 && input[dev].osd_combo == 3) | |
| { | |
| osd_event = 1; | |
| if (mapping && !is_menu()) osd_timer = GetTimer(1000); | |
| } | |
| else if (old_combo == 3 && input[dev].osd_combo != 3) | |
| { | |
| osd_event = 2; | |
| if (mapping && !is_menu()) | |
| { | |
| if (CheckTimer(osd_timer)) | |
| { | |
| cancel = 1; | |
| ev->code = KEY_ESC; | |
| ev->value = 0; | |
| } | |
| else | |
| { | |
| map_skip = 1; | |
| ev->value = 1; | |
| } | |
| } | |
| osd_timer = 0; | |
| } | |
| //mapping | |
| if (mapping && (mapping_dev >= 0 || ev->value) | |
| && !((mapping_type < 2 || !mapping_button) && (cancel || enter)) | |
| && input[dev].quirk != QUIRK_PDSP | |
| && input[dev].quirk != QUIRK_MSSP) | |
| { | |
| int idx = 0; | |
| if (is_menu()) | |
| { | |
| spi_uio_cmd(UIO_KEYBOARD); //ping the Menu core to wakeup | |
| osd_event = 0; | |
| } | |
| // paddle axis - skip from mapping | |
| if ((ev->type == EV_ABS || ev->type == EV_REL) && (ev->code == 7 || ev->code == 8)) return; | |
| // in alternative set, the first button can be skipped, so clear the set now | |
| if (!mapping_button && mapping_set && ev->value == 1 && mapping_dev >= 0) | |
| { | |
| for (uint i = 0; i < sizeof(input[0].map) / sizeof(input[0].map[0]); i++) | |
| { | |
| input[mapping_dev].map[i] &= 0x0000FFFF; | |
| } | |
| } | |
| if (ev->type == EV_KEY && mapping_button>=0 && !osd_event) | |
| { | |
| if (mapping_type == 2) | |
| { | |
| if (ev->code < 256) | |
| { | |
| if (ev->value == 1) | |
| { | |
| if (mapping_dev < 0) | |
| { | |
| mapping_dev = dev; | |
| mapping_button = 0; | |
| } | |
| if (!mapping_button) mapping_button = ev->code; | |
| } | |
| if (ev->value == 0 && mapping_dev >= 0 && mapping_button && mapping_button != ev->code) | |
| { | |
| input[mapping_dev].kbdmap[mapping_button] = ev->code; | |
| mapping_button = 0; | |
| } | |
| } | |
| return; | |
| } | |
| else if (mapping_type == 3) | |
| { | |
| if (ev->value == 1 && !mapping_button) | |
| { | |
| if (mapping_dev < 0) mapping_dev = dev; | |
| if (mapping_dev == dev && ev->code < 1024) mapping_button = ev->code; | |
| } | |
| if (ev->value == 0 && mapping_dev >= 0 && (ev->code<256 || mapping_dev == dev) && mapping_button && mapping_button != ev->code) | |
| { | |
| // Technically it's hard to map the key to button as keyboards | |
| // are all the same while joysticks are personalized and numbered. | |
| input[mapping_dev].jkmap[mapping_button] = ev->code; | |
| mapping_button = 0; | |
| } | |
| return; | |
| } | |
| else | |
| { | |
| int clear = (ev->code == KEY_F12 || ev->code == KEY_MENU || ev->code == KEY_HOMEPAGE) && !is_menu(); | |
| if (ev->value == 1 && mapping_dev < 0 && !clear) | |
| { | |
| mapping_dev = dev; | |
| mapping_type = (ev->code >= 256) ? 1 : 0; | |
| key_mapped = 0; | |
| } | |
| mapping_clear = 0; | |
| if (mapping_dev >= 0 && !map_skip && (mapping_dev == dev || clear) && mapping_button < (is_menu() ? (mapping_type ? SYS_BTN_CNT_ESC + 1 : SYS_BTN_OSD_KTGL + 1) : mapping_count)) | |
| { | |
| if (ev->value == 1 && !key_mapped) | |
| { | |
| if (is_menu()) | |
| { | |
| if (mapping_dev == dev && !(!mapping_button && last_axis && ((ev->code == last_axis) || (ev->code == last_axis + 1)))) | |
| { | |
| if (!mapping_button) memset(input[dev].map, 0, sizeof(input[dev].map)); | |
| input[dev].osd_combo = 0; | |
| int found = 0; | |
| if (mapping_button < SYS_BTN_CNT_OK) | |
| { | |
| for (int i = (mapping_button >= BUTTON_DPAD_COUNT) ? BUTTON_DPAD_COUNT : 0; i < mapping_button; i++) if (input[dev].map[i] == ev->code) found = 1; | |
| } | |
| if (!found || (mapping_button == SYS_BTN_OSD_KTGL && mapping_type)) | |
| { | |
| if (mapping_button == SYS_BTN_CNT_OK) input[dev].map[SYS_BTN_MENU_FUNC] = ev->code & 0xFFFF; | |
| else if (mapping_button == SYS_BTN_CNT_ESC) input[dev].map[SYS_BTN_MENU_FUNC] = (ev->code << 16) | input[dev].map[SYS_BTN_MENU_FUNC]; | |
| else if (mapping_button == SYS_BTN_OSD_KTGL) | |
| { | |
| input[dev].map[SYS_BTN_OSD_KTGL + mapping_type] = ev->code; | |
| input[dev].map[SYS_BTN_OSD_KTGL + 2] = input[dev].map[SYS_BTN_OSD_KTGL + 1]; | |
| } | |
| else input[dev].map[mapping_button] = ev->code; | |
| key_mapped = ev->code; | |
| //check if analog stick has been used for mouse | |
| if (mapping_button == BUTTON_DPAD_COUNT + 1 || mapping_button == BUTTON_DPAD_COUNT + 3) | |
| { | |
| if (input[dev].map[mapping_button] >= KEY_EMU && | |
| input[dev].map[mapping_button - 1] >= KEY_EMU && | |
| (input[dev].map[mapping_button - 1] - input[dev].map[mapping_button] == 1) && // same axis | |
| absinfo) | |
| { | |
| input[dev].map[SYS_AXIS_MX + (mapping_button - (BUTTON_DPAD_COUNT + 1)) / 2] = ((input[dev].map[mapping_button] - KEY_EMU) / 2) | 0x20000; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if (clear) | |
| { | |
| memset(input[mapping_dev].map, 0, sizeof(input[mapping_dev].map)); | |
| mapping_button = 0; | |
| mapping_clear = 1; | |
| } | |
| else | |
| { | |
| if (!mapping_button) | |
| { | |
| for (uint i = 0; i < sizeof(input[0].map) / sizeof(input[0].map[0]); i++) | |
| { | |
| input[dev].map[i] &= mapping_set ? 0x0000FFFF : 0xFFFF0000; | |
| } | |
| } | |
| int found = 0; | |
| for (int i = 0; i < mapping_button; i++) | |
| { | |
| if (mapping_set && (input[dev].map[i] >> 16) == ev->code) found = 1; | |
| if (!mapping_set && (input[dev].map[i] & 0xFFFF) == ev->code) found = 1; | |
| } | |
| if (!found) | |
| { | |
| if (mapping_set) input[dev].map[mapping_button] = (input[dev].map[mapping_button] & 0xFFFF) | (ev->code << 16); | |
| else input[dev].map[mapping_button] = (input[dev].map[mapping_button] & 0xFFFF0000) | ev->code; | |
| key_mapped = ev->code; | |
| } | |
| } | |
| } | |
| } | |
| //combo for osd button | |
| if (ev->value == 1 && key_mapped && key_mapped != ev->code && is_menu() && mapping_button == SYS_BTN_OSD_KTGL && mapping_type) | |
| { | |
| input[dev].map[SYS_BTN_OSD_KTGL + 2] = ev->code; | |
| printf("Set combo: %x + %x\n", input[dev].map[SYS_BTN_OSD_KTGL + 1], input[dev].map[SYS_BTN_OSD_KTGL + 2]); | |
| } | |
| else if(mapping_dev == dev && ev->value == 0 && key_mapped == ev->code) | |
| { | |
| mapping_button++; | |
| key_mapped = 0; | |
| } | |
| if(!ev->value && mapping_dev == dev && ((ev->code == last_axis) || (ev->code == last_axis+1))) | |
| { | |
| last_axis = 0; | |
| } | |
| } | |
| } | |
| } | |
| else if (is_menu()) | |
| { | |
| //Define min-0-max analogs | |
| switch (mapping_button) | |
| { | |
| case 23: idx = SYS_AXIS_X; break; | |
| case 24: idx = SYS_AXIS_Y; break; | |
| case -4: idx = SYS_AXIS1_X; break; | |
| case -3: idx = SYS_AXIS1_Y; break; | |
| case -2: idx = SYS_AXIS2_X; break; | |
| case -1: idx = SYS_AXIS2_Y; break; | |
| } | |
| if (mapping_dev == dev || (mapping_dev < 0 && mapping_button < 0)) | |
| { | |
| int max = 0; // , min = 0; | |
| if (ev->type == EV_ABS) | |
| { | |
| int threshold = (absinfo->maximum - absinfo->minimum) / 5; | |
| max = (ev->value >= (absinfo->maximum - threshold)); | |
| //min = (ev->value <= (absinfo->minimum + threshold)); | |
| //printf("threshold=%d, min=%d, max=%d\n", threshold, min, max); | |
| } | |
| //check DPAD horz | |
| if (mapping_button == -6) | |
| { | |
| last_axis = 0; | |
| if (ev->type == EV_ABS && max) | |
| { | |
| if (mapping_dev < 0) mapping_dev = dev; | |
| mapping_type = 1; | |
| if (absinfo->maximum > 2) | |
| { | |
| tmp_axis[tmp_axis_n++] = ev->code | 0x20000; | |
| mapping_button++; | |
| } | |
| else | |
| { | |
| //Standard DPAD event | |
| mapping_button += 2; | |
| } | |
| } | |
| else if (ev->type == EV_KEY && ev->value == 1) | |
| { | |
| //DPAD uses simple button events | |
| if (!map_skip) | |
| { | |
| mapping_button += 2; | |
| if (mapping_dev < 0) mapping_dev = dev; | |
| if (ev->code < 256) | |
| { | |
| // keyboard, skip stick 1/2 | |
| mapping_button += 4; | |
| mapping_type = 0; | |
| } | |
| } | |
| } | |
| } | |
| //check DPAD vert | |
| else if (mapping_button == -5) | |
| { | |
| if (ev->type == EV_ABS && max && absinfo->maximum > 1 && ev->code != (tmp_axis[0] & 0xFFFF)) | |
| { | |
| tmp_axis[tmp_axis_n++] = ev->code | 0x20000; | |
| mapping_button++; | |
| } | |
| } | |
| //Sticks | |
| else if (ev->type == EV_ABS && idx) | |
| { | |
| if (mapping_dev < 0) mapping_dev = dev; | |
| if (idx && max && absinfo->maximum > 2) | |
| { | |
| if (mapping_button < 0) | |
| { | |
| int found = 0; | |
| for (int i = 0; i < tmp_axis_n; i++) if (ev->code == (tmp_axis[i] & 0xFFFF)) found = 1; | |
| if (!found) | |
| { | |
| mapping_type = 1; | |
| tmp_axis[tmp_axis_n++] = ev->code | 0x20000; | |
| //if (min) tmp_axis[idx - AXIS1_X] |= 0x10000; | |
| mapping_button++; | |
| if (tmp_axis_n >= 4) mapping_button = 0; | |
| last_axis = KEY_EMU + (ev->code << 1); | |
| } | |
| } | |
| else | |
| { | |
| if (idx == SYS_AXIS_X || ev->code != (input[dev].map[idx - 1] & 0xFFFF)) | |
| { | |
| input[dev].map[idx] = ev->code | 0x20000; | |
| //if (min) input[dev].map[idx] |= 0x10000; | |
| mapping_button++; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| while (mapping_type <= 1 && mapping_button < mapping_count) | |
| { | |
| if (map_skip) | |
| { | |
| if (map_skip == 2 || ev->value == 1) | |
| { | |
| if (mapping_dev >= 0) | |
| { | |
| if (idx) input[mapping_dev].map[idx] = 0; | |
| else if (mapping_button > 0) | |
| { | |
| if (!is_menu()) input[mapping_dev].map[mapping_button] &= mapping_set ? 0x0000FFFF : 0xFFFF0000; | |
| } | |
| } | |
| last_axis = 0; | |
| mapping_button++; | |
| if (mapping_button < 0 && (mapping_button & 1)) mapping_button++; | |
| } | |
| } | |
| map_skip = 0; | |
| if (mapping_button >= 4 && !is_menu() && !strcmp(joy_bnames[mapping_button - 4], "-")) map_skip = 2; | |
| if (!map_skip) break; | |
| } | |
| if (is_menu() && mapping_type <= 1 && mapping_dev >= 0) | |
| { | |
| memcpy(&input[mapping_dev].mmap[SYS_AXIS1_X], tmp_axis, sizeof(tmp_axis)); | |
| memcpy(&input[mapping_dev].map[SYS_AXIS1_X], tmp_axis, sizeof(tmp_axis)); | |
| } | |
| } | |
| else | |
| { | |
| key_mapped = 0; | |
| switch (ev->type) | |
| { | |
| case EV_KEY: | |
| if (ev->code < 1024 && input[dev].jkmap[ev->code] && !user_io_osd_is_visible()) ev->code = input[dev].jkmap[ev->code]; | |
| //joystick buttons, digital directions | |
| if (ev->code >= 256) | |
| { | |
| if (input[dev].lightgun_req && !user_io_osd_is_visible()) | |
| { | |
| if (osd_event == 1) | |
| { | |
| input[dev].lightgun = !input[dev].lightgun; | |
| Info(input[dev].lightgun ? "Light Gun mode is ON" : "Light Gun mode is OFF"); | |
| } | |
| } | |
| else | |
| { | |
| if (osd_event == 1) joy_digital(input[dev].num, 0, 0, 1, BTN_OSD); | |
| if (osd_event == 2) joy_digital(input[dev].num, 0, 0, 0, BTN_OSD); | |
| } | |
| if (user_io_osd_is_visible() || video_fb_state()) | |
| { | |
| if (ev->value <= 1) | |
| { | |
| if ((input[dev].mmap[SYS_BTN_MENU_FUNC] & 0xFFFF) ? | |
| (ev->code == (input[dev].mmap[SYS_BTN_MENU_FUNC] & 0xFFFF)) : | |
| (ev->code == input[dev].mmap[SYS_BTN_A])) | |
| { | |
| joy_digital(0, JOY_BTN1, 0, ev->value, 0); | |
| return; | |
| } | |
| if ((input[dev].mmap[SYS_BTN_MENU_FUNC] >> 16) ? | |
| (ev->code == (input[dev].mmap[SYS_BTN_MENU_FUNC] >> 16)) : | |
| (ev->code == input[dev].mmap[SYS_BTN_B])) | |
| { | |
| joy_digital(0, JOY_BTN2, 0, ev->value, 0); | |
| return; | |
| } | |
| if (ev->code == input[dev].mmap[SYS_BTN_L]) | |
| { | |
| joy_digital(0, JOY_L, 0, ev->value, 0); | |
| return; | |
| } | |
| if (ev->code == input[dev].mmap[SYS_BTN_R]) | |
| { | |
| joy_digital(0, JOY_R, 0, ev->value, 0); | |
| return; | |
| } | |
| if (ev->code == input[dev].mmap[SYS_BTN_SELECT]) | |
| { | |
| struct input_event key_ev = *ev; | |
| key_ev.code = KEY_GRAVE; | |
| input_cb(&key_ev, 0, 0); | |
| return; | |
| } | |
| for (int i = 0; i < SYS_BTN_A; i++) | |
| { | |
| if (ev->code == input[dev].mmap[i]) | |
| { | |
| joy_digital(0, 1 << i, 0, ev->value, i); | |
| return; | |
| } | |
| } | |
| for (int i = SYS_MS_RIGHT; i <= SYS_MS_UP; i++) | |
| { | |
| if (ev->code == input[dev].mmap[i]) | |
| { | |
| int n = i - SYS_MS_RIGHT; | |
| joy_digital(0, 1 << n, 0, ev->value, n); | |
| return; | |
| } | |
| } | |
| if (input[dev].mmap[SYS_AXIS_X]) | |
| { | |
| uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[SYS_AXIS_X]*2); | |
| if (ev->code == (key + 1)) joy_digital(0, 1 << 0, 0, ev->value, 0); | |
| if (ev->code == key) joy_digital(0, 1 << 1, 0, ev->value, 1); | |
| } | |
| if (input[dev].mmap[SYS_AXIS_Y]) | |
| { | |
| uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[SYS_AXIS_Y]*2); | |
| if (ev->code == (key + 1)) joy_digital(0, 1 << 2, 0, ev->value, 2); | |
| if (ev->code == key) joy_digital(0, 1 << 3, 0, ev->value, 3); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if (mouse_emu) | |
| { | |
| int use_analog = (input[dev].mmap[SYS_AXIS_MX] || input[dev].mmap[SYS_AXIS_MY]); | |
| for (int i = (use_analog ? SYS_MS_BTN_L : SYS_MS_RIGHT); i <= SYS_MS_BTN_M; i++) | |
| { | |
| if (ev->code == input[dev].mmap[i]) | |
| { | |
| switch (i) | |
| { | |
| case SYS_MS_RIGHT: | |
| mouse_emu_x = ev->value ? 10 : 0; | |
| break; | |
| case SYS_MS_LEFT: | |
| mouse_emu_x = ev->value ? -10 : 0; | |
| break; | |
| case SYS_MS_DOWN: | |
| mouse_emu_y = ev->value ? 10 : 0; | |
| break; | |
| case SYS_MS_UP: | |
| mouse_emu_y = ev->value ? -10 : 0; | |
| break; | |
| default: | |
| mouse_btn = ev->value ? mouse_btn | 1 << (i - SYS_MS_BTN_L) : mouse_btn & ~(1 << (i - SYS_MS_BTN_L)); | |
| mouse_cb(mouse_btn | mice_btn); | |
| break; | |
| } | |
| return; | |
| } | |
| } | |
| } | |
| if (input[dev].has_map >= 2) | |
| { | |
| if (input[dev].has_map == 3) Info("This joystick is not defined"); | |
| input[dev].has_map = 1; | |
| } | |
| for (uint i = 0; i < BTN_NUM; i++) | |
| { | |
| if (ev->code == (input[dev].map[i] & 0xFFFF) || ev->code == (input[dev].map[i] >> 16)) | |
| { | |
| if (i <= 3 && origcode == ev->code) origcode = 0; // prevent autofire for original dpad | |
| if (ev->value <= 1) joy_digital(input[dev].num, 1 << i, origcode, ev->value, i, (ev->code == input[dev].mmap[SYS_BTN_OSD_KTGL + 1] || ev->code == input[dev].mmap[SYS_BTN_OSD_KTGL + 2])); | |
| // support 2 simultaneous functions for 1 button if defined in 2 sets. No return. | |
| } | |
| } | |
| if (ev->code == input[dev].mmap[SYS_MS_BTN_EMU] && (ev->value <= 1) && ((!(mouse_emu & 1)) ^ (!ev->value))) | |
| { | |
| mouse_emu = ev->value ? mouse_emu | 1 : mouse_emu & ~1; | |
| if (input[sub_dev].quirk == QUIRK_DS4) input[dev].ds_mouse_emu = mouse_emu & 1; | |
| printf("mouse_emu = %d\n", mouse_emu); | |
| if (mouse_emu & 2) | |
| { | |
| mouse_sniper = ev->value; | |
| } | |
| else | |
| { | |
| mouse_timer = 0; | |
| mouse_btn = 0; | |
| mouse_emu_x = 0; | |
| mouse_emu_y = 0; | |
| mouse_cb(mice_btn); | |
| } | |
| } | |
| } | |
| return; | |
| } | |
| // keyboard | |
| else | |
| { | |
| if (!input[dev].has_kbdmap) | |
| { | |
| if (!FileLoadConfig(get_kbdmap_name(dev), &input[dev].kbdmap, sizeof(input[dev].kbdmap))) | |
| { | |
| memset(input[dev].kbdmap, 0, sizeof(input[dev].kbdmap)); | |
| } | |
| input[dev].has_kbdmap = 1; | |
| } | |
| uint16_t code = ev->code; | |
| if (code < 256 && input[dev].kbdmap[code]) code = input[dev].kbdmap[code]; | |
| // replace MENU key by RGUI to allow using Right Amiga on reduced keyboards | |
| // (it also disables the use of Menu for OSD) | |
| if (cfg.key_menu_as_rgui && code == 139) code = 126; | |
| //Keyrah v2: USB\VID_18D8&PID_0002\A600/A1200_MULTIMEDIA_EXTENSION_VERSION | |
| int keyrah = (cfg.keyrah_mode && (((((uint32_t)input[dev].vid) << 16) | input[dev].pid) == cfg.keyrah_mode)); | |
| if (keyrah) code = keyrah_trans(code, ev->value); | |
| uint32_t ps2code = get_ps2_code(code); | |
| if (ev->value) modifier |= ps2code; | |
| else modifier &= ~ps2code; | |
| uint16_t reset_m = (modifier & MODMASK) >> 8; | |
| if (code == 111) reset_m |= 0x100; | |
| user_io_check_reset(reset_m, (keyrah && !cfg.reset_combo) ? 1 : cfg.reset_combo); | |
| if(!user_io_osd_is_visible() && ((user_io_get_kbdemu() == EMU_JOY0) || (user_io_get_kbdemu() == EMU_JOY1)) && !video_fb_state()) | |
| { | |
| if (!kbd_toggle) | |
| { | |
| for (uint i = 0; i < BTN_NUM; i++) | |
| { | |
| if (ev->code == input[dev].map[i]) | |
| { | |
| if (i <= 3 && origcode == ev->code) origcode = 0; // prevent autofire for original dpad | |
| if (ev->value <= 1) joy_digital((user_io_get_kbdemu() == EMU_JOY0) ? 1 : 2, 1 << i, origcode, ev->value, i); | |
| return; | |
| } | |
| } | |
| } | |
| if (ev->code == input[dev].mmap[SYS_BTN_OSD_KTGL]) | |
| { | |
| if (ev->value <= 1) joy_digital((user_io_get_kbdemu() == EMU_JOY0) ? 1 : 2, 0, 0, ev->value, BTN_TGL); | |
| return; | |
| } | |
| } | |
| else | |
| { | |
| kbd_toggle = 0; | |
| } | |
| if (!user_io_osd_is_visible() && (user_io_get_kbdemu() == EMU_MOUSE)) | |
| { | |
| if (kbd_mouse_emu) | |
| { | |
| for (int i = SYS_MS_RIGHT; i <= SYS_MS_BTN_M; i++) | |
| { | |
| if (ev->code == input[dev].mmap[i]) | |
| { | |
| switch (i) | |
| { | |
| case SYS_MS_RIGHT: | |
| mouse_emu_x = ev->value ? 10 : 0; | |
| break; | |
| case SYS_MS_LEFT: | |
| mouse_emu_x = ev->value ? -10 : 0; | |
| break; | |
| case SYS_MS_DOWN: | |
| mouse_emu_y = ev->value ? 10 : 0; | |
| break; | |
| case SYS_MS_UP: | |
| mouse_emu_y = ev->value ? -10 : 0; | |
| break; | |
| default: | |
| mouse_btn = ev->value ? mouse_btn | 1 << (i - SYS_MS_BTN_L) : mouse_btn & ~(1 << (i - SYS_MS_BTN_L)); | |
| mouse_cb(mouse_btn | mice_btn); | |
| break; | |
| } | |
| return; | |
| } | |
| } | |
| if (ev->code == input[dev].mmap[SYS_MS_BTN_EMU]) | |
| { | |
| if (ev->value <= 1) mouse_sniper = ev->value; | |
| return; | |
| } | |
| } | |
| if (ev->code == input[dev].mmap[SYS_BTN_OSD_KTGL]) | |
| { | |
| if (ev->value == 1) | |
| { | |
| kbd_mouse_emu = !kbd_mouse_emu; | |
| printf("kbd_mouse_emu = %d\n", kbd_mouse_emu); | |
| mouse_timer = 0; | |
| mouse_btn = 0; | |
| mouse_emu_x = 0; | |
| mouse_emu_y = 0; | |
| mouse_cb(mice_btn); | |
| } | |
| return; | |
| } | |
| } | |
| if (code == KEY_HOMEPAGE) code = KEY_MENU; | |
| user_io_kbd(code, ev->value); | |
| return; | |
| } | |
| break; | |
| //analog joystick | |
| case EV_ABS: | |
| if (!user_io_osd_is_visible()) | |
| { | |
| int value = ev->value; | |
| if (ev->value < absinfo->minimum) value = absinfo->minimum; | |
| else if (ev->value > absinfo->maximum) value = absinfo->maximum; | |
| if (ev->code == 8) | |
| { | |
| if (input[dev].num && input[dev].num <= NUMPLAYERS) | |
| { | |
| value -= absinfo->minimum; | |
| value = (value * 255) / (absinfo->maximum - absinfo->minimum); | |
| user_io_analog_joystick(((input[dev].num - 1) << 4) | 0xF, value, 0); | |
| } | |
| break; | |
| } | |
| int hrange = (absinfo->maximum - absinfo->minimum) / 2; | |
| int dead = hrange/63; | |
| if (input[sub_dev].quirk == QUIRK_CWIID) | |
| { | |
| if(ev->code == 3 || ev->code == 4) dead = 10; | |
| } | |
| if (input[sub_dev].quirk == QUIRK_DS3 || input[sub_dev].quirk == QUIRK_DS4) | |
| { | |
| dead = 10; | |
| } | |
| // normalize to -range/2...+range/2 | |
| value = value - (absinfo->minimum + absinfo->maximum) / 2; | |
| if (ev->code > 1 || !input[dev].lightgun) //lightgun has no dead zone | |
| { | |
| // check the dead-zone and remove it from the range | |
| hrange -= dead; | |
| if (value < -dead) value += dead; | |
| else if (value > dead) value -= dead; | |
| else value = 0; | |
| } | |
| value = (value * 127) / hrange; | |
| //final check to eliminate additive error | |
| if (value < -127) value = -127; | |
| else if (value > 127) value = 127; | |
| if (input[sub_dev].axis_pos[ev->code & 0xFF] == (int8_t)value) break; | |
| input[sub_dev].axis_pos[ev->code & 0xFF] = (int8_t)value; | |
| if (ev->code == (input[dev].mmap[SYS_AXIS_MX] & 0xFFFF) && mouse_emu) | |
| { | |
| mouse_emu_x = 0; | |
| if (value < -1 || value>1) mouse_emu_x = value; | |
| mouse_emu_x /= 12; | |
| return; | |
| } | |
| else if (ev->code == (input[dev].mmap[SYS_AXIS_MY] & 0xFFFF) && mouse_emu) | |
| { | |
| mouse_emu_y = 0; | |
| if (value < -1 || value>1) mouse_emu_y = value; | |
| mouse_emu_y /= 12; | |
| return; | |
| } | |
| else if (ev->code == (input[dev].mmap[SYS_AXIS_X] & 0xFFFF) || (ev->code == 0 && input[dev].lightgun)) | |
| { | |
| // skip if joystick is undefined. | |
| if (!input[dev].num) break; | |
| int offset = 0; | |
| if (value < -1 || value>1 || input[dev].lightgun) offset = value; | |
| //printf("analog_x = %d\n", offset); | |
| joy_analog(input[dev].num, 0, offset); | |
| return; | |
| } | |
| else if (ev->code == (input[dev].mmap[SYS_AXIS_Y] & 0xFFFF) || (ev->code == 1 && input[dev].lightgun)) | |
| { | |
| // skip if joystick is undefined. | |
| if (!input[dev].num) break; | |
| int offset = 0; | |
| if (value < -1 || value>1 || input[dev].lightgun) offset = value; | |
| //printf("analog_y = %d\n", offset); | |
| joy_analog(input[dev].num, 1, offset); | |
| return; | |
| } | |
| } | |
| break; | |
| // spinner | |
| case EV_REL: | |
| if (!user_io_osd_is_visible() && ev->code == 7) | |
| { | |
| if (input[dev].num && input[dev].num <= NUMPLAYERS) | |
| { | |
| int value = ev->value; | |
| if (ev->value < -128) value = -128; | |
| else if (ev->value > 127) value = 127; | |
| user_io_analog_joystick(((input[dev].num - 1) << 4) | 0x8F, value, 0); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| void send_map_cmd(int key) | |
| { | |
| if (mapping && mapping_dev >= 0) | |
| { | |
| input_event ev; | |
| ev.type = EV_KEY; | |
| ev.code = key; | |
| ev.value = 1; | |
| input_cb(&ev, 0, mapping_dev); | |
| } | |
| } | |
| #define CMD_FIFO "/dev/MiSTer_cmd" | |
| #define LED_MONITOR "/sys/class/leds/hps_led0/brightness_hw_changed" | |
| static struct pollfd pool[NUMDEV + 3]; | |
| // add sequential suffixes for non-merged devices | |
| void make_unique(uint16_t vid, uint16_t pid, int type) | |
| { | |
| int cnt = 0; | |
| int lastmin = -1; | |
| int min; | |
| while(1) | |
| { | |
| int idx = -1; | |
| min = INT32_MAX; | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if ((!type && (input[i].vid == vid)) || | |
| (type > 0 && (input[i].vid == vid) && (input[i].pid == pid)) || | |
| (type < 0 && (input[i].vid == vid) && (input[i].pid != pid))) | |
| { | |
| int num = -1; | |
| const char *n = strstr(input[i].devname, "/event"); | |
| if (n) num = strtoul(n + 6, NULL, 10); | |
| if (num >= 0 && num < min && num > lastmin) | |
| { | |
| min = num; | |
| idx = i; | |
| } | |
| } | |
| } | |
| if (idx < 0) break; | |
| lastmin = min; | |
| sprintf(input[idx].id + strlen(input[idx].id), "/%d", cnt++); | |
| } | |
| } | |
| void mergedevs() | |
| { | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| memset(input[i].id, 0, sizeof(input[i].id)); | |
| } | |
| FILE *f = fopen("/proc/bus/input/devices", "r"); | |
| if (!f) | |
| { | |
| printf("Failed to open /proc/bus/input/devices\n"); | |
| return; | |
| } | |
| static char str[1024]; | |
| char phys[64] = {}; | |
| char uniq[64] = {}; | |
| char id[64] = {}; | |
| while (fgets(str, sizeof(str), f)) | |
| { | |
| int len = strlen(str); | |
| while (len && str[len - 1] == '\n') str[--len] = 0; | |
| if (!len) | |
| { | |
| phys[0] = 0; | |
| uniq[0] = 0; | |
| } | |
| else | |
| { | |
| if (!strncmp("P: Phys", str, 7)) snprintf(phys, sizeof(phys), "%s", strchr(str, '=') + 1); | |
| if (!strncmp("U: Uniq", str, 7)) snprintf(uniq, sizeof(uniq), "%s", strchr(str, '=') + 1); | |
| if (!strncmp("H: ", str, 3)) | |
| { | |
| if (strlen(phys) && strlen(uniq)) snprintf(id, sizeof(id), "%s/%s", phys, uniq); | |
| else if (strlen(phys)) strcpy(id, phys); | |
| else strcpy(id, uniq); | |
| char *handlers = strchr(str, '='); | |
| if (handlers && id[0]) | |
| { | |
| handlers++; | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if (pool[i].fd >= 0) | |
| { | |
| char *dev = strrchr(input[i].devname, '/'); | |
| if (dev) | |
| { | |
| char idsp[32]; | |
| strcpy(idsp, dev + 1); | |
| strcat(idsp, " "); | |
| if (strstr(handlers, idsp)) strcpy(input[i].id, id); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fclose(f); | |
| //Bypass merging of specified 2 port/player controllers | |
| make_unique(0x289B, 0x0057, -1); // Raphnet | |
| make_unique(0x0E8F, 0x3013, 1); // Mayflash SNES controller 2 port adapter | |
| make_unique(0x16C0, 0x05E1, 1); // XinMo XM-10 2 player USB Encoder | |
| if (cfg.no_merge_vid) | |
| { | |
| make_unique(cfg.no_merge_vid, cfg.no_merge_pid, (cfg.no_merge_pid ? 1 : 0)); | |
| } | |
| // merge multifunctional devices by id | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| input[i].bind = i; | |
| if (input[i].id[0] && !input[i].mouse) | |
| { | |
| for (int j = 0; j < i; j++) | |
| { | |
| if (!strcmp(input[i].id, input[j].id)) | |
| { | |
| input[i].bind = j; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| //copy missing fields to mouseX | |
| for (int i = 0; i < NUMDEV; i++) if (input[i].mouse) | |
| { | |
| for (int j = 0; j < NUMDEV; j++) if (!input[j].mouse) | |
| { | |
| if (!strcmp(input[i].id, input[j].id)) | |
| { | |
| input[i].bind = j; | |
| input[i].vid = input[j].vid; | |
| input[i].pid = input[j].pid; | |
| input[i].quirk = input[j].quirk; | |
| memcpy(input[i].name, input[j].name, sizeof(input[i].name)); | |
| memcpy(input[i].idstr, input[j].idstr, sizeof(input[i].idstr)); | |
| if (!input[i].quirk) | |
| { | |
| //All mice as spinners | |
| if ((cfg.spinner_vid == 0xFFFF && cfg.spinner_pid == 0xFFFF) | |
| //Mouse as spinner | |
| || (cfg.spinner_vid && cfg.spinner_pid && input[i].vid == cfg.spinner_vid && input[i].pid == cfg.spinner_pid)) | |
| { | |
| input[i].quirk = QUIRK_MSSP; | |
| input[i].bind = i; | |
| input[i].spinner_prediv = 1; | |
| } | |
| //Arcade Spinner TS-BSP01 | |
| if (input[i].vid == 0x32be && input[i].pid == 0x1420) | |
| { | |
| input[i].quirk = QUIRK_MSSP; | |
| input[i].bind = i; | |
| input[i].spinner_prediv = 3; | |
| } | |
| if (input[i].quirk == QUIRK_MSSP) strcat(input[i].id, "_sp"); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| // Jammasd/J-PAC/I-PAC have shifted keys: when 1P start is kept pressed, it acts as a shift key, | |
| // outputting other key signals. Example: 1P start + 2P start = KEY_ESC | |
| // Shifted keys are passed as normal keyboard keys. | |
| static struct | |
| { | |
| uint16_t key; | |
| uint16_t player; | |
| uint16_t btn; | |
| } jamma2joy[] = | |
| { | |
| {KEY_5, 1, 0x120}, // 1P coin | |
| {KEY_1, 1, 0x121}, // 1P start (shift key) | |
| {KEY_UP, 1, 0x122}, // 1P up | |
| {KEY_DOWN, 1, 0x123}, // 1P down | |
| {KEY_LEFT, 1, 0x124}, // 1P left | |
| {KEY_RIGHT, 1, 0x125}, // 1P right | |
| {KEY_LEFTCTRL, 1, 0x126}, // 1P 1 | |
| {KEY_LEFTALT, 1, 0x127}, // 1P 2 | |
| {KEY_SPACE, 1, 0x128}, // 1P 3 | |
| {KEY_LEFTSHIFT, 1, 0x129}, // 1P 4 | |
| {KEY_Z, 1, 0x12A}, // 1P 5 | |
| {KEY_X, 1, 0x12B}, // 1P 6 | |
| {KEY_C, 1, 0x12C}, // 1P 7 | |
| {KEY_V, 1, 0x12D}, // 1P 8 | |
| {KEY_9, 1, 0x12E}, // Test | |
| {KEY_TAB, 1, 0x12F}, // Tab (shift + 1P right) | |
| {KEY_ENTER, 1, 0x130}, // Enter (shift + 1P left) | |
| // ~ Tidle supportted? | |
| {KEY_P, 1, 0x131}, // P (pause) (shift + 1P down) | |
| {KEY_F1, 1, 0x132}, // Service | |
| {KEY_F2, 1, 0x133}, // Test | |
| {KEY_F3, 1, 0x134}, // Tilt | |
| {KEY_6, 2, 0x120}, // 2P coin | |
| {KEY_2, 2, 0x121}, // 2P start | |
| {KEY_R, 2, 0x122}, // 2P up | |
| {KEY_F, 2, 0x123}, // 2P down | |
| {KEY_D, 2, 0x124}, // 2P left | |
| {KEY_G, 2, 0x125}, // 2P right | |
| {KEY_A, 2, 0x126}, // 2P 1 | |
| {KEY_S, 2, 0x127}, // 2P 2 | |
| {KEY_Q, 2, 0x128}, // 2P 3 | |
| {KEY_W, 2, 0x129}, // 2P 4 | |
| {KEY_I, 2, 0x12A}, // 2P 5 | |
| {KEY_K, 2, 0x12B}, // 2P 6 | |
| {KEY_J, 2, 0x12C}, // 2P 7 | |
| {KEY_L, 2, 0x12D}, // 2P 8 | |
| }; | |
| void send_mouse_with_throttle(int dev, int xval, int yval, int btn, uint8_t data_3) | |
| { | |
| int i = dev; | |
| if (input[dev].bind >= 0) dev = input[dev].bind; | |
| if (is_menu() && !video_fb_state()) printf("%s: btn=0x%02X, dx=%d, dy=%d, scroll=%d\n", input[i].devname, btn, xval, yval, data_3); | |
| int throttle = cfg.mouse_throttle ? cfg.mouse_throttle : 1; | |
| if (input[dev].ds_mouse_emu) throttle *= 4; | |
| if (input[dev].quirk == QUIRK_TOUCHGUN) throttle *= 12; | |
| input[i].accx += xval; | |
| xval = input[i].accx / throttle; | |
| input[i].accx -= xval * throttle; | |
| input[i].accy -= yval; | |
| yval = input[i].accy / throttle; | |
| input[i].accy -= yval * throttle; | |
| mice_btn = btn & 7; | |
| if (input[dev].ds_mouse_emu) mice_btn = (mice_btn & 4) | ((mice_btn & 1) << 1); | |
| mouse_cb(mouse_btn | mice_btn, xval, yval, data_3); | |
| } | |
| static uint32_t touch_rel = 0; | |
| void touchscreen_proc(int dev, input_event *ev) | |
| { | |
| struct input_absinfo absinfo; | |
| int i = dev; | |
| if (input[dev].bind >= 0) dev = input[dev].bind; | |
| if (ev->type == EV_KEY) | |
| { | |
| if (ev->value == 1) | |
| { | |
| input[i].misc_flags = 0xC0; | |
| touch_rel = 0; | |
| ioctl(pool[i].fd, EVIOCGABS(ABS_X), &absinfo); | |
| input[i].lastx = absinfo.value; | |
| input[i].startx = absinfo.value; | |
| ioctl(pool[i].fd, EVIOCGABS(ABS_Y), &absinfo); | |
| input[i].lasty = absinfo.value; | |
| input[i].starty = absinfo.value; | |
| } | |
| else | |
| { | |
| input[i].misc_flags = 0; | |
| mice_btn = 0; | |
| if (input[dev].lightgun) | |
| { | |
| menu_lightgun_cb(i, EV_KEY, 0x131, 0); | |
| } | |
| else | |
| { | |
| if (abs(input[i].lastx - input[i].startx) < 8 && abs(input[i].lasty - input[i].starty) < 8) | |
| { | |
| mice_btn |= 1; | |
| touch_rel = GetTimer(100); | |
| } | |
| } | |
| mouse_cb(mice_btn); | |
| } | |
| } | |
| else if (ev->type == EV_ABS && ev->code == ABS_MT_SLOT && ev->value == 3 && (input[i].misc_flags & 0x80)) | |
| { | |
| input[i].misc_flags = 0; | |
| mice_btn = 0; | |
| mouse_cb(mice_btn); | |
| input[dev].lightgun = !input[dev].lightgun; | |
| Info(input[dev].lightgun ? "Light Gun mode is ON" : "Light Gun mode is OFF"); | |
| } | |
| if (input[dev].lightgun) | |
| { | |
| if (ev->type == EV_KEY && ev->value == 1) | |
| { | |
| mice_btn |= 1; | |
| mouse_cb(mice_btn); | |
| menu_lightgun_cb(i, EV_KEY, 0x131, 1); | |
| } | |
| else if (ev->type == EV_ABS) | |
| { | |
| if (ev->code == ABS_MT_POSITION_X) | |
| { | |
| ev->code = ABS_X; | |
| absinfo.minimum = input[i].guncal[2]; | |
| absinfo.maximum = input[i].guncal[3]; | |
| menu_lightgun_cb(i, ev->type, ev->code, ev->value); | |
| input_cb(ev, &absinfo, i); | |
| } | |
| else if (ev->code == ABS_MT_POSITION_Y) | |
| { | |
| ev->code = ABS_Y; | |
| absinfo.minimum = input[i].guncal[0]; | |
| absinfo.maximum = input[i].guncal[1]; | |
| menu_lightgun_cb(i, ev->type, ev->code, ev->value); | |
| input_cb(ev, &absinfo, i); | |
| } | |
| else if (ev->code == ABS_MT_SLOT && (input[i].misc_flags & 0x80)) | |
| { | |
| if (ev->value == 1) input[i].misc_flags |= 1; | |
| if (ev->value == 2) input[i].misc_flags |= 2; | |
| if (input[i].misc_flags & 2) mice_btn = 4; | |
| else if (input[i].misc_flags & 1) mice_btn = 2; | |
| else mice_btn = 1; | |
| mouse_cb(mice_btn); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if (ev->type == EV_ABS) | |
| { | |
| if (input[i].misc_flags & 0x80) | |
| { | |
| if (ev->code == ABS_MT_SLOT) | |
| { | |
| if (ev->value) input[i].misc_flags &= ~0x40; | |
| else input[i].misc_flags |= 0x40; | |
| if (ev->value == 1) input[i].misc_flags |= 1; | |
| if (ev->value == 2) input[i].misc_flags |= 2; | |
| if (input[i].misc_flags & 2) mice_btn = 4; | |
| else if (input[i].misc_flags & 1) mice_btn = 2; | |
| mouse_cb(mice_btn); | |
| } | |
| else if (input[i].misc_flags & 0x40) | |
| { | |
| if (ev->code == ABS_MT_POSITION_X) | |
| { | |
| int dx = ev->value - input[i].lastx; | |
| if (dx > 255) dx = 255; | |
| if (dx < -256) dx = -256; | |
| input[i].lastx = ev->value; | |
| send_mouse_with_throttle(i, dx, 0, mice_btn, 0); | |
| } | |
| else if (ev->code == ABS_MT_POSITION_Y) | |
| { | |
| int dy = ev->value - input[i].lasty; | |
| if (dy > 255) dy = 255; | |
| if (dy < -256) dy = -256; | |
| input[i].lasty = ev->value; | |
| send_mouse_with_throttle(i, 0, -dy, mice_btn, 0); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| int input_test(int getchar) | |
| { | |
| static char cur_leds = 0; | |
| static int state = 0; | |
| struct input_absinfo absinfo; | |
| struct input_event ev; | |
| if (touch_rel && CheckTimer(touch_rel)) | |
| { | |
| touch_rel = 0; | |
| mice_btn = 0; | |
| mouse_cb(mice_btn); | |
| } | |
| if (state == 0) | |
| { | |
| input_uinp_setup(); | |
| memset(pool, -1, sizeof(pool)); | |
| signal(SIGINT, INThandler); | |
| pool[NUMDEV].fd = set_watch(); | |
| pool[NUMDEV].events = POLLIN; | |
| unlink(CMD_FIFO); | |
| mkfifo(CMD_FIFO, 0666); | |
| pool[NUMDEV+1].fd = open(CMD_FIFO, O_RDWR | O_NONBLOCK); | |
| pool[NUMDEV+1].events = POLLIN; | |
| pool[NUMDEV + 2].fd = open(LED_MONITOR, O_RDONLY); | |
| pool[NUMDEV + 2].events = POLLPRI; | |
| state++; | |
| } | |
| if (state == 1) | |
| { | |
| printf("Open up to %d input devices.\n", NUMDEV); | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| pool[i].fd = -1; | |
| pool[i].events = 0; | |
| } | |
| memset(input, 0, sizeof(input)); | |
| int n = 0; | |
| DIR *d = opendir("/dev/input"); | |
| if (d) | |
| { | |
| struct dirent *de; | |
| while ((de = readdir(d))) | |
| { | |
| if (!strncmp(de->d_name, "event", 5) || !strncmp(de->d_name, "mouse", 5)) | |
| { | |
| memset(&input[n], 0, sizeof(input[n])); | |
| sprintf(input[n].devname, "/dev/input/%s", de->d_name); | |
| int fd = open(input[n].devname, O_RDWR); | |
| //printf("open(%s): %d\n", input[n].devname, fd); | |
| if (fd > 0) | |
| { | |
| pool[n].fd = fd; | |
| pool[n].events = POLLIN; | |
| input[n].mouse = !strncmp(de->d_name, "mouse", 5); | |
| char uniq[32] = {}; | |
| if (!input[n].mouse) | |
| { | |
| struct input_id id; | |
| memset(&id, 0, sizeof(id)); | |
| ioctl(pool[n].fd, EVIOCGID, &id); | |
| input[n].vid = id.vendor; | |
| input[n].pid = id.product; | |
| ioctl(pool[n].fd, EVIOCGUNIQ(sizeof(uniq)), uniq); | |
| ioctl(pool[n].fd, EVIOCGNAME(sizeof(input[n].name)), input[n].name); | |
| input[n].led = has_led(pool[n].fd); | |
| } | |
| //skip our virtual device | |
| if (!strcmp(input[n].name, UINPUT_NAME)) | |
| { | |
| close(pool[n].fd); | |
| pool[n].fd = -1; | |
| continue; | |
| } | |
| input[n].bind = -1; | |
| // enable scroll wheel reading | |
| if (input[n].mouse) | |
| { | |
| unsigned char buffer[4]; | |
| static const unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; | |
| if (write(pool[n].fd, mousedev_imps_seq, sizeof(mousedev_imps_seq)) != sizeof(mousedev_imps_seq)) | |
| { | |
| printf("Cannot switch %s to ImPS/2 protocol(1)\n", input[n].devname); | |
| } | |
| else if (read(pool[n].fd, buffer, sizeof buffer) != 1 || buffer[0] != 0xFA) | |
| { | |
| printf("Failed to switch %s to ImPS/2 protocol(2)\n", input[n].devname); | |
| } | |
| } | |
| if (strcasestr(input[n].name, "Wiimote") && input[n].vid == 1 && input[n].pid == 1) | |
| { | |
| input[n].quirk = QUIRK_CWIID; | |
| input[n].lightgun = 1; | |
| } | |
| // RasPad3 touchscreen | |
| if (input[n].vid == 0x222a && input[n].pid == 1) | |
| { | |
| input[n].quirk = QUIRK_TOUCHGUN; | |
| input[n].num = 1; | |
| input[n].map_shown = 1; | |
| input[n].lightgun = 0; | |
| input[n].guncal[0] = 0; | |
| input[n].guncal[1] = 16383; | |
| input[n].guncal[2] = 2047; | |
| input[n].guncal[3] = 14337; | |
| input_lightgun_load(n); | |
| } | |
| if (input[n].vid == 0x054c) | |
| { | |
| if (input[n].pid == 0x0268) input[n].quirk = QUIRK_DS3; | |
| else if (input[n].pid == 0x05c4 || input[n].pid == 0x09cc || input[n].pid == 0x0ba0 || input[n].pid == 0x0ce6) | |
| { | |
| input[n].quirk = QUIRK_DS4; | |
| if (strcasestr(input[n].name, "Touchpad")) | |
| { | |
| input[n].quirk = QUIRK_DS4TOUCH; | |
| } | |
| } | |
| } | |
| if (input[n].vid == 0x0079 && input[n].pid == 0x1802) | |
| { | |
| input[n].lightgun = 1; | |
| input[n].num = 2; // force mayflash mode 1/2 as second joystick. | |
| } | |
| if (input[n].vid == 0x057e && (input[n].pid == 0x0306 || input[n].pid == 0x0330)) | |
| { | |
| if (strcasestr(input[n].name, "Accelerometer")) | |
| { | |
| // don't use Accelerometer | |
| close(pool[n].fd); | |
| pool[n].fd = -1; | |
| continue; | |
| } | |
| else if (strcasestr(input[n].name, "Motion Plus")) | |
| { | |
| // don't use Accelerometer | |
| close(pool[n].fd); | |
| pool[n].fd = -1; | |
| continue; | |
| } | |
| else | |
| { | |
| input[n].quirk = QUIRK_WIIMOTE; | |
| input[n].guncal[0] = 0; | |
| input[n].guncal[1] = 767; | |
| input[n].guncal[2] = 1; | |
| input[n].guncal[3] = 1023; | |
| input_lightgun_load(n); | |
| } | |
| } | |
| //Ultimarc lightgun | |
| if (input[n].vid == 0xd209 && input[n].pid == 0x1601) | |
| { | |
| input[n].lightgun = 1; | |
| } | |
| //Madcatz Arcade Stick 360 | |
| if (input[n].vid == 0x0738 && input[n].pid == 0x4758) input[n].quirk = QUIRK_MADCATZ360; | |
| // mr.Spinner | |
| // 0x120 - Button | |
| // Axis 7 - EV_REL is spinner | |
| // Axis 8 - EV_ABS is Paddle | |
| // Overlays on other existing gamepads | |
| if (strstr(uniq, "MiSTer-S1")) input[n].quirk = QUIRK_PDSP; | |
| // Arcade with spinner and/or paddle: | |
| // Axis 7 - EV_REL is spinner | |
| // Axis 8 - EV_ABS is Paddle | |
| // Includes other buttons and axes, works as a full featured gamepad. | |
| if (strstr(uniq, "MiSTer-A1")) input[n].quirk = QUIRK_PDSP_ARCADE; | |
| //Jamma | |
| if (cfg.jamma_vid && cfg.jamma_pid && input[n].vid == cfg.jamma_vid && input[n].pid == cfg.jamma_pid) | |
| { | |
| input[n].quirk = QUIRK_JAMMA; | |
| } | |
| //Arduino and Teensy devices may share the same VID:PID, so additional field UNIQ is used to differentiate them | |
| if ((input[n].vid == 0x2341 || (input[n].vid == 0x16C0 && (input[n].pid>>8) == 0x4)) && strlen(uniq)) | |
| { | |
| snprintf(input[n].idstr, sizeof(input[n].idstr), "%04x_%04x_%s", input[n].vid, input[n].pid, uniq); | |
| char *p; | |
| while ((p = strchr(input[n].idstr, '/'))) *p = '_'; | |
| while ((p = strchr(input[n].idstr, ' '))) *p = '_'; | |
| while ((p = strchr(input[n].idstr, '*'))) *p = '_'; | |
| while ((p = strchr(input[n].idstr, ':'))) *p = '_'; | |
| strcpy(input[n].name, uniq); | |
| } | |
| else | |
| { | |
| snprintf(input[n].idstr, sizeof(input[n].idstr), "%04x_%04x", input[n].vid, input[n].pid); | |
| } | |
| ioctl(pool[n].fd, EVIOCGRAB, (grabbed | user_io_osd_is_visible()) ? 1 : 0); | |
| n++; | |
| if (n >= NUMDEV) break; | |
| } | |
| } | |
| } | |
| closedir(d); | |
| mergedevs(); | |
| for (int i = 0; i < n; i++) | |
| { | |
| printf("opened %d(%2d): %s (%04x:%04x) %d \"%s\" \"%s\"\n", i, input[i].bind, input[i].devname, input[i].vid, input[i].pid, input[i].quirk, input[i].id, input[i].name); | |
| restore_player(i); | |
| } | |
| unflag_players(); | |
| } | |
| cur_leds |= 0x80; | |
| state++; | |
| } | |
| if (state == 2) | |
| { | |
| int timeout = 0; | |
| if (is_menu() && video_fb_state()) timeout = 25; | |
| while (1) | |
| { | |
| int return_value = poll(pool, NUMDEV + 3, timeout); | |
| if (!return_value) break; | |
| if (return_value < 0) | |
| { | |
| printf("ERR: poll\n"); | |
| break; | |
| } | |
| if ((pool[NUMDEV].revents & POLLIN) && check_devs()) | |
| { | |
| printf("Close all devices.\n"); | |
| for (int i = 0; i < NUMDEV; i++) if (pool[i].fd >= 0) | |
| { | |
| ioctl(pool[i].fd, EVIOCGRAB, 0); | |
| close(pool[i].fd); | |
| } | |
| state = 1; | |
| return 0; | |
| } | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if ((pool[i].fd >= 0) && (pool[i].revents & POLLIN)) | |
| { | |
| if (!input[i].mouse) | |
| { | |
| memset(&ev, 0, sizeof(ev)); | |
| if (read(pool[i].fd, &ev, sizeof(ev)) == sizeof(ev)) | |
| { | |
| if (getchar) | |
| { | |
| if (ev.type == EV_KEY && ev.value >= 1) | |
| { | |
| return ev.code; | |
| } | |
| } | |
| else if (ev.type) | |
| { | |
| int dev = i; | |
| if (input[dev].bind >= 0) dev = input[dev].bind; | |
| int noabs = 0; | |
| if (input[i].quirk == QUIRK_DS4TOUCH && ev.type == EV_KEY) | |
| { | |
| if (ev.code == BTN_TOOL_FINGER || ev.code == BTN_TOUCH || ev.code == BTN_TOOL_DOUBLETAP) continue; | |
| } | |
| if (input[i].quirk == QUIRK_MADCATZ360 && ev.type == EV_KEY) | |
| { | |
| if (ev.code == BTN_THUMBR) input[i].misc_flags = ev.value ? (input[i].misc_flags | 1) : (input[i].misc_flags & ~1); | |
| else if (ev.code == BTN_MODE && !user_io_osd_is_visible()) | |
| { | |
| if (input[i].misc_flags & 1) | |
| { | |
| if (ev.value) | |
| { | |
| if ((input[i].misc_flags & 0x6) == 0) input[i].misc_flags = 0x3; // X | |
| else if ((input[i].misc_flags & 0x6) == 2) input[i].misc_flags = 0x5; // Y | |
| else input[i].misc_flags = 0x1; // None | |
| Info(((input[i].misc_flags & 0x6) == 2) ? "Paddle mode" : | |
| ((input[i].misc_flags & 0x6) == 4) ? "Spinner mode" : | |
| "Normal mode"); | |
| } | |
| continue; | |
| } | |
| } | |
| } | |
| if (input[i].quirk == QUIRK_TOUCHGUN) | |
| { | |
| touchscreen_proc(i, &ev); | |
| continue; | |
| } | |
| if (ev.type == EV_ABS) | |
| { | |
| if (input[i].quirk == QUIRK_WIIMOTE) | |
| { | |
| //nunchuck accel events | |
| if (ev.code >= 3 && ev.code <= 5) continue; | |
| } | |
| //Dualshock: drop accelerator and raw touchpad events | |
| if (input[i].quirk == QUIRK_DS4TOUCH && ev.code == 57) | |
| { | |
| input[dev].lightgun_req = (ev.value >= 0); | |
| } | |
| if ((input[i].quirk == QUIRK_DS4TOUCH || input[i].quirk == QUIRK_DS4 || input[i].quirk == QUIRK_DS3) && ev.code > 40) | |
| { | |
| continue; | |
| } | |
| if (ioctl(pool[i].fd, EVIOCGABS(ev.code), &absinfo) < 0) memset(&absinfo, 0, sizeof(absinfo)); | |
| else | |
| { | |
| //DS4 specific: touchpad as lightgun | |
| if (input[i].quirk == QUIRK_DS4TOUCH && ev.code <= 1) | |
| { | |
| if (!input[dev].lightgun || user_io_osd_is_visible()) continue; | |
| if (ev.code == 1) | |
| { | |
| absinfo.minimum = 300; | |
| absinfo.maximum = 850; | |
| } | |
| else if (ev.code == 0) | |
| { | |
| absinfo.minimum = 200; | |
| absinfo.maximum = 1720; | |
| } | |
| else continue; | |
| } | |
| if (input[i].quirk == QUIRK_DS4 && ev.code <= 1) | |
| { | |
| if (input[dev].lightgun) noabs = 1; | |
| } | |
| if (input[i].quirk == QUIRK_WIIMOTE) | |
| { | |
| input[dev].lightgun = 0; | |
| if (absinfo.maximum == 1023 || absinfo.maximum == 767) | |
| { | |
| if (ev.code == 16) | |
| { | |
| ev.value = absinfo.maximum - ev.value; | |
| ev.code = 0; | |
| input[dev].lightgun = 1; | |
| } | |
| else if (ev.code == 17) | |
| { | |
| ev.code = 1; | |
| input[dev].lightgun = 1; | |
| } | |
| // other 3 IR tracking aren't used | |
| else continue; | |
| } | |
| else if (absinfo.maximum == 62) | |
| { | |
| //LT/RT analog | |
| continue; | |
| } | |
| else if (ev.code & 1) | |
| { | |
| //Y axes on wiimote and accessories are inverted | |
| ev.value = -ev.value; | |
| } | |
| } | |
| } | |
| if (input[i].quirk == QUIRK_MADCATZ360 && (input[i].misc_flags & 0x6) && (ev.code == 16) && !user_io_osd_is_visible()) | |
| { | |
| if (ev.value) | |
| { | |
| if ((input[i].misc_flags & 0x6) == 2) | |
| { | |
| if (ev.value > 0) input[i].paddle_val += 4; | |
| if (ev.value < 0) input[i].paddle_val -= 4; | |
| if (input[i].paddle_val > 256) input[i].paddle_val = 256; | |
| if (input[i].paddle_val < 0) input[i].paddle_val = 0; | |
| absinfo.maximum = 255; | |
| absinfo.minimum = 0; | |
| ev.code = 8; | |
| ev.value = input[i].paddle_val; | |
| } | |
| else | |
| { | |
| ev.type = EV_REL; | |
| ev.code = 7; | |
| } | |
| } | |
| else continue; | |
| } | |
| if (input[i].quirk == QUIRK_CWIID) | |
| { | |
| if (ev.code == 3 || ev.code == 4) | |
| { | |
| absinfo.minimum = 30; | |
| absinfo.maximum = 225; | |
| } | |
| } | |
| } | |
| if (input[dev].quirk == QUIRK_JAMMA && ev.type == EV_KEY) | |
| { | |
| input[dev].num = 0; | |
| for (uint32_t i = 0; i <= sizeof(jamma2joy) / sizeof(jamma2joy[0]); i++) | |
| { | |
| if (jamma2joy[i].key == ev.code) | |
| { | |
| ev.code = jamma2joy[i].btn; | |
| input[dev].num = jamma2joy[i].player; | |
| break; | |
| } | |
| } | |
| } | |
| //Menu combo on 8BitDo receiver in PSC mode | |
| if (input[dev].vid == 0x054c && input[dev].pid == 0x0cda && ev.type == EV_KEY) | |
| { | |
| //in PSC mode these keys coming from separate virtual keyboard device | |
| //so it's impossible to use joystick codes as keyboards aren't personalized | |
| if (ev.code == 164) ev.code = KEY_MENU; | |
| if (ev.code == 1) ev.code = KEY_MENU; | |
| } | |
| if (ev.type == EV_KEY && ev.code == KEY_BACK && input[dev].vid == 0x45E) | |
| { | |
| ev.code = BTN_SELECT; | |
| } | |
| //Menu button quirk of 8BitDo gamepad in X-Input mode | |
| if (input[dev].vid == 0x045e && input[dev].pid == 0x02e0 && ev.type == EV_KEY) | |
| { | |
| if (ev.code == KEY_MENU) ev.code = BTN_MODE; | |
| } | |
| if (is_menu() && !video_fb_state()) | |
| { | |
| /* | |
| if (mapping && mapping_type <= 1 && !(ev.type==EV_KEY && ev.value>1)) | |
| { | |
| static char str[64], str2[64]; | |
| OsdWrite(12, "\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81"); | |
| sprintf(str, " VID=%04X PID=%04X", input[i].vid, input[i].pid); | |
| OsdWrite(13, str); | |
| sprintf(str, "Type=%d Code=%d Value=%d", ev.type, ev.code, ev.value); | |
| str2[0] = 0; | |
| int len = (29 - (strlen(str))) / 2; | |
| while (len-- > 0) strcat(str2, " "); | |
| strcat(str2, str); | |
| OsdWrite(14, str2); | |
| str2[0] = 0; | |
| if (ev.type == EV_ABS) | |
| { | |
| sprintf(str, "Min=%d Max=%d", absinfo.minimum, absinfo.maximum); | |
| int len = (29 - (strlen(str))) / 2; | |
| while (len-- > 0) strcat(str2, " "); | |
| strcat(str2, str); | |
| } | |
| OsdWrite(15, str2); | |
| } | |
| */ | |
| switch (ev.type) | |
| { | |
| //keyboard, buttons | |
| case EV_KEY: | |
| printf("Input event: type=EV_KEY, code=%d(0x%x), value=%d, jnum=%d, ID:%04x:%04x:%02d\n", ev.code, ev.code, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); | |
| break; | |
| case EV_REL: | |
| { | |
| //limit the amount of EV_REL messages, so Menu core won't be laggy | |
| static unsigned long timeout = 0; | |
| if (!timeout || CheckTimer(timeout)) | |
| { | |
| timeout = GetTimer(20); | |
| printf("Input event: type=EV_REL, Axis=%d, Offset=%d, jnum=%d, ID:%04x:%04x:%02d\n", ev.code, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); | |
| } | |
| } | |
| break; | |
| case EV_SYN: | |
| case EV_MSC: | |
| break; | |
| //analog joystick | |
| case EV_ABS: | |
| { | |
| //limit the amount of EV_ABS messages, so Menu core won't be laggy | |
| static unsigned long timeout = 0; | |
| if (!timeout || CheckTimer(timeout)) | |
| { | |
| timeout = GetTimer(20); | |
| //reduce flood from DUALSHOCK 3/4 | |
| if ((input[i].quirk == QUIRK_DS4 || input[i].quirk == QUIRK_DS3) && ev.code <= 5 && ev.value > 118 && ev.value < 138) | |
| { | |
| break; | |
| } | |
| //aliexpress USB encoder floods messages | |
| if (input[dev].vid == 0x0079 && input[dev].pid == 0x0006) | |
| { | |
| if (ev.code == 2) break; | |
| } | |
| printf("Input event: type=EV_ABS, Axis=%d, Offset=%d, jnum=%d, ID:%04x:%04x:%02d,", ev.code, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); | |
| printf(" abs_min = %d, abs_max = %d", absinfo.minimum, absinfo.maximum); | |
| if (absinfo.fuzz) printf(", fuzz = %d", absinfo.fuzz); | |
| if (absinfo.resolution) printf(", res = %d", absinfo.resolution); | |
| printf("\n"); | |
| } | |
| } | |
| break; | |
| default: | |
| printf("Input event: type=%d, code=%d(0x%x), value=%d(0x%x), jnum=%d, ID:%04x:%04x:%02d\n", ev.type, ev.code, ev.code, ev.value, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); | |
| } | |
| } | |
| if (input[i].quirk == QUIRK_CWIID && ev.type == EV_ABS) | |
| { | |
| if (ev.code <= 1 && user_io_osd_is_visible()) | |
| { | |
| // don't pass IR tracking to OSD | |
| continue; | |
| } | |
| } | |
| if (ev.type == EV_ABS && input[i].quirk == QUIRK_WIIMOTE && input[dev].lightgun) | |
| { | |
| menu_lightgun_cb(i, ev.type, ev.code, ev.value); | |
| // don't pass IR tracking to OSD | |
| if (user_io_osd_is_visible()) continue; | |
| if (!ev.code) | |
| { | |
| absinfo.minimum = input[i].guncal[2]; | |
| absinfo.maximum = input[i].guncal[3]; | |
| } | |
| else | |
| { | |
| absinfo.minimum = input[i].guncal[0]; | |
| absinfo.maximum = input[i].guncal[1]; | |
| } | |
| } | |
| if (ev.type == EV_KEY && user_io_osd_is_visible()) | |
| { | |
| if (input[i].quirk == QUIRK_WIIMOTE) | |
| { | |
| if (menu_lightgun_cb(i, ev.type, ev.code, ev.value)) continue; | |
| } | |
| } | |
| if (!noabs) input_cb(&ev, &absinfo, i); | |
| //sumulate digital directions from analog | |
| if (ev.type == EV_ABS && !(mapping && mapping_type <= 1 && mapping_button < -4) && !(ev.code <= 1 && input[dev].lightgun) && input[dev].quirk != QUIRK_PDSP && input[dev].quirk != QUIRK_MSSP) | |
| { | |
| input_absinfo *pai = 0; | |
| uint8_t axis_edge = 0; | |
| if ((absinfo.maximum == 1 && absinfo.minimum == -1) || (absinfo.maximum == 2 && absinfo.minimum == 0)) | |
| { | |
| if (ev.value == absinfo.minimum) axis_edge = 1; | |
| if (ev.value == absinfo.maximum) axis_edge = 2; | |
| } | |
| else | |
| { | |
| pai = &absinfo; | |
| int range = absinfo.maximum - absinfo.minimum + 1; | |
| int center = absinfo.minimum + (range / 2); | |
| int treshold = range / 4; | |
| int only_max = 1; | |
| for (int n = 0; n < 4; n++) if (input[dev].mmap[SYS_AXIS1_X + n] && ((input[dev].mmap[SYS_AXIS1_X + n] & 0xFFFF) == ev.code)) only_max = 0; | |
| if (ev.value < center - treshold && !only_max) axis_edge = 1; | |
| if (ev.value > center + treshold) axis_edge = 2; | |
| } | |
| uint8_t last_state = input[dev].axis_edge[ev.code & 255]; | |
| input[dev].axis_edge[ev.code & 255] = axis_edge; | |
| //printf("last_state=%d, axis_edge=%d\n", last_state, axis_edge); | |
| if (last_state != axis_edge) | |
| { | |
| uint16_t ecode = KEY_EMU + (ev.code << 1) - 1; | |
| ev.type = EV_KEY; | |
| if (last_state) | |
| { | |
| ev.value = 0; | |
| ev.code = ecode + last_state; | |
| input_cb(&ev, pai, i); | |
| } | |
| if (axis_edge) | |
| { | |
| ev.value = 1; | |
| ev.code = ecode + axis_edge; | |
| input_cb(&ev, pai, i); | |
| } | |
| } | |
| // Menu button on 8BitDo Receiver in D-Input mode | |
| if (ev.code == 9 && input[dev].vid == 0x2dc8 && (input[dev].pid == 0x3100 || input[dev].pid == 0x3104)) | |
| { | |
| ev.type = EV_KEY; | |
| ev.code = KEY_EMU + (ev.code << 1); | |
| input_cb(&ev, pai, i); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| uint8_t data[4] = {}; | |
| if (read(pool[i].fd, data, sizeof(data))) | |
| { | |
| int edev = i; | |
| int dev = i; | |
| if (input[i].bind >= 0) edev = input[i].bind; // mouse to event | |
| if (input[edev].bind >= 0) dev = input[edev].bind; // event to base device | |
| if (input[i].quirk == QUIRK_DS4TOUCH && input[dev].lightgun) | |
| { | |
| //disable DS4 mouse in lightgun mode | |
| continue; | |
| } | |
| if (input[i].quirk == QUIRK_TOUCHGUN) | |
| { | |
| //don't use original raspad3 emulated mouse | |
| continue; | |
| } | |
| int xval, yval; | |
| xval = ((data[0] & 0x10) ? -256 : 0) | data[1]; | |
| yval = ((data[0] & 0x20) ? -256 : 0) | data[2]; | |
| input_absinfo absinfo = {}; | |
| absinfo.maximum = 255; | |
| absinfo.minimum = 0; | |
| if (input[dev].quirk == QUIRK_MSSP) | |
| { | |
| int btn = (data[0] & 7) ? 1 : 0; | |
| if (input[i].misc_flags != btn) | |
| { | |
| input[i].misc_flags = btn; | |
| ev.value = btn; | |
| ev.type = EV_KEY; | |
| ev.code = 0x120; | |
| input_cb(&ev, &absinfo, i); | |
| } | |
| int throttle = (cfg.spinner_throttle ? abs(cfg.spinner_throttle) : 100) * input[i].spinner_prediv; | |
| int inv = cfg.spinner_throttle < 0; | |
| input[i].spinner_acc += (xval * 100); | |
| int spinner = (input[i].spinner_acc <= -throttle || input[i].spinner_acc >= throttle) ? (input[i].spinner_acc / throttle) : 0; | |
| input[i].spinner_acc -= spinner * throttle; | |
| if (spinner) | |
| { | |
| ev.value = inv ? -spinner : spinner; | |
| ev.type = EV_REL; | |
| ev.code = 7; | |
| input_cb(&ev, &absinfo, i); | |
| input[i].paddle_val += ev.value; | |
| if (input[i].paddle_val < 0) input[i].paddle_val = 0; | |
| if (input[i].paddle_val > 255) input[i].paddle_val = 255; | |
| ev.value = input[i].paddle_val; | |
| ev.type = EV_ABS; | |
| ev.code = 8; | |
| input_cb(&ev, &absinfo, i); | |
| } | |
| if (is_menu() && !video_fb_state()) printf("%s: xval=%d, btn=%d, spinner=%d, paddle=%d\n", input[i].devname, xval, btn, spinner, input[i].paddle_val); | |
| } | |
| else | |
| { | |
| send_mouse_with_throttle(i, xval, yval, data[0], data[3]); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if ((pool[NUMDEV + 1].fd >= 0) && (pool[NUMDEV + 1].revents & POLLIN)) | |
| { | |
| static char cmd[1024]; | |
| int len = read(pool[NUMDEV + 1].fd, cmd, sizeof(cmd) - 1); | |
| if (len) | |
| { | |
| if (cmd[len - 1] == '\n') cmd[len - 1] = 0; | |
| cmd[len] = 0; | |
| printf("MiSTer_cmd: %s\n", cmd); | |
| if (!strncmp(cmd, "fb_cmd", 6)) video_cmd(cmd); | |
| else if (!strncmp(cmd, "load_core ", 10)) | |
| { | |
| len = strlen(cmd); | |
| if (len > 4 && !strcasecmp(cmd + len - 4, ".mra")) arcade_load(cmd + 10); | |
| else fpga_load_rbf(cmd + 10); | |
| } | |
| } | |
| } | |
| if ((pool[NUMDEV + 2].fd >= 0) && (pool[NUMDEV + 2].revents & POLLPRI)) | |
| { | |
| static char status[16]; | |
| if (read(pool[NUMDEV + 2].fd, status, sizeof(status) - 1) && status[0] != '0') DISKLED_ON; | |
| lseek(pool[NUMDEV + 2].fd, 0, SEEK_SET); | |
| } | |
| } | |
| if (cur_leds != leds_state) | |
| { | |
| cur_leds = leds_state; | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if (input[i].led) | |
| { | |
| ev.type = EV_LED; | |
| ev.code = LED_SCROLLL; | |
| ev.value = (cur_leds&HID_LED_SCROLL_LOCK) ? 1 : 0; | |
| write(pool[i].fd, &ev, sizeof(struct input_event)); | |
| ev.code = LED_NUML; | |
| ev.value = (cur_leds&HID_LED_NUM_LOCK) ? 1 : 0; | |
| write(pool[i].fd, &ev, sizeof(struct input_event)); | |
| ev.code = LED_CAPSL; | |
| ev.value = (cur_leds&HID_LED_CAPS_LOCK) ? 1 : 0; | |
| write(pool[i].fd, &ev, sizeof(struct input_event)); | |
| } | |
| } | |
| } | |
| } | |
| return 0; | |
| } | |
| int input_poll(int getchar) | |
| { | |
| static int af[NUMPLAYERS] = {}; | |
| static uint32_t time[NUMPLAYERS] = {}; | |
| static uint32_t joy_prev[NUMPLAYERS] = {}; | |
| int ret = input_test(getchar); | |
| if (getchar) return ret; | |
| uinp_check_key(); | |
| static int prev_dx = 0; | |
| static int prev_dy = 0; | |
| if (mouse_emu || ((user_io_get_kbdemu() == EMU_MOUSE) && kbd_mouse_emu)) | |
| { | |
| if((prev_dx || mouse_emu_x || prev_dy || mouse_emu_y) && (!mouse_timer || CheckTimer(mouse_timer))) | |
| { | |
| mouse_timer = GetTimer(20); | |
| int dx = mouse_emu_x; | |
| int dy = mouse_emu_y; | |
| if (mouse_sniper ^ cfg.sniper_mode) | |
| { | |
| if (dx > 2) dx = 2; | |
| if (dx < -2) dx = -2; | |
| if (dy > 2) dy = 2; | |
| if (dy < -2) dy = -2; | |
| } | |
| mouse_cb(mouse_btn | mice_btn, dx, dy); | |
| prev_dx = mouse_emu_x; | |
| prev_dy = mouse_emu_y; | |
| } | |
| } | |
| if (!mouse_emu_x && !mouse_emu_y) mouse_timer = 0; | |
| if (grabbed) | |
| { | |
| for (int i = 0; i < NUMPLAYERS; i++) | |
| { | |
| if (af_delay[i] < AF_MIN) af_delay[i] = AF_MIN; | |
| if (!time[i]) time[i] = GetTimer(af_delay[i]); | |
| int send = 0; | |
| int newdir = ((joy[i] & 0xF) != (joy_prev[i] & 0xF)); | |
| if (joy[i] != joy_prev[i]) | |
| { | |
| if ((joy[i] ^ joy_prev[i]) & autofire[i]) | |
| { | |
| time[i] = GetTimer(af_delay[i]); | |
| af[i] = 0; | |
| } | |
| send = 1; | |
| joy_prev[i] = joy[i]; | |
| } | |
| if (CheckTimer(time[i])) | |
| { | |
| time[i] = GetTimer(af_delay[i]); | |
| af[i] = !af[i]; | |
| if (joy[i] & autofire[i]) send = 1; | |
| } | |
| if (send) | |
| { | |
| user_io_digital_joystick(i, af[i] ? joy[i] & ~autofire[i] : joy[i], newdir); | |
| } | |
| } | |
| } | |
| if (!grabbed || user_io_osd_is_visible()) | |
| { | |
| for (int i = 0; i < NUMPLAYERS; i++) | |
| { | |
| if(joy[i]) user_io_digital_joystick(i, 0, 1); | |
| joy[i] = 0; | |
| af[i] = 0; | |
| autofire[i] = 0; | |
| } | |
| } | |
| return 0; | |
| } | |
| int is_key_pressed(int key) | |
| { | |
| unsigned char bits[(KEY_MAX + 7) / 8]; | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if (pool[i].fd > 0) | |
| { | |
| unsigned long evbit = 0; | |
| if (ioctl(pool[i].fd, EVIOCGBIT(0, sizeof(evbit)), &evbit) >= 0) | |
| { | |
| if (evbit & (1 << EV_KEY)) | |
| { | |
| memset(bits, 0, sizeof(bits)); | |
| if (ioctl(pool[i].fd, EVIOCGKEY(sizeof(bits)), &bits) >= 0) | |
| { | |
| if (bits[key / 8] & (1 << (key % 8))) | |
| { | |
| return 1; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return 0; | |
| } | |
| void input_notify_mode() | |
| { | |
| //reset mouse parameters on any mode switch | |
| kbd_mouse_emu = 1; | |
| mouse_sniper = 0; | |
| mouse_timer = 0; | |
| mouse_btn = 0; | |
| mouse_emu_x = 0; | |
| mouse_emu_y = 0; | |
| mouse_cb(mice_btn); | |
| } | |
| void input_switch(int grab) | |
| { | |
| if (grab >= 0) grabbed = grab; | |
| //printf("input_switch(%d), grabbed = %d\n", grab, grabbed); | |
| for (int i = 0; i < NUMDEV; i++) | |
| { | |
| if (pool[i].fd >= 0) ioctl(pool[i].fd, EVIOCGRAB, (grabbed | user_io_osd_is_visible()) ? 1 : 0); | |
| } | |
| } | |
| int input_state() | |
| { | |
| return grabbed; | |
| } | |
| static char ovr_buttons[1024] = {}; | |
| static char ovr_nmap[1024] = {}; | |
| static char ovr_pmap[1024] = {}; | |
| static char *get_btn(int type) | |
| { | |
| int i = 2; | |
| while (1) | |
| { | |
| char *p = user_io_get_confstr(i); | |
| if (!p) break; | |
| if ((p[0] == 'J' && !type) || (p[0] == 'j' && ((p[1] == 'n' && type == 1) || (p[1] == 'p' && type == 2)))) | |
| { | |
| p = strchr(p, ','); | |
| if (!p) break; | |
| p++; | |
| if (!strlen(p)) break; | |
| return p; | |
| } | |
| i++; | |
| } | |
| return NULL; | |
| } | |
| char *get_buttons(int type) | |
| { | |
| if (type == 0 && ovr_buttons[0]) return ovr_buttons; | |
| if (type == 1 && ovr_nmap[0]) return ovr_nmap; | |
| if (type == 2 && ovr_pmap[0]) return ovr_pmap; | |
| return get_btn(type); | |
| } | |
| void set_ovr_buttons(char *s, int type) | |
| { | |
| switch (type) | |
| { | |
| case 0: | |
| snprintf(ovr_buttons, sizeof(ovr_buttons), "%s", s); | |
| break; | |
| case 1: | |
| snprintf(ovr_nmap, sizeof(ovr_nmap), "%s", s); | |
| break; | |
| case 2: | |
| snprintf(ovr_pmap, sizeof(ovr_pmap), "%s", s); | |
| break; | |
| } | |
| } | |
| void parse_buttons() | |
| { | |
| joy_bcount = 0; | |
| char *str = get_buttons(); | |
| if (!str) return; | |
| for (int n = 0; n < 28; n++) | |
| { | |
| substrcpy(joy_bnames[n], str, n); | |
| if (!joy_bnames[n][0]) break; | |
| joy_bcount++; | |
| } | |
| } |