├── .gitignore ├── Makefile ├── README.md ├── assets ├── clap.wav ├── grunt.wav ├── left_hit.wav ├── music.wav ├── ok.wav └── right_hit.wav ├── github └── screencap.png ├── inc ├── keyboard.h ├── main.h ├── mixer.h └── mouse.h └── src ├── keyboard.cpp ├── main.cpp ├── mixer.cpp └── mouse.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CPPFLAGS = -lSDL2 -lSDL2main -lSDL2_mixer 3 | 4 | main: src/*.cpp inc/*.h 5 | $(CXX) src/*.cpp $(CPPFLAGS) -o dkbongo_kbm 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Donkey Kong Bongo To Key 2 | 3 | ![](github/screencap.png) 4 | 5 | A keyboard & mouse interface for the Donkey Kong Bongos DOL-021 as seen in [The Title of this Video was Typed with Donkey Kong Bongos 6 | ](https://www.youtube.com/watch?v=ueZaTTSFU28) 7 | 8 | ## Requirements 9 | * Donkey Kong Bongos for GameCube 10 | * GameCube Controller Adapter to PC (Mayflash, ClouDream, etc.) 11 | * Alternatively: GameCube Controller Adapter to Wii U/Switch (Official Nintendo Adapter) + [GameCube Adapter Driver for PC](http://m4sv.com/page/wii-u-gcn-usb-driver) 12 | * Windows 10 13 | 14 | ## Use 15 | * Clap toggles between keyboard and mouse control 16 | #### Keyboard 17 | * Buttons 1 to 4 (sensors on the surface of the bongos) are assigned to digits 1 to 4, which are assigned to the base-4 representations of the virtual key codes 18 | * Start/Pause button toggles keys held down 19 | #### Mouse 20 | * Buttons 1 to 4 assigned to up/down/left/right mouse movement 21 | * Both left sensors held down at the same time assigned to left click 22 | * Both right sensors held down at the same time assigned to right click 23 | * Start/Pause button toggles mouse buttons held down -------------------------------------------------------------------------------- /assets/clap.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/assets/clap.wav -------------------------------------------------------------------------------- /assets/grunt.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/assets/grunt.wav -------------------------------------------------------------------------------- /assets/left_hit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/assets/left_hit.wav -------------------------------------------------------------------------------- /assets/music.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/assets/music.wav -------------------------------------------------------------------------------- /assets/ok.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/assets/ok.wav -------------------------------------------------------------------------------- /assets/right_hit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/assets/right_hit.wav -------------------------------------------------------------------------------- /github/screencap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/github/screencap.png -------------------------------------------------------------------------------- /inc/keyboard.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern unsigned int digit; 4 | 5 | int printKeyName(int key_code); 6 | void close_kb(); 7 | void kb_handleButtonEvent(SDL_Event event); -------------------------------------------------------------------------------- /inc/main.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevinjycui/DKBongoToKey/30fcb69abf8016f1cc9d1b84cf5552a91aaee37b/inc/main.h -------------------------------------------------------------------------------- /inc/mixer.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void initMixer(); 4 | 5 | int loadMusic(const char * filename, Mix_Music **gMusic); 6 | int loadSFX(const char * filename, Mix_Chunk **gSFX); -------------------------------------------------------------------------------- /inc/mouse.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void close_mouse(); 4 | void mouse_handleButtonEvent(SDL_Event event); 5 | void mouse_handleButtonUpEvent(SDL_Event event); 6 | void runMouseCommands(); -------------------------------------------------------------------------------- /src/keyboard.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../inc/keyboard.h" 7 | 8 | 9 | const int KEYEVENT_KEYUP = 0x02; 10 | 11 | unsigned int digit = 4; 12 | unsigned int value = 0; 13 | 14 | bool hold_k = false; 15 | std::vector holdqueue_k; 16 | 17 | int printKeyName(int key_code) 18 | { 19 | char key_name[1024]; 20 | UINT scanCode = MapVirtualKeyW(key_code, MAPVK_VK_TO_VSC); 21 | LONG lParamValue = (scanCode << 16); 22 | 23 | int rc = GetKeyNameText(lParamValue, key_name, 1024); 24 | if (rc) printf("%s\n", key_name); 25 | return rc; 26 | } 27 | 28 | void close_kb() 29 | { 30 | for (unsigned int key : holdqueue_k) 31 | keybd_event(key, 0, KEYEVENT_KEYUP, 0); 32 | holdqueue_k.clear(); 33 | } 34 | 35 | void kb_handleButtonEvent(SDL_Event event) 36 | { 37 | printf("%d", event.jbutton.button); 38 | if (event.jbutton.button == 9) { 39 | hold_k = !hold_k; 40 | if (!hold_k) { 41 | for (unsigned int key : holdqueue_k) 42 | keybd_event(key, 0, KEYEVENT_KEYUP, 0); 43 | holdqueue_k.clear(); 44 | } 45 | return; 46 | } 47 | digit--; 48 | value += event.jbutton.button * pow(4, digit); 49 | if (digit == 0) { 50 | printf("\n"); 51 | if (printKeyName(value)) { 52 | keybd_event(value, 0, 0, 0); 53 | if (!hold_k) 54 | keybd_event(value, 0, KEYEVENT_KEYUP, 0); 55 | else 56 | holdqueue_k.push_back(value); 57 | } 58 | else printf("Invalid keycode\n"); 59 | digit = 4; 60 | value = 0; 61 | if (hold_k) printf("(hold)"); 62 | printf("> "); 63 | } 64 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #define SDL_MAIN_HANDLED 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../inc/main.h" 10 | #include "../inc/keyboard.h" 11 | #include "../inc/mouse.h" 12 | #include "../inc/mixer.h" 13 | 14 | 15 | Mix_Music *gMusic = NULL; 16 | Mix_Chunk *gSFXs[5] = { NULL }; 17 | 18 | std::time_t exitPressed; 19 | 20 | int main(int argc, char ** argv) 21 | { 22 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0) 23 | { 24 | fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); 25 | exit(2); 26 | } 27 | 28 | initMixer(); 29 | 30 | if (loadMusic("assets/music.wav", &gMusic) != 0) { 31 | printf("Failed to load music\n"); 32 | exit(2); 33 | } 34 | 35 | if (loadSFX("assets/left_hit.wav", &gSFXs[0]) < 0 || 36 | loadSFX("assets/right_hit.wav", &gSFXs[1]) < 0 || 37 | loadSFX("assets/ok.wav", &gSFXs[2]) < 0 || 38 | loadSFX("assets/clap.wav", &gSFXs[3]) < 0 || 39 | loadSFX("assets/grunt.wav", &gSFXs[4]) < 0) { 40 | printf("Failed to load sound effects\n"); 41 | exit(2); 42 | } 43 | 44 | printf("%i joysticks were found.\n\n", SDL_NumJoysticks()); 45 | printf("The names of the joysticks are:\n"); 46 | 47 | for(int i=0; i < SDL_NumJoysticks(); i++) 48 | printf("\t%d %s\n", i, SDL_JoystickName(SDL_JoystickOpen(i))); 49 | 50 | printf("\n\n=== START INPUT ===\n\n> "); 51 | 52 | SDL_Event event; 53 | 54 | bool runstate = true; 55 | int prevAxisValue = 5000; 56 | 57 | bool kbMouseState = true; 58 | 59 | // if (Mix_PlayMusic(gMusic, -1) < 0) fprintf(stderr, "Error playing music: %s\n", Mix_GetError()); 60 | 61 | while (runstate) 62 | { 63 | while(SDL_PollEvent(&event)) 64 | { 65 | switch(event.type) 66 | { 67 | case SDL_JOYBUTTONDOWN: 68 | if (kbMouseState) 69 | kb_handleButtonEvent(event); 70 | else 71 | mouse_handleButtonEvent(event); 72 | 73 | if (event.jbutton.button == 9) { 74 | exitPressed = std::time(0); 75 | Mix_PlayChannel(-1, gSFXs[2], 0); 76 | } 77 | else if (Mix_PlayChannel(-1, gSFXs[event.jbutton.button < 2], 0) < 0) fprintf(stderr, "Error playing channel: %s\n", Mix_GetError()); 78 | break; 79 | case SDL_JOYBUTTONUP: 80 | if (!kbMouseState) mouse_handleButtonUpEvent(event); 81 | if (event.jbutton.button == 9 && std::time(0) - exitPressed >= 5) runstate = false; 82 | break; 83 | case SDL_JOYAXISMOTION: 84 | if (prevAxisValue != 5000 && event.jaxis.value - prevAxisValue > 20000) { 85 | printf("C"); 86 | if (!kbMouseState || digit == 4) { 87 | kbMouseState = !kbMouseState; 88 | if (Mix_PlayChannel(-1, gSFXs[3], 0) < 0) fprintf(stderr, "Error playing channel: %s\n", Mix_GetError()); 89 | } 90 | else if (Mix_PlayChannel(-1, gSFXs[4], 0) < 0) fprintf(stderr, "Error playing channel: %s\n", Mix_GetError()); 91 | } 92 | prevAxisValue = event.jaxis.value; 93 | break; 94 | } 95 | } 96 | 97 | if (!kbMouseState) runMouseCommands(); 98 | 99 | } 100 | 101 | close_kb(); 102 | close_mouse(); 103 | 104 | SDL_Quit(); 105 | 106 | printf("\nTerminated\n"); 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /src/mixer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../inc/mixer.h" 5 | 6 | void initMixer() 7 | { 8 | if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) { 9 | fprintf(stderr, "MIX_OpenAudio: %s\n", Mix_GetError()); 10 | exit(2); 11 | } 12 | } 13 | 14 | int loadMusic(const char * filename, Mix_Music **gMusic) 15 | { 16 | *gMusic = Mix_LoadMUS(filename); 17 | if (*gMusic == NULL) return 2; 18 | return 0; 19 | } 20 | 21 | int loadSFX(const char * filename, Mix_Chunk **gSFX) 22 | { 23 | *gSFX = Mix_LoadWAV(filename); 24 | if (*gSFX == NULL) return 2; 25 | return 0; 26 | } -------------------------------------------------------------------------------- /src/mouse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../inc/mouse.h" 7 | 8 | 9 | bool drumState[4] = { false }; 10 | bool drumClicked[4] = { false }; 11 | int drumMouseMapX[4] = {-16, 16, 0, 0}; 12 | int drumMouseMapY[4] = {0, 0, 16, -16}; 13 | 14 | bool hold_m = false; 15 | std::vector holdqueue_m; 16 | 17 | int move_mouse_relative(int x, int y) 18 | { 19 | POINT current; 20 | if (!GetCursorPos(¤t)) { 21 | fprintf(stderr, "Failed to get cursor position\n"); 22 | return 1; 23 | } 24 | if (!SetCursorPos(current.x + x, current.y + y)) { 25 | fprintf(stderr, "Failed to set cursor position\n"); 26 | return 1; 27 | } 28 | return 0; 29 | } 30 | 31 | int click_mouse(DWORD flag) 32 | { 33 | INPUT Input[1] = {0}; 34 | Input[0].type = INPUT_MOUSE; 35 | Input[0].mi.dwFlags = flag; 36 | if (!SendInput(1, Input, sizeof(INPUT))) { 37 | fprintf(stderr, "Failed to click mouse\n"); 38 | return 1; 39 | } 40 | return 0; 41 | } 42 | 43 | void close_mouse() 44 | { 45 | for (DWORD key : holdqueue_m) 46 | click_mouse(key); 47 | holdqueue_m.clear(); 48 | } 49 | 50 | void mouse_handleButtonEvent(SDL_Event event) 51 | { 52 | printf("%d", event.jbutton.button); 53 | if (event.jbutton.button == 9) { 54 | hold_m = !hold_m; 55 | if (!hold_m) { 56 | for (DWORD key : holdqueue_m) 57 | click_mouse(key); 58 | holdqueue_m.clear(); 59 | } 60 | return; 61 | } 62 | drumState[event.jbutton.button] = true; 63 | drumClicked[event.jbutton.button] = true; 64 | } 65 | 66 | void mouse_handleButtonUpEvent(SDL_Event event) 67 | { 68 | if (event.jbutton.button != 9) drumState[event.jbutton.button] = false; 69 | } 70 | 71 | void runMouseCommands() 72 | { 73 | DWORD value = 0; 74 | DWORD reverse = 0; 75 | bool action = false; 76 | if (drumState[0] && drumState[1] && drumState[2] && drumState[3]) { 77 | value = MOUSEEVENTF_MIDDLEDOWN; 78 | reverse = MOUSEEVENTF_MIDDLEUP; 79 | std::fill(drumState, drumState + 4, false); 80 | } 81 | else { 82 | if (drumState[0] && drumState[1]) { 83 | value = MOUSEEVENTF_RIGHTDOWN; 84 | reverse = MOUSEEVENTF_RIGHTUP; 85 | drumState[0] = drumState[1] = false; 86 | } 87 | if (drumState[2] && drumState[3]) { 88 | value = MOUSEEVENTF_LEFTDOWN; 89 | reverse = MOUSEEVENTF_LEFTUP; 90 | drumState[2] = drumState[3] = false; 91 | } 92 | } 93 | if (value) { 94 | click_mouse(value); 95 | if (!hold_m) 96 | click_mouse(reverse); 97 | else 98 | holdqueue_m.push_back(reverse); 99 | action = true; 100 | } 101 | for (int i=0; i<4; i++) 102 | if (drumState[i] && drumClicked[i]) { 103 | move_mouse_relative(drumMouseMapX[i], drumMouseMapY[i]); 104 | drumClicked[i] = false; 105 | action = true; 106 | } 107 | if (!action) return; 108 | printf("\n"); 109 | if (hold_m) printf("(hold)"); 110 | printf("> "); 111 | } --------------------------------------------------------------------------------