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