├── .gitignore ├── 3DS ├── 3DSController.ini ├── Makefile ├── cxi │ ├── banner.bnr │ ├── banner.png │ ├── build_cia.rsf │ ├── gw_workaround.rsf │ ├── icon.icn │ ├── icon24x24.png │ └── icon48x48.png ├── include │ ├── drawing.h │ ├── inet_pton.h │ ├── input.h │ ├── keyboard.h │ ├── settings.h │ └── wireless.h └── source │ ├── drawing.c │ ├── inet_pton.c │ ├── input.c │ ├── keyboard.c │ ├── main.c │ ├── settings.c │ └── wireless.c ├── Linux ├── 3DSController.py └── 3DSController_gamepad.py ├── PC ├── 3DSController.ini ├── Makefile ├── include │ ├── general.h │ ├── joystick.h │ ├── keyboard.h │ ├── keys.h │ ├── public.h │ ├── settings.h │ ├── vjoyinterface.h │ └── wireless.h ├── lib │ └── vJoyInterface.lib ├── source │ ├── general.c │ ├── joystick.c │ ├── keyboard.c │ ├── keys.c │ ├── main.c │ ├── settings.c │ └── wireless.c └── vJoyInterface.dll └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 3DS/build/ 2 | 3DS/*.elf 3 | 3DS/*stripped.elf 4 | 3DS/*.3dsx 5 | 3DS/*.smdh 6 | 3DS/*.3ds 7 | 3DS/*.cia 8 | PC/build/ 9 | PC/*.exe -------------------------------------------------------------------------------- /3DS/3DSController.ini: -------------------------------------------------------------------------------- 1 | Change the IP to be your PC's local IP, (run 3DSController.exe to find it), 2 | 3 | IP: 192.168.0.4 4 | Port: 8889 -------------------------------------------------------------------------------- /3DS/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITARM)/3ds_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # 19 | # NO_SMDH: if set to anything, no SMDH file is generated. 20 | # APP_TITLE is the name of the app stored in the SMDH file (Optional) 21 | # APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) 22 | # APP_AUTHOR is the author of the app stored in the SMDH file (Optional) 23 | # ICON is the filename of the icon (.png), relative to the project folder. 24 | # If not set, it attempts to use one of the following (in this order): 25 | # - .png 26 | # - icon.png 27 | # - /default_icon.png 28 | #--------------------------------------------------------------------------------- 29 | TARGET := 3DSController 30 | BUILD := build 31 | SOURCES := source 32 | DATA := data 33 | INCLUDES := include 34 | 35 | APP_TITLE := 3DS Controller 36 | APP_DESCRIPTION := 37 | APP_AUTHOR := CTurt 38 | ICON := cxi/icon48x48.png 39 | 40 | #--------------------------------------------------------------------------------- 41 | # options for code generation 42 | #--------------------------------------------------------------------------------- 43 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard 44 | 45 | CFLAGS := -g -Wall -O2 -mword-relocations \ 46 | -fomit-frame-pointer -ffast-math \ 47 | -fms-extensions \ 48 | $(ARCH) 49 | 50 | CFLAGS += $(INCLUDE) -DARM11 -D_3DS 51 | 52 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 53 | 54 | ASFLAGS := -g $(ARCH) 55 | LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 56 | 57 | LIBS := -lctru -lm 58 | 59 | #--------------------------------------------------------------------------------- 60 | # list of directories containing libraries, this must be the top level containing 61 | # include and lib 62 | #--------------------------------------------------------------------------------- 63 | LIBDIRS := $(CTRULIB) 64 | 65 | 66 | #--------------------------------------------------------------------------------- 67 | # no real need to edit anything past this point unless you need to add additional 68 | # rules for different file extensions 69 | #--------------------------------------------------------------------------------- 70 | ifneq ($(BUILD),$(notdir $(CURDIR))) 71 | #--------------------------------------------------------------------------------- 72 | 73 | export OUTPUT := $(CURDIR)/$(TARGET) 74 | export TOPDIR := $(CURDIR) 75 | 76 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 77 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 78 | 79 | export DEPSDIR := $(CURDIR)/$(BUILD) 80 | 81 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 82 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 83 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 84 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 85 | 86 | #--------------------------------------------------------------------------------- 87 | # use CXX for linking C++ projects, CC for standard C 88 | #--------------------------------------------------------------------------------- 89 | ifeq ($(strip $(CPPFILES)),) 90 | #--------------------------------------------------------------------------------- 91 | export LD := $(CC) 92 | #--------------------------------------------------------------------------------- 93 | else 94 | #--------------------------------------------------------------------------------- 95 | export LD := $(CXX) 96 | #--------------------------------------------------------------------------------- 97 | endif 98 | #--------------------------------------------------------------------------------- 99 | 100 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 101 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 102 | 103 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 104 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 105 | -I$(CURDIR)/$(BUILD) 106 | 107 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 108 | 109 | ifeq ($(strip $(ICON)),) 110 | icons := $(wildcard *.png) 111 | ifneq (,$(findstring $(TARGET).png,$(icons))) 112 | export APP_ICON := $(TOPDIR)/$(TARGET).png 113 | else 114 | ifneq (,$(findstring icon.png,$(icons))) 115 | export APP_ICON := $(TOPDIR)/icon.png 116 | endif 117 | endif 118 | else 119 | export APP_ICON := $(TOPDIR)/$(ICON) 120 | endif 121 | 122 | .PHONY: $(BUILD) clean all 123 | 124 | #--------------------------------------------------------------------------------- 125 | all: $(BUILD) 126 | 127 | $(BUILD): 128 | @[ -d $@ ] || mkdir -p $@ 129 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 130 | 131 | #--------------------------------------------------------------------------------- 132 | clean: 133 | @echo clean ... 134 | @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).3ds $(OUTPUT).cia $(OUTPUT).smdh $(TARGET).elf $(OUTPUT)stripped.elf 135 | 136 | 137 | #--------------------------------------------------------------------------------- 138 | else 139 | 140 | DEPENDS := $(OFILES:.o=.d) 141 | 142 | #--------------------------------------------------------------------------------- 143 | # main targets 144 | #--------------------------------------------------------------------------------- 145 | ifeq ($(strip $(NO_SMDH)),) 146 | .PHONY: all 147 | all : $(OUTPUT).3dsx $(OUTPUT).3ds $(OUTPUT).cia $(OUTPUT).smdh 148 | endif 149 | 150 | $(OUTPUT).3dsx : $(OUTPUT).elf 151 | 152 | $(OUTPUT).3ds : $(OUTPUT)stripped.elf 153 | makerom -f cci -o $(OUTPUT).3ds -rsf "$(TOPDIR)/cxi/gw_workaround.rsf" -target d -exefslogo -elf $(OUTPUT)stripped.elf -icon "$(TOPDIR)/cxi/icon.icn" -banner "$(TOPDIR)/cxi/banner.bnr" 154 | 155 | $(OUTPUT).cia : $(OUTPUT)stripped.elf 156 | makerom -f cia -o $(OUTPUT).cia -elf $(OUTPUT)stripped.elf -rsf "$(TOPDIR)/cxi/build_cia.rsf" -icon "$(TOPDIR)/cxi/icon.icn" -banner "$(TOPDIR)/cxi/banner.bnr" -exefslogo -target t 157 | 158 | $(OUTPUT).elf : $(OFILES) 159 | 160 | $(OUTPUT)stripped.elf : $(OUTPUT).elf 161 | cp -f $(OUTPUT).elf $(OUTPUT)stripped.elf 162 | @arm-none-eabi-strip $(OUTPUT)stripped.elf 163 | 164 | #--------------------------------------------------------------------------------- 165 | # you need a rule like this for each extension you use as binary data 166 | #--------------------------------------------------------------------------------- 167 | %.bin.o : %.bin 168 | #--------------------------------------------------------------------------------- 169 | @echo $(notdir $<) 170 | @$(bin2o) 171 | 172 | # WARNING: This is not the right way to do this! TODO: Do it right! 173 | #--------------------------------------------------------------------------------- 174 | %.vsh.o : %.vsh 175 | #--------------------------------------------------------------------------------- 176 | @echo $(notdir $<) 177 | @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin 178 | @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ 179 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h 180 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h 181 | @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h 182 | @rm ../$(notdir $<).shbin 183 | 184 | -include $(DEPENDS) 185 | 186 | #--------------------------------------------------------------------------------------- 187 | endif 188 | #--------------------------------------------------------------------------------------- 189 | -------------------------------------------------------------------------------- /3DS/cxi/banner.bnr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/3DSController/b38db7dcfcb8cd09acfef7654655658e498b19c7/3DS/cxi/banner.bnr -------------------------------------------------------------------------------- /3DS/cxi/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/3DSController/b38db7dcfcb8cd09acfef7654655658e498b19c7/3DS/cxi/banner.png -------------------------------------------------------------------------------- /3DS/cxi/build_cia.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "3DS Controller" 3 | CompanyCode : "00" 4 | ProductCode : "CTR-N-3DSC" 5 | ContentType : Application # Application / SystemUpdate / Manual / Child / Trial 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | RomFs: 9 | # Specifies the root path of the file system to include in the ROM. 10 | # HostRoot : "$(ROMFS_ROOT)" 11 | 12 | 13 | TitleInfo: 14 | UniqueId : 0xf0fc2 # This was/is the first real homebrew app. I hope this TID range is not used by any retail game/app. 15 | Category : Application # Application / SystemApplication / Applet / Firmware / Base / DlpChild / Demo / Contents / SystemContents / SharedContents / AddOnContents / Patch / AutoUpdateContents 16 | 17 | CardInfo: 18 | MediaSize : 512MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB 19 | MediaType : Card1 # Card1 / Card2 20 | CardDevice : NorFlash # NorFlash / None 21 | 22 | 23 | Option: 24 | UseOnSD : true # true if App is to be installed to SD 25 | EnableCompress : true # Compresses exefs code 26 | FreeProductCode : true # Removes limitations on ProductCode 27 | EnableCrypt : false # Enables encryption for NCCH and CIA 28 | MediaFootPadding : false # If true CCI files are created with padding 29 | 30 | AccessControlInfo: 31 | # UseOtherVariationSaveData : true 32 | # UseExtSaveData : true 33 | # ExtSaveDataId: 0xffffffff 34 | # SystemSaveDataId1: 0x220 35 | # SystemSaveDataId2: 0x00040010 36 | # OtherUserSaveDataId1: 0x220 37 | # OtherUserSaveDataId2: 0x330 38 | # OtherUserSaveDataId3: 0x440 39 | # UseExtendedSaveDataAccessControl: true 40 | # AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 41 | FileSystemAccess: 42 | # - CategorySystemApplication 43 | # - CategoryHardwareCheck 44 | # - CategoryFileSystemTool 45 | - Debug 46 | # - TwlCardBackup 47 | # - TwlNandData 48 | # - Boss 49 | - DirectSdmc 50 | # - Core 51 | # - CtrNandRo 52 | # - CtrNandRw 53 | # - CtrNandRoWrite 54 | # - CategorySystemSettings 55 | # - CardBoard 56 | # - ExportImportIvs 57 | # - DirectSdmcWrite 58 | # - SwitchCleanup 59 | # - SaveDataMove 60 | # - Shop 61 | # - Shell 62 | # - CategoryHomeMenu 63 | IoAccessControl: 64 | # - FsMountNand 65 | # - FsMountNandRoWrite 66 | # - FsMountTwln 67 | # - FsMountWnand 68 | # - FsMountCardSpi 69 | # - UseSdif3 70 | # - CreateSeed 71 | # - UseCardSpi 72 | 73 | IdealProcessor : 0 74 | AffinityMask : 1 75 | 76 | Priority : 16 77 | 78 | MaxCpu : 0x9E # Default 79 | 80 | DisableDebug : true 81 | EnableForceDebug : false 82 | CanWriteSharedPage : true 83 | CanUsePrivilegedPriority : false 84 | CanUseNonAlphabetAndNumber : true 85 | PermitMainFunctionArgument : true 86 | CanShareDeviceMemory : true 87 | RunnableOnSleep : false 88 | SpecialMemoryArrange : true 89 | 90 | CoreVersion : 2 91 | DescVersion : 2 92 | 93 | ReleaseKernelMajor : "02" 94 | ReleaseKernelMinor : "33" 95 | MemoryType : Application # Application / System / Base 96 | HandleTableSize: 512 97 | IORegisterMapping: 98 | - 1ff50000-1ff57fff 99 | - 1ff70000-1ff77fff 100 | MemoryMapping: 101 | - 1f000000-1f5fffff:r 102 | SystemCallAccess: 103 | ArbitrateAddress: 34 104 | Break: 60 105 | CancelTimer: 28 106 | ClearEvent: 25 107 | ClearTimer: 29 108 | CloseHandle: 35 109 | ConnectToPort: 45 110 | ControlMemory: 1 111 | CreateAddressArbiter: 33 112 | CreateEvent: 23 113 | CreateMemoryBlock: 30 114 | CreateMutex: 19 115 | CreateSemaphore: 21 116 | CreateThread: 8 117 | CreateTimer: 26 118 | DuplicateHandle: 39 119 | ExitProcess: 3 120 | ExitThread: 9 121 | GetCurrentProcessorNumber: 17 122 | GetHandleInfo: 41 123 | GetProcessId: 53 124 | GetProcessIdOfThread: 54 125 | GetProcessIdealProcessor: 6 126 | GetProcessInfo: 43 127 | GetResourceLimit: 56 128 | GetResourceLimitCurrentValues: 58 129 | GetResourceLimitLimitValues: 57 130 | GetSystemInfo: 42 131 | GetSystemTick: 40 132 | GetThreadContext: 59 133 | GetThreadId: 55 134 | GetThreadIdealProcessor: 15 135 | GetThreadInfo: 44 136 | GetThreadPriority: 11 137 | MapMemoryBlock: 31 138 | OutputDebugString: 61 139 | QueryMemory: 2 140 | ReleaseMutex: 20 141 | ReleaseSemaphore: 22 142 | SendSyncRequest1: 46 143 | SendSyncRequest2: 47 144 | SendSyncRequest3: 48 145 | SendSyncRequest4: 49 146 | SendSyncRequest: 50 147 | SetThreadPriority: 12 148 | SetTimer: 27 149 | SignalEvent: 24 150 | SleepThread: 10 151 | UnmapMemoryBlock: 32 152 | WaitSynchronization1: 36 153 | WaitSynchronizationN: 37 154 | InterruptNumbers: 155 | ServiceAccessControl: 156 | - APT:U 157 | - $hioFIO 158 | - $hostio0 159 | - $hostio1 160 | - ac:u 161 | - boss:U 162 | - cam:u 163 | - cecd:u 164 | - cfg:u 165 | - dlp:FKCL 166 | - dlp:SRVR 167 | - dsp::DSP 168 | - frd:u 169 | - fs:USER 170 | - gsp::Gpu 171 | - hid:USER 172 | - http:C 173 | - mic:u 174 | - ndm:u 175 | - news:u 176 | - nwm::UDS 177 | - ptm:u 178 | - pxi:dev 179 | - soc:U 180 | - ssl:C 181 | - y2r:u 182 | - ldr:ro 183 | - ir:USER 184 | - ir:u 185 | - ir:rst 186 | 187 | 188 | SystemControlInfo: 189 | SaveDataSize: 0KB # It doesn't use any save data. 190 | RemasterVersion: 2 191 | StackSize: 0x40000 192 | # JumpId: 0 193 | Dependency: 194 | ac: 0x0004013000002402L 195 | am: 0x0004013000001502L 196 | boss: 0x0004013000003402L 197 | camera: 0x0004013000001602L 198 | cecd: 0x0004013000002602L 199 | cfg: 0x0004013000001702L 200 | codec: 0x0004013000001802L 201 | csnd: 0x0004013000002702L 202 | dlp: 0x0004013000002802L 203 | dsp: 0x0004013000001a02L 204 | friends: 0x0004013000003202L 205 | gpio: 0x0004013000001b02L 206 | gsp: 0x0004013000001c02L 207 | hid: 0x0004013000001d02L 208 | http: 0x0004013000002902L 209 | i2c: 0x0004013000001e02L 210 | ir: 0x0004013000003302L 211 | mcu: 0x0004013000001f02L 212 | mic: 0x0004013000002002L 213 | ndm: 0x0004013000002b02L 214 | news: 0x0004013000003502L 215 | nim: 0x0004013000002c02L 216 | nwm: 0x0004013000002d02L 217 | pdn: 0x0004013000002102L 218 | ps: 0x0004013000003102L 219 | ptm: 0x0004013000002202L 220 | ro: 0x0004013000003702L 221 | socket: 0x0004013000002e02L 222 | spi: 0x0004013000002302L 223 | ssl: 0x0004013000002f02L 224 | -------------------------------------------------------------------------------- /3DS/cxi/gw_workaround.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "3DS Controller" 3 | CompanyCode : "00" 4 | ProductCode : "CTR-N-3DSC" 5 | ContentType : Application 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | RomFs: 9 | # Specifies the root path of the file system to include in the ROM. 10 | #HostRoot : "romfs" 11 | 12 | 13 | TitleInfo: 14 | UniqueId : 0xf0fc2 15 | Category : Application 16 | 17 | CardInfo: 18 | MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB 19 | MediaType : Card1 # Card1 / Card2 20 | CardDevice : NorFlash # NorFlash(Pick this if you use savedata) / None 21 | 22 | 23 | Option: 24 | FreeProductCode : true # Removes limitations on ProductCode 25 | MediaFootPadding : false # If true CCI files are created with padding 26 | EnableCrypt : true # Enables encryption for NCCH and CIA 27 | EnableCompress : true # Compresses exefs code 28 | 29 | AccessControlInfo: 30 | #UseExtSaveData : true 31 | #ExtSaveDataId: 0xff3ff 32 | #UseExtendedSaveDataAccessControl: true 33 | #AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 34 | 35 | SystemControlInfo: 36 | SaveDataSize: 128KB 37 | RemasterVersion: 0 38 | StackSize: 0x40000 39 | 40 | # DO NOT EDIT BELOW HERE OR PROGRAMS WILL NOT LAUNCH (most likely) 41 | 42 | AccessControlInfo: 43 | FileSystemAccess: 44 | - Debug 45 | - DirectSdmc 46 | - DirectSdmcWrite 47 | 48 | IdealProcessor : 0 49 | AffinityMask : 1 50 | 51 | Priority : 16 52 | 53 | MaxCpu : 0x9E # Default 54 | 55 | CoreVersion : 2 56 | DescVersion : 2 57 | 58 | ReleaseKernelMajor : "02" 59 | ReleaseKernelMinor : "33" 60 | MemoryType : Application 61 | HandleTableSize: 512 62 | IORegisterMapping: 63 | - 1ff50000-1ff57fff 64 | - 1ff70000-1ff77fff 65 | MemoryMapping: 66 | - 1f000000-1f5fffff:r 67 | SystemCallAccess: 68 | ArbitrateAddress: 34 69 | Break: 60 70 | CancelTimer: 28 71 | ClearEvent: 25 72 | ClearTimer: 29 73 | CloseHandle: 35 74 | ConnectToPort: 45 75 | ControlMemory: 1 76 | CreateAddressArbiter: 33 77 | CreateEvent: 23 78 | CreateMemoryBlock: 30 79 | CreateMutex: 19 80 | CreateSemaphore: 21 81 | CreateThread: 8 82 | CreateTimer: 26 83 | DuplicateHandle: 39 84 | ExitProcess: 3 85 | ExitThread: 9 86 | GetCurrentProcessorNumber: 17 87 | GetHandleInfo: 41 88 | GetProcessId: 53 89 | GetProcessIdOfThread: 54 90 | GetProcessIdealProcessor: 6 91 | GetProcessInfo: 43 92 | GetResourceLimit: 56 93 | GetResourceLimitCurrentValues: 58 94 | GetResourceLimitLimitValues: 57 95 | GetSystemInfo: 42 96 | GetSystemTick: 40 97 | GetThreadContext: 59 98 | GetThreadId: 55 99 | GetThreadIdealProcessor: 15 100 | GetThreadInfo: 44 101 | GetThreadPriority: 11 102 | MapMemoryBlock: 31 103 | OutputDebugString: 61 104 | QueryMemory: 2 105 | ReleaseMutex: 20 106 | ReleaseSemaphore: 22 107 | SendSyncRequest1: 46 108 | SendSyncRequest2: 47 109 | SendSyncRequest3: 48 110 | SendSyncRequest4: 49 111 | SendSyncRequest: 50 112 | SetThreadPriority: 12 113 | SetTimer: 27 114 | SignalEvent: 24 115 | SleepThread: 10 116 | UnmapMemoryBlock: 32 117 | WaitSynchronization1: 36 118 | WaitSynchronizationN: 37 119 | InterruptNumbers: 120 | ServiceAccessControl: 121 | - APT:U 122 | - $hioFIO 123 | - $hostio0 124 | - $hostio1 125 | - ac:u 126 | - boss:U 127 | - cam:u 128 | - cecd:u 129 | - cfg:u 130 | - dlp:FKCL 131 | - dlp:SRVR 132 | - dsp::DSP 133 | - frd:u 134 | - fs:USER 135 | - gsp::Gpu 136 | - hid:USER 137 | - http:C 138 | - mic:u 139 | - ndm:u 140 | - news:u 141 | - nwm::UDS 142 | - ptm:u 143 | - pxi:dev 144 | - soc:U 145 | - ssl:C 146 | - y2r:u 147 | - ldr:ro 148 | - ir:USER 149 | 150 | 151 | SystemControlInfo: 152 | Dependency: 153 | ac: 0x0004013000002402L 154 | am: 0x0004013000001502L 155 | boss: 0x0004013000003402L 156 | camera: 0x0004013000001602L 157 | cecd: 0x0004013000002602L 158 | cfg: 0x0004013000001702L 159 | codec: 0x0004013000001802L 160 | csnd: 0x0004013000002702L 161 | dlp: 0x0004013000002802L 162 | dsp: 0x0004013000001a02L 163 | friends: 0x0004013000003202L 164 | gpio: 0x0004013000001b02L 165 | gsp: 0x0004013000001c02L 166 | hid: 0x0004013000001d02L 167 | http: 0x0004013000002902L 168 | i2c: 0x0004013000001e02L 169 | ir: 0x0004013000003302L 170 | mcu: 0x0004013000001f02L 171 | mic: 0x0004013000002002L 172 | ndm: 0x0004013000002b02L 173 | news: 0x0004013000003502L 174 | nim: 0x0004013000002c02L 175 | nwm: 0x0004013000002d02L 176 | pdn: 0x0004013000002102L 177 | ps: 0x0004013000003102L 178 | ptm: 0x0004013000002202L 179 | ro: 0x0004013000003702L 180 | socket: 0x0004013000002e02L 181 | spi: 0x0004013000002302L 182 | ssl: 0x0004013000002f02L 183 | CommonHeaderKey: 184 | D: | 185 | jL2yO86eUQnYbXIrzgFVMm7FVze0LglZ2f5g+c42hWoEdnb5BOotaMQPBfqt 186 | aUyAEmzQPaoi/4l4V+hTJRXQfthVRqIEx27B84l8LA6Tl5Fy9PaQaQ+4yRfP 187 | g6ylH2l0EikrIVjy2uMlFgl0QJCrG+QGKHftxhaGCifdAwFNmiZuyJ/TmktZ 188 | 0RCb66lYcr2h/p2G7SnpKUliS9h9KnpmG+UEgVYQUK+4SCfByUa9PxYGpT0E 189 | nw1UcRz0gsBmdOqcgzwnAd9vVqgb42hVn6uQZyAl+j1RKiMWywZarazIR/k5 190 | Lmr4+groimSEa+3ajyoIho9WaWTDmFU3mkhA2tUDIQ== 191 | Exponent: | 192 | AQAB 193 | Modulus: | 194 | zwCcsyCgMkdlieCgQMVXA6X2jmb1ICjup0Q+jk/AydPkOgsx7I/MjUymFEkU 195 | vgXBtCKtzh3NKXtFFuW51tJ60GPOabLKuG0Qm5li+UXALrWhzWuvd5vv2FZI 196 | dTQCbrq/MFS/M02xNtwqzWiBjE/LwqIdbrDAAvX4HGy0ydaQJ1DKYeQeph5D 197 | lAGBw2nQ4izXhhuLaU3w8VQkIJHdhxIKI5gJY/20AGkG0vHD553Mh5kBINrWp 198 | CRYmmJS8DCYbAiQtKbkeUfzHViGTZuj6PwaY8Mv39PGO47a++pt45IUyCEs4/ 199 | LjMS72cyfo8tU4twRGp76SFGYejYj3wGC1f/POQw== 200 | Signature: | 201 | BOPR0jL0BOV5Zx502BuPbOvi/hvOq5ID8Dz1MQfOjkey6FKP/6cb4f9YXpm6c 202 | ZCHAZLo0GduKdMepiKPUq1rsbbAxkRdQdjOOusEWoxNA58x3E4373tCAhlqM2 203 | DvuQERrIIQ/XnYLV9C3uw4efZwhFqog1jvVyoEHpuvs8xnYtGbsKQ8FrgLwXv 204 | pOZYy9cSgq+jqLy2D9IxiowPcbq2cRlbW9d2xlUfpq0AohyuXQhpxn7d9RUor 205 | 9veoARRAdxRJK12EpcSoEM1LhTRYdJnSRCY3x3p6YIV3c+l1sWvaQwKt0sZ/U 206 | 8TTDx2gb9g7r/+U9icneu/zlqUpSkexCS009Q== 207 | Descriptor: | 208 | AP///wAABAACAAAAAAAFGJ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 209 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiIAAAAAAAABBUFQ6VQAAACRo 210 | aW9GSU8AJGhvc3RpbzAkaG9zdGlvMWFjOnUAAAAAYm9zczpVAABjYW06dQAA 211 | AGNlY2Q6dQAAY2ZnOnUAAABkbHA6RktDTGRscDpTUlZSZHNwOjpEU1BmcmQ6 212 | dQAAAGZzOlVTRVIAZ3NwOjpHcHVoaWQ6VVNFUmh0dHA6QwAAbWljOnUAAABu 213 | ZG06dQAAAG5ld3M6dQAAbndtOjpVRFNwdG06dQAAAHB4aTpkZXYAc29jOlUA 214 | AABzc2w6QwAAAHkycjp1AAAAbGRyOnJvAABpcjpVU0VSAAAAAAAAAAAAAAAA 215 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 216 | AAAAAAAAAABOn/rw/7//8ec/APIA8JH/APaR/1D/gf9Y/4H/cP+B/3j/gf8B 217 | AQD/AAIA/iECAPz///////////////////////////////////////////// 218 | ////////////////////////////////////////AAAAAAAAAAAAAAAAAAAA 219 | AAADAAAAAAAAAAAAAAAAAAI= -------------------------------------------------------------------------------- /3DS/cxi/icon.icn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/3DSController/b38db7dcfcb8cd09acfef7654655658e498b19c7/3DS/cxi/icon.icn -------------------------------------------------------------------------------- /3DS/cxi/icon24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/3DSController/b38db7dcfcb8cd09acfef7654655658e498b19c7/3DS/cxi/icon24x24.png -------------------------------------------------------------------------------- /3DS/cxi/icon48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/3DSController/b38db7dcfcb8cd09acfef7654655658e498b19c7/3DS/cxi/icon48x48.png -------------------------------------------------------------------------------- /3DS/include/drawing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef REG_LCDBACKLIGHTMAIN 4 | #define REG_LCDBACKLIGHTMAIN (u32)(0x1ED02240 - 0x1EB00000) 5 | #endif 6 | 7 | #ifndef REG_LCDBACKLIGHTSUB 8 | #define REG_LCDBACKLIGHTSUB (u32)(0x1ED02A40 - 0x1EB00000) 9 | #endif 10 | 11 | void clearScreen(void); 12 | 13 | #define drawPixelRGB(x, y, r, g, b) drawPixelRGBFramebuffer(0, x, y, r, g, b) 14 | void drawPixelRGBFramebuffer(u8 *fb, int x, int y, u8 r, u8 g, u8 b); 15 | 16 | #define drawBox(x, y, width, height, r, g, b) drawBoxFramebuffer(0, x, y, width, height, r, g, b) 17 | void drawBoxFramebuffer(u8 *fb, int x, int y, int width, int height, u8 r, u8 g, u8 b); 18 | 19 | #define drawString(sx, sy, text, ...) drawStringFramebuffer(0, sx, sy, text, ##__VA_ARGS__) 20 | void drawStringFramebuffer(u8 *fb, int sx, int sy, char *text, ...); 21 | 22 | void disableBacklight(); 23 | void enableBacklight(); 24 | -------------------------------------------------------------------------------- /3DS/include/inet_pton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define INADDRSZ 4 4 | 5 | int inet_pton4(const char *src, unsigned char *dst); 6 | -------------------------------------------------------------------------------- /3DS/include/input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int inputIP(void); 4 | -------------------------------------------------------------------------------- /3DS/include/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern const char keyboardChars[60]; 4 | 5 | extern unsigned char keyboardActive; 6 | extern unsigned char keyboardToggle; 7 | 8 | extern unsigned char keyboardGfx[320 * 240 * 3]; 9 | 10 | void preRenderKeyboard(void); 11 | extern void drawKeyboard(void); 12 | -------------------------------------------------------------------------------- /3DS/include/settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct settings { 6 | char IPString[16]; 7 | int port; 8 | }; 9 | 10 | extern struct settings settings; 11 | extern struct settings defaultSettings; 12 | 13 | extern Handle fileHandle; 14 | 15 | bool readSettings(void); 16 | -------------------------------------------------------------------------------- /3DS/include/wireless.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include <3ds.h> 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "inet_pton.h" 14 | 15 | #define SCREENSHOT_CHUNK 4000 16 | 17 | #define DEFAULT_PORT 8889 18 | 19 | enum NET_COMMANDS { 20 | CONNECT, 21 | KEYS, 22 | SCREENSHOT, 23 | }; 24 | 25 | // It is deliberately set up to have an anonymous struct as well as a named struct for convenience, not a mistake! 26 | struct packet { 27 | union { 28 | struct packetHeader { 29 | unsigned char command; 30 | unsigned char keyboardActive; 31 | }; 32 | struct packetHeader packetHeader; 33 | }; 34 | 35 | union { 36 | // CONNECT 37 | union { 38 | struct connectPacket { 39 | }; 40 | struct connectPacket connectPacket; 41 | }; 42 | 43 | // KEYS 44 | union { 45 | struct keysPacket { 46 | unsigned int keys; 47 | 48 | struct { 49 | short x; 50 | short y; 51 | } circlePad; 52 | 53 | struct { 54 | unsigned short x; 55 | unsigned short y; 56 | } touch; 57 | 58 | struct { 59 | short x; 60 | short y; 61 | } cStick; 62 | }; 63 | struct keysPacket keysPacket; 64 | }; 65 | 66 | // SCREENSHOT 67 | union { 68 | struct screenshotPacket { 69 | unsigned short offset; 70 | unsigned char data[SCREENSHOT_CHUNK]; 71 | }; 72 | struct screenshotPacket screenshotPacket; 73 | }; 74 | }; 75 | }; 76 | 77 | extern int sock; 78 | extern struct sockaddr_in sain, saout; 79 | extern struct packet outBuf, rcvBuf; 80 | 81 | extern socklen_t sockaddr_in_sizePtr; 82 | 83 | bool openSocket(int port); 84 | void sendBuf(int length); 85 | int receiveBuffer(int length); 86 | void sendConnectionRequest(void); 87 | void sendKeys(unsigned int keys, circlePosition circlePad, touchPosition touch, circlePosition cStick); 88 | -------------------------------------------------------------------------------- /3DS/source/drawing.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include <3ds.h> 6 | 7 | #include "drawing.h" 8 | 9 | static const char fonts[] = { //Fonte 8x8 1BPP 10 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:0 11 | , 0x18, 0x18, 0x18, 0x18, 0x18, 0x0, 0x18, 0x0 //tile:1 12 | , 0x6c, 0x6c, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:2 13 | , 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x0 //tile:3 14 | , 0x18, 0x7e, 0xc0, 0x7c, 0x6, 0xfc, 0x18, 0x0 //tile:4 15 | , 0x0, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x0 //tile:5 16 | , 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x0 //tile:6 17 | , 0x30, 0x30, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:7 18 | , 0xc, 0x18, 0x30, 0x30, 0x30, 0x18, 0xc, 0x0 //tile:8 19 | , 0x30, 0x18, 0xc, 0xc, 0xc, 0x18, 0x30, 0x0 //tile:9 20 | , 0x0, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x0, 0x0 //tile:10 21 | , 0x0, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x0, 0x0 //tile:11 22 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x30 //tile:12 23 | , 0x0, 0x0, 0x0, 0x7e, 0x0, 0x0, 0x0, 0x0 //tile:13 24 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x0 //tile:14 25 | , 0x6, 0xc, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x0 //tile:15 26 | , 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0x7c, 0x0 //tile:16 27 | , 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x0 //tile:17 28 | , 0x7c, 0xc6, 0x6, 0x7c, 0xc0, 0xc0, 0xfe, 0x0 //tile:18 29 | , 0xfc, 0x6, 0x6, 0x3c, 0x6, 0x6, 0xfc, 0x0 //tile:19 30 | , 0xc, 0xcc, 0xcc, 0xcc, 0xfe, 0xc, 0xc, 0x0 //tile:20 31 | , 0xfe, 0xc0, 0xfc, 0x6, 0x6, 0xc6, 0x7c, 0x0 //tile:21 32 | , 0x7c, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x0 //tile:22 33 | , 0xfe, 0x6, 0x6, 0xc, 0x18, 0x30, 0x30, 0x0 //tile:23 34 | , 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x0 //tile:24 35 | , 0x7c, 0xc6, 0xc6, 0x7e, 0x6, 0x6, 0x7c, 0x0 //tile:25 36 | , 0x0, 0x18, 0x18, 0x0, 0x0, 0x18, 0x18, 0x0 //tile:26 37 | , 0x0, 0x18, 0x18, 0x0, 0x0, 0x18, 0x18, 0x30 //tile:27 38 | , 0xc, 0x18, 0x30, 0x60, 0x30, 0x18, 0xc, 0x0 //tile:28 39 | , 0x0, 0x0, 0x7e, 0x0, 0x7e, 0x0, 0x0, 0x0 //tile:29 40 | , 0x30, 0x18, 0xc, 0x6, 0xc, 0x18, 0x30, 0x0 //tile:30 41 | , 0x3c, 0x66, 0xc, 0x18, 0x18, 0x0, 0x18, 0x0 //tile:31 42 | , 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x7e, 0x0 //tile:32 43 | , 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x0 //tile:33 44 | , 0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0x0 //tile:34 45 | , 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x0 //tile:35 46 | , 0xf8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x0 //tile:36 47 | , 0xfe, 0xc0, 0xc0, 0xf8, 0xc0, 0xc0, 0xfe, 0x0 //tile:37 48 | , 0xfe, 0xc0, 0xc0, 0xf8, 0xc0, 0xc0, 0xc0, 0x0 //tile:38 49 | , 0x7c, 0xc6, 0xc0, 0xc0, 0xce, 0xc6, 0x7c, 0x0 //tile:39 50 | , 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x0 //tile:40 51 | , 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x0 //tile:41 52 | , 0x6, 0x6, 0x6, 0x6, 0x6, 0xc6, 0x7c, 0x0 //tile:42 53 | , 0xc6, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0xc6, 0x0 //tile:43 54 | , 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x0 //tile:44 55 | , 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x0 //tile:45 56 | , 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x0 //tile:46 57 | , 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x0 //tile:47 58 | , 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x0 //tile:48 59 | , 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x6 //tile:49 60 | , 0xfc, 0xc6, 0xc6, 0xfc, 0xd8, 0xcc, 0xc6, 0x0 //tile:50 61 | , 0x7c, 0xc6, 0xc0, 0x7c, 0x6, 0xc6, 0x7c, 0x0 //tile:51 62 | , 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0 //tile:52 63 | , 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0x0 //tile:53 64 | , 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x38, 0x0 //tile:54 65 | , 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x0 //tile:55 66 | , 0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x0 //tile:56 67 | , 0xc6, 0xc6, 0xc6, 0x7c, 0x18, 0x30, 0xe0, 0x0 //tile:57 68 | , 0xfe, 0x6, 0xc, 0x18, 0x30, 0x60, 0xfe, 0x0 //tile:58 69 | , 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x0 //tile:59 70 | , 0xc0, 0x60, 0x30, 0x18, 0xc, 0x6, 0x2, 0x0 //tile:60 71 | , 0x3c, 0xc, 0xc, 0xc, 0xc, 0xc, 0x3c, 0x0 //tile:61 72 | , 0x10, 0x38, 0x6c, 0xc6, 0x0, 0x0, 0x0, 0x0 //tile:62 73 | , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff //tile:63 74 | , 0x18, 0x18, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:64 75 | , 0x0, 0x0, 0x7c, 0x6, 0x7e, 0xc6, 0x7e, 0x0 //tile:65 76 | , 0xc0, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xfc, 0x0 //tile:66 77 | , 0x0, 0x0, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x0 //tile:67 78 | , 0x6, 0x6, 0x6, 0x7e, 0xc6, 0xc6, 0x7e, 0x0 //tile:68 79 | , 0x0, 0x0, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x0 //tile:69 80 | , 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x0 //tile:70 81 | , 0x0, 0x0, 0x7e, 0xc6, 0xc6, 0x7e, 0x6, 0xfc //tile:71 82 | , 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x0 //tile:72 83 | , 0x18, 0x0, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x0 //tile:73 84 | , 0x6, 0x0, 0x6, 0x6, 0x6, 0x6, 0xc6, 0x7c //tile:74 85 | , 0xc0, 0xc0, 0xcc, 0xd8, 0xf8, 0xcc, 0xc6, 0x0 //tile:75 86 | , 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x0 //tile:76 87 | , 0x0, 0x0, 0xcc, 0xfe, 0xfe, 0xd6, 0xd6, 0x0 //tile:77 88 | , 0x0, 0x0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x0 //tile:78 89 | , 0x0, 0x0, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x0 //tile:79 90 | , 0x0, 0x0, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0 //tile:80 91 | , 0x0, 0x0, 0x7e, 0xc6, 0xc6, 0x7e, 0x6, 0x6 //tile:81 92 | , 0x0, 0x0, 0xfc, 0xc6, 0xc0, 0xc0, 0xc0, 0x0 //tile:82 93 | , 0x0, 0x0, 0x7e, 0xc0, 0x7c, 0x6, 0xfc, 0x0 //tile:83 94 | , 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0xe, 0x0 //tile:84 95 | , 0x0, 0x0, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x0 //tile:85 96 | , 0x0, 0x0, 0xc6, 0xc6, 0xc6, 0x7c, 0x38, 0x0 //tile:86 97 | , 0x0, 0x0, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x0 //tile:87 98 | , 0x0, 0x0, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x0 //tile:88 99 | , 0x0, 0x0, 0xc6, 0xc6, 0xc6, 0x7e, 0x6, 0xfc //tile:89 100 | , 0x0, 0x0, 0xfe, 0xc, 0x38, 0x60, 0xfe, 0x0 //tile:90 101 | , 0xe, 0x18, 0x18, 0x70, 0x18, 0x18, 0xe, 0x0 //tile:91 102 | , 0x18, 0x18, 0x18, 0x0, 0x18, 0x18, 0x18, 0x0 //tile:92 103 | , 0x70, 0x18, 0x18, 0xe, 0x18, 0x18, 0x70, 0x0 //tile:93 104 | , 0x76, 0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 //tile:94 105 | , 0x0, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x0 //tile:95 106 | }; 107 | 108 | inline void clearScreen(void) { 109 | u8 *frame = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); 110 | memset(frame, 0, 320 * 240 * 3); 111 | } 112 | 113 | void drawPixelRGBFramebuffer(u8 *fb, int x, int y, u8 r, u8 g, u8 b) { 114 | y = 240 - y; 115 | x = x; 116 | u32 v = (y + x * 240) * 3; 117 | u8 *topLeftFB = fb ? fb : gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); 118 | topLeftFB[v] = (b >> 3) + ((g & 0x1C) << 3); 119 | topLeftFB[v+1] = ((g & 0xE0) >> 5) + (r & 0xF8); 120 | } 121 | 122 | inline void drawBoxFramebuffer(u8 *fb, int x, int y, int width, int height, u8 r, u8 g, u8 b) { 123 | int lx, ly; 124 | for(lx = x; lx < x + width; lx++) { 125 | for(ly = y; ly < y + height; ly++) { 126 | drawPixelRGBFramebuffer(fb, lx, ly, r, g, b); 127 | } 128 | } 129 | } 130 | 131 | void drawStringFramebuffer(u8 *fb, int sx, int sy, char *text, ...) { 132 | char str[1024]; 133 | va_list args; 134 | va_start(args, text); 135 | vsnprintf(str, 1023, text, args); 136 | va_end(args); 137 | 138 | int i; 139 | for(i = 0; i < strlen(str); i++) { 140 | int fntnum = (str[i] - 32) & 0xFF; 141 | int y; 142 | for(y = 0; y < 8; y++) { 143 | int currbyte = fonts[(fntnum * 8) + y]; 144 | //Desenha sprite de 1BPP 145 | int x; 146 | int mult = 0x80; 147 | for(x = 0; x < 8; x++) { 148 | if((currbyte & mult) == mult) { 149 | drawPixelRGBFramebuffer(fb, sx + x, sy + y, 0xFF, 0xFF, 0xFF); 150 | drawPixelRGBFramebuffer(fb, sx + x, sy + y + 1, 0, 0, 0); //Sombra 151 | } 152 | mult /= 2; 153 | } 154 | } 155 | sx += 8; 156 | } 157 | } 158 | 159 | static u32 brightnessMain; 160 | static u32 brightnessSub; 161 | 162 | void disableBacklight() { 163 | u32 off = 0; 164 | 165 | GSPGPU_ReadHWRegs(REG_LCDBACKLIGHTMAIN, &brightnessMain, 4); 166 | GSPGPU_ReadHWRegs(REG_LCDBACKLIGHTSUB, &brightnessSub, 4); 167 | 168 | GSPGPU_WriteHWRegs(REG_LCDBACKLIGHTMAIN, &off, 4); 169 | GSPGPU_WriteHWRegs(REG_LCDBACKLIGHTSUB, &off, 4); 170 | } 171 | 172 | void enableBacklight() { 173 | GSPGPU_WriteHWRegs(REG_LCDBACKLIGHTMAIN, &brightnessMain, 4); 174 | GSPGPU_WriteHWRegs(REG_LCDBACKLIGHTSUB, &brightnessSub, 4); 175 | } 176 | -------------------------------------------------------------------------------- /3DS/source/inet_pton.c: -------------------------------------------------------------------------------- 1 | #include "wireless.h" 2 | 3 | #include "inet_pton.h" 4 | 5 | int inet_pton4(const char *src, unsigned char *dst) { 6 | static const char digits[] = "0123456789"; 7 | int saw_digit, octets, ch; 8 | unsigned char tmp[INADDRSZ], *tp; 9 | 10 | saw_digit = 0; 11 | octets = 0; 12 | tp = tmp; 13 | *tp = 0; 14 | while((ch = *src++) != '\0') { 15 | const char *pch; 16 | 17 | if((pch = strchr(digits, ch)) != NULL) { 18 | unsigned int val = *tp * 10 + (unsigned int)(pch - digits); 19 | 20 | if(saw_digit && *tp == 0) 21 | return (0); 22 | if(val > 255) 23 | return (0); 24 | *tp = (unsigned char)val; 25 | if(! saw_digit) { 26 | if(++octets > 4) 27 | return (0); 28 | saw_digit = 1; 29 | } 30 | } 31 | else if(ch == '.' && saw_digit) { 32 | if(octets == 4) 33 | return (0); 34 | *++tp = 0; 35 | saw_digit = 0; 36 | } 37 | else 38 | return (0); 39 | } 40 | if(octets < 4) 41 | return (0); 42 | memcpy(dst, tmp, INADDRSZ); 43 | return (1); 44 | } 45 | -------------------------------------------------------------------------------- /3DS/source/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include <3ds.h> 6 | 7 | #include "drawing.h" 8 | 9 | #include "input.h" 10 | 11 | int inputIP(void) { 12 | touchPosition touch; 13 | hidTouchRead(&touch); 14 | 15 | //Draw Keypad 16 | drawString(160-20,50, "1"); 17 | drawString(160, 50, "2"); 18 | drawString(160+20, 50, "3"); 19 | 20 | drawString(160-20, 50+20, "4"); 21 | drawString(160, 50+20, "5"); 22 | drawString(160+20, 50+20, "6"); 23 | 24 | drawString(160-20, 50+40, "7"); 25 | drawString(160, 50+40, "8"); 26 | drawString(160+20, 50+40, "9"); 27 | 28 | drawString(160-10, 50+60, "."); 29 | drawString(160+10, 50+60, "0"); 30 | 31 | //Bottom Strip 32 | if(touch.py > 50+50 && touch.py < 50+70) { 33 | if(touch.px < 160 && touch.px > 160-20) return 11; // Dot 34 | else if(touch.px < 160+20 && touch.px > 160) return 0; // Zero 35 | } 36 | 37 | //First Column 38 | else if(touch.px < 160-10 && touch.px > 160-30) { 39 | if(touch.py < 50+10 && touch.py > 50-10) return 1; // One 40 | else if(touch.py < 50+30 && touch.py > 50+10) return 4; // Four 41 | else if(touch.py < 50+50 && touch.py > 50+30) return 7; // Seven 42 | } 43 | 44 | // Second Column 45 | else if(touch.px < 160+10 && touch.px > 160-10) { 46 | if(touch.py < 50+10 && touch.py > 50-10) return 2; // Two 47 | else if(touch.py < 50+30 && touch.py > 50+10) return 5; // Five 48 | else if(touch.py < 50+50 && touch.py > 50+30) return 8; // Eight 49 | } 50 | 51 | // Third Column 52 | else if(touch.px < 160+30 && touch.px > 160+10) { 53 | if(touch.py < 50+10 && touch.py > 50-10) return 3; // Three 54 | else if(touch.py < 50+30 && touch.py > 50+10) return 6; // Six 55 | else if(touch.py < 50+50 && touch.py > 50+30) return 9; // Nine 56 | } 57 | 58 | return 10; 59 | } -------------------------------------------------------------------------------- /3DS/source/keyboard.c: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | #include 3 | #include 4 | 5 | #include "drawing.h" 6 | 7 | #include "keyboard.h" 8 | 9 | const char keyboardChars[60] = "!1234567890\x08QWERTYUIOP\13\13ASDFGHJKL-\13\13ZXCVBNM,.?\13\13\0\0\0 \0\0\0\0"; 10 | 11 | unsigned char keyboardActive = false; 12 | unsigned char keyboardToggle = true; 13 | 14 | unsigned char keyboardGfx[320 * 240 * 3]; 15 | 16 | void preRenderKeyboard(void) { 17 | const char chars[60] = "!1234567890\x08QWERTYUIOP\13\13ASDFGHJKL-\13\13ZXCVBNM,.?\13\13\0\0\0 \0\0\0\0"; 18 | 19 | int x, y; 20 | for(x = 0; x < 12; x++) { 21 | for(y = 0; y < 4; y++) { 22 | // Not enter 23 | if(chars[x + y * 12] != '\13') { 24 | drawBoxFramebuffer(keyboardGfx, (int)((float)x * 320.0f / 12.0f), (int)(78.0f + (float)y * 320.0f / 12.0f), 25, 25, 31, 31, 31); 25 | drawBoxFramebuffer(keyboardGfx, (int)((float)x * 320.0f / 12.0f) + 1, (int)(78.0f + (float)y * 320.0f / 12.0f) + 1, 24, 24, 31, 0, 0); 26 | 27 | // Backspace 28 | if(chars[x + y * 12] == '\x08') { 29 | drawStringFramebuffer(keyboardGfx, (int)((float)x * 320.0f / 12.0f) + 10, (int)(78.0f + (float)y * 320.0f / 12.0f) + 9, "-"); 30 | drawStringFramebuffer(keyboardGfx, (int)((float)x * 320.0f / 12.0f) + 8, (int)(78.0f + (float)y * 320.0f / 12.0f) + 9, "<"); 31 | } 32 | else drawStringFramebuffer(keyboardGfx, (int)((float)x * 320.0f / 12.0f) + 9, (int)(78.0f + (float)y * 320.0f / 12.0f) + 9, "%c", chars[x + y * 12]); 33 | } 34 | } 35 | } 36 | 37 | // Space 38 | drawBoxFramebuffer(keyboardGfx, (int)((float)3 * 320.0f / 12.0f), (int)(78.0f + (float)4 * 320.0f / 12.0f), (int)(5.0f * 320.0f / 12.0f), 25, 31, 31, 31); 39 | drawBoxFramebuffer(keyboardGfx, (int)((float)3 * 320.0f / 12.0f) + 1, (int)(78.0f + (float)4 * 320.0f / 12.0f) + 1, (int)(5.0f * 320.0f / 12.0f) - 1, 24, 31, 0, 0); 40 | 41 | // Enter 42 | drawBoxFramebuffer(keyboardGfx, (int)((float)10 * 320.0f / 12.0f), (int)(78.0f + (float)1 * 320.0f / 12.0f), (int)(2.0f * 320.0f / 12.0f), (int)(3.0f * 320.0f / 12.0f), 31, 31, 31); 43 | drawBoxFramebuffer(keyboardGfx, (int)((float)10 * 320.0f / 12.0f) + 1, (int)(78.0f + (float)1 * 320.0f / 12.0f) + 1, (int)(2.0f * 320.0f / 12.0f) - 1, (int)(3.0f * 320.0f / 12.0f) - 1, 31, 0, 0); 44 | } 45 | 46 | inline void drawKeyboard(void) { 47 | u8 *topLeftFB = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); 48 | memcpy(topLeftFB, keyboardGfx, sizeof(keyboardGfx)); 49 | 50 | /*const char chars[60] = "!1234567890\x08QWERTYUIOP\13\13ASDFGHJKL-\13\13ZXCVBNM,.?\13\13\0\0\0 \0\0\0\0"; 51 | 52 | int x, y; 53 | for(x = 0; x < 12; x++) { 54 | for(y = 0; y < 4; y++) { 55 | // Not enter 56 | if(chars[x + y * 12] != '\13') { 57 | drawBox((int)((float)x * 320.0f / 12.0f), (int)(78.0f + (float)y * 320.0f / 12.0f), 25, 25, 31, 31, 31); 58 | drawBox((int)((float)x * 320.0f / 12.0f) + 1, (int)(78.0f + (float)y * 320.0f / 12.0f) + 1, 24, 24, 31, 0, 0); 59 | 60 | // Backspace 61 | if(chars[x + y * 12] == '\x08') { 62 | drawString((int)((float)x * 320.0f / 12.0f) + 10, (int)(78.0f + (float)y * 320.0f / 12.0f) + 9, "-"); 63 | drawString((int)((float)x * 320.0f / 12.0f) + 8, (int)(78.0f + (float)y * 320.0f / 12.0f) + 9, "<"); 64 | } 65 | else drawString((int)((float)x * 320.0f / 12.0f) + 9, (int)(78.0f + (float)y * 320.0f / 12.0f) + 9, "%c", chars[x + y * 12]); 66 | } 67 | } 68 | } 69 | 70 | // Space 71 | drawBox((int)((float)3 * 320.0f / 12.0f), (int)(78.0f + (float)4 * 320.0f / 12.0f), (int)(5.0f * 320.0f / 12.0f), 25, 31, 31, 31); 72 | drawBox((int)((float)3 * 320.0f / 12.0f) + 1, (int)(78.0f + (float)4 * 320.0f / 12.0f) + 1, (int)(5.0f * 320.0f / 12.0f) - 1, 24, 31, 0, 0); 73 | 74 | // Enter 75 | drawBox((int)((float)10 * 320.0f / 12.0f), (int)(78.0f + (float)1 * 320.0f / 12.0f), (int)(2.0f * 320.0f / 12.0f), (int)(3.0f * 320.0f / 12.0f), 31, 31, 31); 76 | drawBox((int)((float)10 * 320.0f / 12.0f) + 1, (int)(78.0f + (float)1 * 320.0f / 12.0f) + 1, (int)(2.0f * 320.0f / 12.0f) - 1, (int)(3.0f * 320.0f / 12.0f) - 1, 31, 0, 0); 77 | */ 78 | } 79 | -------------------------------------------------------------------------------- /3DS/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include <3ds.h> 7 | 8 | #include "wireless.h" 9 | #include "settings.h" 10 | #include "drawing.h" 11 | #include "input.h" 12 | #include "keyboard.h" 13 | 14 | static jmp_buf exitJmp; 15 | 16 | void hang(char *message) { 17 | while(aptMainLoop()) { 18 | hidScanInput(); 19 | 20 | clearScreen(); 21 | drawString(10, 10, "%s", message); 22 | drawString(10, 20, "Press Start and Select to exit."); 23 | 24 | u32 kHeld = hidKeysHeld(); 25 | if((kHeld & KEY_START) && (kHeld & KEY_SELECT)) longjmp(exitJmp, 1); 26 | 27 | gfxFlushBuffers(); 28 | gspWaitForVBlank(); 29 | gfxSwapBuffers(); 30 | } 31 | } 32 | 33 | int main(void) { 34 | acInit(); 35 | gfxInitDefault(); 36 | 37 | gfxSetDoubleBuffering(GFX_TOP, false); 38 | gfxSetDoubleBuffering(GFX_BOTTOM, false); 39 | 40 | if(setjmp(exitJmp)) goto exit; 41 | 42 | preRenderKeyboard(); 43 | 44 | clearScreen(); 45 | drawString(10, 10, "Initialising FS..."); 46 | gfxFlushBuffers(); 47 | gfxSwapBuffers(); 48 | 49 | fsInit(); 50 | 51 | clearScreen(); 52 | drawString(10, 10, "Initialising SOC..."); 53 | gfxFlushBuffers(); 54 | gfxSwapBuffers(); 55 | 56 | socInit((u32 *)memalign(0x1000, 0x100000), 0x100000); 57 | 58 | while(aptMainLoop()) { /* Wait for WiFi; break when WiFiStatus is truthy */ 59 | u32 wifiStatus = 0; 60 | ACU_GetWifiStatus(&wifiStatus); 61 | if(wifiStatus) break; 62 | 63 | hidScanInput(); 64 | clearScreen(); 65 | drawString(10, 10, "Waiting for WiFi connection..."); 66 | drawString(10, 20, "Ensure you are in range of an access point,"); 67 | drawString(10, 30, "and that wireless communications are enabled."); 68 | drawString(10, 50, "You can alternatively press Start and Select to exit."); 69 | 70 | u32 kHeld = hidKeysHeld(); 71 | if((kHeld & KEY_START) && (kHeld & KEY_SELECT)) longjmp(exitJmp, 1); 72 | 73 | gfxFlushBuffers(); 74 | gspWaitForVBlank(); 75 | gfxSwapBuffers(); 76 | } 77 | 78 | clearScreen(); 79 | drawString(10, 10, "Reading settings..."); 80 | gfxFlushBuffers(); 81 | gfxSwapBuffers(); 82 | 83 | if(!readSettings()) { 84 | hang("Could not read 3DSController.ini!"); 85 | } 86 | 87 | clearScreen(); 88 | drawString(10, 10, "Connecting to %s on port %d...", settings.IPString, settings.port); 89 | gfxFlushBuffers(); 90 | gfxSwapBuffers(); 91 | 92 | openSocket(settings.port); 93 | sendConnectionRequest(); 94 | 95 | clearScreen(); 96 | gfxFlushBuffers(); 97 | gfxSwapBuffers(); 98 | 99 | disableBacklight(); 100 | 101 | while(aptMainLoop()) { 102 | hidScanInput(); 103 | irrstScanInput(); 104 | 105 | u32 kHeld = hidKeysHeld(); 106 | circlePosition circlePad; 107 | circlePosition cStick; 108 | hidCstickRead(&cStick); 109 | hidCircleRead(&circlePad); 110 | touchPosition touch; 111 | touchRead(&touch); 112 | 113 | clearScreen(); 114 | 115 | if((kHeld & KEY_L) && (kHeld & KEY_R) && (kHeld & KEY_X)) { 116 | if(keyboardToggle) { 117 | keyboardActive = !keyboardActive; 118 | keyboardToggle = false; 119 | 120 | if(keyboardActive) enableBacklight(); 121 | } 122 | } 123 | else keyboardToggle = true; 124 | 125 | if(keyboardActive) { 126 | drawKeyboard(); 127 | 128 | if(touch.px >= 1 && touch.px <= 312 && touch.py >= 78 && touch.py <= 208) { 129 | int x = (int)((float)touch.px * 12.0f / 320.0f); 130 | int y = (int)((float)(touch.py - 78) * 12.0f / 320.0f); 131 | int width = 24; 132 | int height = 24; 133 | 134 | if(keyboardChars[x + y * 12] == ' ') { 135 | while(keyboardChars[(x - 1) + y * 12] == ' ') x--; 136 | 137 | width = (int)(5.0f * 320.0f / 12.0f) - 1; 138 | } 139 | 140 | else if(keyboardChars[x + y * 12] == '\13') { 141 | while(keyboardChars[(x - 1) + y * 12] == '\13') x--; 142 | while(keyboardChars[x + (y - 1) * 12] == '\13') y--; 143 | 144 | width = (int)(2.0f * 320.0f / 12.0f) - 1; 145 | height = (int)(3.0f * 320.0f / 12.0f) - 1; 146 | } 147 | 148 | if(keyboardChars[x + y * 12]) drawBox((int)((float)x * 320.0f / 12.0f) + 1, (int)(78.0f + (float)y * 320.0f / 12.0f) + 1, width, height, 31, 31, 0); 149 | } 150 | } 151 | 152 | sendKeys(kHeld, circlePad, touch, cStick); 153 | 154 | //receiveBuffer(sizeof(struct packet)); 155 | 156 | if((kHeld & KEY_START) && (kHeld & KEY_SELECT)) longjmp(exitJmp, 1); 157 | 158 | gfxFlushBuffers(); 159 | gspWaitForVBlank(); 160 | gfxSwapBuffers(); 161 | } 162 | 163 | exit: 164 | 165 | enableBacklight(); 166 | 167 | SOCU_ShutdownSockets(); 168 | 169 | svcCloseHandle(fileHandle); 170 | fsExit(); 171 | 172 | gfxExit(); 173 | acExit(); 174 | 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /3DS/source/settings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include <3ds.h> 5 | 6 | #include "wireless.h" 7 | 8 | #include "settings.h" 9 | 10 | struct settings settings; 11 | 12 | struct settings defaultSettings = { 13 | IPString: "", 14 | port: DEFAULT_PORT, 15 | }; 16 | 17 | Handle fileHandle; 18 | 19 | static bool getSetting(char *name, char *src, char *dest) { 20 | char *start = strstr(src, name); 21 | 22 | if(start) { 23 | start += strlen(name); 24 | 25 | char *end = start + strlen(start); 26 | if(strstr(start, "\n") - 1 < end) end = strstr(start, "\n") - 1; 27 | size_t size = (size_t)end - (size_t)start; 28 | 29 | strncpy(dest, start, size); 30 | dest[size] = '\0'; 31 | 32 | return true; 33 | } 34 | 35 | return false; 36 | } 37 | 38 | bool readSettings(void) { 39 | char *buffer = NULL; 40 | u64 size; 41 | u32 bytesRead; 42 | 43 | FS_Path filePath = fsMakePath(PATH_ASCII, "/3DSController.ini"); 44 | 45 | Result ret = FSUSER_OpenFileDirectly(&fileHandle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), filePath, FS_OPEN_READ, 0x00000000); 46 | if(ret) return false; 47 | 48 | ret = FSFILE_GetSize(fileHandle, &size); 49 | if(ret) return false; 50 | 51 | buffer = malloc(size); 52 | if(!buffer) return false; 53 | 54 | ret = FSFILE_Read(fileHandle, &bytesRead, 0x0, buffer, size); 55 | if(ret || size != bytesRead) return false; 56 | 57 | ret = FSFILE_Close(fileHandle); 58 | if(ret) return false; 59 | 60 | memcpy(&settings, &defaultSettings, sizeof(struct settings)); 61 | 62 | char setting[64] = { '\0' }; 63 | 64 | if(getSetting("IP: ", buffer, settings.IPString)) { 65 | //inet_pton(AF_INET, settings.IPString, &(saout.sin_addr)); 66 | inet_pton4(settings.IPString, (unsigned char *)&(saout.sin_addr)); 67 | } 68 | else { 69 | free(buffer); 70 | return false; 71 | } 72 | 73 | if(getSetting("Port: ", buffer, setting)) { 74 | sscanf(setting, "%d", &settings.port); 75 | } 76 | 77 | free(buffer); 78 | 79 | return true; 80 | } 81 | -------------------------------------------------------------------------------- /3DS/source/wireless.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "keyboard.h" 4 | 5 | #include "wireless.h" 6 | 7 | int sock; 8 | struct sockaddr_in sain, saout; 9 | struct packet outBuf, rcvBuf; 10 | 11 | socklen_t sockaddr_in_sizePtr = (int)sizeof(struct sockaddr_in); 12 | 13 | bool openSocket(int port) { 14 | sock = socket(AF_INET, SOCK_DGRAM, 0); 15 | 16 | saout.sin_family = sain.sin_family = AF_INET; 17 | saout.sin_port = sain.sin_port = htons(port); 18 | sain.sin_addr.s_addr = INADDR_ANY; 19 | 20 | bind(sock, (struct sockaddr *)&sain, sizeof(sain)); 21 | 22 | fcntl(sock, F_SETFL, O_NONBLOCK); 23 | 24 | return true; 25 | } 26 | 27 | void sendBuf(int length) { 28 | sendto(sock, (char *)&outBuf, length, 0, (struct sockaddr *)&saout, sizeof(saout)); 29 | } 30 | 31 | int receiveBuffer(int length) { 32 | return recvfrom(sock, (char *)&rcvBuf, length, 0, (struct sockaddr *)&sain, &sockaddr_in_sizePtr); 33 | } 34 | 35 | void sendConnectionRequest(void) { 36 | outBuf.command = CONNECT; 37 | outBuf.keyboardActive = keyboardActive; 38 | sendBuf(offsetof(struct packet, connectPacket) + sizeof(struct connectPacket)); 39 | } 40 | 41 | void sendKeys(unsigned int keys, circlePosition circlePad, touchPosition touch, circlePosition cStick) { 42 | outBuf.command = KEYS; 43 | outBuf.keyboardActive = keyboardActive; 44 | memcpy(&outBuf.keys, &keys, 4); 45 | memcpy(&outBuf.circlePad, &circlePad, 4); 46 | memcpy(&outBuf.touch, &touch, 4); 47 | memcpy(&outBuf.cStick, &cStick, 4); 48 | sendBuf(offsetof(struct packet, keysPacket) + sizeof(struct keysPacket)); 49 | } 50 | -------------------------------------------------------------------------------- /Linux/3DSController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Compatible with both Python 2.7.6 and 3.4.3 3 | 4 | from __future__ import print_function 5 | import socket, struct, time 6 | import Xlib, Xlib.display, Xlib.XK 7 | LMouse = []; RMouse = [] 8 | Button = []; MouseAbs = []; MouseRel = []; MouseAbsClick = []; MouseRelClick = [] 9 | 10 | ########################################################## 11 | # CONFIGURABLE REGION START - Don't touch anything above # 12 | ########################################################## 13 | port = 8889 14 | 15 | #This tells what the touch screen does if touched. 16 | #Valid values: Button, MouseAbs, MouseRel, MouseRelClick, MouseRelClick 17 | #Button sends the Tap button. 18 | #MouseAbs moves your mouse to the same part of the screen as the touch screen was touched. 19 | #MouseRel moves your mouse by the same distance as you drag across the touch screen. 20 | #MouseAbsClick and MouseRelClick send the primary mouse button event if the screen is tapped, not held. 21 | touch = MouseRelClick 22 | 23 | mouse_speed = 4 24 | # The number of pixels on each side of the 3DS screen which are ignored, since you can't reach the outermost corners. 25 | abs_deadzone = 10 26 | 27 | #Valid values can be found in any of these locations on your Linux system (some may not exist): 28 | # /usr/include/X11/keysymdef.h 29 | # /usr/lib/python3/dist-packages/Xlib/keysymdef/ 30 | # /usr/lib/python2.7/dist-packages/Xlib/keysymdef/ 31 | #Additionally, LMouse and RMouse can also be used on any button. 32 | btn_map = { 33 | "A": "A", 34 | "B": "B", 35 | "X": "X", 36 | "Y": "Y", 37 | "L": "L", 38 | "R": "R", 39 | "ZL": "Q", 40 | "ZR": "W", 41 | "Left": Xlib.XK.XK_Left, 42 | "Right": Xlib.XK.XK_Right, 43 | "Up": Xlib.XK.XK_Up, 44 | "Down": Xlib.XK.XK_Down, 45 | "Start": Xlib.XK.XK_Return, 46 | "Select": Xlib.XK.XK_BackSpace, 47 | "Tap": LMouse, 48 | } 49 | ######################################################## 50 | # CONFIGURABLE REGION END - Don't touch anything below # 51 | ######################################################## 52 | 53 | def pprint(obj): 54 | import pprint 55 | pprint.PrettyPrinter().pprint(obj) 56 | 57 | class x: pass 58 | 59 | command = x() 60 | command.CONNECT = 0 61 | command.KEYS = 1 62 | command.SCREENSHOT = 2 63 | 64 | keynames = [ 65 | "A", "B", "Select", "Start", "Right", "Left", "Up", "Down", 66 | "R", "L", "X", "Y", None, None, "ZL", "ZR", 67 | None, None, None, None, "Tap", None, None, None, 68 | "CSRight", "CSLeft", "CSUp", "CSDown", "CRight", "CLeft", "CUp", "CDown", 69 | ] 70 | 71 | keys = x() 72 | keys.A = 1<<0 73 | keys.B = 1<<1 74 | keys.Select = 1<<2 75 | keys.Start = 1<<3 76 | keys.Right = 1<<4 77 | keys.Left = 1<<5 78 | keys.Up = 1<<6 79 | keys.Down = 1<<7 80 | keys.R = 1<<8 81 | keys.L = 1<<9 82 | keys.X = 1<<10 83 | keys.Y = 1<<11 84 | keys.ZL = 1<<14 # (new 3DS only) 85 | keys.ZR = 1<<15 # (new 3DS only) 86 | keys.Tap = 1<<20 # Not actually provided by HID 87 | keys.CSRight = 1<<24 # c-stick (new 3DS only) 88 | keys.CSLeft = 1<<25 # c-stick (new 3DS only) 89 | keys.CSUp = 1<<26 # c-stick (new 3DS only) 90 | keys.CSDown = 1<<27 # c-stick (new 3DS only) 91 | keys.CRight = 1<<28 # circle pad 92 | keys.CLeft = 1<<29 # circle pad 93 | keys.CUp = 1<<30 # circle pad 94 | keys.CDown = 1<<31 # circle pad 95 | 96 | def currentKeyboardKey(x, y): 97 | chars = ("!1234567890\x08"+ 98 | "QWERTYUIOP\13\13"+ 99 | "ASDFGHJKL-\13\13"+ 100 | "ZXCVBNM,.?\13\13"+ 101 | "\0\0\0 \0\0\0\0") 102 | 103 | if x>=1 and x<=312 and y>=78 and y<=208: 104 | xi = int(x*12/320) 105 | yi = int((y-78)*12/320) 106 | return chars[yi*12 + xi] 107 | else: return None 108 | 109 | def key_to_keysym(key): 110 | if not key: return 0 111 | 112 | if isinstance(key,str): 113 | if key=="\x08": return Xlib.XK.XK_BackSpace 114 | if key=="\13": return Xlib.XK.XK_Return 115 | if key==" ": return Xlib.XK.XK_space 116 | return Xlib.XK.string_to_keysym(key) 117 | 118 | return key 119 | 120 | def action_key(key, action): 121 | x_action = Xlib.X.ButtonRelease 122 | x_action2 = Xlib.X.KeyRelease 123 | if action: 124 | x_action = Xlib.X.ButtonPress 125 | x_action2 = Xlib.X.KeyPress 126 | 127 | if key is LMouse or key is RMouse: 128 | if key is LMouse: button = 1 129 | if key is RMouse: button = 3 130 | button = disp.get_pointer_mapping()[button-1] # account for left-handed mice 131 | disp.xtest_fake_input(x_action, button) 132 | disp.sync() 133 | return 134 | 135 | keysym = key_to_keysym(key) 136 | if not keysym: return 137 | 138 | keycode = disp.keysym_to_keycode(keysym) 139 | disp.xtest_fake_input(x_action2, keycode) 140 | disp.sync() 141 | 142 | def press_key(key): 143 | action_key(key,True) 144 | 145 | def release_key(key): 146 | action_key(key,False) 147 | 148 | def move_mouse(x,y): 149 | x=int(x) 150 | y=int(y) 151 | if not x and not y: return 152 | 153 | disp.warp_pointer(x,y) 154 | disp.sync() 155 | 156 | def move_mouse_abs_frac(x,y): 157 | root = disp.screen().root 158 | geom = root.get_geometry() 159 | 160 | root.warp_pointer(int(x*geom.width), int(y*geom.height)) 161 | disp.sync() 162 | 163 | disp = Xlib.display.Display() 164 | 165 | touch_click = (touch is MouseAbsClick or touch is MouseRelClick) 166 | if touch is MouseAbsClick: touch = MouseAbs 167 | if touch is MouseRelClick: touch = MouseRel 168 | 169 | if touch is MouseAbs and disp.screen_count()!=1: 170 | print("Sorry, but MouseAbs only supports a single monitor. I'll use MouseRel instead.") 171 | touch = MouseRel 172 | 173 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 174 | sock.bind(("", port)) 175 | 176 | prevkeys = 0 177 | 178 | touch_start = 0 179 | touch_last_x = 0 180 | touch_last_y = 0 181 | keyboard_prevkey = currentKeyboardKey(0, 0) 182 | 183 | while True: 184 | rawdata, addr = sock.recvfrom(4096) 185 | rawdata = bytearray(rawdata) 186 | #print("received message", rawdata, "from", addr) 187 | 188 | if rawdata[0]==command.CONNECT: 189 | pass # CONNECT packets are empty 190 | 191 | if rawdata[0]==command.KEYS: 192 | fields = struct.unpack("=16 or abs(data["circleY"])>=16: 250 | move_mouse(data["circleX"]*mouse_speed/32.0, -data["circleY"]*mouse_speed/32.0) 251 | 252 | if rawdata[0]==command.SCREENSHOT: 253 | pass # unused by both 3DS and PC applications 254 | -------------------------------------------------------------------------------- /Linux/3DSController_gamepad.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Compatible with both Python 2.7.6 and 3.4.3 3 | 4 | from __future__ import print_function 5 | import socket, struct, time 6 | import uinput 7 | 8 | ########################################################## 9 | # CONFIGURABLE REGION START - Don't touch anything above # 10 | ########################################################## 11 | port = 8889 12 | 13 | #Valid values can be found in any of these locations on your Linux system (some may not exist): 14 | # /usr/include/linux/input-event-codes.h 15 | #The virtual device is defined on the device variable and the mapping of the keys on btn_map 16 | #RECAP keynames (DO NOT TOUCH) are the keys that we expect commming from the 3ds, device is 17 | #the virtual device that we define and btn_map maps what we recieve with our virtual device 18 | btn_map = { 19 | "A": uinput.BTN_A, 20 | "B": uinput.BTN_B, 21 | "X": uinput.BTN_X, 22 | "Y": uinput.BTN_Y, 23 | "L": uinput.BTN_TL, 24 | "R": uinput.BTN_TR, 25 | "ZL": uinput.BTN_THUMBL, 26 | "ZR": uinput.BTN_THUMBR, 27 | "Left": uinput.BTN_DPAD_LEFT, 28 | "Right": uinput.BTN_DPAD_RIGHT, 29 | "Up": uinput.BTN_DPAD_UP, 30 | "Down": uinput.BTN_DPAD_DOWN, 31 | "Start": uinput.BTN_START, 32 | "Select": uinput.BTN_SELECT, 33 | "Tap": uinput.BTN_MODE, 34 | } 35 | 36 | device = uinput.Device([ 37 | uinput.ABS_X + (-159, 159, 0, 10), 38 | uinput.ABS_Y + (-159, 159, 0, 10), 39 | uinput.ABS_RX + (-146, 146, 0, 16), 40 | uinput.ABS_RY + (-146, 146, 0, 16), 41 | uinput.BTN_A, 42 | uinput.BTN_B, 43 | uinput.BTN_X, 44 | uinput.BTN_Y, 45 | uinput.BTN_TL, 46 | uinput.BTN_TR, 47 | uinput.BTN_THUMBL, 48 | uinput.BTN_THUMBR, 49 | uinput.BTN_DPAD_LEFT, 50 | uinput.BTN_DPAD_RIGHT, 51 | uinput.BTN_DPAD_UP, 52 | uinput.BTN_DPAD_DOWN, 53 | uinput.BTN_START, 54 | uinput.BTN_SELECT, 55 | uinput.BTN_MODE, 56 | ]) 57 | ######################################################## 58 | # CONFIGURABLE REGION END - Don't touch anything below # 59 | ######################################################## 60 | 61 | def pprint(obj): 62 | import pprint 63 | pprint.PrettyPrinter().pprint(obj) 64 | 65 | class x: pass 66 | 67 | command = x() 68 | command.CONNECT = 0 69 | command.KEYS = 1 70 | command.SCREENSHOT = 2 71 | 72 | keynames = [ 73 | "A", "B", "Select", "Start", "Right", "Left", "Up", "Down", 74 | "R", "L", "X", "Y", None, None, "ZL", "ZR", 75 | None, None, None, None, "Tap", None, None, None, 76 | "CSRight", "CSLeft", "CSUp", "CSDown", "CRight", "CLeft", "CUp", "CDown", 77 | ] 78 | 79 | keys = x() 80 | keys.A = 1<<0 81 | keys.B = 1<<1 82 | keys.Select = 1<<2 83 | keys.Start = 1<<3 84 | keys.Right = 1<<4 85 | keys.Left = 1<<5 86 | keys.Up = 1<<6 87 | keys.Down = 1<<7 88 | keys.R = 1<<8 89 | keys.L = 1<<9 90 | keys.X = 1<<10 91 | keys.Y = 1<<11 92 | keys.ZL = 1<<14 # (new 3DS only) 93 | keys.ZR = 1<<15 # (new 3DS only) 94 | keys.Tap = 1<<20 # Not actually provided by HID 95 | keys.CSRight = 1<<24 # c-stick (new 3DS only) 96 | keys.CSLeft = 1<<25 # c-stick (new 3DS only) 97 | keys.CSUp = 1<<26 # c-stick (new 3DS only) 98 | keys.CSDown = 1<<27 # c-stick (new 3DS only) 99 | keys.CRight = 1<<28 # circle pad 100 | keys.CLeft = 1<<29 # circle pad 101 | keys.CUp = 1<<30 # circle pad 102 | keys.CDown = 1<<31 # circle pad 103 | 104 | def press_key(key): 105 | device.emit(key, 1) 106 | 107 | def release_key(key): 108 | device.emit(key,0) 109 | 110 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 111 | sock.bind(("", port)) 112 | 113 | prevkeys = 0 114 | 115 | touch_start = 0 116 | touch_last_x = 0 117 | touch_last_y = 0 118 | 119 | while True: 120 | rawdata, addr = sock.recvfrom(4096) 121 | rawdata = bytearray(rawdata) 122 | #print("received message", rawdata, "from", addr) 123 | 124 | if rawdata[0]==command.CONNECT: 125 | pass # CONNECT packets are empty 126 | 127 | if rawdata[0]==command.KEYS: 128 | fields = struct.unpack(" 4 | 5 | void error(const char *functionName); 6 | -------------------------------------------------------------------------------- /PC/include/joystick.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef WINVER 4 | #define WINVER 0x0500 5 | #endif 6 | 7 | #include 8 | 9 | #include "public.h" 10 | #include "vjoyinterface.h" 11 | 12 | #define joyX iReport.wAxisX 13 | #define joyY iReport.wAxisY 14 | #define joyRX iReport.wAxisXRot 15 | #define joyRY iReport.wAxisYRot 16 | #define joyButtons iReport.lButtons 17 | 18 | #define JOY_MIDDLE (128 * 128) 19 | 20 | extern int ContPovNumber; 21 | extern UINT iInterface; 22 | //extern BOOL ContinuousPOV; 23 | 24 | extern JOYSTICK_POSITION iReport; 25 | 26 | BOOL updateJoystick(void); 27 | -------------------------------------------------------------------------------- /PC/include/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern unsigned char keyboardActive; 4 | extern unsigned char keyboardToggle; 5 | 6 | inline char currentKeyboardKey(void); 7 | -------------------------------------------------------------------------------- /PC/include/keys.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // For some reason, these are not defined in winuser.h like they used to be... 8 | #ifndef VK_OEM_MINUS 9 | #define VK_OEM_MINUS 0xBD 10 | #endif 11 | #ifndef VK_OEM_COMMA 12 | #define VK_OEM_COMMA 0xBC 13 | #endif 14 | #ifndef KEYEVENTF_SCANCODE 15 | #define KEYEVENTF_SCANCODE 0x08 16 | #endif 17 | 18 | #ifndef MAPVK_VK_TO_VSC 19 | #define MAPVK_VK_TO_VSC 0 20 | #endif 21 | 22 | #define newpress(key) ((currentKeys & key) && !(lastKeys & key)) 23 | #define release(key) (!(currentKeys & key) && (lastKeys & key)) 24 | 25 | #define handleKey(DSKey, PCKey) do {\ 26 | if(!PCKey.useJoypad) {\ 27 | if(newpress(DSKey)) simulateKeyNewpress(PCKey.virtualKey);\ 28 | if(release(DSKey)) simulateKeyRelease(PCKey.virtualKey);\ 29 | }\ 30 | else if(PCKey.useJoypad == 1) {\ 31 | if(currentKeys & DSKey) joyButtons |= PCKey.joypadButton;\ 32 | else joyButtons &= ~PCKey.joypadButton;\ 33 | }\ 34 | else if(PCKey.useJoypad == 2) {\ 35 | if(currentKeys & DSKey) joyButtons |= PCKey.joypadButton << 8;\ 36 | else joyButtons &= ~(PCKey.joypadButton << 8);\ 37 | }\ 38 | } while(0) 39 | 40 | #define BIT(n) (1 << (n)) 41 | 42 | typedef enum { 43 | KEY_A = BIT(0), 44 | KEY_B = BIT(1), 45 | KEY_SELECT = BIT(2), 46 | KEY_START = BIT(3), 47 | KEY_DRIGHT = BIT(4), 48 | KEY_DLEFT = BIT(5), 49 | KEY_DUP = BIT(6), 50 | KEY_DDOWN = BIT(7), 51 | KEY_R = BIT(8), 52 | KEY_L = BIT(9), 53 | KEY_X = BIT(10), 54 | KEY_Y = BIT(11), 55 | KEY_ZL = BIT(14), // (new 3DS only) 56 | KEY_ZR = BIT(15), // (new 3DS only) 57 | KEY_TOUCH = BIT(20), // Not actually provided by HID 58 | KEY_CSTICK_RIGHT = BIT(24), // c-stick (new 3DS only) 59 | KEY_CSTICK_LEFT = BIT(25), // c-stick (new 3DS only) 60 | KEY_CSTICK_UP = BIT(26), // c-stick (new 3DS only) 61 | KEY_CSTICK_DOWN = BIT(27), // c-stick (new 3DS only) 62 | KEY_CPAD_RIGHT = BIT(28), // circle pad 63 | KEY_CPAD_LEFT = BIT(29), // circle pad 64 | KEY_CPAD_UP = BIT(30), // circle pad 65 | KEY_CPAD_DOWN = BIT(31), // circle pad 66 | 67 | // Generic catch-all directions 68 | KEY_UP = KEY_DUP | KEY_CPAD_UP, 69 | KEY_DOWN = KEY_DDOWN | KEY_CPAD_DOWN, 70 | KEY_LEFT = KEY_DLEFT | KEY_CPAD_LEFT, 71 | KEY_RIGHT = KEY_DRIGHT | KEY_CPAD_RIGHT, 72 | } KEYPAD_BITS; 73 | 74 | struct keyMapping { 75 | unsigned char useJoypad; // 0 keyboard key, 1 joypad1-8, 2 joypad9-16 76 | union { 77 | unsigned char virtualKey; 78 | unsigned char joypadButton; 79 | }; 80 | }; 81 | 82 | struct circlePad { 83 | short x; 84 | short y; 85 | }; 86 | 87 | struct cStick { 88 | short x; 89 | short y; 90 | }; 91 | 92 | struct touch { 93 | short x; 94 | short y; 95 | }; 96 | 97 | extern unsigned int lastKeys; 98 | extern unsigned int currentKeys; 99 | 100 | extern struct circlePad circlePad; 101 | extern struct cStick cStick; 102 | extern struct touch lastTouch; 103 | extern struct touch currentTouch; 104 | 105 | inline unsigned int mapVirtualKey(unsigned int key); 106 | void simulateKeyNewpress(unsigned int key); 107 | void simulateKeyRelease(unsigned int key); 108 | -------------------------------------------------------------------------------- /PC/include/public.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Shaul Eizikovich. All rights reserved. 4 | 5 | THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 6 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 7 | IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 8 | PURPOSE. 9 | 10 | Module Name: 11 | 12 | public.h 13 | 14 | Abstract: 15 | 16 | Public header file for the vJoy project 17 | Developpers that need to interface with vJoy need to include this file 18 | 19 | Author: 20 | 21 | 22 | Environment: 23 | 24 | kernel mode and User mode 25 | 26 | Notes: 27 | 28 | 29 | Revision History: 30 | 31 | 32 | --*/ 33 | #ifndef _PUBLIC_H 34 | #define _PUBLIC_H 35 | 36 | // Compilation directives 37 | #define PPJOY_MODE 38 | #undef PPJOY_MODE // Comment-out for compatibility mode 39 | 40 | #ifdef PPJOY_MODE 41 | #include "PPJIoctl.h" 42 | #endif 43 | 44 | #include // Definitions for controlling GUID initialization 45 | 46 | // 47 | // Usage example: 48 | // CreateFile(TEXT("\\\\.\\vJoy"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 49 | #ifdef PPJOY_MODE 50 | #define DEVICENAME_STRING "PPJoyIOCTL1" 51 | #else 52 | #define DEVICENAME_STRING "vJoy" 53 | #endif 54 | #define NTDEVICE_NAME_STRING "\\Device\\"DEVICENAME_STRING 55 | #define SYMBOLIC_NAME_STRING "\\DosDevices\\"DEVICENAME_STRING 56 | #define DOS_FILE_NAME "\\\\.\\"DEVICENAME_STRING 57 | #define VJOY_INTERFACE L"Device_" 58 | 59 | // Version parts 60 | #define VER_X_ 0 61 | #define VER_H_ 2 62 | #define VER_M_ 0 63 | #define VER_L_ 5 64 | 65 | #define STRINGIFY_1(x) #x 66 | #define STRINGIFY(x) STRINGIFY_1(x) 67 | #define PASTE(x, y) x##y 68 | #define MAKEWIDE(x) PASTE(L,x) 69 | 70 | // Device Attributes 71 | // 72 | #define VENDOR_N_ID 0x1234 73 | #define PRODUCT_N_ID 0xBEAD 74 | #define VERSION_N (VER_L_ + 0x10*VER_M_ + 0x100*VER_H_ + 0x1000*VER_X_) 75 | 76 | // Device Strings 77 | // 78 | #define VENDOR_STR_ID L"Shaul Eizikovich" 79 | #define PRODUCT_STR_ID L"vJoy - Virtual Joystick" 80 | #define SERIALNUMBER_STR MAKEWIDE(STRINGIFY(VER_H_)) L"." MAKEWIDE(STRINGIFY(VER_M_)) L"." MAKEWIDE(STRINGIFY(VER_L_)) 81 | 82 | // Function codes; 83 | //#define LOAD_POSITIONS 0x910 84 | //#define GETATTRIB 0x911 85 | // #define GET_FFB_DATA 0x00222912 // METHOD_OUT_DIRECT + FILE_DEVICE_UNKNOWN + FILE_ANY_ACCESS 86 | //#define SET_FFB_STAT 0x913 // METHOD_NEITHER 87 | //#define GET_FFB_STAT 0x916 88 | 89 | #define F_LOAD_POSITIONS 0x910 90 | #define F_GETATTRIB 0x911 91 | #define F_GET_FFB_DATA 0x912 92 | #define F_SET_FFB_STAT 0x913 93 | #define F_GET_FFB_STAT 0x916 94 | #define F_GET_DEV_INFO 0x917 95 | // IO Device Control codes; 96 | #define IOCTL_VJOY_GET_ATTRIB CTL_CODE (FILE_DEVICE_UNKNOWN, GETATTRIB, METHOD_BUFFERED, FILE_WRITE_ACCESS) 97 | #define LOAD_POSITIONS CTL_CODE (FILE_DEVICE_UNKNOWN, F_LOAD_POSITIONS, METHOD_BUFFERED, FILE_WRITE_ACCESS) 98 | #define GET_FFB_DATA CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_FFB_DATA, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 99 | #define SET_FFB_STAT CTL_CODE (FILE_DEVICE_UNKNOWN, F_SET_FFB_STAT, METHOD_NEITHER, FILE_ANY_ACCESS) 100 | #define GET_FFB_STAT CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_FFB_STAT, METHOD_BUFFERED, FILE_ANY_ACCESS) 101 | #define GET_DEV_INFO CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_DEV_INFO, METHOD_BUFFERED, FILE_ANY_ACCESS) 102 | 103 | #ifndef __HIDPORT_H__ 104 | // Copied from hidport.h 105 | #define IOCTL_HID_SET_FEATURE 0xB0191 106 | #define IOCTL_HID_WRITE_REPORT 0xB000F 107 | 108 | #define MAX_N_DEVICES 16 // Maximum number of vJoy devices 109 | 110 | 111 | typedef struct _HID_DEVICE_ATTRIBUTES { 112 | 113 | ULONG Size; 114 | // 115 | // sizeof (struct _HID_DEVICE_ATTRIBUTES) 116 | // 117 | 118 | // 119 | // Vendor ids of this hid device 120 | // 121 | USHORT VendorID; 122 | USHORT ProductID; 123 | USHORT VersionNumber; 124 | USHORT Reserved[11]; 125 | 126 | } HID_DEVICE_ATTRIBUTES, * PHID_DEVICE_ATTRIBUTES; 127 | #endif 128 | 129 | // Error levels for status report 130 | enum ERRLEVEL {INFO, WARN, ERR, FATAL, APP}; 131 | // Status report function prototype 132 | #ifdef WINAPI 133 | typedef BOOL (WINAPI *StatusMessageFunc)(void * output, TCHAR * buffer, enum ERRLEVEL level); 134 | #endif 135 | 136 | /////////////////////////////////////////////////////////////// 137 | 138 | /////////////////////// Joystick Position /////////////////////// 139 | // 140 | // This structure holds data that is passed to the device from 141 | // an external application such as SmartPropoPlus. 142 | // 143 | // Usage example: 144 | // JOYSTICK_POSITION iReport; 145 | // : 146 | // DeviceIoControl (hDevice, 100, &iReport, sizeof(HID_INPUT_REPORT), NULL, 0, &bytes, NULL) 147 | typedef struct _JOYSTICK_POSITION 148 | { 149 | BYTE bDevice; // Index of device. 1-based. 150 | LONG wThrottle; 151 | LONG wRudder; 152 | LONG wAileron; 153 | LONG wAxisX; 154 | LONG wAxisY; 155 | LONG wAxisZ; 156 | LONG wAxisXRot; 157 | LONG wAxisYRot; 158 | LONG wAxisZRot; 159 | LONG wSlider; 160 | LONG wDial; 161 | LONG wWheel; 162 | LONG wAxisVX; 163 | LONG wAxisVY; 164 | LONG wAxisVZ; 165 | LONG wAxisVBRX; 166 | LONG wAxisVBRY; 167 | LONG wAxisVBRZ; 168 | LONG lButtons; // 32 buttons: 0x00000001 means button1 is pressed, 0x80000000 -> button32 is pressed 169 | DWORD bHats; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 170 | DWORD bHatsEx1; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 171 | DWORD bHatsEx2; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 172 | DWORD bHatsEx3; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 173 | } JOYSTICK_POSITION, *PJOYSTICK_POSITION; 174 | 175 | // Superset of JOYSTICK_POSITION 176 | // Extension of JOYSTICK_POSITION with Buttons 33-128 appended to the end of the structure. 177 | typedef struct _JOYSTICK_POSITION_V2 178 | { 179 | /// JOYSTICK_POSITION 180 | BYTE bDevice; // Index of device. 1-based. 181 | LONG wThrottle; 182 | LONG wRudder; 183 | LONG wAileron; 184 | LONG wAxisX; 185 | LONG wAxisY; 186 | LONG wAxisZ; 187 | LONG wAxisXRot; 188 | LONG wAxisYRot; 189 | LONG wAxisZRot; 190 | LONG wSlider; 191 | LONG wDial; 192 | LONG wWheel; 193 | LONG wAxisVX; 194 | LONG wAxisVY; 195 | LONG wAxisVZ; 196 | LONG wAxisVBRX; 197 | LONG wAxisVBRY; 198 | LONG wAxisVBRZ; 199 | LONG lButtons; // 32 buttons: 0x00000001 means button1 is pressed, 0x80000000 -> button32 is pressed 200 | DWORD bHats; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 201 | DWORD bHatsEx1; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 202 | DWORD bHatsEx2; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 203 | DWORD bHatsEx3; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch LONG lButtonsEx1; // Buttons 33-64 204 | 205 | /// JOYSTICK_POSITION_V2 Extenssion 206 | LONG lButtonsEx1; // Buttons 33-64 207 | LONG lButtonsEx2; // Buttons 65-96 208 | LONG lButtonsEx3; // Buttons 97-128 209 | } JOYSTICK_POSITION_V2, *PJOYSTICK_POSITION_V2; 210 | 211 | 212 | // HID Descriptor definitions 213 | #define HID_USAGE_X 0x30 214 | #define HID_USAGE_Y 0x31 215 | #define HID_USAGE_Z 0x32 216 | #define HID_USAGE_RX 0x33 217 | #define HID_USAGE_RY 0x34 218 | #define HID_USAGE_RZ 0x35 219 | #define HID_USAGE_SL0 0x36 220 | #define HID_USAGE_SL1 0x37 221 | #define HID_USAGE_WHL 0x38 222 | #define HID_USAGE_POV 0x39 223 | 224 | 225 | #endif 226 | 227 | 228 | -------------------------------------------------------------------------------- /PC/include/settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "keys.h" 6 | 7 | enum analogue { 8 | mouse, 9 | joystick1, 10 | joystick2, 11 | }; 12 | 13 | struct settings { 14 | int port; 15 | int throttle; 16 | enum analogue circlePad; 17 | enum analogue cStick; 18 | enum analogue touch; 19 | int mouseSpeed; 20 | struct keyMapping A, B, X, Y, L, R, ZL, ZR, Left, Right, Up, Down, Start, Select, Tap; 21 | }; 22 | 23 | extern struct settings settings; 24 | extern struct settings defaultSettings; 25 | 26 | bool readSettings(void); 27 | -------------------------------------------------------------------------------- /PC/include/vjoyinterface.h: -------------------------------------------------------------------------------- 1 | // The following ifdef block is the standard way of creating macros which make exporting 2 | // from a DLL simpler. All files within this DLL are compiled with the VJOYINTERFACE_EXPORTS 3 | // symbol defined on the command line. this symbol should not be defined on any project 4 | // that uses this DLL. This way any other project whose source files include this file see 5 | // VJOYINTERFACE_API functions as being imported from a DLL, whereas this DLL sees symbols 6 | // defined with this macro as being exported. 7 | #ifdef VJOYINTERFACE_EXPORTS 8 | #define VJOYINTERFACE_API __declspec(dllexport) 9 | #else 10 | #define VJOYINTERFACE_API __declspec(dllimport) 11 | #endif 12 | 13 | ///////////////////////////// vJoy device (collection) status //////////////////////////////////////////// 14 | #ifndef VJDSTAT 15 | #define VJDSTAT 16 | enum VjdStat /* Declares an enumeration data type called BOOLEAN */ 17 | { 18 | VJD_STAT_OWN, // The vJoy Device is owned by this application. 19 | VJD_STAT_FREE, // The vJoy Device is NOT owned by any application (including this one). 20 | VJD_STAT_BUSY, // The vJoy Device is owned by another application. It cannot be acquired by this application. 21 | VJD_STAT_MISS, // The vJoy Device is missing. It either does not exist or the driver is down. 22 | VJD_STAT_UNKN // Unknown 23 | }; 24 | 25 | /* Error codes for some of the functions */ 26 | #define NO_HANDLE_BY_INDEX -1 27 | #define BAD_PREPARSED_DATA -2 28 | #define NO_CAPS -3 29 | #define BAD_N_BTN_CAPS -4 30 | #define BAD_CALLOC -5 31 | #define BAD_BTN_CAPS -6 32 | #define BAD_BTN_RANGE -7 33 | #define BAD_N_VAL_CAPS -8 34 | #define BAD_ID_RANGE -9 35 | #define NO_SUCH_AXIS -10 36 | 37 | /* Environment Variables */ 38 | #define INTERFACE_LOG_LEVEL "VJOYINTERFACELOGLEVEL" 39 | #define INTERFACE_LOG_FILE "VJOYINTERFACELOGFILE" 40 | #define INTERFACE_DEF_LOG_FILE "vJoyInterface.log" 41 | 42 | struct DEV_INFO { 43 | BYTE DeviceID; // Device ID: Valid values are 1-16 44 | BYTE nImplemented; // Number of implemented device: Valid values are 1-16 45 | BYTE isImplemented; // Is this device implemented? 46 | BYTE MaxDevices; // Maximum number of devices that may be implemented (16) 47 | BYTE DriverFFB; // Does this driver support FFB (False) 48 | BYTE DeviceFFB; // Does this device support FFB (False) 49 | } ; 50 | 51 | typedef void (CALLBACK *RemovalCB)(BOOL, BOOL, PVOID); 52 | 53 | #endif 54 | ///////////////////////////// vJoy device (collection) Control interface ///////////////////////////////// 55 | /* 56 | These functions allow writing feeders and other applications that interface with vJoy 57 | It is assumed that only one vJoy top-device (= Raw PDO) exists. 58 | This top-level device can have up to 16 siblings (=top-level Reports/collections) 59 | Each sibling is refered to as a "vJoy Device" and is attributed a unique Report ID (Range: 1-16). 60 | 61 | Naming convetion: 62 | VJD = vJoy Device 63 | rID = Report ID 64 | */ 65 | 66 | ///// General driver data 67 | VJOYINTERFACE_API SHORT __cdecl GetvJoyVersion(void); 68 | VJOYINTERFACE_API BOOL __cdecl vJoyEnabled(void); 69 | VJOYINTERFACE_API PVOID __cdecl GetvJoyProductString(void); 70 | VJOYINTERFACE_API PVOID __cdecl GetvJoyManufacturerString(void); 71 | VJOYINTERFACE_API PVOID __cdecl GetvJoySerialNumberString(void); 72 | VJOYINTERFACE_API BOOL __cdecl DriverMatch(WORD * DllVer, WORD * DrvVer); 73 | VJOYINTERFACE_API VOID __cdecl RegisterRemovalCB(RemovalCB cb, PVOID data); 74 | 75 | 76 | ///// vJoy Device properties 77 | VJOYINTERFACE_API int __cdecl GetVJDButtonNumber(UINT rID); // Get the number of buttons defined in the specified VDJ 78 | VJOYINTERFACE_API int __cdecl GetVJDDiscPovNumber(UINT rID); // Get the number of descrete-type POV hats defined in the specified VDJ 79 | VJOYINTERFACE_API int __cdecl GetVJDContPovNumber(UINT rID); // Get the number of descrete-type POV hats defined in the specified VDJ 80 | VJOYINTERFACE_API BOOL __cdecl GetVJDAxisExist(UINT rID, UINT Axis); // Test if given axis defined in the specified VDJ 81 | VJOYINTERFACE_API BOOL __cdecl GetVJDAxisMax(UINT rID, UINT Axis, LONG * Max); // Get logical Maximum value for a given axis defined in the specified VDJ 82 | VJOYINTERFACE_API BOOL __cdecl GetVJDAxisMin(UINT rID, UINT Axis, LONG * Min); // Get logical Minimum value for a given axis defined in the specified VDJ 83 | 84 | ///// Write access to vJoy Device - Basic 85 | VJOYINTERFACE_API BOOL __cdecl AcquireVJD(UINT rID); // Acquire the specified vJoy Device. 86 | VJOYINTERFACE_API VOID __cdecl RelinquishVJD(UINT rID); // Relinquish the specified vJoy Device. 87 | VJOYINTERFACE_API BOOL __cdecl UpdateVJD(UINT rID, PVOID pData); // Update the position data of the specified vJoy Device. 88 | VJOYINTERFACE_API enum VjdStat __cdecl GetVJDStatus(UINT rID); // Get the status of the specified vJoy Device. 89 | 90 | ///// Write access to vJoy Device - Modifyiers 91 | // This group of functions modify the current value of the position data 92 | // They replace the need to create a structure of position data then call UpdateVJD 93 | 94 | //// Reset functions 95 | VJOYINTERFACE_API BOOL __cdecl ResetVJD(UINT rID); // Reset all controls to predefined values in the specified VDJ 96 | VJOYINTERFACE_API VOID __cdecl ResetAll(void); // Reset all controls to predefined values in all VDJ 97 | VJOYINTERFACE_API BOOL __cdecl ResetButtons(UINT rID); // Reset all buttons (To 0) in the specified VDJ 98 | VJOYINTERFACE_API BOOL __cdecl ResetPovs(UINT rID); // Reset all POV Switches (To -1) in the specified VDJ 99 | 100 | // Write data 101 | VJOYINTERFACE_API BOOL __cdecl SetAxis(LONG Value, UINT rID, UINT Axis); // Write Value to a given axis defined in the specified VDJ 102 | VJOYINTERFACE_API BOOL __cdecl SetBtn(BOOL Value, UINT rID, UCHAR nBtn); // Write Value to a given button defined in the specified VDJ 103 | VJOYINTERFACE_API BOOL __cdecl SetDiscPov(int Value, UINT rID, UCHAR nPov); // Write Value to a given descrete POV defined in the specified VDJ 104 | VJOYINTERFACE_API BOOL __cdecl SetContPov(DWORD Value, UINT rID, UCHAR nPov); // Write Value to a given continuous POV defined in the specified VDJ 105 | -------------------------------------------------------------------------------- /PC/include/wireless.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef WINVER 4 | #define WINVER 0x0500 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #define SCREENSHOT_CHUNK 4000 13 | 14 | #define IP INADDR_ANY 15 | 16 | enum NET_COMMANDS { 17 | CONNECT, 18 | KEYS, 19 | SCREENSHOT, 20 | }; 21 | 22 | // It is deliberately set up to have an anonymous struct as well as a named struct for convenience, not a mistake! 23 | struct packet { 24 | struct packetHeader { 25 | unsigned char command; 26 | unsigned char keyboardActive; 27 | }; 28 | struct packetHeader packetHeader; 29 | 30 | union { 31 | // CONNECT 32 | struct connectPacket { 33 | }; 34 | struct connectPacket connectPacket; 35 | 36 | // KEYS 37 | struct keysPacket { 38 | unsigned int keys; 39 | 40 | struct { 41 | short x; 42 | short y; 43 | } circlePad; 44 | 45 | struct { 46 | unsigned short x; 47 | unsigned short y; 48 | } touch; 49 | 50 | struct { 51 | short x; 52 | short y; 53 | } cStick; 54 | }; 55 | struct keysPacket keysPacket; 56 | 57 | // SCREENSHOT 58 | struct screenshotPacket { 59 | unsigned short offset; 60 | unsigned char data[SCREENSHOT_CHUNK]; 61 | }; 62 | struct screenshotPacket screenshotPacket; 63 | }; 64 | }; 65 | 66 | extern SOCKET listener; 67 | extern SOCKET client; 68 | 69 | extern struct sockaddr_in client_in; 70 | 71 | extern int sockaddr_in_sizePtr; 72 | 73 | extern struct packet buffer; 74 | extern char hostName[80]; 75 | 76 | void initNetwork(void); 77 | void printIPs(void); 78 | void startListening(void); 79 | void sendBuffer(int length); 80 | int receiveBuffer(int length); 81 | 82 | void sendScreenshot(void); 83 | -------------------------------------------------------------------------------- /PC/lib/vJoyInterface.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/3DSController/b38db7dcfcb8cd09acfef7654655658e498b19c7/PC/lib/vJoyInterface.lib -------------------------------------------------------------------------------- /PC/source/general.c: -------------------------------------------------------------------------------- 1 | #include "wireless.h" 2 | 3 | #include "general.h" 4 | 5 | void error(const char *functionName) { 6 | char errorMsg[92]; 7 | ZeroMemory(errorMsg, 92); 8 | 9 | sprintf(errorMsg, "Call to %s returned error %d!", (char *)functionName, WSAGetLastError()); 10 | 11 | MessageBox(NULL, errorMsg, "socketIndication", MB_OK); 12 | 13 | closesocket(client); 14 | closesocket(listener); 15 | WSACleanup(); 16 | 17 | exit(0); 18 | } 19 | -------------------------------------------------------------------------------- /PC/source/joystick.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "joystick.h" 5 | 6 | int ContPovNumber; 7 | UINT iInterface = 1; 8 | //BOOL ContinuousPOV = FALSE; 9 | 10 | JOYSTICK_POSITION iReport; 11 | 12 | BOOL updateJoystick(void) { 13 | BYTE id = (BYTE)iInterface; 14 | 15 | iReport.bDevice = id; 16 | 17 | if(!UpdateVJD(iInterface, (PVOID)&iReport)) { 18 | /*printf("vJoy device %d failed - try to enable device\n", iInterface); 19 | printf("PRESS ENTER TO CONTINUE\n"); 20 | getchar(); 21 | AcquireVJD(iInterface); 22 | ContinuousPOV = (BOOL)GetVJDContPovNumber(iInterface);*/ 23 | return false; 24 | } 25 | 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /PC/source/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "keys.h" 4 | 5 | #include "keyboard.h" 6 | 7 | unsigned char keyboardActive = false; 8 | unsigned char keyboardToggle = true; 9 | 10 | inline char currentKeyboardKey(void) { 11 | const char chars[60] = "!1234567890\x08QWERTYUIOP\13\13ASDFGHJKL-\13\13ZXCVBNM,.?\13\13\0\0\0 \0\0\0\0"; 12 | 13 | if(currentTouch.x >= 1 && currentTouch.x <= 312 && currentTouch.y >= 78 && currentTouch.y <= 208) { 14 | int x = (int)((float)currentTouch.x * 12.0f / 320.0f); 15 | int y = (int)((float)(currentTouch.y - 78) * 12.0f / 320.0f); 16 | 17 | return chars[x + y * 12]; 18 | } 19 | 20 | else return 0; 21 | } 22 | -------------------------------------------------------------------------------- /PC/source/keys.c: -------------------------------------------------------------------------------- 1 | #include "keys.h" 2 | 3 | // Sideband comunication with vJoy Device 4 | //{781EF630-72B2-11d2-B852-00C04FAD5101} 5 | DEFINE_GUID(GUID_DEVINTERFACE_VJOY, 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x01); 6 | 7 | unsigned int lastKeys; 8 | unsigned int currentKeys; 9 | 10 | struct circlePad circlePad; 11 | struct cStick cStick; 12 | struct touch lastTouch; 13 | struct touch currentTouch; 14 | 15 | inline unsigned int mapVirtualKey(unsigned int key) { 16 | return MapVirtualKey(key, MAPVK_VK_TO_VSC); 17 | } 18 | 19 | void simulateKeyNewpress(unsigned int key) { 20 | if(!key) return; 21 | 22 | unsigned char unshift = 0; 23 | 24 | INPUT ip = { 0 }; 25 | 26 | if(key == VK_LBUTTON || key == VK_RBUTTON) { 27 | ip.type = INPUT_MOUSE; 28 | ip.mi.dwFlags = key == VK_LBUTTON ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; 29 | } 30 | else { 31 | if(key == '!') { 32 | key = '1'; 33 | simulateKeyNewpress(VK_SHIFT); 34 | unshift = 1; 35 | } 36 | else if(key == '?') { 37 | key = VK_DIVIDE; 38 | simulateKeyNewpress(VK_SHIFT); 39 | unshift = 1; 40 | } 41 | 42 | else if(key == '-') key = VK_OEM_MINUS; 43 | else if(key == ',') key = VK_OEM_COMMA; 44 | else if(key == '\13') key = VK_RETURN; 45 | 46 | ip.type = INPUT_KEYBOARD; 47 | ip.ki.wScan = mapVirtualKey(key); 48 | ip.ki.time = 0; 49 | ip.ki.dwExtraInfo = 0; 50 | ip.ki.wVk = 0; 51 | ip.ki.dwFlags = KEYEVENTF_SCANCODE; 52 | } 53 | 54 | SendInput(1, &ip, sizeof(INPUT)); 55 | 56 | if(unshift) simulateKeyRelease(VK_SHIFT); 57 | } 58 | 59 | void simulateKeyRelease(unsigned int key) { 60 | if(!key) return; 61 | 62 | INPUT ip = { 0 }; 63 | 64 | if(key == VK_LBUTTON || key == VK_RBUTTON) { 65 | ip.type = INPUT_MOUSE; 66 | ip.mi.dwFlags = key == VK_LBUTTON ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; 67 | } 68 | else { 69 | ip.type = INPUT_KEYBOARD; 70 | ip.ki.wScan = mapVirtualKey(key); 71 | ip.ki.time = 0; 72 | ip.ki.dwExtraInfo = 0; 73 | ip.ki.wVk = 0; 74 | ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; 75 | } 76 | 77 | SendInput(1, &ip, sizeof(INPUT)); 78 | } 79 | -------------------------------------------------------------------------------- /PC/source/main.c: -------------------------------------------------------------------------------- 1 | // 3DS Controller Server 2 | 3 | #define VERSION 0.6 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "wireless.h" 10 | #include "keys.h" 11 | #include "general.h" 12 | #include "joystick.h" 13 | #include "settings.h" 14 | #include "keyboard.h" 15 | 16 | int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShow) { 17 | printf("3DS Controller Server %.1f\n", VERSION); 18 | 19 | DWORD screenWidth = GetSystemMetrics(SM_CXSCREEN); 20 | DWORD screenHeight = GetSystemMetrics(SM_CYSCREEN); 21 | 22 | double widthMultiplier = screenWidth / 320.0; 23 | double heightMultiplier = screenHeight / 240.0; 24 | 25 | bool vJoy = true; 26 | UINT iInterface = 1; 27 | 28 | iReport.wAxisX = JOY_MIDDLE; 29 | iReport.wAxisY = JOY_MIDDLE; 30 | iReport.wAxisZ = JOY_MIDDLE; 31 | iReport.wAxisXRot = JOY_MIDDLE; 32 | iReport.wAxisYRot = JOY_MIDDLE; 33 | iReport.wAxisZRot = JOY_MIDDLE; 34 | iReport.wSlider = JOY_MIDDLE; 35 | iReport.wDial = JOY_MIDDLE; 36 | iReport.lButtons = 0; 37 | iReport.bHats = -1; 38 | 39 | if(vJoy && !vJoyEnabled()) { 40 | printf("vJoy failed (1)! Buttons will still work, but joy stick won't work.\n"); 41 | vJoy = false; 42 | } 43 | 44 | enum VjdStat status = GetVJDStatus(iInterface); 45 | if(vJoy && (status == VJD_STAT_OWN || (status == VJD_STAT_FREE && !AcquireVJD(iInterface)))) { 46 | printf("vJoy failed (2)! Buttons will still work, but joy stick won't work.\n"); 47 | vJoy = false; 48 | } 49 | 50 | ContPovNumber = GetVJDContPovNumber(iInterface); 51 | //int DiscPovNumber = GetVJDDiscPovNumber(iInterface); 52 | 53 | if(vJoy && !updateJoystick()) { 54 | printf("vJoy failed (3)! Buttons will still work, but joystick won't work.\n"); 55 | vJoy = false; 56 | } 57 | 58 | if(!readSettings()) { 59 | printf("Couldn't read settings file, using default key bindings.\n"); 60 | } 61 | 62 | initNetwork(); 63 | 64 | char nButtons = GetVJDButtonNumber(iInterface); 65 | if(nButtons <16) printf("Your vJoy has less than 16 buttons (8 by default), some may not work!\n"); 66 | 67 | printf("Port: %d\n", settings.port); 68 | 69 | printf("Running on: %s\n", hostName); 70 | 71 | printf("Your local IP(s):\n"); 72 | printIPs(); 73 | 74 | printf("\n"); 75 | 76 | startListening(); 77 | 78 | while(1) { 79 | memset(&buffer, 0, sizeof(struct packet)); 80 | 81 | while(receiveBuffer(sizeof(struct packet)) <= 0) { 82 | // Waiting 83 | 84 | Sleep(settings.throttle); 85 | } 86 | 87 | keyboardActive = buffer.keyboardActive; 88 | 89 | switch(buffer.command) { 90 | case CONNECT: 91 | lastKeys = 0; 92 | currentKeys = 0; 93 | circlePad.x = 0; 94 | circlePad.y = 0; 95 | lastTouch.x = 0; 96 | lastTouch.y = 0; 97 | currentTouch.x = 0; 98 | currentTouch.y = 0; 99 | cStick.x = 0; 100 | cStick.y = 0; 101 | 102 | buffer.command = CONNECT; 103 | printf("3DS Connected!\n"); 104 | 105 | Sleep(50); 106 | sendBuffer(1); 107 | 108 | Sleep(50); 109 | sendBuffer(1); 110 | 111 | Sleep(50); 112 | sendBuffer(1); 113 | break; 114 | 115 | case KEYS: 116 | lastKeys = currentKeys; 117 | if(currentKeys & KEY_TOUCH) lastTouch = currentTouch; 118 | 119 | memcpy(¤tKeys, &buffer.keys, 4); 120 | memcpy(&circlePad, &buffer.circlePad, 4); 121 | memcpy(¤tTouch, &buffer.touch, 4); 122 | memcpy(&cStick, &buffer.cStick, 4); 123 | 124 | handleKey(KEY_A, settings.A); 125 | handleKey(KEY_B, settings.B); 126 | handleKey(KEY_SELECT, settings.Select); 127 | handleKey(KEY_START, settings.Start); 128 | handleKey(KEY_DRIGHT, settings.Right); 129 | handleKey(KEY_DLEFT, settings.Left); 130 | handleKey(KEY_DUP, settings.Up); 131 | handleKey(KEY_DDOWN, settings.Down); 132 | handleKey(KEY_R, settings.R); 133 | handleKey(KEY_L, settings.L); 134 | handleKey(KEY_ZR, settings.ZR); 135 | handleKey(KEY_ZL, settings.ZL); 136 | handleKey(KEY_X, settings.X); 137 | handleKey(KEY_Y, settings.Y); 138 | 139 | //handleKey(KEY_LID, 'I'); 140 | 141 | if(newpress(KEY_TOUCH)) { 142 | lastTouch.x = currentTouch.x; 143 | lastTouch.y = currentTouch.y; 144 | } 145 | 146 | if((currentKeys & KEY_TOUCH)) { 147 | if(keyboardActive) { 148 | if(newpress(KEY_TOUCH)) { 149 | char letter = currentKeyboardKey(); 150 | if(letter) { 151 | simulateKeyNewpress(letter); 152 | simulateKeyRelease(letter); 153 | } 154 | } 155 | } 156 | else if(settings.touch == mouse) { 157 | if(settings.mouseSpeed) { 158 | POINT p; 159 | GetCursorPos(&p); 160 | SetCursorPos(p.x + (currentTouch.x - lastTouch.x) * settings.mouseSpeed, p.y + (currentTouch.y - lastTouch.y) * settings.mouseSpeed); 161 | } 162 | else { 163 | SetCursorPos((int)((double)currentTouch.x * widthMultiplier), (int)((double)currentTouch.y * heightMultiplier)); 164 | } 165 | } 166 | else if(settings.touch == joystick1) { 167 | joyX = (currentTouch.x) * 128; 168 | joyY = (currentTouch.y) * 128; 169 | } 170 | 171 | else if(settings.touch == joystick2) { 172 | joyRX = (currentTouch.x) * 128; 173 | joyRY = (currentTouch.y) * 128; 174 | } 175 | else { 176 | handleKey(KEY_TOUCH, settings.Tap); 177 | } 178 | } 179 | 180 | if(settings.circlePad == mouse) { 181 | if(abs(circlePad.x) < settings.mouseSpeed * 3) circlePad.x = 0; 182 | if(abs(circlePad.y) < settings.mouseSpeed * 3) circlePad.y = 0; 183 | 184 | POINT p; 185 | GetCursorPos(&p); 186 | SetCursorPos(p.x + (circlePad.x * settings.mouseSpeed) / 32, p.y - (circlePad.y * settings.mouseSpeed) / 32); 187 | } 188 | else if(settings.circlePad == joystick1) { 189 | joyX = (circlePad.x + 128) * 128; 190 | joyY = (128 - circlePad.y) * 128; 191 | } 192 | 193 | else if(settings.circlePad == joystick2) { 194 | joyRX = (circlePad.x + 128) * 128; 195 | joyRY = (128 - circlePad.y) * 128; 196 | } 197 | 198 | if(settings.cStick == mouse) { 199 | if(abs(cStick.x) < settings.mouseSpeed * 3) cStick.x = 0; 200 | if(abs(cStick.y) < settings.mouseSpeed * 3) cStick.y = 0; 201 | 202 | POINT p; 203 | GetCursorPos(&p); 204 | SetCursorPos(p.x + (cStick.x * settings.mouseSpeed) / 32, p.y - (cStick.y * settings.mouseSpeed) / 32); 205 | } 206 | 207 | else if(settings.cStick == joystick1) { 208 | joyX = (cStick.x + 128) * 128; 209 | joyY = (128 - cStick.y) * 128; 210 | } 211 | 212 | else if(settings.cStick == joystick2) { 213 | joyRX = (cStick.x + 128) * 128; 214 | joyRY = (128 - cStick.y) * 128; 215 | } 216 | 217 | break; 218 | } 219 | 220 | if(vJoy) updateJoystick(); 221 | } 222 | 223 | error("accept()"); 224 | return 0; 225 | } 226 | -------------------------------------------------------------------------------- /PC/source/settings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "keys.h" 6 | #include "wireless.h" 7 | 8 | #include "settings.h" 9 | 10 | struct settings settings; 11 | 12 | struct settings defaultSettings = { 13 | port: 8889, 14 | throttle: 20, 15 | circlePad: joystick1, 16 | cStick: joystick2, 17 | touch: mouse, 18 | mouseSpeed: 4, 19 | A: { 1, {'A'} }, 20 | B: { 1, {'B'} }, 21 | X: { 1, {'X'} }, 22 | Y: { 1, {'Y'} }, 23 | L: { 1, {'L'} }, 24 | R: { 1, {'R'} }, 25 | ZL: { 1, {'Q'} }, 26 | ZR: { 1, {'W'} }, 27 | Left: { 1, {VK_LEFT} }, 28 | Right: { 1, {VK_RIGHT} }, 29 | Up: { 1, {VK_UP} }, 30 | Down: { 1, {VK_DOWN} }, 31 | Start: { 1, {VK_RETURN} }, 32 | Select: { 1, {VK_BACK} }, 33 | Tap: { 1, {'T'} }, 34 | }; 35 | 36 | static bool getSetting(char *name, char *src, char *dest) { 37 | char *start = strstr(src, name); 38 | 39 | if(start) { 40 | start += strlen(name); 41 | 42 | char *end = start + strlen(start); 43 | if(strstr(start, "\n") - 1 < end) end = strstr(start, "\n") - 1; 44 | size_t size = (size_t)end - (size_t)start; 45 | 46 | strncpy(dest, start, size); 47 | dest[size] = '\0'; 48 | 49 | return true; 50 | } 51 | 52 | return false; 53 | } 54 | 55 | static struct keyMapping getButton(char *string) { 56 | struct keyMapping k = { 1, {0} }; 57 | 58 | k.useJoypad = 0; 59 | if(strcmp(string, "SPACE") == 0) k.virtualKey = VK_SPACE; 60 | else if(strcmp(string, "CLICK") == 0) k.virtualKey = VK_LBUTTON; 61 | else if(strcmp(string, "RIGHT CLICK") == 0) k.virtualKey = VK_RBUTTON; 62 | else if(strcmp(string, "ENTER") == 0) k.virtualKey = VK_RETURN; 63 | else if(strcmp(string, "BACKSPACE") == 0) k.virtualKey = VK_BACK; 64 | else if(strcmp(string, "SHIFT") == 0) k.virtualKey = VK_SHIFT; 65 | else if(strcmp(string, "TAB") == 0) k.virtualKey = VK_TAB; 66 | else if(strcmp(string, "LEFT") == 0) k.virtualKey = VK_LEFT; 67 | else if(strcmp(string, "RIGHT") == 0) k.virtualKey = VK_RIGHT; 68 | else if(strcmp(string, "UP") == 0) k.virtualKey = VK_UP; 69 | else if(strcmp(string, "DOWN") == 0) k.virtualKey = VK_DOWN; 70 | else if(strcmp(string, "PAGE UP") == 0) k.virtualKey = VK_PRIOR; 71 | else if(strcmp(string, "PAGE DOWN") == 0) k.virtualKey = VK_NEXT; 72 | else if(strcmp(string, "WINDOWS") == 0) k.virtualKey = VK_LWIN; 73 | else if(strcmp(string, "NONE") == 0) k.virtualKey = 0; 74 | 75 | else if(strcmp(string, "JOY1") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 0; } 76 | else if(strcmp(string, "JOY2") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 1; } 77 | else if(strcmp(string, "JOY3") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 2; } 78 | else if(strcmp(string, "JOY4") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 3; } 79 | else if(strcmp(string, "JOY5") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 4; } 80 | else if(strcmp(string, "JOY6") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 5; } 81 | else if(strcmp(string, "JOY7") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 6; } 82 | else if(strcmp(string, "JOY8") == 0) { k.useJoypad = 1; k.joypadButton = 1 << 7; } 83 | else if(strcmp(string, "JOY9") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 0; } 84 | else if(strcmp(string, "JOY10") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 1; } 85 | else if(strcmp(string, "JOY11") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 2; } 86 | else if(strcmp(string, "JOY12") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 3; } 87 | else if(strcmp(string, "JOY13") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 4; } 88 | else if(strcmp(string, "JOY14") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 5; } 89 | else if(strcmp(string, "JOY15") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 6; } 90 | else if(strcmp(string, "JOY16") == 0) { k.useJoypad = 2; k.joypadButton = 1 << 7; } 91 | 92 | else k.virtualKey = (int)string[0]; 93 | 94 | return k; 95 | } 96 | 97 | bool readSettings(void) { 98 | FILE *f; 99 | size_t len = 0; 100 | char *buffer = NULL; 101 | 102 | memcpy(&settings, &defaultSettings, sizeof(struct settings)); 103 | 104 | f = fopen("3DSController.ini", "rb"); 105 | if(!f) { 106 | return false; 107 | } 108 | 109 | fseek(f, 0, SEEK_END); 110 | len = ftell(f); 111 | rewind(f); 112 | 113 | buffer = malloc(len); 114 | if(!buffer) { 115 | fclose(f); 116 | return false; 117 | } 118 | 119 | fread(buffer, 1, len, f); 120 | 121 | char setting[64] = { '\0' }; 122 | 123 | if(getSetting("Port: ", buffer, setting)) { 124 | sscanf(setting, "%d", &settings.port); 125 | } 126 | 127 | if(getSetting("Throttle: ", buffer, setting)) { 128 | sscanf(setting, "%d", &settings.throttle); 129 | } 130 | 131 | if(getSetting("Circle Pad: ", buffer, setting)) { 132 | if(strcmp(setting, "MOUSE") == 0) settings.circlePad = mouse; 133 | else if(strcmp(setting, "JOYSTICK1") == 0) settings.circlePad = joystick1; 134 | else if(strcmp(setting, "JOYSTICK2") == 0) settings.circlePad = joystick2; 135 | } 136 | 137 | if(getSetting("C Stick: ", buffer, setting)) { 138 | if(strcmp(setting, "MOUSE") == 0) settings.cStick = mouse; 139 | else if(strcmp(setting, "JOYSTICK1") == 0) settings.cStick = joystick1; 140 | else if(strcmp(setting, "JOYSTICK2") == 0) settings.cStick = joystick2; 141 | } 142 | 143 | if(getSetting("Touch: ", buffer, setting)) { 144 | if(strcmp(setting, "MOUSE") == 0) settings.touch = mouse; 145 | else if(strcmp(setting, "JOYSTICK1") == 0) settings.touch = joystick1; 146 | else if(strcmp(setting, "JOYSTICK2") == 0) settings.touch = joystick2; 147 | } 148 | 149 | if(getSetting("Mouse Speed: ", buffer, setting)) { 150 | sscanf(setting, "%d", &settings.mouseSpeed); 151 | } 152 | 153 | if(getSetting("A: ", buffer, setting)) settings.A = getButton(setting); 154 | if(getSetting("B: ", buffer, setting)) settings.B = getButton(setting); 155 | if(getSetting("X: ", buffer, setting)) settings.X = getButton(setting); 156 | if(getSetting("Y: ", buffer, setting)) settings.Y = getButton(setting); 157 | if(getSetting("L: ", buffer, setting)) settings.L = getButton(setting); 158 | if(getSetting("R: ", buffer, setting)) settings.R = getButton(setting); 159 | if(getSetting("ZL: ", buffer, setting)) settings.ZL = getButton(setting); 160 | if(getSetting("ZR: ", buffer, setting)) settings.ZR = getButton(setting); 161 | if(getSetting("Left: ", buffer, setting)) settings.Left = getButton(setting); 162 | if(getSetting("Right: ", buffer, setting)) settings.Right = getButton(setting); 163 | if(getSetting("Up: ", buffer, setting)) settings.Up = getButton(setting); 164 | if(getSetting("Down: ", buffer, setting)) settings.Down = getButton(setting); 165 | if(getSetting("Start: ", buffer, setting)) settings.Start = getButton(setting); 166 | if(getSetting("Select: ", buffer, setting)) settings.Select = getButton(setting); 167 | if(getSetting("Tap: ", buffer, setting)) settings.Tap = getButton(setting); 168 | 169 | fclose(f); 170 | 171 | return true; 172 | } 173 | -------------------------------------------------------------------------------- /PC/source/wireless.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "general.h" 4 | 5 | #include "settings.h" 6 | 7 | #include "wireless.h" 8 | 9 | SOCKET listener; 10 | SOCKET client; 11 | 12 | struct sockaddr_in client_in; 13 | 14 | int sockaddr_in_sizePtr = (int)sizeof(struct sockaddr_in); 15 | 16 | struct packet buffer; 17 | char hostName[80]; 18 | 19 | void initNetwork(void) { 20 | WSADATA wsaData; 21 | 22 | WSAStartup(MAKEWORD(2, 2), &wsaData); 23 | 24 | if(gethostname(hostName, sizeof(hostName)) == SOCKET_ERROR) { 25 | error("gethostname()"); 26 | } 27 | } 28 | 29 | void printIPs(void) { 30 | struct hostent *phe = gethostbyname(hostName); 31 | if(phe == 0) { 32 | error("gethostbyname()"); 33 | } 34 | 35 | int i; 36 | for(i = 0; phe->h_addr_list[i] != 0; i++) { 37 | struct in_addr addr; 38 | memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); 39 | printf("%s\n", inet_ntoa(addr)); 40 | } 41 | 42 | if(i) { 43 | printf("Usually you want the first one.\n"); 44 | } 45 | } 46 | 47 | void startListening(void) { 48 | int nret; 49 | 50 | listener = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 51 | 52 | if(listener == INVALID_SOCKET) { 53 | error("socket()"); 54 | } 55 | 56 | SOCKADDR_IN serverInfo; 57 | 58 | serverInfo.sin_family = AF_INET; 59 | serverInfo.sin_addr.s_addr = IP; 60 | serverInfo.sin_port = htons(settings.port); 61 | 62 | u_long one = 1; 63 | ioctlsocket(listener, FIONBIO, &one); 64 | 65 | nret = bind(listener, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr)); 66 | 67 | if(nret == SOCKET_ERROR) { 68 | error("bind()"); 69 | } 70 | } 71 | 72 | void sendBuffer(int length) { 73 | if(sendto(listener, (char *)&buffer, length, 0, (struct sockaddr *)&client_in, sizeof(struct sockaddr_in)) != length) { 74 | error("sendto"); 75 | } 76 | } 77 | 78 | int receiveBuffer(int length) { 79 | return recvfrom(listener, (char *)&buffer, length, 0, (struct sockaddr *)&client_in, &sockaddr_in_sizePtr); 80 | } 81 | -------------------------------------------------------------------------------- /PC/vJoyInterface.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/3DSController/b38db7dcfcb8cd09acfef7654655658e498b19c7/PC/vJoyInterface.dll -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 3DSController ![](/3DS/cxi/icon48x48.png?raw=true) 2 | === 3 | A 3DS homebrew application which allows you to use your 3DS as a wireless controller for Windows. 4 | 5 | ### Download 6 | The latest release will always be downloadable from [here](https://github.com/CTurt/3DSController/releases/). 7 | 8 | If you are updating to 0.6 from an older version, you will need to make sure you update vJoy to the recommended version. 9 | 10 | ### Setup and Usage 11 | Firstly, if you want to be able to register the circle pad or touch screen as a joystick you will need to install [vJoy (version 2.0.5-120515 is preferable)](http://sourceforge.net/projects/vjoystick/files/Beta%202.x/2.0.5-120515/vJoy_205_050515.exe/download). However, if you just want to use keyboard buttons, this is not necessary. 12 | 13 | Extract the archive and copy the executable in the `3DS` directory with the extension that applies to your loader: `3DSController.3dsx` and `3DSController.smdh` for Ninjhax, `3DSController.3ds` for flashcards, or `3DSController.cia` for CFWs, into your 3DS's SD card or flashcard's micro SD card. 14 | 15 | Copy the file `3DS/3DSController.ini` to the root of your 3DS's SD card, and change the line that says `IP: 192.168.0.4` to match your computer's local IP. 16 | 17 | If you are unsure of your local IP address, run `3DSController.exe` and it will tell you. 18 | 19 | Run `3DSController.exe` on your computer. If you are prompted, make sure to allow it through your firewall. 20 | 21 | Start the application on your 3DS, there is no GUI, it will automatically try to connect to the IP address you put in `3DSController.ini`. 22 | 23 | If it wasn't able to read the IP from `3DSController.ini`, it will notify you and quit. 24 | 25 | Otherwise, you should just see a black screen, this is a good sign. To see if it works, open Notepad and press some buttons on the 3DS, they should show up. You can also test if the joystick works by going to Configure USB Game Controllers in Control Panel, it shows up as vJoy. 26 | 27 | If using version 0.4 or above you can press L, R and X to bring up the keyboard. Press L, R and X again to close it. 28 | 29 | If using version 0.6 or above, up to 16 joystick buttons are available. If you wish to use more than 8, you need to configure vJoy. Search in your start menu for vJoyConfig and set buttons to 16. 30 | 31 | If using Ninjhax press Start and Select to return to the Homebrew Loader, otherwise you can just exit with the Home button. 32 | 33 | ### Setup and Usage (Linux) 34 | -For keyboard emulation 35 | Follow the Windows instructions, but use `3DSController.py` instead of the EXE. 36 | 37 | -For Joystick emulation, first, install [python-uinput](https://github.com/tuomasjjrasanen/python-uinput). BEWARE: The latest release of this library as of the writing of this tutorial is 0.10.2 which is broken for most updated systems. Download the master branch directly. 38 | 39 | Make sure that uinput module is running. You can do it from cosole like so: `#!sudo modprobe uinput` 40 | 41 | Then, follow the Windows instructions, but use `3DSController_gamepad.py` instead of the EXE. 42 | 43 | May work on OS X too, but this is not tested. 44 | 45 | ### Configuration 46 | Find the line `Port: 8889` and change it to your desired port, do this for both the 3DS's `3DSController.ini` and the PC's `3DSController.ini`. 47 | 48 | To use custom key bindings, just change the PC's `3DSController.ini` file, it should be straight forward. 49 | 50 | ### Configuration (Linux) 51 | The configuration for the keyboard emulation is in `3DSController.py`, not the INI. 52 | 53 | The configuration for the joystick emulation is in `3DSController_gamepad.py`, not the INI. 54 | 55 | ### Troubleshooting 56 | - Make sure that you are using the 3DS and PC application from the same release, 57 | - Make sure your 3DS has internet access (turn on the switch on the side of the 3DS so that an orange light shows) and is on the same network as your PC, 58 | - Make sure that the `3DSController.ini` is in the root of your 3DS's SD card (not flashcard micro SD), 59 | - Make sure that the `3DSController.ini` has the local IP of your computer, not your public IP, 60 | - Make sure your firewall isn't blocking the application, 61 | - Try using a different port (change the port for both the 3DS and PC's .ini file), 62 | --------------------------------------------------------------------------------