Changeset 1163 for Daodan/src
- Timestamp:
- Oct 24, 2021, 4:50:48 AM (3 years ago)
- Location:
- Daodan/src
- Files:
-
- 1 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
Daodan/src/Daodan.h
r1017 r1163 3 3 4 4 #include <windows.h> 5 #include <windowsx.h> 5 6 #include <assert.h> 6 7 #include "stdint.h" -
Daodan/src/Daodan_Config.c
r1162 r1163 252 252 {.intBoolVal = true}, 253 253 {.intBoolVal = true} }, 254 { "daodaninput", 255 "New input system that reports input on every frame, supports Raw Input for mice.", 256 C_BOOL, 257 {.intBoolVal = true}, 258 {.intBoolVal = true} }, 254 259 { "directinput", 255 260 "Enforces the usage of DirectInput on every system. Should be off for Linux/Wine.", … … 257 262 {.intBoolVal = true}, 258 263 {.intBoolVal = true} }, 264 { "mousesensitivity", 265 "Multiplier for Oni's mouse sensitivity. 1.0 is Oni's default.", 266 C_FLOAT, 267 {.floatVal = 1.0f}, 268 {.floatVal = 1.0f} }, 259 269 { "disablecmdline", 260 270 "Disables Oni's existing command line parser as Daodan has its own.", -
Daodan/src/Oni/GameState.h
r1161 r1163 1353 1353 int field_FC; 1354 1354 int field_100; 1355 char field_104;1355 char SlowMotion; 1356 1356 char gap_105[3]; 1357 int SlowMotion ;1357 int SlowMotionTimer; 1358 1358 char gap_10c[4]; 1359 1359 int field_110; … … 1362 1362 char field_138; 1363 1363 char gap_139[7]; 1364 int field_140;1364 int LastSixtieths; 1365 1365 int GameTime; 1366 int field_148;1366 int TargetGameTime; 1367 1367 int field_14C; 1368 1368 OniLevel* Level; -
Daodan/src/Oni/Oni.h
r1017 r1163 9 9 #define ONICALL __fastcall 10 10 11 typedef struct { 12 short x; 13 short y; 14 } IMtPoint; 11 15 16 // The following headers were written when Daodan used -fpack-struct, and 17 // should be rewritten 18 #pragma pack(push, 1) 12 19 #include "stdtypes.h" 13 20 #include "BFW_Motoko_Draw.h" … … 17 24 #include "GL.h" 18 25 #include "OBJt.h" 26 #pragma pack(pop) 27 28 #include "Input.h" 19 29 20 30 #define DDmAssert(expr) assert(expr); … … 34 44 } UUtRect; 35 45 36 typedef struct {37 uint32_t input;38 float analog;39 } LItDeviceInput;40 41 46 #include "Symbols_Var.h" 42 47 #include "Symbols_Func.h" -
Daodan/src/Oni/Symbols_Func.h
r1017 r1163 57 57 58 58 DefFunc(void, ONrGameState_Timer_Start, ONICALL, (char* function, int time), 0x004FD370); 59 DefFunc(void, ONrGameState_HandleUtilityInput, ONICALL, ( const void* inInput), 0x004f6200);59 DefFunc(void, ONrGameState_HandleUtilityInput, ONICALL, (GameInput *input), 0x004f6200); 60 60 DefFunc(uint8_t, ONrDebugKey_WentDown, ONICALL, (uint32_t inKey), 0x005050d0); 61 61 … … 177 177 DefFunc(void, LIrActionBuffer_Add, ONICALL, (void* unknown, LItDeviceInput* input), 0x00403b30); 178 178 179 // Called during the game loop to run the Windows message loop 180 DefFunc(UUtBool, LIiPlatform_InputEvent_GetEvent, ONICALL, (void), 0x004036d0); 181 182 // Called by the game loop to get the latest input frames 183 DefFunc(void, LIrActionBuffer_Get, ONICALL, (short* count, LItActionBuffer **buffers), 0x00403be0); 184 185 // Gets the mouse position 186 DefFunc(void, LIrPlatform_InputEvent_GetMouse, ONICALL, (int active, LItInputEvent *info), 0x00402ca0); 187 188 // Checks if a keyboard key is pressed 189 DefFunc(UUtBool, LIrPlatform_TestKey, ONICALL, (int key, int active), 0x00403930); 190 191 // Translates a key name (from key_config.txt) to a key code 192 DefFunc(int, LIrTranslate_InputName, ONICALL, (char *name), 0x00403a90); 193 194 // Updates TargetGameTime in the game state 195 DefFunc(void, ONrGameState_UpdateServerTime, ONICALL, (GameState *game_state), 0x004fbeb0); 196 197 // Basically stricmp, but it only ever does ASCII case folding 198 DefFunc(int, UUrString_Compare_NoCase, ONICALL, (const char *str1, const char *str2), 0x004266d0); 199 200 // A safe strcpy which lets you specify the size of the target buffer and always 201 // NUL-terminates. Kind of like strlcpy. Just don't call it with dest_size = 0. 202 DefFunc(void, UUrString_Copy, ONICALL, (char *dest, const char *src, size_t dest_size), 0x004265f0); 179 203 180 204 #undef DefFunc -
Daodan/src/Oni/Symbols_Var.h
r994 r1163 84 84 //#define OBJgFlag_DrawNameDistance (*((void*)0x005ec634)) 85 85 86 // Oni's platform input system stores the window HWND in this global 87 #define LIgPlatform_HWND (*((HWND *)0x0055cae8)) 88 89 // Is Oni's input system active? True in gameplay and false in menus. 90 // LIrPlatform_Mode_Set gets called when this changes. 91 #define LIgMode_Internal (*((UUtBool *)0x0055fd40)) 92 93 // List of bindings from Oni's internal key codes to LItActionDescriptions 94 #define LIgBindingArray ((LItBinding *)0x0055fa20) 95 96 // Is "Invert Mouse" checked in the Options menu? If so, platform specific input 97 // code should invert the cursor's Y offset when building LItActionBuffers. 98 #define LIgMode_InvertMouse (*((UUtBool *)0x0052ecf4)) 99 100 // This is a map from DirectInput scan codes to Oni's internal key codes, the 101 // latter of which mostly match ASCII for a US keyboard layout. DirectInput scan 102 // codes are mostly the same as the PS2 make codes that Windows uses in other 103 // APIs except that extended keys are represented by bit 0x80 being set. 104 #define LIgPlatform_ScanCodeToChar ((uint8_t *)0x005292b8) 105 106 // Script variable to enable/disable centering the cursor in the window when 107 // processing input. On by default. 108 #define LIgCenterCursor (*((int *)0x0052d88d)) 109 110 // List of bindable input actions 111 #define LIgActionDescriptions ((LItActionDescription*)0x0052db18) 112 86 113 #endif -
Daodan/src/Patches/Cheater.c
r1017 r1163 297 297 298 298 299 static void BindableCheatCallback ( CustomActionCallbackArgument cheatnum) {299 static void BindableCheatCallback (intptr_t cheatnum) { 300 300 uint8_t res = DDrCheater (cheatnum); 301 301 if (res) … … 308 308 oniCheatCode* cur; 309 309 for (cur = DDr_CheatTable; cur->name != 0; cur++) { 310 // char* val = malloc(20); 311 // sprintf(val, "cheat_%s", cur->name); 312 Input_RegisterCustomAction (cur->name, EVENT_KEYPRESS, 0, BindableCheatCallback, cur->func); 310 DDrInput_RegisterCustomAction(cur->name, DDcEventType_KeyPress, 311 BindableCheatCallback, cur->func); 313 312 } 314 313 } -
Daodan/src/Patches/Input.c
r1017 r1163 5 5 #include "Input.h" 6 6 #include "../Oni/Oni.h" 7 #include "../Daodan_Config.h" 7 8 #include "../Daodan_Patch.h" 8 9 #include "Utility.h" 9 10 10 #define EVENT_KEYPRESS_SECURETIME 311 12 11 typedef struct { 13 uint32_t key; 14 const char* actionname; 15 ActionEventType_t eventType; 16 uint32_t keydownTimeoutTicks; 17 int64_t lastevent; 18 19 CustomActionCallback_t callback; 20 CustomActionCallbackArgument callbackArgument; 21 } DD_CustomAction_t; 22 23 static DD_CustomAction_t customActions[100]; 24 25 26 void Input_RegisterCustomAction (const char* actionname, ActionEventType_t eventType, uint32_t keydownTimeoutTicks, CustomActionCallback_t callback, CustomActionCallbackArgument callbackArgument) { 27 uint16_t i = 0; 28 DD_CustomAction_t* cur = customActions; 29 30 while ( (i < ARRAY_SIZE(customActions)) && (cur->callback != 0)) { 31 cur++; 32 i++; 33 } 34 35 if (i < ARRAY_SIZE(customActions)) { 36 cur->actionname = actionname; 37 cur->eventType = eventType; 38 cur->keydownTimeoutTicks = keydownTimeoutTicks; 39 cur->callback = callback; 40 cur->callbackArgument = callbackArgument; 12 LItActionDescription descr; 13 DDtActionEventType eventType; 14 15 DDtCustomActionCallback callback; 16 intptr_t ctx; 17 } DDtCustomAction; 18 19 static DDtCustomAction DDgCustomActions[100] = { 0 }; 20 21 // Extra keys (make sure these don't collide with Oni's LIc_* keys) 22 enum { 23 DDcKey_MouseButton5 = LIcKey_Max, 24 DDcKey_ScrollUp, 25 DDcKey_ScrollDown, 26 DDcKey_ScrollLeft, 27 DDcKey_ScrollRight, 28 }; 29 30 // Enhanced version of LIgInputNames from Oni with some extra keys 31 static const LItInputName DDgInputNames[] = { 32 // The following key names are mapped in Oni 33 {"fkey1", LIcKey_FKey1}, {"fkey2", LIcKey_FKey2}, {"fkey3", LIcKey_FKey3}, 34 {"fkey4", LIcKey_FKey4}, {"fkey5", LIcKey_FKey5}, {"fkey6", LIcKey_FKey6}, 35 {"fkey7", LIcKey_FKey7}, {"fkey8", LIcKey_FKey8}, {"fkey9", LIcKey_FKey9}, 36 {"fkey10", LIcKey_FKey10}, {"fkey11", LIcKey_FKey11}, 37 {"fkey12", LIcKey_FKey12}, {"fkey13", LIcKey_FKey13}, 38 {"fkey14", LIcKey_FKey14}, {"fkey15", LIcKey_FKey15}, 39 {"backspace", LIcKey_Backspace}, {"tab", LIcKey_Tab}, 40 {"capslock", LIcKey_CapsLock}, {"enter", LIcKey_Enter}, 41 {"leftshift", LIcKey_LeftShift}, {"rightshift", LIcKey_RightShift}, 42 {"leftcontrol", LIcKey_LeftControl}, 43 {"leftwindows", 0x94}, {"leftoption", 0x94}, // Does nothing in Oni 44 {"leftalt", LIcKey_LeftAlt}, {"space", ' '}, {"rightalt", LIcKey_RightAlt}, 45 {"rightoption", 0x97}, {"rightwindows", 0x97}, // Does nothing in Oni 46 {"rightcontrol", LIcKey_RightControl}, {"printscreen", LIcKey_PrintScreen}, 47 {"scrolllock", LIcKey_ScrollLock}, {"pause", LIcKey_Pause}, 48 {"insert", LIcKey_Insert}, {"home", LIcKey_Home}, {"pageup", LIcKey_PageUp}, 49 {"delete", LIcKey_Delete}, {"end", LIcKey_End}, 50 {"pagedown", LIcKey_PageDown}, {"uparrow", LIcKey_UpArrow}, 51 {"leftarrow", LIcKey_LeftArrow}, {"downarrow", LIcKey_DownArrow}, 52 {"rightarrow", LIcKey_RightArrow}, {"numlock", LIcKey_NumLock}, 53 {"divide", LIcKey_Divide}, {"multiply", LIcKey_Multiply}, 54 {"subtract", LIcKey_Subtract}, {"add", LIcKey_Add}, 55 {"numpadequals", LIcKey_NumpadEquals}, {"numpadenter", LIcKey_NumpadEnter}, 56 {"decimal", LIcKey_Decimal}, {"numpad0", LIcKey_Numpad0}, 57 {"numpad1", LIcKey_Numpad1}, {"numpad2", LIcKey_Numpad2}, 58 {"numpad3", LIcKey_Numpad3}, {"numpad4", LIcKey_Numpad4}, 59 {"numpad5", LIcKey_Numpad5}, {"numpad6", LIcKey_Numpad6}, 60 {"numpad7", LIcKey_Numpad7}, {"numpad8", LIcKey_Numpad8}, 61 {"numpad9", LIcKey_Numpad9}, {"backslash", '\\'}, {"semicolon", ';'}, 62 {"period", '.'}, {"apostrophe", '\''}, {"slash", '/'}, {"leftbracket", '['}, 63 {"rightbracket", ']'}, {"comma", ','}, 64 {"mousebutton1", LIcKey_MouseButton1}, 65 {"mousebutton2", LIcKey_MouseButton2}, 66 {"mousebutton3", LIcKey_MouseButton3}, 67 {"mousebutton4", LIcKey_MouseButton4}, 68 {"mousexaxis", LIcKey_MouseXAxis}, {"mouseyaxis", LIcKey_MouseYAxis}, 69 {"mousezaxis", LIcKey_MouseZAxis}, 70 71 // Extra keys for Daodan Input 72 {"mousebutton5", DDcKey_MouseButton5}, 73 {"scrollup", DDcKey_ScrollUp}, 74 {"scrolldown", DDcKey_ScrollDown}, 75 {"scrollleft", DDcKey_ScrollLeft}, 76 {"scrollright", DDcKey_ScrollRight}, 77 78 {"", 0} 79 }; 80 81 // Enhanced version of LIgPlatform_ScanCodeToChar from Oni 82 static const uint8_t DDgPlatform_ScanCodeToChar[256] = { 83 // The following scan codes are mapped in Oni 84 [0x01] = LIcKey_Escape, [0x02] = '1', [0x03] = '2', [0x04] = '3', 85 [0x05] = '4', [0x06] = '5', [0x07] = '6', [0x08] = '7', [0x09] = '8', 86 [0x0a] = '9', [0x0b] = '0', [0x0c] = '-', [0x0d] = '=', 87 [0x0e] = LIcKey_Backspace, [0x0f] = LIcKey_Tab, [0x10] = 'q', [0x11] = 'w', 88 [0x12] = 'e', [0x13] = 'r', [0x14] = 't', [0x15] = 'y', [0x16] = 'u', 89 [0x17] = 'i', [0x18] = 'o', [0x19] = 'p', [0x1a] = '[', [0x1b] = ']', 90 [0x1c] = LIcKey_Enter, [0x1d] = LIcKey_LeftControl, [0x1e] = 'a', 91 [0x1f] = 's', [0x20] = 'd', [0x21] = 'f', [0x22] = 'g', [0x23] = 'h', 92 [0x24] = 'j', [0x25] = 'k', [0x26] = 'l', [0x27] = ';', [0x28] = '\'', 93 [0x29] = '`', [0x2a] = LIcKey_LeftShift, [0x2b] = '\\', [0x2c] = 'z', 94 [0x2d] = 'x', [0x2e] = 'c', [0x2f] = 'v', [0x30] = 'b', [0x31] = 'n', 95 [0x32] = 'm', [0x33] = ',', [0x34] = '.', [0x35] = '/', 96 [0x36] = LIcKey_RightShift, [0x37] = LIcKey_Multiply, 97 [0x38] = LIcKey_LeftAlt, [0x39] = ' ', [0x3a] = LIcKey_CapsLock, 98 [0x3b] = LIcKey_FKey1, [0x3c] = LIcKey_FKey2, [0x3d] = LIcKey_FKey3, 99 [0x3e] = LIcKey_FKey4, [0x3f] = LIcKey_FKey5, [0x40] = LIcKey_FKey6, 100 [0x41] = LIcKey_FKey7, [0x42] = LIcKey_FKey8, [0x43] = LIcKey_FKey9, 101 [0x44] = LIcKey_FKey10, [0x45] = LIcKey_NumLock, [0x46] = LIcKey_ScrollLock, 102 [0x47] = LIcKey_Numpad7, [0x48] = LIcKey_Numpad8, [0x49] = LIcKey_Numpad9, 103 [0x4a] = LIcKey_Subtract, [0x4b] = LIcKey_Numpad4, [0x4c] = LIcKey_Numpad5, 104 [0x4d] = LIcKey_Numpad6, [0x4e] = LIcKey_Add, [0x4f] = LIcKey_Numpad1, 105 [0x50] = LIcKey_Numpad2, [0x51] = LIcKey_Numpad3, [0x52] = LIcKey_Numpad0, 106 [0x53] = LIcKey_Decimal, [0x57] = LIcKey_FKey11, [0x58] = LIcKey_FKey12, 107 [0x64] = LIcKey_FKey13, [0x65] = LIcKey_FKey14, [0x66] = LIcKey_FKey15, 108 [0x8d] = LIcKey_NumpadEquals, [0x9c] = LIcKey_NumpadEnter, 109 [0x9d] = LIcKey_RightControl, [0xb3] = LIcKey_NumpadComma, 110 [0xb5] = LIcKey_Divide, [0xb8] = LIcKey_RightAlt, [0xc7] = LIcKey_Home, 111 [0xc8] = LIcKey_UpArrow, [0xc9] = LIcKey_PageUp, [0xcb] = LIcKey_LeftArrow, 112 [0xcd] = LIcKey_RightArrow, [0xcf] = LIcKey_End, [0xd0] = LIcKey_DownArrow, 113 [0xd2] = LIcKey_Insert, [0xd3] = LIcKey_Delete, [0xdb] = LIcKey_LeftWindows, 114 [0xdc] = LIcKey_RightWindows, [0xdd] = LIcKey_Apps, 115 116 // Missing in Oni 117 [0xd1] = LIcKey_PageDown, 118 }; 119 120 // Set in Patches.c if the Daodan input patches are applied. This just enables 121 // the windows message handling for now 122 bool DDgUseDaodanInput = false; 123 124 // The Oni key codes that correspond to the togglable keys 125 static uint8_t DDgCapsOniKey = 0; 126 static uint8_t DDgScrollOniKey = 0; 127 static uint8_t DDgNumLockOniKey = 0; 128 129 // Multiplier for mouse values 130 static float DDgMouseSensitivity = 1.0; 131 132 // Accumulators for mouse scrolling. These are needed because some mice have 133 // continuous scroll wheels (not to mention touchpads.) We should only add an 134 // action to Oni's input if one of these accumulators exceeds +/-WHEEL_DELTA. 135 static int DDgWheelDelta_V = 0; 136 static int DDgWheelDelta_H = 0; 137 138 // UUrMachineTime_High for the last update of the accumulators. Used so they can 139 // be reset after a period of no scroll events. 140 static int64_t DDgWheelDelta_Updated = 0; 141 142 // Temporary action buffer that we build over the duration of a frame with the 143 // input we're going to send to the engine. This includes the accumulated 144 // movement of the mouse cursor and all actions (keyboard and mouse buttons) 145 // that were pressed this frame (but not held down from previous frames - that 146 // gets added later from DDgInputState.) 147 static LItActionBuffer DDgActionBuffer = { 0 }; 148 149 // Temporary buffer containing the current state of the keyboard and mouse 150 // buttons, that is, if they're being held now 151 static char DDgInputState[256] = { 0 }; 152 153 static short ONICALL DDrBinding_Add(int key, const char *name) 154 { 155 // First try to replace an existing binding for the same key 156 LItBinding *binding = NULL; 157 for (int i = 0; i < 100; i++) { 158 if (LIgBindingArray[i].key == key) { 159 binding = &LIgBindingArray[i]; 160 break; 161 } 162 } 163 164 // If there are no existing bindings for this key, find a free entry 165 if (!binding) { 166 for (int i = 0; i < 100; i++) { 167 if (!LIgBindingArray[i].key) { 168 binding = &LIgBindingArray[i]; 169 break; 170 } 171 } 172 } 173 // No free entries, so give up 174 if (!binding) 175 return 2; 176 177 // Now try to find the action to bind to. First check Oni's built-in list 178 // of actions. 179 LItActionDescription *descr = NULL; 180 for (int i = 0; LIgActionDescriptions[i].name[0]; i++) { 181 if (!UUrString_Compare_NoCase(name, LIgActionDescriptions[i].name)) { 182 descr = &LIgActionDescriptions[i]; 183 break; 184 } 185 } 186 187 // Next, try Daodan's list of custom actions 188 if (!descr) { 189 for (int i = 0; i < ARRAY_SIZE(DDgCustomActions); i++) { 190 if (!DDgCustomActions[i].descr.name[0]) 191 break; 192 193 if (!UUrString_Compare_NoCase(name, DDgCustomActions[i].descr.name)) { 194 descr = &DDgCustomActions[i].descr; 195 break; 196 } 197 } 198 } 199 if (!descr) 200 return 0; 201 202 binding->key = key; 203 binding->descr = descr; 204 return 0; 205 } 206 207 static void ONICALL DDrGameState_HandleUtilityInput(GameInput *input) 208 { 209 // Mac Oni 1.2.1 checks the cheat binds here, so we should too. Note that 210 // unlike Mac Oni, which hardcodes each cheat here, we use our flexible 211 // custom action system. 212 for (int i = 0; i < ARRAY_SIZE(DDgCustomActions); i++) { 213 if (!DDgCustomActions[i].descr.name[0]) 214 break; 215 216 uint64_t action = 1ull << DDgCustomActions[i].descr.index; 217 bool active = false; 218 219 switch (DDgCustomActions[i].eventType) { 220 case DDcEventType_KeyPress: 221 if (input->ActionsPressed & action) 222 active = true; 223 break; 224 case DDcEventType_KeyDown: 225 if (input->ActionsDown & action) 226 active = true; 227 break; 228 } 229 230 if (active) 231 DDgCustomActions[i].callback(DDgCustomActions[i].ctx); 232 } 233 234 // Now do everything Oni does in this function 235 ONrGameState_HandleUtilityInput(input); 236 237 // This is for show_triggervolumes. Mac Oni does this at the end of 238 // HandleUtilityInput too. 239 if (ONrDebugKey_WentDown(7)) 240 OBJgTriggerVolume_Visible = !OBJgTriggerVolume_Visible; 241 } 242 243 static int GetLowestFreeDigitalAction(void) 244 { 245 // Get the digital action indexes that Oni is using right now, plus any in 246 // use by our custom actions 247 uint64_t used = 0; 248 for (int i = 0; LIgActionDescriptions[i].name[0]; i++) { 249 if (LIgActionDescriptions[i].type != LIcActionType_Digital) 250 continue; 251 used |= 1ull << LIgActionDescriptions[i].index; 252 } 253 for (int i = 0; i < ARRAY_SIZE(DDgCustomActions); i++) { 254 if (!DDgCustomActions[i].descr.name[0]) 255 break; 256 257 if (DDgCustomActions[i].descr.type != LIcActionType_Digital) 258 continue; 259 used |= 1ull << DDgCustomActions[i].descr.index; 260 } 261 262 // Get the lowest unused action index and use it. This isn't totally safe 263 // since Oni _might_ have "orphaned" actions that are checked in the code 264 // but not bindable, but Mac Oni 1.2.1 seems to have allocated its new 265 // bindings this way, including filling the gaps between eg. f12 and 266 // lookmode, so we're probably fine to do the same thing. 267 unsigned long lowest; 268 if (BitScanForward(&lowest, ~(unsigned long)used)) 269 return lowest; 270 if (BitScanForward(&lowest, ~(unsigned long)(used >> 32))) 271 return lowest + 32; 272 return -1; 273 } 274 275 void DDrInput_RegisterCustomAction(const char *name, DDtActionEventType type, 276 DDtCustomActionCallback callback, 277 intptr_t ctx) 278 { 279 int index = GetLowestFreeDigitalAction(); 280 if (index < 0) { 281 STARTUPMESSAGE("Registering action %s failed, maximum actions reached", 282 name); 283 return; 284 } 285 286 DDtCustomAction *action; 287 for (int i = 0; i < ARRAY_SIZE(DDgCustomActions); i++) { 288 if (!DDgCustomActions[i].descr.name[0]) { 289 action = &DDgCustomActions[i]; 290 break; 291 } 292 } 293 if (!action) { 294 STARTUPMESSAGE("Registering action %s failed, maximum actions reached", 295 name); 296 return; 297 } 298 299 *action = (DDtCustomAction) { 300 .descr = { 301 .type = 1, 302 .index = index, 303 }, 304 .callback = callback, 305 .ctx = ctx, 306 }; 307 UUrString_Copy(action->descr.name, name, sizeof(action->descr.name)); 308 } 309 310 static uint8_t VKeyToChar(UINT vkey) 311 { 312 int sc = MapVirtualKeyA(vkey, MAPVK_VK_TO_VSC_EX); 313 if ((sc & 0xff00) == 0xe000) 314 sc |= 0x80; 315 sc &= 0xff; 316 return DDgPlatform_ScanCodeToChar[sc]; 317 } 318 319 static int ONICALL DDrTranslate_InputName(char *name) 320 { 321 // Mutate the source argument to convert to lowercase. It's ugly but Oni 322 // does this too. Unlike Oni, we don't use tolower, since passing 323 // potentially out-of-range values to tolower is undefined. 324 for (char *c = name; *c; c++) { 325 if (*c >= 'A' && *c <= 'Z') 326 *c = *c - 0x20; 327 } 328 329 // Single character names just use that character as the key code. Unlike 330 // Oni, we restrict this to printable ASCII. 331 if (strlen(name) == 1 && name[0] >= ' ' && name[0] <= '~') 332 return name[0]; 333 334 // Otherwise, look up the name in DDgInputNames 335 for (int i = 0; DDgInputNames[i].name[0]; i++) { 336 if (!strcmp(name, DDgInputNames[i].name)) 337 return DDgInputNames[i].key; 338 } 339 return 0; 340 } 341 342 static void CenterCursor(void) 343 { 344 // This can be set to false by script. Not sure why you'd turn it off, but 345 // let's respect it. 346 if (!LIgCenterCursor) 347 return; 348 349 RECT rc; 350 if (!GetClientRect(LIgPlatform_HWND, &rc)) 351 return; 352 POINT mid = { rc.right / 2, rc.bottom / 2 }; 353 if (!ClientToScreen(LIgPlatform_HWND, &mid)) 354 return; 355 SetCursorPos(mid.x, mid.y); 356 } 357 358 static void ONICALL DDrPlatform_Mode_Set(int active) 359 { 360 // Oni's input system uses LIgPlatform_HWND instead of 361 // ONgPlatformData.Window, but they should both have the same value 362 DDmAssert(LIgPlatform_HWND); 363 364 // Clear the input state when switching input modes 365 for (int i = 0; i < ARRAY_SIZE(DDgInputState); i++) 366 DDgInputState[i] = 0; 367 DDgActionBuffer = (LItActionBuffer) { 0 }; 368 369 // Center the cursor before switching modes. Raw Input doesn't need the 370 // cursor to be centered, but when switching modes, centering the cursor 371 // means it will be in a predictable position for using the pause or F1 372 // menu, which are centered on the screen. Also, the cursor must be inside 373 // the clip region when we call ClipCursor, otherwise it doesn't work. 374 CenterCursor(); 375 376 // If leaving input mode (switching from gameplay to menus,) unregister the 377 // input device. Otherwise, register it. 378 RegisterRawInputDevices(&(RAWINPUTDEVICE) { 379 .usUsagePage = 0x01, // HID_USAGE_PAGE_GENERIC 380 .usUsage = 0x02, // HID_USAGE_GENERIC_MOUSE 381 .hwndTarget = LIgPlatform_HWND, 382 .dwFlags = active ? 0 : RIDEV_REMOVE, 383 }, 1, sizeof(RAWINPUTDEVICE)); 384 385 if (active) { 386 DDgMouseSensitivity = 387 DDrConfig_GetOptOfType("windows.mousesensitivity", C_FLOAT)->value.floatVal; 388 389 // Get the Oni key codes corresponding to the togglable keys 390 DDgCapsOniKey = VKeyToChar(VK_CAPITAL); 391 DDgScrollOniKey = VKeyToChar(VK_SCROLL); 392 DDgNumLockOniKey = VKeyToChar(VK_NUMLOCK); 393 394 // Clip the cursor to the window bounds when entering input mode to 395 // prevent other programs being clicked in windowed mode 396 RECT rc; 397 if (GetClientRect(LIgPlatform_HWND, &rc)) { 398 if (MapWindowRect(LIgPlatform_HWND, NULL, &rc)) 399 ClipCursor(&rc); 400 } 41 401 } else { 42 STARTUPMESSAGE("Registering action %s failed, maximum actions reached", actionname); 43 } 44 } 45 46 47 _LIrBinding_Add Oni_LIrBinding_Add = (_LIrBinding_Add)0; 48 uint16_t ONICALL DD_LIrBinding_Add(uint32_t key, const char* name) { 49 DD_CustomAction_t* cur; 50 for (cur = customActions; cur->callback != 0; cur++) { 51 if (!strcmp(name, cur->actionname)) { 52 cur->key = key; 53 return 0; 54 } 55 } 56 57 return Oni_LIrBinding_Add(key, name); 58 } 59 60 _LIrActionBuffer_Add Oni_LIrActionBuffer_Add = (_LIrActionBuffer_Add)0; 61 void ONICALL DD_LIrActionBuffer_Add(void* unknown, LItDeviceInput* input) { 62 DD_CustomAction_t* cur; 63 for (cur = customActions; cur->callback != 0; cur++) { 64 if (cur->key == input->input) { 65 int64_t curTime = UUrMachineTime_Sixtieths(); 66 if (cur->eventType == EVENT_KEYPRESS) { 67 if (cur->lastevent + EVENT_KEYPRESS_SECURETIME < curTime) { 68 cur->callback(cur->callbackArgument); 69 } 70 cur->lastevent = curTime; 71 } else if (cur->eventType == EVENT_KEYDOWN) { 72 if (cur->lastevent + cur->keydownTimeoutTicks < curTime) { 73 cur->callback(cur->callbackArgument); 74 cur->lastevent = curTime; 75 } 402 ClipCursor(NULL); 403 } 404 } 405 406 static void ONICALL DDrPlatform_InputEvent_GetMouse(int active, 407 LItInputEvent *event) 408 { 409 POINT pt; 410 if (!GetCursorPos(&pt)) 411 goto error; 412 413 // Unlike Oni's version of this function, we support windowed mode by 414 // mapping the cursor coordinates to the window's client area 415 if (!ScreenToClient(LIgPlatform_HWND, &pt)) 416 goto error; 417 418 *event = (LItInputEvent) { .mouse_pos = { pt.x, pt.y } }; 419 return; 420 421 error: 422 *event = (LItInputEvent) { 0 }; 423 return; 424 } 425 426 static UUtBool ONICALL DDrPlatform_TestKey(int ch, int active) 427 { 428 // DDrPlatform_TestKey is always called with active = LIgMode_Internal 429 430 if (active) { 431 // The input system is running, which means DDgInputState will be up to 432 // date, so just use that 433 return DDgInputState[ch]; 434 } else { 435 // Use Oni's map from key codes to DirectInput scan codes to get the 436 // scan code we want to test for 437 int sc = 0; 438 for (int i = 0; i < 256; i++) { 439 if (DDgPlatform_ScanCodeToChar[i] == ch) { 440 sc = i; 441 break; 76 442 } 443 } 444 if (!sc) 445 return UUcFalse; 446 447 // DirectInput scan codes have 0x80 set for extended keys. Replace this 448 // with an 0xe0 prefix for MapVirtualKey. 449 if (sc & 0x80) { 450 sc &= 0x7f; 451 sc |= 0xe000; 452 } 453 int vkey = MapVirtualKeyA(sc, MAPVK_VSC_TO_VK_EX); 454 455 // Now check if the key is down. We must use GetAsyncKeyState here 456 // because DDrPlatform_TestKey can be called from anywhere, even before 457 // we have a message loop or game loop. For example, it's called from 458 // ONiMain to test the state of the shift key on startup. 459 return (GetAsyncKeyState(vkey) & 0x8000) ? UUcTrue : UUcFalse; 460 } 461 } 462 463 // Update DDgInputState and DDgActionBuffer with a new key state 464 static void SetKeyState(int key, bool down) 465 { 466 // Keep track of held keys. Held keys are added to every buffer and they're 467 // also checked in DDrPlatform_TestKey. 468 DDgInputState[key] = down; 469 470 if (down) { 471 // Add the key to the next buffer. This is so key presses are never 472 // dropped, even if the key is released before Oni checks the buffer. 473 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 474 .input = key, 475 .analog = 1.0, 476 }); 477 } 478 } 479 480 static void ProcessRawInputPacket(RAWINPUT *ri) 481 { 482 if (ri->header.dwType != RIM_TYPEMOUSE) 483 return; 484 485 // We don't handle MOUSE_MOVE_ABSOLUTE at all yet 486 if (!(ri->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)) { 487 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 488 .input = LIcKey_MouseXAxis, 489 .analog = (float)ri->data.mouse.lLastX * 0.25 * DDgMouseSensitivity, 490 }); 491 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 492 .input = LIcKey_MouseYAxis, 493 .analog = (float)ri->data.mouse.lLastY * 494 (LIgMode_InvertMouse ? -0.25 : 0.25) * DDgMouseSensitivity, 495 }); 496 } 497 498 // Oni supports using the mouse wheel to look up and down or left and right 499 // by binding mousezaxis to aim_lr or aim_ud. We don't support this 500 // incredibly useful feature, but if you need it, let me know. Instead, we 501 // allow scrolling to be bound to digital actions. 502 if (ri->data.mouse.usButtonFlags & (RI_MOUSE_WHEEL | RI_MOUSE_HWHEEL)) { 503 int64_t now = UUrMachineTime_High(); 504 int64_t last_updated = now - DDgWheelDelta_Updated; 505 DDgWheelDelta_Updated = now; 506 507 // Reset the accumulators if too much time has passed since the last 508 // scroll event. The player is assumed to have finished scrolling. 509 if (last_updated / UUrMachineTime_High_Frequency() > 0.3) { 510 DDgWheelDelta_V = 0; 511 DDgWheelDelta_H = 0; 512 } 513 514 int neg_key, pos_key; 515 int *delta; 516 if (ri->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) { 517 neg_key = DDcKey_ScrollUp; 518 pos_key = DDcKey_ScrollDown; 519 delta = &DDgWheelDelta_V; 520 } else { 521 neg_key = DDcKey_ScrollLeft; 522 pos_key = DDcKey_ScrollRight; 523 delta = &DDgWheelDelta_H; 524 } 525 526 // To support touchpad scrolling and mice with continuous scroll wheels, 527 // accumulate the wheel delta and only generate an input event once it 528 // crosses the WHEEL_DELTA threshold 529 *delta += (short)ri->data.mouse.usButtonData; 530 if (*delta >= WHEEL_DELTA) { 531 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 532 .input = neg_key, 533 .analog = 1.0, 534 }); 535 536 *delta -= (*delta / WHEEL_DELTA) * WHEEL_DELTA; 537 } else if (*delta <= -WHEEL_DELTA) { 538 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 539 .input = pos_key, 540 .analog = 1.0, 541 }); 542 543 *delta -= (*delta / -WHEEL_DELTA) * -WHEEL_DELTA; 544 } 545 } 546 547 // This probably doesn't obey SM_SWAPBUTTON... should it? 548 if (ri->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) 549 SetKeyState(LIcKey_MouseButton1, true); 550 if (ri->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) 551 SetKeyState(LIcKey_MouseButton1, false); 552 if (ri->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) 553 SetKeyState(LIcKey_MouseButton2, true); 554 if (ri->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) 555 SetKeyState(LIcKey_MouseButton2, false); 556 if (ri->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) 557 SetKeyState(LIcKey_MouseButton3, true); 558 if (ri->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) 559 SetKeyState(LIcKey_MouseButton3, false); 560 561 // Oni supports binding this button too. It's the back button on most mice. 562 if (ri->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) 563 SetKeyState(LIcKey_MouseButton4, true); 564 if (ri->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) 565 SetKeyState(LIcKey_MouseButton4, false); 566 567 // Daodan supports binding the forward button too 568 if (ri->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) 569 SetKeyState(DDcKey_MouseButton5, true); 570 if (ri->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) 571 SetKeyState(DDcKey_MouseButton5, false); 572 } 573 574 static void DrainRawInput(void) 575 { 576 if (!LIgMode_Internal) 577 return; 578 579 UINT ri_size = 10240; 580 static RAWINPUT *ri_buf = NULL; 581 if (!ri_buf) 582 ri_buf = calloc(1, ri_size); 583 584 BOOL wow_hack; 585 IsWow64Process(GetCurrentProcess(), &wow_hack); 586 587 for (;;) { 588 UINT count = GetRawInputBuffer(ri_buf, &ri_size, sizeof ri_buf->header); 589 if (count == 0 || count == (UINT)-1) 77 590 return; 78 } 79 } 80 Oni_LIrActionBuffer_Add(unknown, input); 81 } 82 83 void Input_PatchCode () { 84 Oni_LIrBinding_Add = DDrPatch_MakeDetour((void*)LIrBinding_Add, (void*)DD_LIrBinding_Add); 85 Oni_LIrActionBuffer_Add = DDrPatch_MakeDetour((void*)LIrActionBuffer_Add, (void*)DD_LIrActionBuffer_Add); 86 } 87 591 592 RAWINPUT *ri = ri_buf; 593 for (UINT i = 0; i < count; i++) { 594 // In WOW64, these structures are aligned like in Win64 and they 595 // have to be fixed to use from 32-bit code. Yes, really. 596 if (wow_hack) { 597 memmove(&ri->data, ((char *)&ri->data) + 8, 598 ri->header.dwSize - offsetof(RAWINPUT, data) - 8); 599 } 600 601 ProcessRawInputPacket(ri); 602 ri = NEXTRAWINPUTBLOCK(ri); 603 } 604 } 605 } 606 607 static UUtBool ONICALL DDiPlatform_InputEvent_GetEvent(void) 608 { 609 // Center the cursor just in case. Raw Input doesn't need it, but sometimes 610 // ClipCursor doesn't work for some reason and in that case we should still 611 // prevent the user from accidentally clicking on other windows. 612 if (LIgMode_Internal) 613 CenterCursor(); 614 615 // Do a buffered read of raw input. Apparently this is faster for high-res 616 // mice. Note that we still have to handle WM_INPUT in our wndproc in case 617 // a WM_INPUT message arrives during the message loop. 618 DrainRawInput(); 619 620 // Oni only processes a maximum of three messages here (for performance 621 // reasons?) We're actually using Windows messages for input so we need to 622 // process all of them. 623 MSG msg; 624 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { 625 TranslateMessage(&msg); 626 DispatchMessageA(&msg); 627 } 628 629 // Oni returns true here if there are still messages to process, so that 630 // LIrMode_Set and LIrMode_Set_Internal can call this repeatedly to drain 631 // all messages. We always drain all messages so return false. 632 return UUcFalse; 633 } 634 635 static bool HandleWmInput(HRAWINPUT hri, WPARAM wparam) 636 { 637 if (!LIgMode_Internal) 638 return false; 639 640 static RAWINPUT* ri = NULL; 641 static UINT ri_size = 0; 642 UINT minsize = 0; 643 644 GetRawInputData(hri, RID_INPUT, NULL, &minsize, sizeof ri->header); 645 if (ri_size < minsize) { 646 if (ri) 647 free(ri); 648 ri_size = minsize; 649 ri = calloc(1, ri_size); 650 } 651 if (GetRawInputData(hri, RID_INPUT, ri, &ri_size, sizeof ri->header) == (UINT)-1) 652 return false; 653 654 ProcessRawInputPacket(ri); 655 return true; 656 } 657 658 static void HandleWmWindowPosChanged(WINDOWPOS *pos) 659 { 660 if (!LIgMode_Internal) 661 return; 662 663 CenterCursor(); 664 665 RECT rc = { pos->x, pos->y, pos->x + pos->cx, pos->y + pos->cy }; 666 ClipCursor(&rc); 667 } 668 669 static void HandleWmKeyboard(int vkey, WORD repeat_count, WORD flags) 670 { 671 if (!LIgMode_Internal) 672 return; 673 674 bool is_extended = flags & KF_EXTENDED; 675 bool is_repeat = flags & KF_REPEAT; 676 bool is_up = flags & KF_UP; 677 BYTE sc = LOBYTE(flags); 678 679 // Ignore togglable keys since we handle them specially 680 if (vkey == VK_CAPITAL || vkey == VK_SCROLL || vkey == VK_NUMLOCK) 681 return; 682 683 // Ignore key down messages sent because of key-repeat 684 if (!is_up && is_repeat) 685 return; 686 687 // Apparently some synthetic keyboard messages can be missing the scancode, 688 // so get it from the vkey 689 if (!sc) 690 sc = MapVirtualKeyA(vkey, MAPVK_VK_TO_VSC); 691 692 // DirectInput scan codes have 0x80 set for extended keys, and we're using 693 // a map based on Oni's DirectInput map to convert to key codes 694 if (is_extended) 695 sc |= 0x80; 696 uint8_t ch = DDgPlatform_ScanCodeToChar[sc]; 697 if (!ch) 698 return; 699 700 SetKeyState(ch, !is_up); 701 } 702 703 bool DDrInput_WindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam, 704 LRESULT* res) 705 { 706 // This is called from our own window proc for now, so we only want to use 707 // it when Daodan input is enabled 708 if (!DDgUseDaodanInput) 709 return false; 710 711 switch (msg) { 712 case WM_INPUT: 713 if (HandleWmInput((HRAWINPUT)lparam, wparam)) { 714 *res = 0; 715 return true; 716 } 717 break; 718 case WM_WINDOWPOSCHANGED: 719 HandleWmWindowPosChanged((WINDOWPOS *)lparam); 720 break; 721 case WM_KEYDOWN: 722 case WM_SYSKEYDOWN: 723 case WM_KEYUP: 724 case WM_SYSKEYUP: 725 HandleWmKeyboard(LOWORD(wparam), LOWORD(lparam), HIWORD(lparam)); 726 break; 727 } 728 729 return false; 730 } 731 732 static void ONICALL DDrActionBuffer_Get(short* count, LItActionBuffer** buffers) 733 { 734 // So, Oni's version of this function was totally different. In unpatched 735 // Oni, action buffers were produced at 60Hz by a separate high-priority 736 // input thread, LIiInterruptHandleProc, and consumed by 737 // LIrActionBuffer_Get, which was called from the game loop and could 738 // provide multiple outstanding action buffers to the engine at once. 739 // 740 // That was a problem for a couple of reasons. Firstly, the resolution of 741 // Windows timers is limited by the timer frequency, which can be as low as 742 // 15.6ms and in the worst case would cause a delay of 31.2ms between action 743 // buffers. That meant that even if Oni was running at a steady 60 fps, the 744 // input thread would provide no action buffers on a lot of frames. 745 // 746 // Secondly, even though Oni drained the list of pending action buffers by 747 // calling DDrActionBuffer_Get on every frame, the engine only uses them 748 // when the internal game time advances, and that happens on a separate 60Hz 749 // timer which was totally unsynchronized with the 60Hz timer on the input 750 // thread. That wasn't too much of a problem when the game loop was running 751 // at less than 60 fps, but when it ran faster, the only action buffers that 752 // got processed were the ones produced when the game timer and the input 753 // thread timer happened to tick at the same time, meaning potentially a lot 754 // of dropped input. 755 // 756 // Oni's input system was probably designed that way so that input would 757 // still run at 60Hz even on PCs that weren't powerful enough to render at 758 // 60 fps. It was a well-meaning design, but due to the aforementioned 759 // flaws, we do something much different and simpler here. On the frames 760 // that Oni will consume input, we generate a single action buffer inside 761 // DDrActionBuffer_Get based on most up-to-date input. 762 763 // Update ONgGameState->TargetGameTime. We use TargetGameTime to determine 764 // if Oni is going to consume input on this frame. Unfortunately, in 765 // unpatched Oni, the call to ONrGameState_UpdateServerTime happened after 766 // LIrActionBuffer_Get. In Daodan, we NOOP out the original call and call it 767 // here instead, so it runs before our code. 768 ONrGameState_UpdateServerTime(ONgGameState); 769 bool time_updated = ONgGameState->GameTime != ONgGameState->TargetGameTime; 770 771 // Only produce input buffers when input is enabled. LIrActionBuffer_Get 772 // does the same thing. Also only produce them when Oni will consume them. 773 if (!LIgMode_Internal || !time_updated) { 774 *count = 0; 775 *buffers = NULL; 776 return; 777 } 778 779 // Add held keys to the action buffer 780 for (int i = 0; i < ARRAY_SIZE(DDgInputState); i++) { 781 if (DDgInputState[i]) { 782 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 783 .input = i, 784 .analog = 1.0, 785 }); 786 } 787 } 788 789 // Add togglable keys to the action buffer 790 if (DDgCapsOniKey && (GetKeyState(VK_CAPITAL) & 0x01)) { 791 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 792 .input = DDgCapsOniKey, 793 .analog = 1.0, 794 }); 795 } 796 if (DDgScrollOniKey && (GetKeyState(VK_SCROLL) & 0x01)) { 797 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 798 .input = DDgScrollOniKey, 799 .analog = 1.0, 800 }); 801 } 802 if (DDgNumLockOniKey && (GetKeyState(VK_NUMLOCK) & 0x01)) { 803 LIrActionBuffer_Add(&DDgActionBuffer, &(LItDeviceInput) { 804 .input = DDgNumLockOniKey, 805 .analog = 1.0, 806 }); 807 } 808 809 // Make a copy of our temporary action buffer with all the input we've 810 // gathered this frame. This is the copy that Oni's engine will see. 811 static LItActionBuffer buf = { 0 }; 812 buf = DDgActionBuffer; 813 DDgActionBuffer = (LItActionBuffer) { 0 }; 814 815 *count = 1; 816 *buffers = &buf; 817 } 818 819 void DDrInput_PatchUtilityInput(void) 820 { 821 // Patch the call to ONrGameState_HandleUtilityInput in 822 // ONrGameState_ProcessHeartbeat. This is where Oni checks a bunch of 823 // miscellaneous inputs, and where Mac Oni 1.2.1 checks the cheat bindings. 824 // It's also where Mac Oni toggles the show_triggervolumes flag. 825 DDrPatch_MakeCall((void *)0x004fa91c, (void *)DDrGameState_HandleUtilityInput); 826 } 827 828 void DDrInput_PatchCustomActions(void) 829 { 830 DDrInput_PatchUtilityInput(); 831 832 // Replace the function which adds bindings with ours, which checks the list 833 // of custom bindings as well 834 DDrPatch_MakeJump((void *)LIrBinding_Add, (void *)DDrBinding_Add); 835 } 836 837 void DDrInput_PatchDaodanInput(void) 838 { 839 // In LIrInitialize, NOOP the call to UUrInterruptProc_Install and 840 // associated error checking 841 DDrPatch_NOOP((char *)(OniExe + 0x421f), 106); 842 843 // In LIrPlatform_Initialize, NOOP the Windows version checks so we never 844 // use DirectInput 845 DDrPatch_NOOP((char *)(OniExe + 0x2e64), 11); 846 847 // Replace Oni's Windows message loop with one that does buffered raw input 848 // reads and processes all messages 849 DDrPatch_MakeJump((void *)LIiPlatform_InputEvent_GetEvent, (void *)DDiPlatform_InputEvent_GetEvent); 850 851 // Replace the function that gets the latest input frames 852 DDrPatch_MakeJump((void *)LIrActionBuffer_Get, (void *)DDrActionBuffer_Get); 853 854 // Replace the function that gets the mouse cursor position 855 DDrPatch_MakeJump((void *)LIrPlatform_InputEvent_GetMouse, (void *)DDrPlatform_InputEvent_GetMouse); 856 857 // Replace the function that performs platform-specific actions when the 858 // input mode changes 859 DDrPatch_MakeJump((void *)LIrPlatform_Mode_Set, (void *)DDrPlatform_Mode_Set); 860 861 // Replaces the function that tests the state of keyboard keys 862 DDrPatch_MakeJump((void *)LIrPlatform_TestKey, (void *)DDrPlatform_TestKey); 863 864 // Enable extra key names in key_config.txt 865 DDrPatch_MakeJump((void *)LIrTranslate_InputName, (void *)DDrTranslate_InputName); 866 867 // Patch out the call to ONrGameState_UpdateServerTime in ONiRunGame because 868 // we want to do it earlier, in DDrActionBuffer_Get 869 DDrPatch_NOOP((char *)(OniExe + 0xd4708), 11); 870 871 DDgUseDaodanInput = true; 872 } -
Daodan/src/Patches/Input.h
r1017 r1163 4 4 #include "../Daodan.h" 5 5 6 typedef uint32_t CustomActionCallbackArgument; 7 8 typedef void (*CustomActionCallback_t) (CustomActionCallbackArgument argument); 6 typedef void (*DDtCustomActionCallback)(intptr_t ctx); 9 7 10 8 typedef enum { 11 EVENT_KEYPRESS,12 EVENT_KEYDOWN,13 } ActionEventType_t;9 DDcEventType_KeyPress, 10 DDcEventType_KeyDown, 11 } DDtActionEventType; 14 12 15 void Input_PatchCode (); 13 void DDrInput_RegisterCustomAction(const char *name, DDtActionEventType type, 14 DDtCustomActionCallback callback, 15 intptr_t ctx); 16 bool DDrInput_WindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam, 17 LRESULT* res); 16 18 17 void Input_RegisterCustomAction (const char* actionname, ActionEventType_t eventType, uint32_t keydownTimeoutTicks, CustomActionCallback_t callback, CustomActionCallbackArgument callbackArgument); 19 void DDrInput_PatchUtilityInput(void); 20 void DDrInput_PatchCustomActions(void); 21 void DDrInput_PatchDaodanInput(void); 18 22 19 23 #endif -
Daodan/src/Patches/Patches.c
r1017 r1163 183 183 return Oni_ONrMechanics_Register(inObjectType, inObjectTypeIndex, inGroupName, inSizeInMemory, inObjectMethods, inFlags, inMechanicsMethods); 184 184 } 185 186 _ONrGameState_HandleUtilityInput Oni_ONrGameState_HandleUtilityInput = (_ONrGameState_HandleUtilityInput)0;187 void ONICALL DD_ONrGameState_HandleUtilityInput(const void* inInput)188 {189 Oni_ONrGameState_HandleUtilityInput(inInput);190 191 if (ONrDebugKey_WentDown(7)) {192 OBJgTriggerVolume_Visible = !OBJgTriggerVolume_Visible;193 }194 }195 196 185 197 186 // Enables d_regen script command. Instead of one global flag to only regenerate player each char has a flag to enable local regeneration … … 385 374 DD_Patch_Chinese(); 386 375 387 // Limit cursor to Oni's window388 if (DDrConfig_GetOptOfType("windows.clipcursor", C_BOOL)->value.intBoolVal)389 {390 // LIrMode_Set: replace LIrPlatform_Mode_Set call with our hook.391 DDrPatch_MakeCall((void*)(OniExe + 0x00003f9f), (void*) DD_LIrPlatform_Mode_Set);392 393 // LIrMode_Set_Internal: replace LIrPlatform_Mode_Set call with our hook.394 DDrPatch_MakeCall((void*)(OniExe + 0x00003fff), (void*) DD_LIrPlatform_Mode_Set);395 396 // LIrTerminate: replace LIrPlatform_Terminate call with our hook.397 DDrPatch_MakeCall((void*)(OniExe + 0x000004cb8), (void*) DD_LIrPlatform_Terminate);398 }399 400 376 // Disables weapon cooldown exploit 401 377 if (DDrConfig_GetOptOfType("gameplay.cooldowntimer", C_BOOL)->value.intBoolVal) … … 410 386 DDrPatch_MakeJump((void*)gl_enumerate_valid_display_modes, (void*)DD_GLrEnumerateDisplayModes); 411 387 } 412 413 // Forced DirectInput (for Windows NT) 414 if (DDrConfig_GetOptOfType("windows.directinput", C_BOOL)->value.intBoolVal) 415 { 416 // LIrPlatform_Initialize: replace conditional jump by unconditional 417 DDrPatch_Byte((char*)(OniExe + 0x00002e6d), 0xeb); 388 389 if (DDrConfig_GetOptOfType("windows.daodaninput", C_BOOL)->value.intBoolVal) 390 { 391 DDrInput_PatchDaodanInput(); 392 } 393 else 394 { 395 // The following patches aren't compatible with, or are superseded by 396 // Daodan input 397 398 // Limit cursor to Oni's window 399 if (DDrConfig_GetOptOfType("windows.clipcursor", C_BOOL)->value.intBoolVal) 400 { 401 // LIrMode_Set: replace LIrPlatform_Mode_Set call with our hook. 402 DDrPatch_MakeCall((void*)(OniExe + 0x00003f9f), (void*) DD_LIrPlatform_Mode_Set); 403 404 // LIrMode_Set_Internal: replace LIrPlatform_Mode_Set call with our hook. 405 DDrPatch_MakeCall((void*)(OniExe + 0x00003fff), (void*) DD_LIrPlatform_Mode_Set); 406 407 // LIrTerminate: replace LIrPlatform_Terminate call with our hook. 408 DDrPatch_MakeCall((void*)(OniExe + 0x000004cb8), (void*) DD_LIrPlatform_Terminate); 409 } 410 411 // Forced DirectInput (for Windows NT) 412 if (DDrConfig_GetOptOfType("windows.directinput", C_BOOL)->value.intBoolVal) 413 { 414 // LIrPlatform_Initialize: replace conditional jump by unconditional 415 DDrPatch_Byte((char*)(OniExe + 0x00002e6d), 0xeb); 416 } 418 417 } 419 418 … … 449 448 // Allow custom actions to be bound through Daodan 450 449 if (DDrConfig_GetOptOfType("gameplay.customactions", C_BOOL)->value.intBoolVal) 451 { 452 Input_PatchCode (); 453 } 454 450 DDrInput_PatchCustomActions(); 451 455 452 // Hackish fix for Konoko not kicking guns 456 453 // Don't use this, it breaks stairs. … … 571 568 if (DDrConfig_GetOptOfType("devmode.showtriggervolumes", C_BOOL)->value.intBoolVal) 572 569 { 570 DDrInput_PatchUtilityInput(); 573 571 Oni_ONrMechanics_Register = DDrPatch_MakeDetour((void*)ONrMechanics_Register, (void*)DD_ONrMechanics_Register); 574 Oni_ONrGameState_HandleUtilityInput = DDrPatch_MakeDetour((void*)ONrGameState_HandleUtilityInput, (void*)DD_ONrGameState_HandleUtilityInput); 575 } 576 572 } 573 577 574 // Experiment with allowing enemies to be thrown over railings 578 575 if (DDrConfig_GetOptOfType("gameplay.throwtest", C_BOOL)->value.intBoolVal) … … 591 588 DDrPatch_NOOP((char*) OniExe + 0x0002651c, 6); 592 589 DDrPatch_MakeCall((char*) OniExe + 0x0002651c, (void*) GetClientRect); 590 591 // Note: Daodan input makes the following GetCursorPos and SetCursorPos 592 // patches unnecessary 593 593 594 594 // LIrPlatform_PollInputForAction: fix GetCursorPos call to return client coordinates. -
Daodan/src/Patches/Utility.c
r1161 r1163 102 102 memcpy(output_ptr, default_msg, sizeof(default_msg)); 103 103 } 104 104 105 105 } 106 106 107 typedef struct 108 { 109 uint16_t x; 110 uint16_t y; 111 112 } IMtPoint2D; 113 IMtPoint2D Point = {256, 250}; 107 IMtPoint Point = {256, 250}; 114 108 extern void* TSrTest; 115 109 extern void* TSrScores; -
Daodan/src/Patches/Win32.c
r1000 r1163 3 3 #include "../Daodan.h" 4 4 #include "../Daodan_Config.h" 5 #include "Input.h" 5 6 #include "Win32.h" 6 7 … … 105 106 return TRUE; 106 107 } 107 108 108 109 break; 109 110 } 110 111 112 LRESULT res; 113 if (DDrInput_WindowProc(hWnd, uMsg, wParam, lParam, &res)) 114 return res; 115 111 116 return ONrPlatform_WindowProc(hWnd, uMsg, wParam, lParam); 112 117 } -
Daodan/src/makefile
r1045 r1163 6 6 DEF = BEA_ENGINE_STATIC 7 7 INCLUDEPATHS = . 8 GCCFLAGS = -std=gnu99 - O0 -Wall -fomit-frame-pointer -fpack-struct-Wextra -Wno-pragmas -Wno-unused-variable $(addprefix -I,$(INCLUDEPATHS)) -Wno-unused-parameter $(addprefix -D,$(DEF))9 LINKFLAGS = -O0 -Wall -fomit-frame-pointer - fpack-struct -s -mdll8 GCCFLAGS = -std=gnu99 -ggdb -O0 -Wall -fomit-frame-pointer -Wextra -Wno-pragmas -Wno-unused-variable $(addprefix -I,$(INCLUDEPATHS)) -Wno-unused-parameter $(addprefix -D,$(DEF)) 9 LINKFLAGS = -O0 -Wall -fomit-frame-pointer -mdll 10 10 LOCALE = LC_MESSAGES=C 11 11
Note:
See TracChangeset
for help on using the changeset viewer.