Git Product home page Git Product logo

uiohook-napi's People

Contributors

hsource avatar lmk123 avatar noahandrews avatar snosme avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

uiohook-napi's Issues

Crash when used together with Electron

Hello, thanks for the package.

It works great except for one condition when it is used together with Electron (v21.0.0 tested). On macOS, if the user has not granted the application the Accessibility permission then the application crashes when you call uIOhook.start().

I created an Electron Fiddle to make it easy for you to reproduce: https://gist.github.com/stefansundin/937b9b20b28d58bc4d3ff05157d412c5

I included the full crash log in the gist above (scroll to the bottom), but here's the important part:

Thread 0 Crashed:: CrBrowserMain Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib                 0x19cdced98 __pthread_kill + 8
1   libsystem_pthread.dylib                0x19ce03ee0 pthread_kill + 288
2   libsystem_c.dylib                      0x19cd3e340 abort + 168
3   Electron Framework                     0x10c74019c uv_mutex_destroy + 28
4   uiohook_napi.node                      0x104f51d4c uiohook_worker_start + 148
5   uiohook_napi.node                      0x104f51438 AddonStart + 264
6   Electron Framework                     0x11247604c napi_is_detached_arraybuffer + 296
7   Electron Framework                     0x10d586af8 v8::internal::Accessors::MakeAccessor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Name>, void (*)(v8::Local<v8::Name>, v8::PropertyCallbackInfo<v8::Value> const&), void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&)) + 15136
8   Electron Framework                     0x10d586688 v8::internal::Accessors::MakeAccessor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Name>, void (*)(v8::Local<v8::Name>, v8::PropertyCallbackInfo<v8::Value> const&), void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&)) + 14000
9   Electron Framework                     0x10d585b40 v8::internal::Accessors::MakeAccessor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Name>, void (*)(v8::Local<v8::Name>, v8::PropertyCallbackInfo<v8::Value> const&), void (*)(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&)) + 11112

If you run the application from the terminal then it is the terminal app's permission that takes effect. So if you've already given it accessibility permissions then you may have to revoke that in System Preferences -> Security & Privacy to trigger the crash.

Before the crash this is printed:

hook_run [1407]: Accessibility API is disabled!

The prompt to grant accessibility permissions is shown as expected (see screenshot below), followed immediately by the crash. When run through Electron Fiddle the macOS crash reporter isn't shown.

Screen Shot 2022-09-28 at 15 01 52

The crash is happening on this line:

uv_mutex_destroy(&hook_running_mutex);

I tried commenting that out and it prevents the crash, but of course there may be a memory leak created in that case.

Would love to hear if you have any ideas on how to safely address this problem. Thank you!

Versions: uiohook-napi v1.5.0, Electron v21.0.0, node.js v16.17.0

crashes on latest version of ubuntu and fedora( linux based systems)

crashes on latest version of ubuntu and fedora( linux based systems)
throws below error on ubuntu 22.02 and fedora 39 before crashing in console:

hook_thread_proc [101]: Could not set thread priority 49 for thread 0x7FC90EC006C0!
FATAL ERROR: tsfn_to_js_proxy napi_call_function

Adding support for relative mouse movement

Hello, I noticed that the new feature of the libuiohook library is what I need. In the new feature, mouse monitoring can output relative positions, making it easier for the mouse to continue outputting offsets beyond the screen edge. However, this feature is not synchronized in your uiohook napi code. If possible, could you add this feature.

WechatIMG267

Electron No native build was found for platform=win32

Hey im glad this lib exists -

Im on a windows machine and trying to get it running on my electron app.
However i get the error :

`Uncaught Error: No native build was found for platform=win32 arch=x64 runtime=electron abi=113 uv=1 libc=glibc node=18.12.1 electron=23.3.10
loaded from: C:\repos\electron-vite-react-express-llm\node_modules\electron\dist\resources\electron.asar

at load.resolve.load.path (node-gyp-build.js:60:9)
at load (node-gyp-build.js:22:30)
at node_modules/uiohook-napi/dist/index.js (index.ts:3:27)
at __require2 (chunk-AUZ3RYOM.js?v=c42660a0:18:50)
at index.ts:270:39`

I tried to add a similar setup like in iohook to my package.json, but it didnt helped:

"uiohook-napi": { "targets": [ "electron-76" ], "platforms": [ "win32", "darwin", "linux" ], "arches": [ "x64", "ia32" ] },

What am i missing here :/

Macos 14.1 (23B74) don't work

a.mjs

import { uIOhook, UiohookKey } from 'uiohook-napi'
console.log('1')
uIOhook.on('keydown', (e) => {
  if (e.keycode === UiohookKey.Q) {
    console.log('Hello!')
  }

  if (e.keycode === UiohookKey.Escape) {
    process.exit(0)
  }
})

uIOhook.on('mousedown', (evt) => {
  console.log('mousedown')
  if (evt.button) {
    console.log('mousedown', evt.button)
  }
})

uIOhook.on('mouseup', (evt) => {
  console.log('mouseup')
  if (evt.button) {
    console.log('mouseup', evt.button)
  }
})

uIOhook.start()
console.log('2')
❯ node -v
v18.18.2
❯ node a.mjs
1
2

There is no output either by pressing the mouse button or by the keyboard

image

Missing keypress

Hi!

Thanks for working on this. One thing I'm missing from the original iohook implementation is the keypress event which contains a "keychar" property that allows to transform a keycode into its matching key. I tried using the UiohookKey import but it doesn't work with the / key for instance (52 vs 53).

Do you have any insight on this?

Support macOS arm64

When used on a Macbook M1, the following error is reported:

Error: No native build was found for platform=darwin arch=arm64 runtime=electron abi=103 uv=1 armv=8 libc=glibc node=16.13.2 electron=18.2.0 webpack=true

I hope you can provide the prebuild for macOS arm64, thanks.

An error is reported when exiting the electron application

macOS: 12.3.1 arm64
Electron: 18.2.0

I generated the prebuild on my own macOS arm64 computer and then tried to use it in my electron project in the main process, and when I quit the application, electron reported the following error:

FATAL ERROR: uiohook_to_js_event napi_define_properties
 1: 0x111e2e09c node::FatalException(v8::Isolate*, v8::TryCatch const&) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 2: 0x111e2e21c node::OnFatalError(char const*, char const*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 3: 0x111e2e0b4 node::OnFatalError(char const*, char const*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 4: 0x111de76d4 napi_open_callback_scope [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 5: 0x10bee9e90 tsfn_to_js_proxy [/Users/myproject/node_modules/uiohook-napi/prebuilds/darwin-arm64/node.napi.node]
 6: 0x10bee9ecc tsfn_to_js_proxy [/Users/myproject/node_modules/uiohook-napi/prebuilds/darwin-arm64/node.napi.node]
 7: 0x111de9f58 node_api_get_module_file_name [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 8: 0x10c4202dc uv_async_send [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 9: 0x10c4310d0 uv_free_interface_addresses [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
10: 0x10c4206f0 uv_run [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
11: 0x111dceffc node::EmitAsyncDestroy(node::Environment*, node::async_context) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
12: 0x111dcf330 node::EmitAsyncDestroy(node::Environment*, node::async_context) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
13: 0x111d9d274 node::FreeEnvironment(node::Environment*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
14: 0x10c506210 heap::base::Stack::SetStackStart(void const*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
15: 0x10c4f2820 v8::internal::compiler::RawMachineAssembler::TargetParameter() [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
16: 0x10dfc86c0 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
17: 0x10dfc9d4c v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
18: 0x10dfc61ac v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
19: 0x10c6a7bbc v8::internal::compiler::BasicBlock::set_loop_header(v8::internal::compiler::BasicBlock*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
20: 0x10c6a8bdc v8::internal::compiler::BasicBlock::set_loop_header(v8::internal::compiler::BasicBlock*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
21: 0x10c6a8778 v8::internal::compiler::BasicBlock::set_loop_header(v8::internal::compiler::BasicBlock*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
22: 0x10c6a7280 v8::internal::compiler::BasicBlock::set_loop_header(v8::internal::compiler::BasicBlock*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
23: 0x10c6a774c v8::internal::compiler::BasicBlock::set_loop_header(v8::internal::compiler::BasicBlock*) [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
24: 0x10c431688 ElectronMain [/Users/myproject/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
25: 0x10488d088 
/Users/myproject/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron exited with signal SIGABRT

iohook also has this problem, but I can fix it by uninstalling .node before exiting the app:

app.on('will-quit', () => {
  iohook.unload()
})

This problem can probably be solved by upgrading libuiohook to the latest version.

Issue building binary for darwin

This is the gyp file i modified for darwin -

{
    'targets': [{
            'target_name': 'uiohook_napi',
            'dependencies': ['libuiohook'],
            'sources': [
                'src/lib/addon.c',
                'src/lib/napi_helpers.c',
                'src/lib/uiohook_worker.c',
            ],
            'include_dirs': [
                'libuiohook/include',
                'src/lib',
            ]
        },
        {
            'target_name': 'libuiohook',
            'type': 'static_library',
            'sources': [
                'libuiohook/src/logger.c',
            ],
            'include_dirs': [
                'libuiohook/include',
                'libuiohook/src',
            ],
            "conditions": [
                ['OS=="darwin"', {
                    "defines": [
                        "__MACOSX_CORE__"
                    ],
                    "link_settings": {
                        "libraries": [
                            "-framework IOKit",
                            "-framework Carbon",
                            "-framework CoreFoundation"
                        ],
                    },
                    'sources': [
                        "libuiohook/src/darwin/input_helper.c",
                        "libuiohook/src/darwin/input_hook.c",
                        "libuiohook/src/darwin/post_event.c",
                        "libuiohook/src/darwin/system_properties.c"
                    ],
                    'include_dirs': [
                        'libuiohook/src/darwin'
                    ]
                }],
                ['OS=="win"', {
                    'sources': [
                        'libuiohook/src/windows/input_helper.c',
                        'libuiohook/src/windows/input_hook.c',
                        'libuiohook/src/windows/post_event.c',
                        'libuiohook/src/windows/system_properties.c'
                    ],
                    'include_dirs': [
                        'libuiohook/src/windows'
                    ]
                }],
                ['OS=="linux"', {
                    'defines': [
                        'USE_XRANDR', 'USE_EVDEV', 'USE_XT'
                    ],
                    'link_settings': {
                        'libraries': [
                            '-lX11', '-lXrandr', '-lXtst', '-lpthread', '-lXt'
                        ],
                    },
                    'cflags': ['-std=c99', '-pedantic', '-Wall', '-pthread'],
                    'sources': [
                        'libuiohook/src/x11/input_helper.c',
                        'libuiohook/src/x11/input_hook.c',
                        'libuiohook/src/x11/post_event.c',
                        'libuiohook/src/x11/system_properties.c'
                    ],
                    'include_dirs': [
                        'libuiohook/src/x11'
                    ]
                }]
            ]
        }
    ]
}

Its getting compiled fine. But, when i import it and run , it throws the following error -

_### **_dyld: lazy symbol binding failed: Symbol not found: _hook_set_dispatch_proc
  Referenced from: /Users/mahadityakaushik/crewscaleagent/electron-dist/electron-darwin-x64-napi.node
  Expected in: flat namespace

dyld: Symbol not found: _hook_set_dispatch_proc
  Referenced from: /Users/mahadityakaushik/crewscaleagent/electron-dist/electron-darwin-x64-napi.node
  Expected in: flat namespace_**_

I am not able to figure out, which library linking am i missing here. Btw it works very well with linux. Kudos

With Electron, title bar menu is not responsive when clicked

Thanks for maintaining this project! I am using this project with electron. I found a problem:

when started listening (uIOhook.start();), right-clicking on the title bar, the click on the menu content will most likely not respond.

Is anyone else experiencing the same problem?

_hook_set_dispatch_proc

dyld: Symbol not found: _hook_set_dispatch_proc
  Referenced from: /node_modules/uiohook-napi/build/Release/uiohook_napi.node
  Expected in: flat namespace

Everything working fine in Linux and windows this happens only macOs

Add the function of displaying mouse status

thanks for a great lib.
Is it possible to add a display of the mouse state to the interface UiohookMouseEvent? For example, normal select, text select, unavailable, etc.
Just this mouse state, as shown in the picture.
image

Keyboard layout ? - current US

Thank you for this package, which so far works great.

I wonder if you have any suggestion to get the correct keycode char based on physical layout ?

I'm on a "azerty" and the current results are qwerty on event.

Thanks a lot

Can not find module "uiohook-napi" after installation .exe

I am using electron forge with webpack and typescript, uiohook-napi is working properly in my development platform. Compiling the program is also working. But when I tried to install the .exe file this error is appearing.

Capture

My enviroment

uiohook-napi Version: ^1.5.3
Environment name and version: nodejs 20.9.0, electron: 29.1.5, electron-forge: ^7.3.1
Operating System and version: win32 x64

Touch support

Is touch event planned to be supported anytime soon?

Mac OS issues with keyboard lags

In the latest version of poe-trade I have started to see keyboard/mouse lags issues outside the game.
Seems like there are some lags in macros processing.

On the console I see a some

hook_event_proc [991]: CGEventTap timeout!
hook_event_proc [991]: CGEventTap timeout!
hook_event_proc [991]: CGEventTap timeout!

Issues disappeared when I reverted uiohook-napi to 1.5.2.

Right Alt seems to be replaced with Alt on tap / toggle

Hi, thanks for a great lib.

I have one problem - when I send a right alt key, the lib seems to ignore the distinction between left and right alt and treat it as the same key (left alt). That's a problem, because it makes it impossible to type some special characters that work only with the right alt.

Am I missing something?

Example:

uIOhook.keyToggle(UiohookKey.AltRight, "down");
uIOhook.keyTap(UiohookKey[5]);
uIOhook.keyToggle(UiohookKey.AltRight, "up");

Should type a sign, but instead triggers whatever is assigned to LeftAlt+5 (for example, goes to the fifth the tab in a browser).

Please let me know if there is a way to achieve that in the current version.

The Enter key is getting reported incorrectly on Windows

Enter on my Windows computer is reported with code 0xE1C (NumpadEnter, see #44) instead of 28.

I was going to submit this as a bug report to uiohook directly, but I see we're patching the library, and it's plausible that could have introduced this bug.

platform=win32 arch=ia32

No native build was found for platform=win32 arch=ia32 runtime=electron abi=103 uv=1 libc=glibc node=16.13.2 electron=18.2.3

App threw an error during load When I use electron-forge create a templates=webpack electron project

It's right run when I use electron-forge create a normal electron project. But if I use templates=webpack or templates=webpack-typescript to create an electron project, it's will be abnormal when I use yarn start to run the project. This screenshot show the error: Error: No native build was found for platform=darwin arch=x64 runtime=electron abi=110 uv=1 libc=glibc node=16.17.1 electron=22.0.0 webpack=true;
image

Freezes after one key, mouse Input

In the simplest form of
`const { uIOhook, UiohookKey } = require("uiohook-napi");

uIOhook.on("keydown", (e) => {
if (e.keycode === UiohookKey.Q) {
console.log("Hello!");
}

if (e.keycode === UiohookKey.Escape) {
process.exit(0);
}
});

uIOhook.start();
`

The application lib is still running but after getting one key and outputting "hello" it stops working without an error message.

Mac OS ARM 12.5.1 strangely two months ago it worked without any problems but tested now back to version 1.3 and it still doesn't work. Not sure how to debug this since no output or sigterm but will try to look if I find something and close the ticket if it is only a problem occurring on my device

Event timestamp

I need to record mouse movement with high precision in terms of "when" mouse movement occured

use case - rendering smooth cursor movement over screen recording video. This means even slight screen-recording-video<>mouse-data time mismatch is clearly visible

Seems that events triggered by the lib do not include time when event occurred. Eg event.timestamp

I can of course include Date.now in my event handler, but it will be date at the moment when I handle the event, not the time when event actually occured (eg system picked mouse move). As JS is single threaded - delay between event and my code handling it might vary a lot. (In my case more than 1/60s delay can already "ruin" it)

Do you think it is possible to include such information or do you have some tips how can I captures timestamp of mouse movements as precisely as possible?

linux-arm64 prebuild is actually x64

It seems like in 1.5.2 and 1.5.4 the linux-arm64 prebuild is actually an x64 build, see below:

file /Users/pierr3/Code/<project>/node_modules/uiohook-napi/prebuilds/linux-arm64/node.napi.node 

/Users/pierre/Code/<project>/node_modules/uiohook-napi/prebuilds/linux-arm64/node.napi.node: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=6c04c7bb612fb941debc40d351c61fcc24bdfe63, not stripped
 

Don't work with active window

If I make the window inactive, it works without problems.
However, if I make the window active, it is as if it stops working

uIOhook.on('keydown', (e) => {
    if (e.keycode === UiohookKey.T) {
      if(!isPressed) isPressed = true;
      else if(isPressed) return;
      mainWindow.webContents.send('responseAudioButton', true);
      console.log('[DBG KEY]: SEND PRESSED!')

    }
  })
  uIOhook.on('keyup', (e) => {
    if (e.keycode === UiohookKey.T) {
      if(isPressed) isPressed = false;
      else if(!isPressed) return;
      mainWindow.webContents.send('responseAudioButton', false);
      console.log('[DBG KEY]: SEND UNPRESSED!')
    }
  })

  uIOhook.start()

keyToggle only keep some keys pressed.

Hey,
good work on this, but I'm a bit confused on something, the keytoggle function set to toggle down only seems to hold some keys pressed. When tested with "Shift" it holds the key down and as expected any typed letter is uppercased while its toggled down. But with letter such as "a" it only outputs one "a" and nothing more, when the expected behavior (for me) is that will keep outputting "a" until it toggles up.

Is this a error or intended behavior?

Update: Okay interesting, done some more testing, in game it seems to recognize that any key is pressed down, but any text editor or text field only type a single characters.

Update 2: Though it would be also worth mentioning that the keyTap function don't seems to be picked up in most games, while the toggle does. But it is picked up in text editors and textboxes.

[Feature request] gamepads support?

Thank you very much for maintaining this library. I have used it in my project and it works fine.

But I found that this library does not handle gamepad events. Is it possible to support gamepad in the future?

Anyway to get multikey input?

Trying to send inputs to an Arduino board (remote car project with WASD keys) via bluetooth and using serialport library for that. I need to be able to detect multiple keys being pressed at once. E.g. WS pressed together. I assume an event should return something like an array of the inputs returned together that occurred at that time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.