jgeumlek / moltengamepad Goto Github PK
View Code? Open in Web Editor NEWFlexible Linux input device translator, geared for gamepads
License: MIT License
Flexible Linux input device translator, geared for gamepads
License: MIT License
When detected either as individual controllers or as a pair, evtest
reports all button events, but no axis events from either Joy-Con stick. move jc1 to debugslot
, likewise, reports all button events, but no stick events.
The joycon
plugin is built-in and default configuration is used (all directories under ~/.config/moltengamepad
are empty).
I recently got a chance to try out MG on a raspberry pi.
The old udev on raspbian did not support "TAG-=uaccess" in our udev rules. Even just force setting permissions does not appear to work, as the uaccess functionality appears to kick in again when switching sessions.
We might need to invoke last_rule
prior to the tag being set, but this isn't ideal. (More testing required.)
Love it or hate it, Debian dpkg-buildpackage/debuid has some rulesets when building, some warnings are treated as errors for instance.
make -j1
make[1]: Entering directory '/build/molten-gamepad-1.1.0+git+bsos'
compiling source/core/commandline.cpp...
mv -f .d/source/core/commandline.Td .d/source/core/commandline.d
compiling source/core/config_parse.cpp...
mv -f .d/source/core/config_parse.Td .d/source/core/config_parse.d
compiling source/core/main.cpp...
mv -f .d/source/core/main.Td .d/source/core/main.d
compiling source/core/moltengamepad.cpp...
source/core/moltengamepad.cpp: In function 'int clear_fifo(const char*, bool)':
source/core/moltengamepad.cpp:217:51: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(fifo,"\nexit_process_leave_fifo\n",25);
^
source/core/moltengamepad.cpp:222:31: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(fifo,"\nquit\n",6);
^
mv -f .d/source/core/moltengamepad.Td .d/source/core/moltengamepad.d
compiling source/core/options.cpp...
mv -f .d/source/core/options.Td .d/source/core/options.d
compiling source/core/output_slot.cpp...
source/core/output_slot.cpp: In member function 'virtual void virtual_keyboard::take_event(input_event)':
source/core/output_slot.cpp:148:37: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(mouse_fd, &in, sizeof(in));
^
source/core/output_slot.cpp:151:36: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(uinput_fd, &in, sizeof(in));
mv -f .d/source/core/output_slot.Td .d/source/core/output_slot.d
compiling source/core/parser.cpp...
mv -f .d/source/core/parser.Td .d/source/core/parser.d
compiling source/core/plugin_loader.cpp...
mv -f .d/source/core/plugin_loader.Td .d/source/core/plugin_loader.d
compiling source/core/profile.cpp...
mv -f .d/source/core/profile.Td .d/source/core/profile.d
compiling source/core/slot_manager.cpp...
mv -f .d/source/core/slot_manager.Td .d/source/core/slot_manager.d
compiling source/core/udev.cpp...
source/core/udev.cpp: In destructor 'udev_handler::~udev_handler()':
source/core/udev.cpp:90:44: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(pipe_fd, &signal, sizeof(signal));
^
source/core/udev.cpp: In member function 'int udev_handler::read_monitor()':
source/core/udev.cpp:167:14: warning: ignoring return value of 'int pipe(int*)', declared with attribute warn_unused_result [-Wunused-result]
pipe(pipes);
^
mv -f .d/source/core/udev.Td .d/source/core/udev.d
compiling source/core/uinput.cpp...
source/core/uinput.cpp: In member function 'int uinput::make_gamepad(const uinput_ids&, bool, bool, bool)':
source/core/uinput.cpp:71:71: error: format not a string literal and no format arguments [-Werror=format-security]
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, ids.device_string.c_str());
source/core/uinput.cpp:71:71: error: format not a string literal and no format arguments [-Werror=format-security]
source/core/uinput.cpp: In member function 'int uinput::make_keyboard(const uinput_ids&)':
source/core/uinput.cpp:150:71: error: format not a string literal and no format arguments [-Werror=format-security]
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, ids.device_string.c_str());
^
source/core/uinput.cpp:150:71: error: format not a string literal and no format arguments [-Werror=format-security]
source/core/uinput.cpp: In member function 'int uinput::make_mouse(const uinput_ids&)':
source/core/uinput.cpp:206:71: error: format not a string literal and no format arguments [-Werror=format-security]
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, ids.device_string.c_str());
^
source/core/uinput.cpp:206:71: error: format not a string literal and no format arguments [-Werror=format-security]
source/core/uinput.cpp: In member function 'int uinput::make_gamepad(const uinput_ids&, bool, bool, bool)':
source/core/uinput.cpp:129:35: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(fd, &uidev, sizeof(uidev));
^
source/core/uinput.cpp: In member function 'int uinput::make_keyboard(const uinput_ids&)':
source/core/uinput.cpp:187:35: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(fd, &uidev, sizeof(uidev));
^
source/core/uinput.cpp: In member function 'int uinput::make_mouse(const uinput_ids&)':
source/core/uinput.cpp:232:35: warning: ignoring return value of 'ssize_t write(int, const void*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
write(fd, &uidev, sizeof(uidev));
^
cc1plus: some warnings being treated as errors
Hi there. It looks like you have started to do in C++ what I was going to do with bash and xboxdrv. I'm going to back you as much as I can on this and I'll start with testing and making drivers, but I am very uncomfortable with C++ so I can't hack on the codebase much, if at all.
So one thing I want to look into is possibly bundling pre-made drivers with the codebase such that users can get their controllers to mimic x360 controllers and work with Unity and SDL2 games out of the box without having to make their own molten or SDL2 mappings. Is this something you'd be interested in doing?
If so, I can get access to a wide variety of controllers due to my proximity to an arcade; expect me to contribute a buttload of fight sticks and adapters. I have a few such controllers in my own possession.
With the rest of MG stabilizing, it is time to consider allowing the number of virtual gamepads to change during runtime. (Right now the user can only control the number that might get input sources mapped to them).
When trying to assign an input source and all output slots are full, why not add a new virtual device?
Persistent devices are still useful for games that don't handle disconnecting controllers, so the user should be able to specify a minimum number of slots to maintain. Might as well also allow for a maximum to be specified.
Player numbering becomes a mess, but it was already a bit of a mess, and is a reasonable sacrifice in this setting.
When I run the systemuser installation script for MoltenGamepad it throws up an error with rmmod.
rmmod: ERROR: Module uinput is builtin.
The offending line is line 23 in install.sh:
rmmod uinput
The script halts and doesn’t complete the installation. Only by commenting the line out does the script finish. This seems to have had no adverse effect on the installation.
$ cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"
NAME="Ubuntu"
VERSION="16.04.2 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.2 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
$ uname -a
Linux htpc 4.4.0-75-generic #96-Ubuntu SMP Thu Apr 20 09:56:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
Hi, I was trying to get my nunchuck to work with my wiimote, the C and Z buttons are working fine, but no output from my thumb stick actions..
This is my profile:
[wiimote]
wiimote.?nk_ir_active = true
wiimote.?nk_accel_active = true
wiimote.nk_a = key(btn_left)
wiimote.nk_b = key(btn_right)
wiimote.nk_1 = key(key_8)
wiimote.nk_2 = key(key_9)
wiimote.nk_up = key(key_o)
wiimote.nk_down = key(key_y)
wiimote.nk_left = key(key_u)
wiimote.nk_right = key(key_i)
wiimote.nk_plus = key(key_leftalt)
wiimote.nk_minus = key(key_7)
wiimote.nk_home = key(key_h)
wiimote.nk_ir_x = mouse(abs_x)
wiimote.nk_ir_y = mouse(abs_y)
wiimote.nk_c = key(key_c)
wiimote.nk_z = key(key_z)
wiimote.nk_stick_x = key_v,key_b
wiimote.nk_stick_y = key_n,key_m
Tha'ts the output:
sudo ./Dropbox/MoltenGamepad/MoltenGamepad/moltengamepad
warning: Running MoltenGamepad as root is not recommended. Instead, please run as a non-superuser that has been granted the appropriate permissions.
loading /etc/xdg/moltengamepad/moltengamepad.cfg
driver: wiimote driver initialized.
Loading profiles from /home/gustavo/.config/moltengamepad/profiles/dota-2/dota2.2
parse: header is wiimote
parse: option "nk_ir_active" set.
parse: option "nk_accel_active" set.
parse: setting wiimote.nk_a = key(btn_mouse)
parse: setting wiimote.nk_b = key(btn_right)
parse: setting wiimote.nk_1 = key(key_8)
parse: setting wiimote.nk_2 = key(key_9)
parse: setting wiimote.nk_up = key(key_o)
parse: setting wiimote.nk_down = key(key_y)
parse: setting wiimote.nk_left = key(key_u)
parse: setting wiimote.nk_right = key(key_i)
parse: setting wiimote.nk_plus = key(key_leftalt)
parse: setting wiimote.nk_minus = key(key_7)
parse: setting wiimote.nk_home = key(key_h)
parse: setting wiimote.nk_ir_x = key(left_x+)
parse: setting wiimote.nk_ir_y = key(left_y+)
parse: setting wiimote.nk_c = key(key_c)
parse: setting wiimote.nk_z = key(key_z)
parse: setting wiimote.nk_stick_x = (key_v,key_b)
parse: setting wiimote.nk_stick_y = (key_n,key_m)
stdin: ready to read commands from standard input. Try "help" for more info.
This would basically add split screen support to any game that can setup local networking (and that can run multiple process instances of course, I think some block this).
so it would be something like:
/dev/controller1 -> pid10
/dev/controller2 -> pid20
I want to do this myself but I honestly don't know that much about the lower levels.
With the helpful install scripts provided by TiZ-EX1, installing MoltenGamepad as a system service is easier than ever.
This has highlighted some unfortunate behavior that should be smoothed out:
The quick fix is to ensure we clean up the FIFO even when start-up has an error. It will take a little work to restructure the init phase to guarantee this. It should be up soon as v0.3.2.
The second issue is a bit more open. When not running as a system service, this behavior is useful as a simple way of ensuring only one instance is running. However, when running as a system service, we don't have to worry about multiple instances (and keeping this logic can cause strange failure states!).
Proposals:
I'm leaning towards the middle choice, enabling some sort of "replace the running instance" behavior. Perhaps --replace-fifo
?
MoltenGamepad attempts to support changing device permissions so that other software cannot see the original controller devices.
The generic driver however only grabs the /dev/input/eventX
nodes and not the /dev/input/jsX
nodes. This needs to be corrected, and will involve some hierarchy walking to get the correct js
node.
Hey,
so i feel a little bit stupid, cause i trying to create a profile for a wii U Pro Controller. (which i would love to upload here so nobody got the same trouble as me)
But it seems i dont understand anything here...
Well first i installed MoltenGamepad and after starting it with the command ./moltengamepad --mimic-xpad i realized that the games i tried recognize the gamepad as Mouse (horray for progress!).
But back to the Problem: after pressing a button i get the following message:
No moltengamepad.cfg found.
driver: wiimote driver initialized.
plug: wm1 added
device hiding: changing permissions of /dev/input/event25 failed.
device hiding: changing permissions of /dev/input/js4 failed.
stdin: ready to read commands from standard input. Try "help" for more info.
slot: wm1 assigned to slot virtpad1
then i typed print devices wm1
and got the following output:
wm1
"Wii U Pro Controller"
type: gamepad
uniq: "------" (i removed it)
phys: "-----" (i removed it too)
events:
btn cc_a: Classic Controller A button
btn cc_b: Classic Controller B button
btn cc_x: Classic Controller X button
btn cc_y: Classic Controller Y button
btn cc_plus: Classic Controller + button
btn cc_minus: Classic Controller - button
btn cc_home: Classic Controller Home button
btn cc_left: Classic Controller Dpad left
btn cc_right: Classic Controller Dpad right
btn cc_up: Classic Controller Dpad up
btn cc_down: Classic Controller Dpad down
btn cc_l: Classic Controller L button
btn cc_zl: Classic Controller ZL button
btn cc_r: Classic Controller R button
btn cc_zr: Classic Controller ZR button
btn cc_thumbl: Classic Controller Left Stick Click (Wii U Pro only)
btn cc_thumbr: Classic Controller Right Stick Click (Wii U Pro only)
axis cc_left_x: Classic Controller Left Stick X
axis cc_left_y: Classic Controller Left Stick Y
axis cc_right_x: Classic Controller Right Stick X
axis cc_right_y: Classic Controller Right Stick Y
options:
?grab_exclusive = true
Grab device events via ioctl EVIOCGRAB
?grab_permissions = true
Grab device via blocking all read permissions`
well... now is the problem: i don't know what to do now? The main goal is to get the wiiU Pro pad recognized as xbox360 controller (or something simliar) but i don't know what to do next.
Well, I'm trying to use MoltenGamepad to control my mouse pointer with my wiimote. I'm doing that cause I don't use keyboard and mouse to play some games cause my hands get pain over time.
Well, it compiles fine, it runs like shown below:
loading /etc/xdg/moltengamepad/moltengamepad.cfg
driver: wiimote driver initialized.
hotplug: device wm1 added.
wiimote: wm1: added core
wiimote: wm1: added accelerometers
wiimote: wm1: added IR
wiimote: wm1: added motion+
slot: wm1 assigned to slot virtpad1
But it just doesn't work at all. No keyboard buttons are mapped, and my profile file looks ok, I have tryied to setup it for hours, but there is something wrong here. Can you anyone help me with that?... I want to do a tutorial on how to setup it after get it working.
(yeah, I have read all the documentation, but there is no step by step simple and direct page that could help me)
(there is no forum, so here is the only place I found to get help, sorry for that)
GNU gdb (GDB) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from moltengamepad...(no debugging symbols found)...done.
(gdb) run
Starting program: /usr/bin/moltengamepad
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
loading /home/azelphur/.config/moltengamepad/moltengamepad.cfg
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a3a794 in uw_update_context_1 (context=0x7fffffffe048, fs=0x7fffffffde88) at /build/gcc/src/gcc/libgcc/unwind-dw2.c:1395
1395 /build/gcc/src/gcc/libgcc/unwind-dw2.c: No such file or directory.
(gdb) bt full
#0 0x00007ffff7a3a794 in uw_update_context_1 (context=0x7fffffffe048, fs=0x7fffffffde88) at /build/gcc/src/gcc/libgcc/unwind-dw2.c:1395
orig_context = {reg = {0x0, 0xbbec89db747cf400, 0x0, 0x7fffffffe048, 0x7fffffffde88, 0x7fffffffe0f0, 0x7fffffffe048, 0x8,
0x7ffff7a3b62a <_Unwind_Resume+58>, 0x7ffff7a3d476 <_Unwind_Find_FDE+102>, 0x7ffff7a3b62a <_Unwind_Resume+58>, 0x0, 0x0, 0x7fffffffddc0,
0x7ffff7a406c4, 0x0, 0x0, 0x7ffff7a406d5}, cfa = 0x7ffff7a406d5, ra = 0x7fffffffe048, lsda = 0x7ffff7a406c4, bases = {tbase = 0x7ffff7a3f1e0,
dbase = 0x7fffffffde88, func = 0x7ffff7a39ca0 <uw_frame_state_for+816>}, flags = 140737351474608, version = 93824993037192,
args_size = 93824992511466, by_value = "\te\327\367\377\177\000\000Pe\327\367\377\177\000\000`0"}
cfa = <optimized out>
i = <optimized out>
tmp_sp = {ptr = 0, word = 0}
#1 0x00007ffff7a3ac57 in uw_init_context_1 (context=0x7fffffffe048, outer_cfa=0x7fffffffe278, outer_ra=0x55555556d24a)
at /build/gcc/src/gcc/libgcc/unwind-dw2.c:1607
ra = <optimized out>
fs = {regs = {reg = {{loc = {reg = 18446744073709551544, offset = -72,
exp = 0xffffffffffffffb8 <error: Cannot access memory at address 0xffffffffffffffb8>}, how = REG_SAVED_OFFSET}, {loc = {
reg = 18446744073709551552, offset = -64, exp = 0xffffffffffffffc0 <error: Cannot access memory at address 0xffffffffffffffc0>},
how = REG_SAVED_OFFSET}, {loc = {reg = 0, offset = 0, exp = 0x0}, how = REG_UNSAVED}, {loc = {reg = 18446744073709551560, offset = -56,
exp = 0xffffffffffffffc8 <error: Cannot access memory at address 0xffffffffffffffc8>}, how = REG_SAVED_OFFSET}, {loc = {reg = 0,
offset = 0, exp = 0x0}, how = REG_UNSAVED}, {loc = {reg = 0, offset = 0, exp = 0x0}, how = REG_UNSAVED}, {loc = {
reg = 18446744073709551600, offset = -16, exp = 0xfffffffffffffff0 <error: Cannot access memory at address 0xfffffffffffffff0>},
how = REG_SAVED_OFFSET}, {loc = {reg = 0, offset = 0, exp = 0x0}, how = REG_UNSAVED}, {loc = {reg = 0, offset = 0, exp = 0x0},
how = REG_UNSAVED}, {loc = {reg = 0, offset = 0, exp = 0x0}, how = REG_UNSAVED}, {loc = {reg = 0, offset = 0, exp = 0x0},
how = REG_UNSAVED}, {loc = {reg = 0, offset = 0, exp = 0x0}, how = REG_UNSAVED}, {loc = {reg = 18446744073709551568, offset = -48,
exp = 0xffffffffffffffd0 <error: Cannot access memory at address 0xffffffffffffffd0>}, how = REG_SAVED_OFFSET}, {loc = {
reg = 18446744073709551576, offset = -40, exp = 0xffffffffffffffd8 <error: Cannot access memory at address 0xffffffffffffffd8>},
how = REG_SAVED_OFFSET}, {loc = {reg = 18446744073709551584, offset = -32,
exp = 0xffffffffffffffe0 <error: Cannot access memory at address 0xffffffffffffffe0>}, how = REG_SAVED_OFFSET}, {loc = {
reg = 18446744073709551592, offset = -24, exp = 0xffffffffffffffe8 <error: Cannot access memory at address 0xffffffffffffffe8>},
how = REG_SAVED_OFFSET}, {loc = {reg = 18446744073709551608, offset = -8,
exp = 0xfffffffffffffff8 <error: Cannot access memory at address 0xfffffffffffffff8>}, how = REG_SAVED_OFFSET}, {loc = {reg = 0,
offset = 0, exp = 0x0}, how = REG_UNSAVED}}, prev = 0x0, cfa_offset = 0, cfa_reg = 7, cfa_exp = 0x0, cfa_how = CFA_REG_OFFSET},
pc = 0x7ffff7a3b7b7 <_Unwind_Resume+455>, personality = 0x0, data_align = -8, code_align = 1, retaddr_column = 16, fde_encoding = 27 '\033',
lsda_encoding = 255 '\377', saw_z = 1 '\001', signal_frame = 0 '\000', eh_ptr = 0x0}
sp_slot = {ptr = 140737488347768, word = 140737488347768}
code = <optimized out>
#2 0x00007ffff7a3b62b in _Unwind_Resume (exc=0x5555555fddf0) at /build/gcc/src/gcc/libgcc/unwind.inc:235
this_context = {reg = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7fffffffde80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, cfa = 0x0,
ra = 0x7ffff7a3b62b <_Unwind_Resume+59>, lsda = 0x0, bases = {tbase = 0x0, dbase = 0x0, func = 0x7ffff7a3b5f0 <_Unwind_Resume>},
flags = 4611686018427387904, version = 0, args_size = 0, by_value = '\000' <repeats 17 times>}
cur_context = {reg = {0x0, 0x3000000002, 0x0, 0x0, 0x6e0000005b, 0x0, 0x7c00000077, 0x7fffffffe180, 0xf, 0x8, 0x0, 0xffffffffffffff80, 0x8,
0x7fffffffe258, 0x7ffff78eb967 <malloc+151>, 0x1af, 0x8, 0x0}, cfa = 0x0, ra = 0x555555618a40,
--Type <RET> for more, q to quit, c to continue without paging--
lsda = 0x7ffff7c5b5fd <operator new(unsigned long)+29>, bases = {tbase = 0x555555618b18, dbase = 0x5555555a7a4b, func = 0x1e}, flags = 0,
version = 0, args_size = 22, by_value = "\036\000\000\000\000\000\000\000\020\213aUUU\000\000\260]"}
code = <optimized out>
frames = 4063479899412916480
#3 0x000055555556d24a in ?? ()
No symbol table info available.
#4 0x0000000000000001 in ?? ()
No symbol table info available.
#5 0x00007fffffffe320 in ?? ()
No symbol table info available.
#6 0x00007fffffffe4c0 in ?? ()
No symbol table info available.
#7 0x00007fffffffe460 in ?? ()
No symbol table info available.
#8 0x0000000000000001 in ?? ()
No symbol table info available.
#9 0x00007ffff7fa69e0 in ?? ()
No symbol table info available.
#10 0x00007fffffffe300 in ?? ()
No symbol table info available.
#11 0x00007fffffffe340 in ?? ()
No symbol table info available.
#12 0x0000000000000001 in ?? ()
No symbol table info available.
#13 0x00007ffff7fa64f0 in ?? ()
No symbol table info available.
#14 0x00007fffffffe2a0 in ?? ()
No symbol table info available.
#15 0x0000555555612b30 in ?? ()
No symbol table info available.
#16 0x0000000000000000 in ?? ()
No symbol table info available.```
I'm running MoltenGamepas as root, I know it is not the recommended but I didn't have an option with my current setup. I want to have the same mapping on the wiimote buttons with/without nunchuck connected. That way, I don't have to change the wiimote orientation when navigating the Media Center application with/without nunchuck. Everything works like a charm (other than the custom profile). I can create custom mappings on my other applications (Kodi, EmulationStation, and RetroArch). But when I disconnect the nunchuck the mappings are different because MoltedGamepad is sending different command to the buttons for each mode.
First, I saved the default wiimote profile, cleaned it up, and made my edits. The profile file is in 'root/.config/moltengamepad/profiles/'. Then, I created a configuration file in 'root/.config/moltengamepad/moltengamepad.cfg'. with the command load profiles from "profilename"
. I double checked and triple checked the profile syntax and looked for typos. After trying a few times and getting no results, I tested the configuration file by also adding mimin_xpad=true
and this command worked.
while trying to install with single or system user it keeps giving a permission error and will not launch. Trying to use joycon drivers for my project any help would be most appreciated.
Hiya. I've been happily playing games through MG without any problems so I haven't had anything to report for a while. Though I did have an idea.
I'm not doing anything to check the battery life of my DualShock 4s, so they periodically just die while I'm in the middle of gameplay. Right now, what seems to happen is that the last input that occurred when the controller died just persists, which could result in you killing yourself in some silly manner before you can hook up another one. It'd be better for inputs to just be totally cleared and for the controller to do nothing, but it'd be even better still if the game paused automatically after losing a controller. Since nearly every game that exists treats start as pause, all we'd have to do is press start if a controller disappears. Some games require you to hold it for x seconds to prevent accidental pauses, so maybe that could be a config option.
What do you think?
Hello, I have about 99% of my setup working, but I am bumping my head now at a problem.
Moltengamepad seems to have somewhat of a virtual mouse support.
I have following situation, I have a generic joystick, which has exactly one button connected (emits btn_thumb atm) I try to map this button press into a mouse left click to recycle that button in an arcade setup with multiple mapped devices. For some reason I cannot remap the button. The mouse although it shows up as a device never emits the left_btn event in evtest.
`[name = "Ultimarc UltraStik Ultimarc Ultra-Stik Player 1" order="11"]
name = "mouse_1"
devname = "m1_"
exclusive = "false"
change_permissions = "false"
flatten = "false"
rumble = "false"
split = 1
btn_thumb = "btn_left", "Button Left"
`
The stick is registered into virtualjoypad1 i tried to move the device into another slot, but there seems to be no mouse slot only a keyboard one, which does not react either to any mapping atm.
Any ideas on what I am doing wrong here?
It seems to happen with GameMaker games
GAMEPAD: device name Virtual Keyboard (MoltenGamepad)
./run.sh: line 3: 28389 Segmentation fault LD_LIBRARY_PATH=./lib $LD_LIBRARY_PATH ./runner
Some gamepads have digital triggers, like the Wii U Pro controller. The triggers are just buttons.
Some have analog triggers, like the Xbox 360 controller.
Some have both, like the Gamecube controller or DS4. For the former, the digital button fires when the trigger is pressed fully. For the later, it fires on even the slightest trigger pull.
Current configs have mappings like
gamepad.tr2 = tr2
gamepad.tr2_axis = tr2_axis
When simulating a 360 controller, the tr2 event sends a full trigger pull. (Allowing a device like the Wii U Pro to fake the analog trigger as best it can.)
This leads to a problem for the DS4: It's trigger button fires on the slightest pull, which then sends a full pull events. For the Gamecube controller, the problem happens when going from 100% to 90%, as the release of the digital button maps the trigger to 0%. This leads to the output device's trigger jumping around sharply.
Potential solution:
Create a distinct event for trigger-button-with-axis-present versus trigger-button-with-no-axis. The former should be mapped to nothing for most games, as the trigger axis events do all the work.
I am low on name suggestions though. I feel the digital trigger should get to keep the "tr2" name. What about the other?
tr2_axis_btn
tr2_extra_btn
????
Hello, I'm interested in using MoltenGamepad
with the standard classic controller.
First of all, during compilation I had to comment out the following:
{KEY_RIGHT_UP, "key_right_up", ""},
{KEY_RIGHT_DOWN, "key_right_down", ""},
{KEY_LEFT_UP, "key_left_up", ""},
{KEY_LEFT_DOWN, "key_left_down", ""},
{KEY_ROOT_MENU, "key_root_menu", ""},
{KEY_MEDIA_TOP_MENU, "key_media_top_menu", ""},
{KEY_NUMERIC_11, "key_numeric_11", ""},
{KEY_NUMERIC_12, "key_numeric_12", ""},
{KEY_AUDIO_DESC, "key_audio_desc", ""},
{KEY_3D_MODE, "key_3d_mode", ""},
{KEY_NEXT_FAVORITE, "key_next_favorite", ""},
{KEY_STOP_RECORD, "key_stop_record", ""},
{KEY_PAUSE_RECORD, "key_pause_record", ""},
{KEY_VOD, "key_vod", ""},
{KEY_UNMUTE, "key_unmute", ""},
{KEY_FASTREVERSE, "key_fastreverse", ""},
{KEY_SLOWREVERSE, "key_slowreverse", ""},
{KEY_DATA, "key_data", ""},
When running jstest-gtk
on the controller without MoltenGamepad
, I get the following reasonable results:
tr2_axis
and tl2_axis
.When running jstest-gtk
on Virtual Gamepad
however:
tr
and tl
) and no buttons are triggered. *tr2_axis
tl2_axis
do nothing.Setting the following before wm1 is detected appears to have no effect (Although I could have misunderstood how configuration/inheritance is done) : *
gamepad.tl2_axis_btn = tl2
gamepad.tr2_axis_btn = tr2
There is currently a script generate_key_codes
that can generate the files key_list.cpp
, axis_list.cpp
, and rel_list.cpp
.
These lists should match the user's machine, as more recent versions of Linux have included more event names.
The script appears to be working fine on Arch Linux, but it might need more testing on other distros.
It needs to handle finding the appropriate header file (linux/input-event-codes.h
or linux/input.h
).
It also needs to be integrated into the Makefile for convenience.
Joycons aren't detected, I'm obviously using bluetooth, on my PC it says that it's connected but when I write print devices I get this:
print devices
(wiimote)
no devices
(steamcontroller)
no devices
(joycon)
no devices
Exactly what it says on the tin. I definitely have the development libs installed. 15.10 has udev 225. Here's my make output:
WC130-TiZ:MoltenGamepad$ make
g++ -std=c++14 -ludev -lpthread -I source source/*.cpp source/*/*.cpp source/*/*/*.cpp -o moltengamepad
source/uinput.cpp: In member function ‘int uinput::make_gamepad(const uinput_ids&, bool, bool)’:
source/uinput.cpp:55:71: warning: format not a string literal and no format arguments [-Wformat-security]
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, ids.device_string.c_str());
^
source/uinput.cpp:55:71: warning: format not a string literal and no format arguments [-Wformat-security]
source/uinput.cpp: In member function ‘int uinput::make_keyboard(const uinput_ids&)’:
source/uinput.cpp:130:71: warning: format not a string literal and no format arguments [-Wformat-security]
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, ids.device_string.c_str());
^
source/uinput.cpp:130:71: warning: format not a string literal and no format arguments [-Wformat-security]
/tmp/ccDTOSq9.o: In function `std::thread::thread<void (exclusive_chord::*)(), exclusive_chord*>(void (exclusive_chord::*&&)(), exclusive_chord*&&)':
event_change.cpp:(.text._ZNSt6threadC2IM15exclusive_chordFvvEJPS1_EEEOT_DpOT0_[_ZNSt6threadC5IM15exclusive_chordFvvEJPS1_EEEOT_DpOT0_]+0x93): undefined reference to `pthread_create'
/tmp/cc00bN2L.o: In function `std::thread::thread<int (&)(moltengamepad*), moltengamepad*>(int (&)(moltengamepad*), moltengamepad*&&)':
moltengamepad.cpp:(.text._ZNSt6threadC2IRFiP13moltengamepadEJS2_EEEOT_DpOT0_[_ZNSt6threadC5IRFiP13moltengamepadEJS2_EEEOT_DpOT0_]+0x93): undefined reference to `pthread_create'
/tmp/ccQzM8mx.o: In function `udev_handler::pass_along_device(udev_device*)':
udev.cpp:(.text+0x101): undefined reference to `udev_device_get_syspath'
/tmp/ccQzM8mx.o: In function `udev_handler::udev_handler()':
udev.cpp:(.text+0x277): undefined reference to `udev_new'
/tmp/ccQzM8mx.o: In function `udev_handler::~udev_handler()':
udev.cpp:(.text+0x33d): undefined reference to `udev_monitor_unref'
udev.cpp:(.text+0x35a): undefined reference to `udev_unref'
/tmp/ccQzM8mx.o: In function `udev_handler::start_monitor()':
udev.cpp:(.text+0x3cd): undefined reference to `udev_monitor_new_from_netlink'
udev.cpp:(.text+0x3f2): undefined reference to `udev_monitor_filter_add_match_subsystem_devtype'
udev.cpp:(.text+0x40c): undefined reference to `udev_monitor_filter_add_match_subsystem_devtype'
udev.cpp:(.text+0x41c): undefined reference to `udev_monitor_enable_receiving'
/tmp/ccQzM8mx.o: In function `udev_handler::enumerate()':
udev.cpp:(.text+0x4c2): undefined reference to `udev_enumerate_new'
udev.cpp:(.text+0x4d7): undefined reference to `udev_enumerate_add_match_subsystem'
udev.cpp:(.text+0x4e8): undefined reference to `udev_enumerate_add_match_subsystem'
udev.cpp:(.text+0x4f4): undefined reference to `udev_enumerate_scan_devices'
udev.cpp:(.text+0x500): undefined reference to `udev_enumerate_get_list_entry'
udev.cpp:(.text+0x51f): undefined reference to `udev_list_entry_get_name'
udev.cpp:(.text+0x53a): undefined reference to `udev_device_new_from_syspath'
udev.cpp:(.text+0x55d): undefined reference to `udev_device_unref'
udev.cpp:(.text+0x569): undefined reference to `udev_list_entry_get_next'
udev.cpp:(.text+0x57b): undefined reference to `udev_enumerate_unref'
/tmp/ccQzM8mx.o: In function `udev_handler::read_monitor()':
udev.cpp:(.text+0x5f5): undefined reference to `udev_monitor_get_fd'
udev.cpp:(.text+0x6ac): undefined reference to `udev_monitor_receive_device'
udev.cpp:(.text+0x6d6): undefined reference to `udev_device_unref'
/tmp/ccQzM8mx.o: In function `std::thread::thread<int (udev_handler::*)(), udev_handler*>(int (udev_handler::*&&)(), udev_handler*&&)':
udev.cpp:(.text._ZNSt6threadC2IM12udev_handlerFivEJPS1_EEEOT_DpOT0_[_ZNSt6threadC5IM12udev_handlerFivEJPS1_EEEOT_DpOT0_]+0x93): undefined reference to `pthread_create'
/tmp/ccgS5ifT.o: In function `std::thread::thread<void (input_source::*)(), input_source*>(void (input_source::*&&)(), input_source*&&)':
input_source.cpp:(.text._ZNSt6threadC2IM12input_sourceFvvEJPS1_EEEOT_DpOT0_[_ZNSt6threadC5IM12input_sourceFvvEJPS1_EEEOT_DpOT0_]+0x93): undefined reference to `pthread_create'
/tmp/cchzvL6l.o: In function `generic_device::~generic_device()':
generic_input.cpp:(.text+0x461): undefined reference to `udev_device_unref'
/tmp/ccAogSsL.o: In function `generic_manager::accept_device(udev*, udev_device*)':
generic_manager.cpp:(.text+0xa84): undefined reference to `udev_device_get_syspath'
generic_manager.cpp:(.text+0xa94): undefined reference to `udev_device_get_subsystem'
generic_manager.cpp:(.text+0xaa4): undefined reference to `udev_device_get_action'
generic_manager.cpp:(.text+0xc33): undefined reference to `udev_device_get_sysname'
generic_manager.cpp:(.text+0xc69): undefined reference to `udev_device_get_parent'
generic_manager.cpp:(.text+0xc7e): undefined reference to `udev_device_get_sysattr_value'
/tmp/ccAogSsL.o: In function `generic_file::open_node(udev_device*)':
generic_manager.cpp:(.text._ZN12generic_file9open_nodeEP11udev_device[_ZN12generic_file9open_nodeEP11udev_device]+0x43): undefined reference to `udev_device_get_devnode'
generic_manager.cpp:(.text._ZN12generic_file9open_nodeEP11udev_device[_ZN12generic_file9open_nodeEP11udev_device]+0xdc): undefined reference to `udev_device_get_devnode'
generic_manager.cpp:(.text._ZN12generic_file9open_nodeEP11udev_device[_ZN12generic_file9open_nodeEP11udev_device]+0x17e): undefined reference to `udev_device_get_devnode'
generic_manager.cpp:(.text._ZN12generic_file9open_nodeEP11udev_device[_ZN12generic_file9open_nodeEP11udev_device]+0x23a): undefined reference to `udev_device_ref'
/tmp/ccAogSsL.o: In function `generic_file::close_node(udev_device*, bool)':
generic_manager.cpp:(.text._ZN12generic_file10close_nodeEP11udev_deviceb[_ZN12generic_file10close_nodeEP11udev_deviceb]+0x2d): undefined reference to `udev_device_get_devnode'
/tmp/ccAogSsL.o: In function `generic_file::close_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)':
generic_manager.cpp:(.text._ZN12generic_file10close_nodeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb[_ZN12generic_file10close_nodeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb]+0xc6): undefined reference to `udev_device_unref'
/tmp/ccAogSsL.o: In function `std::thread::thread<void (generic_file::*)(), generic_file*>(void (generic_file::*&&)(), generic_file*&&)':
generic_manager.cpp:(.text._ZNSt6threadC2IM12generic_fileFvvEJPS1_EEEOT_DpOT0_[_ZNSt6threadC5IM12generic_fileFvvEJPS1_EEEOT_DpOT0_]+0x93): undefined reference to `pthread_create'
/tmp/ccY00ulV.o: In function `wiimote::clear_node(dev_node*)':
wiimote.cpp:(.text+0x91d): undefined reference to `udev_device_unref'
/tmp/ccY00ulV.o: In function `wiimote::handle_event(udev_device*)':
wiimote.cpp:(.text+0x970): undefined reference to `udev_device_get_subsystem'
wiimote.cpp:(.text+0x980): undefined reference to `udev_device_get_action'
wiimote.cpp:(.text+0x9ac): undefined reference to `udev_device_get_parent'
wiimote.cpp:(.text+0x9b9): undefined reference to `udev_device_get_sysattr_value'
wiimote.cpp:(.text+0xa58): undefined reference to `udev_device_get_sysname'
wiimote.cpp:(.text+0xa8a): undefined reference to `udev_device_get_parent'
wiimote.cpp:(.text+0xa9f): undefined reference to `udev_device_get_sysattr_value'
/tmp/ccY00ulV.o: In function `wiimote::store_node(udev_device*, char const*)':
wiimote.cpp:(.text+0xc7a): undefined reference to `udev_device_ref'
wiimote.cpp:(.text+0xcf9): undefined reference to `udev_device_ref'
wiimote.cpp:(.text+0xdbb): undefined reference to `udev_device_ref'
wiimote.cpp:(.text+0xe7d): undefined reference to `udev_device_ref'
wiimote.cpp:(.text+0xeaa): undefined reference to `udev_device_ref'
/tmp/ccY00ulV.o:wiimote.cpp:(.text+0xf43): more undefined references to `udev_device_ref' follow
/tmp/ccY00ulV.o: In function `wiimote::open_node(dev_node*)':
wiimote.cpp:(.text+0x1543): undefined reference to `udev_device_get_devnode'
/tmp/ccY00ulV.o: In function `wiimote::grab_chmod_node(dev_node*, bool)':
wiimote.cpp:(.text+0x1663): undefined reference to `udev_device_get_devnode'
wiimote.cpp:(.text+0x168e): undefined reference to `udev_device_get_devnode'
/tmp/ccJqVgPA.o: In function `find_wii_dev_by_path(std::vector<wiimote*, std::allocator<wiimote*> >*, char const*)':
wiimote_manager.cpp:(.text+0x199): undefined reference to `udev_device_get_syspath'
/tmp/ccJqVgPA.o: In function `destroy_wii_dev_by_path(moltengamepad*, std::vector<wiimote*, std::allocator<wiimote*> >*, char const*)':
wiimote_manager.cpp:(.text+0x288): undefined reference to `udev_device_get_syspath'
/tmp/ccJqVgPA.o: In function `wiimote_manager::accept_device(udev*, udev_device*)':
wiimote_manager.cpp:(.text+0x4b1): undefined reference to `udev_device_get_syspath'
wiimote_manager.cpp:(.text+0x4c7): undefined reference to `udev_device_get_subsystem'
wiimote_manager.cpp:(.text+0x4dd): undefined reference to `udev_device_get_action'
wiimote_manager.cpp:(.text+0x524): undefined reference to `udev_device_get_syspath'
wiimote_manager.cpp:(.text+0x5f2): undefined reference to `udev_device_get_parent_with_subsystem_devtype'
wiimote_manager.cpp:(.text+0x608): undefined reference to `udev_device_get_subsystem'
wiimote_manager.cpp:(.text+0x64f): undefined reference to `udev_device_get_driver'
wiimote_manager.cpp:(.text+0x688): undefined reference to `udev_device_get_syspath'
wiimote_manager.cpp:(.text+0x706): undefined reference to `udev_device_ref'
collect2: error: ld returned 1 exit status
Makefile:3: recipe for target 'all' failed
make: *** [all] Error 1
MoltenGamepad acts like a daemon, and its user interface is not very friendly.
A control socket would add a bidirectional way to connect to a running instance of MoltenGamepad. This allows different clients to grow, such as a better CLI or a GUI, without adding extra complexity to the main binary.
There are use-cases for MG without an active X session, and it would be nice to minimize the build requirements.
D-Bus or a simple OSC-based protocol? Perhaps start with the OSC method for development agility, and switch to D-Bus when this project is more mature.
When I use the left analog stick it controls the mouse. It also sends the correct gamepad inputs but moving the mouse is annoying and not sure if intended.
I am also receiving duplicate inputs as if my original controller is not being locked properly.
Running Mint 18.2 with kernel 4.13.4
I have the proper sony generic config for the new kernel gamepad updates so that doesn't appear to be the problem.
Any help would be greatly appreciated!
Now that output slots maintain a list of devices, it is feasible to add rumble support.
Will need to figure out the uinput force-feedback API and implement it correctly.
Pushing the joystick on the nunchuck up about a third of the way tells the software it is pushed up all the way.
Extending issues #21 and #28. Wii remotes have a lot of sensors, and it is a shame to not use them fully. Currently MG does very basic processing to emit these events.
This issue is likely to be open for a long time, as there will always be room for improvement.
Asking for some help, be it coding or testing to see how "fun" the mappings are. My limited time on this project is likely to go towards improving the framework/enabling new use cases rather than fine-tuning input translations. Play testing takes a lot more time!
You don't need to know anything low-level to help code this. MG will handle reading in all the sensor data, and sending the output values to the virtual devices.
If you were given the sensor values, can you compute sensible output values?
All of them require some sort of smoothing: the raw data is far too jittery to use in most games. What smoothing is best?
For the motion-plus gyros, we have a suggested way to generate relative mouse movements. See #28 for one implementation, and the "gyro mouse" project of this repo for the progress towards merging this into MG.
For tilt support, does it make sense to emit the accel data, or do some trig to emit an estimated angle? Changing the semantics to an angle also gives us more freedom to handle the case where you turn so far the controller goes past vertical or upside down...
Hi there. So, I have a couple old games that only pay attention to the left stick, as well as games where it would benefit to be able to use either method. The impression I got from the documentation is that I should be able to load a profile to do this, something like this:
gamepad.left = -left_x
gamepad.right = +left_x
gamepad.up = -left_y
gamepad.down = +left_y
If I echo load profiles from dpad_to_ls
, the log indicates it does do that, but testing the controller in antimicro shows the dpad is still sending dpad inputs and not left stick inputs. Am I doing this wrong?
In addition, I'm not clear on how I would revert these changes when I'm done playing a game that would use this.
Thanks for everything, I've been trucking along with zero trouble since the last time I came here. :D
Hi, first of all thanks for the great project, as an opensource developer I know how hard it is to find time to work on such things. So my biggest thanks to you. So dont see this question as a high priority question, whenever you have time...
But now to the problem, I am currently working on a custom arcade panel, and I am using MoltenGamepad to get everything up and running, so far it looks promising however I encountered a showstopper.
Following. My panel consists of two analog joysticks registered as separate game controllers with their own ids, then i have a central pcb exposing the controllers for possible 4 players including the buttons.
The main issue I face atm, is that I have everything wired up on the PCB for 2 players and it works, but
the pcb exposes two generic controllers with the same device id. This is registered in linux as
/dev/input/js0
and
/dev/input/js1
and also in separate event devices
/dev/input/event0
and
/dev/input/event1
The problem I face now is both seem to have the same vendor and device id, but are registered as separate controllers. I now try to map all of this into a generic controller with one analog stick and only one digital one (taking half of the connected pcb)
Now due to the same names device ids and vendor ids both pcb joysticks are taken into account. Resulting in the same events if I trigger for player 1 or 2.
(Player 2 triggers are unwanted)
Any idea how to resolve this?
A possible solution would be to restrict the incoming events to one joystick or one event node, but I cannot find a way how to do it.
I tried to filter out via uniq and the event ids and or js0 but to no result.
(I tried with the latest dev version because I ran into issues with the head, which were resolved by the current dev branch)
So I moved my configs and compiled binary to a nice place where all my computers would get it. Everything in this directory is world-readable, and it has to be in this case since I have a system user/group that MG runs as. The gendevices work just fine in this configuration. But moltengamepad.cfg, which is also world-readable, is silently ignored. A github search of the source code indicates that it should say that it's attempting to load the file, but I'm not getting that output. Even root of all users doesn't try to load it:
TiZLappy:~$ sudo /home/common/bin/moltengamepad -c /home/common/confdata/moltengamepad
loading
driver: wiimote driver initialized.
driver: xpad-dt driver initialized.
driver: xpad-at driver initialized.
driver: playstation4-dt driver initialized.
driver: playstation4-at driver initialized.
driver: mayflash-ps2 driver initialized.
driver: dualshock3 driver initialized.
hotplug: device ps4_dt_1 added.
^CShutting down.
stopping udev thread
I did a github search of the locate function that is seemingly used to find the config file, and it looks like that function just doesn't respect the --config-path option, and only checks for the profile dir and the gendev dir. But I don't know your code, so I don't know if that means anything.
Motivation:
I have a 4 player game configured to use virtpadX for player X.
I start playing with 3 friends. We each press a button in turn on our physical controllers which causes the respective controller to be plugged into a virtpad slot.
Now the friend who is currently player 2 leaves (and takes his controller with him).
At this point we need to change our mapping from physical controllers to virtpads, so that we end up with virtpad1,...,virtpad3.
Currently I don't see how to achieve this with MoltenGamepad without getting up from the couch. What I would like to do is press Home+Start+Select on any controller to trigger the command "move all to nothing", thereby unplugging all controllers so that they will be replugged into the appropriate virtpad slots when we press buttons.
My idea to achieve this is to have an event translator
script("commands for MG daemon")
to be used like this:
gamepad.(start,select,home) = chord(unplug_all)
gamepad.unplug_all = script("move all to nothing")
The script should be able to contain multiple commands separated by ";" or something like that.
Side note: I don't know if button releases are considered "notable input" for the purpose of plugging. If they are, there would be the need for a delay to allow the start, home and select buttons to be released before unplugging the controllers, to avoid replugging the controller used to send the command immediately. So the script would turn into something like
gamepad.unplug_all = script("delay(500); move all to nothing")
The WiimoteGlue project that came before MG supported changing the wiimote LEDs to match their assigned output slot. It's time for MG to regain that.
This will require specialized drivers for each input source that supports this, as there really isn't a generic interface for setting controller LEDs.
In terms of API, pass each device a number to display. Leave it up to the driver to decide what LED pattern/color is appropriate.
In the future, possibly add a way to query a device for either an LED pattern or color, so that clients can display it...
With the addition of matching generic devices based on the events reported, we have what we might consider a low priority match. It is likely best to save this as a fallback in case all other matches fail.
When MoltenGamepad sees a device, it currently goes through each driver once letting them answer yes/no on whether they want to claim that device. The search stops at the first yes. There is not a way for a driver to say "yes, but only if no other driver wants it."
So the issue is two-fold:
The current way of enforcing priority is by the ordering of drivers in terms of when MoltenGamepad reads them. This can prove insufficient when we have two drivers that each wish to be a fallback while also superseding the other on specific matches. The current work around would be to duplicate both drivers, one for specific matching and one for fingerprinting.
I don't want to get in the mess of hardcoding heuristics on what matching criteria gets precedence, since each match line can contain different fields and different numbers of fields. It seems messy, and likely to be wrong for some use case some where down the road.
Some ideas:
priority=X
field to match lines, with the default being the strongest priority. This allows the event-fingerprinting lines to be given weaker priorities without requiring extra work on the other match lines. It adds some overhead to the config writer, as they now need to balance priority levels across files.I think that first idea is the best of those.
It would be nice to expand the available events a controller can send by using one button to modify the events sent by others. This would be an important feature, but it has a lot of semantics that need to be clarified.
Some feature requirements:
One nice feature: allow the modifier button to send a separate event only if no modified events were used.
Syntax goals:
wiimote.(home,wm_a,wm_b) = overlay( <event for wm_a>, <event for wm_b>)
driving
or meta
or what not.Current ideas
A profile should declare what layout shifts it intends to have prior to adding event mappings. This will also clean up any pre-existing layout shifts giving a clean slate (note: do not clean up the base unshifted mapping). Should this be treated as subfield, kinda like device options? Or should this get a dedicated command? What if the user wanted one layout shift to always be available, like a "meta" or "mediacontrol" layout shift? The name "default" should be reserved to refer to the base mapping.
wiimote.?layouts = driving,swimming,meta
Once declared, layouts shifts can be assigned to just like usual. Should we do this with just an extra dot? Perhaps slightly different syntax, like wiimote:driving.wm_a = ...
? Might want to protect against ambiguity...
wiimote.driving.wm_a = tr2
A layout starts empty, with each event just falling back to using the default base mapping. After being set, we need to give a way to reset a mapping back to this fallback state. We shouldn't use the nothing
mapping, as this should be reserved for actually sending no event. This is the syntax I'm most unhappy with.
wiimote.driving.wm_a = fall_back
Changing layouts is done via special event translators. This will allow good flexibility, with things like
wiimote.home = layout_shift("meta")
wiimote.home = layout_toggle("driving","swimming","default")
We could even do a group translation of modifier keys that elegantly gives the layout shift intended for every combination of modifiers. Think of "shift+alt" being different from "alt" and "shift".
Though we might end up with too much flexibility. Should we allow layout shifts to be chained? What if the "meta" layout had another button that acted as another layout shift? What if two layout shifts affect the same button, and the shifts are released in the opposite order?
Right now I'm leaning towards just implementing layouts as a stack, if the user somehow creates a config that leads to creating a layout stack a hundred deep, that's on them. Otherwise allowing independent shifts to occur at the same time seems like too much a hassle.
Should shifts also allow for device options to be different? If so, we'd need a better way to unset them back to the fall back state...
I'm trying to get my rejoy configurations ported over, and the program's radio silence is causing me a lot of trouble because I have no idea what's not working or even why. I know that I could use cout << thing << endl myself, but as I said in #16, I don't even know where to begin in regards to navigating this codebase. Or any non-trivial C++ codebase, really.
Anyways, the main thing I'd like to see in regards to a debug switch is as follows: any time a device is examined, all the things that could be used to match against it should be printed out. Its name. Vendor ID. Model ID. Driver. And maybe if you wanted to go this far, if a device fails a fingerprint match, the reason why should be printed out.
This is all I can think of right now.
Installed as systemuser. Everything works with "sudo moltengamepad". Udev rules appear to be non-functional (had to manually chmod uinput; previously was getting "open uinput: permission denied").
moltengamepad
No moltengamepad.cfg found.
driver: playstation4 driver initialized.
device hiding: changing permissions of /dev/input/event11 failed.
device hiding: changing permissions of /dev/input/js0 failed.
plug: ps4_1 added
stdin: ready to read commands from standard input. Try "help" for more info.
Edit: this appears to be issue with the fact that I'm in a chroot (crouton on a Chromebook). Any suggestions?
Hi,
I've followed the build and installation instructions for SingleUser as I'm running a Retropie install on OSMC (Rpi3). All appears to have been successful, apart from having to manually connect the controller each time through bluetoothctl
and the Wiimote's sync button.
Emulationstation detects the controller and I can configure all of the buttons. But i can't set up the analog axes. This I anticipated would come from the Wiimote accelerometers (I'm doing all this to let my daughter use a Wiimote and steering wheel for N64 MarioKart as her hands are too small for handling analog sticks on a joypad and the first thing she tried to do was intuitively steer by tilting the controller).
I tried to diagnose using jstest
from the commandline but that doesn't even register the button presses that are already proven to work, let alone the axes, so that's not been helpful at all.
So is tilt support actually a part of the driver? I wondered if it was a configuration issue, but I can't find any config files. The installer didn't create anything under ~/.config/
or in /etc/
as I was expecting so I can't see anything to be tweaked.
Many thanks.
Please consider this low priority. Like, so low that I kept thinking about fixing this but never got around to asking you how.
Recent kernels keep switching things up with the dualshocks. DS4s now show up as three separate devices! One for the accelerometers, one for the touchpad (which interacts with X by default; fun!), and one for the regular gamepad inputs. I'd like to be able to merge together the touchpad and regular inputs so that I can get back touchpad-as-select functionality. Is that currently possible? I know we have splitting; what about merging?
It's really no big deal if that's not feasible at the moment.
Hiya. I know it's been a while since I've contributed. I think I mentioned last time a bash daemon I had that starts xboxdrv on event devices and hides them. I actually have it on github right here. I wanted to just start using your project, but there is one problem I realized that caused me to go back to rejoy and tweak it. I'm no good at C++, it scares the crap out of me, so I couldn't just write the feature myself, sorry.
My laptop goes with me to Arcade Legacy where there are many many many many different kinds of controllers. The only kinds of controllers that tend to get introduced to my laptop are 360, PS3, and PS4 controllers, alongside the odd Mayflash PS2 to PC every once in a while. The problem is, if someone plugs in their controller and it doesn't work for any reason and/or I have to take time to configure it, it's an embarrassment to me and an embarrassment to Linux.
Names to match devices are a good start, it gets around the thing where multiple similar devices have different model IDs but the sane name, and that's good. But I feel we should be able to do better than that. If a friend plugs in a fight stick that fits a well-known event code layout but it fails to work just because its name hasn't been added to the appropriate gendevice profile, it's an embarrassing inconvenience. I came up with a way to automatically accommodate 99% of the controllers that my laptop will ever see with my script, and I'd like to pitch that method here for inclusion into this program so I can eventually stop using that particular bash monstrosity.
The first and maybe easiest thing to do is match on the device's driver. Anything using the xpad driver is always going to have the same button mapping no matter what, so rather than waiting for an xpad device not called "Microsoft X-Box 360 pad" to come out and cause trouble, we could just match the xpad driver and any device using that will use the same gendevice profile.
That fixes the easiest case, but other drivers don't have the same convention that xpad does, not even sony. The dualshock 3 and dualshock 4 have different mappings. However... they also expose different events. They have different "fingerprints". For example, the DS3's guide button maps to key 704, which doesn't exist on the DS4. To match based on fingerprint, I load a xboxdrv evdev config and see if the new joystick exposes events to match every event specified in that config. If not, move on until there is a match. So if I plug in a DS4, it first checks the DS3 config. The DS3 config calls for 704, which doesn't exist. So it moves onto DS4, and every event called for in the config does exist on that device, so it uses that config.
This can be used for hid-generic devices too--which a lot of fight sticks tend to use even when they're technically PS3 controllers--as well as those funky Mayflash adapters. I use the same strategy here. Mayflash's PS2 adapters use a different subset of event codes--a fairly exotic one at that--from PS3 fight sticks which use a more standard set of event codes. When a PS3 fight stick gets plugged in, it will first check the Mayflash config, fail that check, and move on to the PS3-on-generic config, succeed, and use that. This fingerprint strategy relies on trying the more exotic fingerprints first, which will usually fail pretty fast and will prevent false positives.
Is this something you would have interest in implementing, or at least not be opposed to having implemented? If I were to try and get over my fear of C++ to do it, I'm a bit lost in this maze of code. What files would I want to look at to figure this out?
Missing features:
When im using ~/Desktop/MoltenGamepad-master$ make
compiling source/core/eventlists/key_list.cpp...
source/core/eventlists/key_list.cpp:157:4: error: ‘KEY_ROTATE_DISPLAY’ was not declared in this scope
{KEY_ROTATE_DISPLAY, "key_rotate_display", ""},
^
source/core/eventlists/key_list.cpp:244:4: error: ‘KEY_BRIGHTNESS_AUTO’ was not declared in this scope
{KEY_BRIGHTNESS_AUTO, "key_brightness_auto", ""},
^
source/core/eventlists/key_list.cpp:403:4: error: ‘KEY_BRIGHTNESS_TOGGLE’ was not declared in this scope
{KEY_BRIGHTNESS_TOGGLE, "key_brightness_toggle", ""},
^
source/core/eventlists/key_list.cpp:462:4: error: ‘KEY_NUMERIC_A’ was not declared in this scope
{KEY_NUMERIC_A, "key_numeric_a", ""},
^
source/core/eventlists/key_list.cpp:463:4: error: ‘KEY_NUMERIC_B’ was not declared in this scope
{KEY_NUMERIC_B, "key_numeric_b", ""},
^
source/core/eventlists/key_list.cpp:464:4: error: ‘KEY_NUMERIC_C’ was not declared in this scope
{KEY_NUMERIC_C, "key_numeric_c", ""},
^
source/core/eventlists/key_list.cpp:465:4: error: ‘KEY_NUMERIC_D’ was not declared in this scope
{KEY_NUMERIC_D, "key_numeric_d", ""},
^
source/core/eventlists/key_list.cpp:486:4: error: ‘KEY_BUTTONCONFIG’ was not declared in this scope
{KEY_BUTTONCONFIG, "key_buttonconfig", ""},
^
source/core/eventlists/key_list.cpp:487:4: error: ‘KEY_TASKMANAGER’ was not declared in this scope
{KEY_TASKMANAGER, "key_taskmanager", ""},
^
source/core/eventlists/key_list.cpp:488:4: error: ‘KEY_JOURNAL’ was not declared in this scope
{KEY_JOURNAL, "key_journal", ""},
^
source/core/eventlists/key_list.cpp:489:4: error: ‘KEY_CONTROLPANEL’ was not declared in this scope
{KEY_CONTROLPANEL, "key_controlpanel", ""},
^
source/core/eventlists/key_list.cpp:490:4: error: ‘KEY_APPSELECT’ was not declared in this scope
{KEY_APPSELECT, "key_appselect", ""},
^
source/core/eventlists/key_list.cpp:491:4: error: ‘KEY_SCREENSAVER’ was not declared in this scope
{KEY_SCREENSAVER, "key_screensaver", ""},
^
source/core/eventlists/key_list.cpp:492:4: error: ‘KEY_VOICECOMMAND’ was not declared in this scope
{KEY_VOICECOMMAND, "key_voicecommand", ""},
^
source/core/eventlists/key_list.cpp:493:4: error: ‘KEY_BRIGHTNESS_MIN’ was not declared in this scope
{KEY_BRIGHTNESS_MIN, "key_brightness_min", ""},
^
source/core/eventlists/key_list.cpp:494:4: error: ‘KEY_KBDINPUTASSIST_PREV’ was not declared in this scope
{KEY_KBDINPUTASSIST_PREV, "key_kbdinputassist_prev", ""},
^
source/core/eventlists/key_list.cpp:495:4: error: ‘KEY_KBDINPUTASSIST_NEXT’ was not declared in this scope
{KEY_KBDINPUTASSIST_NEXT, "key_kbdinputassist_next", ""},
^
source/core/eventlists/key_list.cpp:496:4: error: ‘KEY_KBDINPUTASSIST_PREVGROUP’ was not declared in this scope
{KEY_KBDINPUTASSIST_PREVGROUP, "key_kbdinputassist_prevgroup", ""},
^
source/core/eventlists/key_list.cpp:497:4: error: ‘KEY_KBDINPUTASSIST_NEXTGROUP’ was not declared in this scope
{KEY_KBDINPUTASSIST_NEXTGROUP, "key_kbdinputassist_nextgroup", ""},
^
source/core/eventlists/key_list.cpp:498:4: error: ‘KEY_KBDINPUTASSIST_ACCEPT’ was not declared in this scope
{KEY_KBDINPUTASSIST_ACCEPT, "key_kbdinputassist_accept", ""},
^
source/core/eventlists/key_list.cpp:499:4: error: ‘KEY_KBDINPUTASSIST_CANCEL’ was not declared in this scope
{KEY_KBDINPUTASSIST_CANCEL, "key_kbdinputassist_cancel", ""},
^
source/core/eventlists/key_list.cpp:500:4: error: ‘KEY_RIGHT_UP’ was not declared in this scope
{KEY_RIGHT_UP, "key_right_up", ""},
^
source/core/eventlists/key_list.cpp:501:4: error: ‘KEY_RIGHT_DOWN’ was not declared in this scope
{KEY_RIGHT_DOWN, "key_right_down", ""},
^
source/core/eventlists/key_list.cpp:502:4: error: ‘KEY_LEFT_UP’ was not declared in this scope
{KEY_LEFT_UP, "key_left_up", ""},
^
source/core/eventlists/key_list.cpp:503:4: error: ‘KEY_LEFT_DOWN’ was not declared in this scope
{KEY_LEFT_DOWN, "key_left_down", ""},
^
source/core/eventlists/key_list.cpp:504:4: error: ‘KEY_ROOT_MENU’ was not declared in this scope
{KEY_ROOT_MENU, "key_root_menu", ""},
^
source/core/eventlists/key_list.cpp:505:4: error: ‘KEY_MEDIA_TOP_MENU’ was not declared in this scope
{KEY_MEDIA_TOP_MENU, "key_media_top_menu", ""},
^
source/core/eventlists/key_list.cpp:506:4: error: ‘KEY_NUMERIC_11’ was not declared in this scope
{KEY_NUMERIC_11, "key_numeric_11", ""},
^
source/core/eventlists/key_list.cpp:507:4: error: ‘KEY_NUMERIC_12’ was not declared in this scope
{KEY_NUMERIC_12, "key_numeric_12", ""},
^
source/core/eventlists/key_list.cpp:508:4: error: ‘KEY_AUDIO_DESC’ was not declared in this scope
{KEY_AUDIO_DESC, "key_audio_desc", ""},
^
source/core/eventlists/key_list.cpp:509:4: error: ‘KEY_3D_MODE’ was not declared in this scope
{KEY_3D_MODE, "key_3d_mode", ""},
^
source/core/eventlists/key_list.cpp:510:4: error: ‘KEY_NEXT_FAVORITE’ was not declared in this scope
{KEY_NEXT_FAVORITE, "key_next_favorite", ""},
^
source/core/eventlists/key_list.cpp:511:4: error: ‘KEY_STOP_RECORD’ was not declared in this scope
{KEY_STOP_RECORD, "key_stop_record", ""},
^
source/core/eventlists/key_list.cpp:512:4: error: ‘KEY_PAUSE_RECORD’ was not declared in this scope
{KEY_PAUSE_RECORD, "key_pause_record", ""},
^
source/core/eventlists/key_list.cpp:513:4: error: ‘KEY_VOD’ was not declared in this scope
{KEY_VOD, "key_vod", ""},
^
source/core/eventlists/key_list.cpp:514:4: error: ‘KEY_UNMUTE’ was not declared in this scope
{KEY_UNMUTE, "key_unmute", ""},
^
source/core/eventlists/key_list.cpp:515:4: error: ‘KEY_FASTREVERSE’ was not declared in this scope
{KEY_FASTREVERSE, "key_fastreverse", ""},
^
source/core/eventlists/key_list.cpp:516:4: error: ‘KEY_SLOWREVERSE’ was not declared in this scope
{KEY_SLOWREVERSE, "key_slowreverse", ""},
^
source/core/eventlists/key_list.cpp:517:4: error: ‘KEY_DATA’ was not declared in this scope
{KEY_DATA, "key_data", ""},
^
make: *** [source/core/eventlists/key_list.o] Error
1
how can i solve it?
Title says it all, atm the device mathiching is rather rigid, it only allows a fixed match however some ids might change over multiple machines or if you plug into another usb port.
A more flexible maybe regexped based device matching would allow to resolve those issues.
Also I noticed a sysfs match atm is not possible.
Hello, I was trying to set up your program to work with RetroPie, and I've run into a compiler problem. I'm really not familiar with C++, so sorry if this is something trivial!
While make is running on moltengamepad.cpp, it throws a bunch of errors similar to:
/source/moltengamepad.cpp:180:1: error: could not convert {"num_gamepads", "Number of virtual gamepads to create", "4", MG_INT} from to option_info
};
^
This continues for the rest of the lines in const option_info general_options[]
, which you'll forgive me if I don't retype! Is there a straight-forward way to correct this?
Hi guys, I'm still testing MoltenGamepad, not so frequently as I should cause I'm having a lot of personal problems and Brazil is not in the best financial days... anyway... I tried a version from Ryochan archive, which worked very good considering how response it's to the relative mouse input, but there is a little bug(tested only on my Xubuntu) which makes my mouse pointer go slowly to the top left corner all the time...
there is his archive if you guys wanna test it:
https://drive.google.com/open?id=0B6yGHDx0CFzDakR3SzJHLW1VUjg
Back to the compile issue, I just can not compile MoltenGamepad on Arch Linux anymore(which is strange cause it compiles fine on Xubuntu), the output is always the same:
make
compiling source/core/output_slot.cpp...
In file included from source/core/output_slot.cpp:1:0:
source/core/output_slot.h:35:29: error: ‘std::function’ has not been declared
void for_all_devices(std::function<void (std::shared_ptr<input_source>&)> func);
^~~~~~~~
source/core/output_slot.h:35:37: error: expected ‘,’ or ‘...’ before ‘<’ token
void for_all_devices(std::function<void (std::shared_ptr<input_source>&)> func);
^
make: *** [Makefile:60: source/core/output_slot.o] Error 1
If you guys want to take a look...
Hi,
I recently did a clean install of kubuntu 17.04 and I'm unable to get mg working properly with my dualshock 4 ever since.
All the files are in place, I compiled a fresh new build, and ran the systemuser install script.
Running evtest returns
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event16: Microsoft X-Box 360 pad
Selecting the device event 16 returns
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x45e product 0x28e version 0x110
Input device name: "Microsoft X-Box 360 pad"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 304 (BTN_SOUTH)
Event code 305 (BTN_EAST)
Event code 307 (BTN_NORTH)
Event code 308 (BTN_WEST)
Event code 310 (BTN_TL)
Event code 311 (BTN_TR)
Event code 314 (BTN_SELECT)
Event code 315 (BTN_START)
Event code 316 (BTN_MODE)
Event code 317 (BTN_THUMBL)
Event code 318 (BTN_THUMBR)
Event type 3 (EV_ABS)
Event code 0 (ABS_X)
Value 0
Min -32768
Max 32767
Flat 1024
Event code 1 (ABS_Y)
Value 0
Min -32768
Max 32767
Flat 1024
Event code 2 (ABS_Z)
Value 0
Min 0
Max 255
Event code 3 (ABS_RX)
Value 0
Min -32768
Max 32767
Flat 1024
Event code 4 (ABS_RY)
Value 0
Min -32768
Max 32767
Flat 1024
Event code 5 (ABS_RZ)
Value 0
Min 0
Max 255
Event code 16 (ABS_HAT0X)
Value 0
Min -1
Max 1
Event code 17 (ABS_HAT0Y)
Value 0
Min -1
Max 1
Event type 21 (EV_FF)
Event code 80 (FF_RUMBLE)
Properties:
Testing ... (interrupt to exit)
... but it doesn't pick up any input.
If I stop the service and launch moltengamepad as a process, it returns
loading /system/config/moltengamepad/moltengamepad.cfg
open uinput: Permission denied
No uinput node available.
Shutting down.
if I run it normally and
warning: Running MoltenGamepad as root is not recommended. Instead, please run as a non-superuser that has been granted the appropriate permissions.
loading /system/config/moltengamepad/moltengamepad.cfg
driver: dualshock4 driver initialized.
stdin: ready to read commands from standard input. Try "help" for more info
if I run it as root.
I'm using the Dualshock 4 driver file from https://github.com/jgeumlek/MoltenGamepad/blob/master/documentation/gendev.md
So i installed MoltenGamepad and used the installation script for "systemuser".
The service works fine , but the system still sees the physical controller.
My Setup:
Version: retropie 4.3
Udev: 215
controller: joycons
I followed the instructions to comment out the correct line in /lib/udev/rules.d/70-uaccess.rules
#SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess"
Also the compiled moltengamepad is placed in /usr/local/bin/moltengamepad.
I am wondering if i need to comment out some more lines in /liv/udev/rules.d ?
Following files exist in this folder by default in retropie 4.3
10-local-rpi.rules
15-i2c-modprobe.rules
15-rfkill.rules
40-usb_modeswitch.rules
42-usb-hid-pm.rules
50-bluetooth-hci-auto-poweron.rules
50-firmware.rules
50-udev-default.rules
55-dm.rules
60-cdrom_id.rules
60-crda.rules
60-drm.rules
60-fuse.rules
60-gnupg.rules
60-inputattach.rules
60-joystick.rules
60-keyboard.rules
60-persistent-alsa.rules
60-persistent-input.rules
60-persistent-serial.rules
60-persistent-storage-dm.rules
60-persistent-storage.rules
60-persistent-storage-tape.rules
60-persistent-v4l.rules
60-triggerhappy.rules
61-accelerometer.rules
61-partuuid.rules
64-btrfs.rules
69-libmtp.rules
69-libmtp.rules
70-power-switch.rules
70-uaccess.rules
71-seat.rules
73-idrac.rules
73-seat-late.rules
75-net-description.rules
75-persistent-net-generator.rules
75-probe_mtd.rules
75-tty-description.rules
78-sound-card.rules
80-drivers.rules
80-net-setup-link.rules
80-networking.rules
85-hwclock.rules
85-regulatory.rules
90-alsa-restore.rules
rules.zip
90-usbmount.rules
95-udev-late.rules
97-hid2hci.rules
99-systemd.rules
I added those rules as a zip folder, also willing to search these myself, if someone tells me what to look for ;)
When i try to pair my joycons as "pair" or single nothing happens, still the physical devices are detected.
I could also provide more informations , i would like to be helping with this issue where i can.
I have a mini-keyboard with mouse pad (amazon link: https://www.amazon.com/gp/product/B071FT92F8/ref=oh_aui_detailpage_o02_s01?ie=UTF8&psc=1). I want to use this in my raspberry pi with retropie. The problem is that retropie's default mapping doesn't support the four keys on the top-right of the keyboard (volume up, volume down, homepage, and compose).
I ahve MoltenGamepad installed in my raspberry pi working with a wiimote. I would like to know if there is a way to make a gendevices .cfg file to map the keyboard and mouse events to a virtual gamepad.
Any help will be greatly appreciated.
Thanks!
Hi,
I just upgraded to v1.1. I'm forced to run MoltenGamepad as root, since I cannot get the udev rule to work properly. I'd like to get that fixed since I would like to integrate MoltenGamepad in my gaming frontend.
Whenever I try to run /installation/systemuser/install.sh, the error 'rmmod: ERROR: Module uinput is builtin.
' is returned, despite commenting it out (line 23), as described in the previous issue (I'm on Kubuntu 16.10)
What am I doing wrong?
Hi there. I'm working on a profile that will allow me to control various system events (screenshot, media controls, volume, etc) from my gamepad by holding the mode button--which no game uses anyways--and then pressing another button. I don't want any underlying apps to see the underlying face button though if I'm doing it as a mode chord.
Documentation indicates that the exclusive chord is what I want. When I made my profile, it didn't seem to be working. Then I switched it to chord and it was working, but the underlying event was visible. I switched back to exclusive and remembered some specific wording from the document: "all involved buttons must be pressed down at the same time". So I mashed mode+primary a few times until I happened to get it perfectly simultaneously, and the target event did go off. In addition, the underlying components did not go off. (Although I did set mode to nothing to prevent it from doing anything by itself anyways)
This is kind of way too hard to use practically. I play fighting games and I don't even have timing that good. I can't use chord, because I don't want to make my character do stuff when I just need to change tracks. Is there anything that can be done about this?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.