diff --git a/desmume/src/windows/aviout.h b/desmume/src/windows/aviout.h index 38dc381a5..f55c031f6 100644 --- a/desmume/src/windows/aviout.h +++ b/desmume/src/windows/aviout.h @@ -1,5 +1,5 @@ -bool DRV_AviBegin(const char* fname); -void DRV_AviEnd(); -void DRV_AviSoundUpdate(void* soundData, int soundLen); -bool DRV_AviIsRecording(); +bool DRV_AviBegin(const char* fname); +void DRV_AviEnd(); +void DRV_AviSoundUpdate(void* soundData, int soundLen); +bool DRV_AviIsRecording(); void DRV_AviVideoUpdate(const u16* buffer); \ No newline at end of file diff --git a/desmume/src/windows/config.h b/desmume/src/windows/config.h index fc3646704..fbf96dd8e 100644 --- a/desmume/src/windows/config.h +++ b/desmume/src/windows/config.h @@ -1,6 +1,6 @@ -#ifndef _CONFIG_H -#define _CONFIG_H - -#include "userconfig.h" - -#endif +#ifndef _CONFIG_H +#define _CONFIG_H + +#include "userconfig.h" + +#endif diff --git a/desmume/src/windows/defaultconfig/userconfig.h b/desmume/src/windows/defaultconfig/userconfig.h index 9ce974c00..9ff3d33c9 100644 --- a/desmume/src/windows/defaultconfig/userconfig.h +++ b/desmume/src/windows/defaultconfig/userconfig.h @@ -1,12 +1,12 @@ -#ifndef _USERCONFIG_H -#define _USERCONFIG_H - -//this is a default file. it should not be edited, or else you will mess up the defaults. -//to customize your build, place a customized copy in the userconfig directory -//(alongside this defaultconfig directory) - -//#define NOSSE2 //disables SSE2 optimizations (better change it in the vc++ codegen options too) -//#define DEVELOPER //enables dev+ features - - -#endif //_USERCONFIG_H +#ifndef _USERCONFIG_H +#define _USERCONFIG_H + +//this is a default file. it should not be edited, or else you will mess up the defaults. +//to customize your build, place a customized copy in the userconfig directory +//(alongside this defaultconfig directory) + +//#define NOSSE2 //disables SSE2 optimizations (better change it in the vc++ codegen options too) +//#define DEVELOPER //enables dev+ features + + +#endif //_USERCONFIG_H diff --git a/desmume/src/windows/ram_search.cpp b/desmume/src/windows/ram_search.cpp index bb32a9cda..add4a1123 100644 --- a/desmume/src/windows/ram_search.cpp +++ b/desmume/src/windows/ram_search.cpp @@ -1,1946 +1,1946 @@ -//RamSearch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ -//Authors: Upthorn, Nitsuja, adelikat - -// A few notes about this implementation of a RAM search window: -// -// Speed of update was one of the highest priories. -// This is because I wanted the RAM search window to be able to -// update every single value in RAM every single frame, and -// keep track of the exact number of frames across which each value has changed, -// without causing the emulation to run noticeably slower than normal. -// -// The data representation was changed from one entry per valid address -// to one entry per contiguous range of uneliminated addresses -// which references uniform pools of per-address properties. -// - This saves time when there are many items because -// it minimizes the amount of data that needs to be stored and processed per address. -// - It also saves time when there are few items because -// it ensures that no time is wasted in iterating through -// addresses that have already been eliminated from the search. -// -// The worst-case scenario is when every other item has been -// eliminated from the search, maximizing the number of regions. -// This implementation manages to handle even that pathological case -// acceptably well. In fact, it still updates faster than the previous implementation. -// The time spent setting up or clearing such a large number of regions -// is somewhat horrendous, but it seems reasonable to have poor worst-case speed -// during these sporadic "setup" steps to achieve an all-around faster per-update speed. -// (You can test this case by performing the search: Modulo 2 Is Specific Address 0) - -#include "resource.h" - -#include "common.h" -#include "NDSSystem.h" -#include "ramwatch.h" - -#include "ram_search.h" -#include -#include -#include "ramwatch.h" -#include -#include -#ifdef _WIN32 - #include "BaseTsd.h" - typedef INT_PTR intptr_t; -#else - #include "stdint.h" -#endif - -HWND RamSearchHWnd = NULL; - -extern HWND RamWatchHWnd; - -extern char Str_Tmp[1024]; - -int Rom_Size; //TODO -unsigned char* Rom_Data; //TODO - -struct MemoryRegion -{ - unsigned int hardwareAddress; // hardware address of the start of this region - unsigned int size; // number of bytes to the end of this region - unsigned char* softwareAddress; // pointer to the start of the live emulator source values for this region - BOOL byteSwapped; // true if this is a byte-swapped region of memory - - unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions() - unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false -}; - -static struct Buffers { - unsigned char s_prevValues [MAX_RAM_SIZE+4]; // values at last search or reset - unsigned char s_curValues [MAX_RAM_SIZE+4]; // values at last frame update - unsigned short s_numChanges [MAX_RAM_SIZE+4]; // number of changes of the item starting at this virtual index address - MemoryRegion* s_itemIndexToRegionPointer [MAX_RAM_SIZE+4]; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false -} *buffers = NULL; -static BOOL s_itemIndicesInvalid = true; // if true, the link from listbox items to memory regions (s_itemIndexToRegionPointer) and the link from memory regions to list box items (MemoryRegion::itemIndex) both need to be recalculated -static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled -static unsigned int s_maxItemIndex = 0; // max currently valid item index, the listbox sometimes tries to update things past the end of the list so we need to know this to ignore those attempts - -static const MemoryRegion s_prgRegion = { 0x02000000, 0x400000, (unsigned char*)ARM9Mem.MAIN_MEM, false}; - -/* -static const MemoryRegion s_prgRegion = { 0x020000, SEGACD_RAM_PRG_SIZE, (unsigned char*)Ram_Prg, true}; -static const MemoryRegion s_word1MRegion = { 0x200000, SEGACD_1M_RAM_SIZE, (unsigned char*)Ram_Word_1M, true}; -static const MemoryRegion s_word2MRegion = { 0x200000, SEGACD_2M_RAM_SIZE, (unsigned char*)Ram_Word_2M, true}; -static const MemoryRegion s_z80Region = { 0xA00000, Z80_RAM_SIZE, (unsigned char*)Ram_Z80, true}; -static const MemoryRegion s_68kRegion = { 0xFF0000, _68K_RAM_SIZE, (unsigned char*)Ram_68k, true}; -static const MemoryRegion s_32xRegion = {0x06000000, _32X_RAM_SIZE, (unsigned char*)_32X_Ram, false}; -*/ -// list of contiguous uneliminated memory regions -typedef std::list MemoryList; -static MemoryList s_activeMemoryRegions; - -// for undo support (could be better, but this way was really easy) -static MemoryList s_activeMemoryRegionsBackup; -static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo - -void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg); -static const int tooManyRegionsForUndo = 10000; - -void InitRamSearch() -{ - if(buffers == NULL) - { - buffers = new Buffers; - memset(buffers,0,sizeof(Buffers)); - } -} - -void ResetMemoryRegions() -{ -// Clear_Sound_Buffer(); - - s_activeMemoryRegions.clear(); - - s_activeMemoryRegions.push_back(s_prgRegion); - - /*if(Genesis_Started || _32X_Started || SegaCD_Started) - { - s_activeMemoryRegions.push_back(s_68kRegion); - s_activeMemoryRegions.push_back(s_z80Region); - if(SegaCD_Started) - { - s_activeMemoryRegions.push_back(s_prgRegion); - s_activeMemoryRegions.push_back((Ram_Word_State & 0x2) ? s_word1MRegion : s_word2MRegion); - } - if(_32X_Started) - { - s_activeMemoryRegions.push_back(s_32xRegion); - } - }*/ - - int nextVirtualIndex = 0; - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - region.virtualIndex = nextVirtualIndex; - assert(((intptr_t)region.softwareAddress & 1) == 0 && "somebody need to reimplement ReadValueAtSoftwareAddress()"); - nextVirtualIndex = region.virtualIndex + region.size; - } -// assert(nextVirtualIndex <= MAX_RAM_SIZE); TODO -} - -// eliminates a range of hardware addresses from the search results -// returns 2 if it changed the region and moved the iterator to another region -// returns 1 if it changed the region but didn't move the iterator -// returns 0 if it had no effect -// warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion... -// doing so would be tremendously slow because DeactivateRegion invalidates the index cache -int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, unsigned int hardwareAddress, unsigned int size) -{ - if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size) - { - // region is unaffected - return 0; - } - else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) - { - // erase end of region - region.size = hardwareAddress - region.hardwareAddress; - return 1; - } - else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) - { - // erase start of region - int eraseSize = (hardwareAddress + size) - region.hardwareAddress; - region.hardwareAddress += eraseSize; - region.size -= eraseSize; - region.softwareAddress += eraseSize; - region.virtualIndex += eraseSize; - return 1; - } - else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) - { - // erase entire region - iter = s_activeMemoryRegions.erase(iter); - s_itemIndicesInvalid = TRUE; - return 2; - } - else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) - { - // split region - int eraseSize = (hardwareAddress + size) - region.hardwareAddress; - MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.softwareAddress + eraseSize, region.byteSwapped, region.virtualIndex + eraseSize}; - region.size = hardwareAddress - region.hardwareAddress; - iter = s_activeMemoryRegions.insert(++iter, region2); - s_itemIndicesInvalid = TRUE; - return 2; - } -} - -/* -// eliminates a range of hardware addresses from the search results -// this is a simpler but usually slower interface for the above function -void DeactivateRegion(unsigned int hardwareAddress, unsigned int size) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - if(2 != DeactivateRegion(region, iter, hardwareAddress, size)) - ++iter; - } -} -*/ - -// warning: can be slow -void CalculateItemIndices(int itemSize) -{ - unsigned int itemIndex = 0; - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - region.itemIndex = itemIndex; - int startSkipSize = ((unsigned int)(itemSize - region.hardwareAddress)) % itemSize; - unsigned int start = startSkipSize; - unsigned int end = region.size; - for(unsigned int i = start; i < end; i += itemSize) - buffers->s_itemIndexToRegionPointer[itemIndex++] = ®ion; - } - s_maxItemIndex = itemIndex; - s_itemIndicesInvalid = FALSE; -} - -template -void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr) -{ - if(s_prevValuesNeedUpdate) - memcpy(buffers->s_prevValues + region.virtualIndex, buffers->s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); - - unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - - unsigned char* sourceAddr = region.softwareAddress - region.virtualIndex; - unsigned int indexStart = region.virtualIndex + startSkipSize; - unsigned int indexEnd = region.virtualIndex + region.size; - - if(sizeof(compareType) == 1) - { - for(unsigned int i = indexStart; i < indexEnd; i++) - { - if(buffers->s_curValues[i] != sourceAddr[i^swapXOR]) // if value changed - { - buffers->s_curValues[i] = sourceAddr[i^swapXOR]; // update value - //if(s_numChanges[i] != 0xFFFF) - buffers->s_numChanges[i]++; // increase change count - } - } - } - else // it's more complicated for non-byte sizes because: - { // - more than one byte can affect a given change count entry - // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1 - // - a few of those bytes can be outside the region - - unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType); - unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType); - unsigned int lastIndexToCopy = lastIndexToRead; - if(nextRegionPtr) - { - const MemoryRegion& nextRegion = *nextRegionPtr; - int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType); - unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize; - if(lastIndexToCopy > nextIndexStart) - lastIndexToCopy = nextIndexStart; - } - - unsigned int nextValidChange [sizeof(compareType)]; - for(unsigned int i = 0; i < sizeof(compareType); i++) - nextValidChange[i] = indexStart + i; - - for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++) - { - if(buffers->s_curValues[i] != sourceAddr[i^swapXOR]) // if value of this byte changed - { - if(i < lastIndexToCopy) - buffers->s_curValues[i] = sourceAddr[i^swapXOR]; // update value - for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte - { - if(i >= indexEnd+k) - continue; - int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1); - if(nextValidChange[m]+sizeof(compareType) <= i+sizeof(compareType)) // if we didn't already increase the change count for this entry - { - //if(s_numChanges[i-k] != 0xFFFF) - buffers->s_numChanges[i-k]++; // increase the change count for this entry - nextValidChange[m] = i+sizeof(compareType); // and remember not to increase it again - } - } - } - } - } -} - -template -void UpdateRegionsT() -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();) - { - const MemoryRegion& region = *iter; - ++iter; - const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter; - - if(region.byteSwapped) - UpdateRegionT(region, nextRegion); - else - UpdateRegionT(region, nextRegion); - } - - s_prevValuesNeedUpdate = false; -} - -template -int CountRegionItemsT() -{ - if(sizeof(stepType) == 1) - { - if(s_activeMemoryRegions.empty()) - return 0; - - if(s_itemIndicesInvalid) - CalculateItemIndices(sizeof(stepType)); - - MemoryRegion& lastRegion = s_activeMemoryRegions.back(); - return lastRegion.itemIndex + lastRegion.size; - } - else // the branch above is faster but won't work if the step size isn't 1 - { - int total = 0; - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType); - } - return total; - } -} - -// returns information about the item in the form of a "fake" region -// that has the item in it and nothing else -template -void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion) -{ - if(s_itemIndicesInvalid) - CalculateItemIndices(sizeof(stepType)); - - if(itemIndex >= s_maxItemIndex) - { - memset(&virtualRegion, 0, sizeof(MemoryRegion)); - return; - } - - const MemoryRegion* regionPtr = buffers->s_itemIndexToRegionPointer[itemIndex]; - const MemoryRegion& region = *regionPtr; - - int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType); - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - bytesWithinRegion += startSkipSize; - - virtualRegion.size = sizeof(compareType); - virtualRegion.hardwareAddress = region.hardwareAddress + bytesWithinRegion; - virtualRegion.softwareAddress = region.softwareAddress + bytesWithinRegion; - virtualRegion.virtualIndex = region.virtualIndex + bytesWithinRegion; - virtualRegion.byteSwapped = region.byteSwapped; - virtualRegion.itemIndex = itemIndex; - return; -} - -template -unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex) -{ - MemoryRegion virtualRegion; - ItemIndexToVirtualRegion(itemIndex, virtualRegion); - return virtualRegion.virtualIndex; -} - -template -T ReadBigEndian(const unsigned char* data) -{ - T rv = 0; - for(int i = 0; i < sizeof(T); i++) - { - rv <<= 8; - rv |= *data++; - } - return rv; -} -template<> signed char ReadBigEndian(const unsigned char* data) { return *data; } -template<> unsigned char ReadBigEndian(const unsigned char* data) { return *data; } - - -template -compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex) -{ -// return ReadBigEndian(buffers->s_prevValues + virtualIndex); - return *(compareType*)(buffers->s_prevValues+virtualIndex); -} -template -compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex) -{ -// return ReadBigEndian(buffers->s_curValues + virtualIndex); - return *(compareType*)(buffers->s_curValues+virtualIndex); -} -template -unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex) -{ - unsigned short num = buffers->s_numChanges[virtualIndex]; - //for(unsigned int i = 1; i < sizeof(stepType); i++) - // if(num < s_numChanges[virtualIndex+i]) - // num = s_numChanges[virtualIndex+i]; - return num; -} - -template -compareType GetPrevValueFromItemIndex(unsigned int itemIndex) -{ - int virtualIndex = ItemIndexToVirtualIndex(itemIndex); - return GetPrevValueFromVirtualIndex(virtualIndex); -} -template -compareType GetCurValueFromItemIndex(unsigned int itemIndex) -{ - int virtualIndex = ItemIndexToVirtualIndex(itemIndex); - return GetCurValueFromVirtualIndex(virtualIndex); -} -template -unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex) -{ - int virtualIndex = ItemIndexToVirtualIndex(itemIndex); - return GetNumChangesFromVirtualIndex(virtualIndex); -} -template -unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex) -{ - MemoryRegion virtualRegion; - ItemIndexToVirtualRegion(itemIndex, virtualRegion); - return virtualRegion.hardwareAddress; -} - -// this one might be unreliable, haven't used it much -template -unsigned int HardwareAddressToItemIndex(unsigned int hardwareAddress) -{ - if(s_itemIndicesInvalid) - CalculateItemIndices(sizeof(stepType)); - - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size) - { - int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType); - return region.itemIndex + indexWithinRegion; - } - } - - return -1; -} - - - - -// workaround for a parser error in MSVC that sometimes deletes a comma preceeding a macro -// this macro takes a type and a signed/unsigned modifier, and returns the same type with that modifier whether or not the compiler decides to delete the comma between them -template -struct DummyType { typedef T t; }; -#define COMMAHACK(sign, type) DummyType::t -#ifdef _MSC_VER -#pragma warning(disable : 4114) // disable "same modifier used twice" warning that otherwise would get issued when the compiler bug happens -#endif - -// it's ugly but I can't think of a better way to call these functions that isn't also slower, since -// I need the current values of these arguments to determine which primitive types are used within the function -#define CALL_WITH_T_SIZE_TYPES(functionName, sizeTypeID, isSigned, requireAligned, ...) \ - (sizeTypeID == 'b' \ - ? (isSigned \ - ? functionName(__VA_ARGS__) \ - : functionName(__VA_ARGS__)) \ - : sizeTypeID == 'w' \ - ? (isSigned \ - ? (requireAligned \ - ? functionName(__VA_ARGS__) \ - : functionName(__VA_ARGS__)) \ - : (requireAligned \ - ? functionName(__VA_ARGS__) \ - : functionName(__VA_ARGS__))) \ - : sizeTypeID == 'd' \ - ? (isSigned \ - ? (requireAligned \ - ? functionName(__VA_ARGS__) \ - : functionName(__VA_ARGS__)) \ - : (requireAligned \ - ? functionName(__VA_ARGS__) \ - : functionName(__VA_ARGS__))) \ - : functionName(__VA_ARGS__)) - -// version that takes a forced comparison type -#define CALL_WITH_T_STEP(functionName, sizeTypeID, sign,type, requireAligned, ...) \ - (sizeTypeID == 'b' \ - ? functionName(__VA_ARGS__) \ - : sizeTypeID == 'w' \ - ? (requireAligned \ - ? functionName(__VA_ARGS__) \ - : functionName(__VA_ARGS__)) \ - : sizeTypeID == 'd' \ - ? (requireAligned \ - ? functionName(__VA_ARGS__) \ - : functionName(__VA_ARGS__)) \ - : functionName(__VA_ARGS__)) - - -// basic comparison functions: -template inline bool LessCmp (T x, T y, T i) { return x < y; } -template inline bool MoreCmp (T x, T y, T i) { return x > y; } -template inline bool LessEqualCmp (T x, T y, T i) { return x <= y; } -template inline bool MoreEqualCmp (T x, T y, T i) { return x >= y; } -template inline bool EqualCmp (T x, T y, T i) { return x == y; } -template inline bool UnequalCmp (T x, T y, T i) { return x != y; } -template inline bool DiffByCmp (T x, T y, T p) { return x - y == p || y - x == p; } -template inline bool ModIsCmp (T x, T y, T p) { return p && x % p == y; } - -// compare-to type functions: -template -void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(GetCurValueFromVirtualIndex(i), GetPrevValueFromVirtualIndex(i), param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} -template -void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(GetCurValueFromVirtualIndex(i), value, param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} -template -void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(hwaddr, address, param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} -template -void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(GetNumChangesFromVirtualIndex(i), changes, param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} - -char rs_c='s'; -char rs_o='='; -char rs_t='s'; -int rs_param=0, rs_val=0, rs_val_valid=0; -char rs_type_size = 'b', rs_last_type_size = rs_type_size; -bool noMisalign = true, rs_last_no_misalign = noMisalign; -bool littleEndian = false; -int last_rs_possible = -1; -int last_rs_regions = -1; - -void prune(char c,char o,char t,int v,int p) -{ - // repetition-reducing macros - #define DO_SEARCH(sf) \ - switch (o) \ - { \ - case '<': DO_SEARCH_2(LessCmp,sf); break; \ - case '>': DO_SEARCH_2(MoreCmp,sf); break; \ - case '=': DO_SEARCH_2(EqualCmp,sf); break; \ - case '!': DO_SEARCH_2(UnequalCmp,sf); break; \ - case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \ - case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \ - case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \ - case '%': DO_SEARCH_2(ModIsCmp,sf); break; \ - default: assert(!"Invalid operator for this search type."); break; \ - } - - // perform the search, eliminating nonmatching values - switch (c) - { - #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES(sf, rs_type_size, t, noMisalign, CmpFun,v,p) - case 'r': DO_SEARCH(SearchRelative); break; - case 's': DO_SEARCH(SearchSpecific); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP(sf, rs_type_size, unsigned,int, noMisalign, CmpFun,v,p); - case 'a': DO_SEARCH(SearchAddress); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP(sf, rs_type_size, unsigned,short, noMisalign, CmpFun,v,p); - case 'n': DO_SEARCH(SearchChanges); break; - - default: assert(!"Invalid search comparison type."); break; - } - - s_prevValuesNeedUpdate = true; - - int prevNumItems = last_rs_possible; - - CompactAddrs(); - - if(prevNumItems == last_rs_possible) - { - SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo - } -} - - - - -template -bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param) -{ - return cmpFun(GetCurValueFromItemIndex(itemIndex), GetPrevValueFromItemIndex(itemIndex), param); -} -template -bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param) -{ - return cmpFun(GetCurValueFromItemIndex(itemIndex), value, param); -} -template -bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param) -{ - return cmpFun(GetHardwareAddressFromItemIndex(itemIndex), address, param); -} -template -bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param) -{ - return cmpFun(GetNumChangesFromItemIndex(itemIndex), changes, param); -} - -int ReadControlInt(int controlID, bool forceHex, BOOL& success) -{ - int rv = 0; - BOOL ok = false; - - if(!forceHex) - { - rv = GetDlgItemInt(RamSearchHWnd,controlID,&ok,(rs_t == 's')); - } - - if(!ok) - { - if(GetDlgItemText(RamSearchHWnd,controlID,Str_Tmp,16)) - { - for(int i = 0; Str_Tmp[i]; i++) {if(toupper(Str_Tmp[i]) == 'O') Str_Tmp[i] = '0';} - const char* strPtr = Str_Tmp; - bool negate = false; - while(strPtr[0] == '-') - strPtr++, negate = !negate; - if(strPtr[0] == '+') - strPtr++; - if(strPtr[0] == '0' && tolower(strPtr[1]) == 'x') - strPtr += 2, forceHex = true; - if(strPtr[0] == '$') - strPtr++, forceHex = true; - if(!forceHex) - { - const char* strSearchPtr = strPtr; - while(*strSearchPtr) - { - int c = tolower(*strSearchPtr++); - if(c >= 'a' && c <= 'f') - forceHex = true; - } - } - const char* formatString = forceHex ? "%X" : ((rs_t=='s') ? "%d" : "%u"); - if(sscanf(strPtr, formatString, &rv) > 0) - ok = true; - if(negate) - rv = -rv; - } - } - - success = ok; - return rv; -} - - -bool Set_RS_Val() -{ - BOOL success; - - // update rs_val - switch(rs_c) - { - case 'r': - default: - rs_val = 0; - break; - case 's': - rs_val = ReadControlInt(IDC_EDIT_COMPAREVALUE, rs_t == 'h', success); - if(!success) - return false; - if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) || - (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) || - (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) || - (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535))) - return false; - break; - case 'a': - rs_val = ReadControlInt(IDC_EDIT_COMPAREADDRESS, true, success); - if(!success || rs_val < 0 || rs_val > 0x06040000) - return false; - break; - case 'n': { - rs_val = ReadControlInt(IDC_EDIT_COMPARECHANGES, false, success); - if(!success || rs_val < 0 || rs_val > 0xFFFF) - return false; - } break; - } - - // also update rs_param - switch(rs_o) - { - default: - rs_param = 0; - break; - case 'd': - rs_param = ReadControlInt(IDC_EDIT_DIFFBY, false, success); - if(!success) - return false; - if(rs_param < 0) - rs_param = -rs_param; - break; - case '%': - rs_param = ReadControlInt(IDC_EDIT_MODBY, false, success); - if(!success || rs_param == 0) - return false; - break; - } - - // validate that rs_param fits in the comparison data type - { - int appliedSize = rs_type_size; - int appliedSign = rs_t; - if(rs_c == 'n') - appliedSize = 'w', appliedSign = 'u'; - if(rs_c == 'a') - appliedSize = 'd', appliedSign = 'u'; - if((appliedSize == 'b' && appliedSize == 's' && (rs_param < -128 || rs_param > 127)) || - (appliedSize == 'b' && appliedSize != 's' && (rs_param < 0 || rs_param > 255)) || - (appliedSize == 'w' && appliedSize == 's' && (rs_param < -32768 || rs_param > 32767)) || - (appliedSize == 'w' && appliedSize != 's' && (rs_param < 0 || rs_param > 65535))) - return false; - } - - return true; -} - -bool IsSatisfied(int itemIndex) -{ - if(!rs_val_valid) - return true; - int o = rs_o; - switch (rs_c) - { - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_SIZE_TYPES(sf, rs_type_size,(rs_t=='s'),noMisalign, CmpFun,itemIndex,rs_val,rs_param); - case 'r': DO_SEARCH(CompareRelativeAtItem); break; - case 's': DO_SEARCH(CompareSpecificAtItem); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP(sf, rs_type_size, unsigned,int, noMisalign, CmpFun,itemIndex,rs_val,rs_param); - case 'a': DO_SEARCH(CompareAddressAtItem); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP(sf, rs_type_size, unsigned,short, noMisalign, CmpFun,itemIndex,rs_val,rs_param); - case 'n': DO_SEARCH(CompareChangesAtItem); break; - } - return false; -} - - - -// this is mainly for the RAM watch window -unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size, int byteSwapped = false) -{ - unsigned int value = 0; - if(!byteSwapped) - { - // convert to current endianness - for(unsigned int i = 0; i < size; i++) - { - value <<= 8; - value |= *address++; - } - } - else - { - // byte-swap and convert to current endianness at the same time - for(unsigned int i = 0; i < size; i++) - { - value <<= 8; - value |= *((unsigned char*)((intptr_t)address++^1)); - } - } - return value; -} -void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size, int byteSwapped = false) -{ - if(!byteSwapped) - { - // write as big endian - for(int i = size-1; i >= 0; i--) - { - address[i] = value & 0xFF; - value >>= 8; - } - } - else - { - // byte-swap and write as big endian at the same time - for(int i = size-1; i >= 0; i--) - { - *((unsigned char*)((intptr_t)(address+i)^1)) = value & 0xFF; - value >>= 8; - } - } -} -inline bool IsInRange(unsigned int x, unsigned int min, unsigned int size) -{ - x -= min; - return x < size; -} -unsigned int ReadValueAtHardwareAddress(unsigned int address, unsigned int size) -{ - if((address & ~0xFFFFFF) == ~0xFFFFFF) - address &= 0xFFFFFF; - - - char buf[4]; - MMU_DumpMemBlock(0, address, 4, (u8*)buf); - - u32 val_u32 = *(u32*)buf; - u16 val_u16 = *(u16*)buf; - u8 val_u8 = *(u8*)buf; - - switch (size) - { - case 1: return val_u8; - case 2: return val_u16; - case 4: return val_u32; - } -// if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) -// return ReadValueAtSoftwareAddress(Ram_68k + address - 0xFF0000, size, true); -/* if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) TODO - return ReadValueAtSoftwareAddress(Ram_68k + address - 0xFF0000, size, true); - if(IsInRange(address, 0xA00000, Z80_RAM_SIZE)) - return ReadValueAtSoftwareAddress(Ram_Z80 + address - 0xA00000, size, true); - if(SegaCD_Started && IsInRange(address, 0x020000, SEGACD_RAM_PRG_SIZE)) - return ReadValueAtSoftwareAddress(Ram_Prg + address - 0x020000, size, true); - if(SegaCD_Started && IsInRange(address, 0x200000, SEGACD_1M_RAM_SIZE)) - return ReadValueAtSoftwareAddress(((Ram_Word_State & 0x2) ? Ram_Word_1M : Ram_Word_2M) + address - 0x200000, size, true); - if(IsInRange(address, 0x0, Rom_Size)) - return ReadValueAtSoftwareAddress(Rom_Data + address, size, true); - if(_32X_Started && IsInRange(address, 0x06000000, _32X_RAM_SIZE)) - return ReadValueAtSoftwareAddress(_32X_Ram + address - 0x06000000, size, false);*/ - return 0; -} -bool WriteValueAtHardwareRAMAddress(unsigned int address, unsigned int value, unsigned int size, bool hookless) -{ - if((address & ~0xFFFFFF) == ~0xFFFFFF) - address &= 0xFFFFFF; -/* if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) TODO - WriteValueAtSoftwareAddress(Ram_68k + address - 0xFF0000, value, size, true); - else if(IsInRange(address, 0xA00000, Z80_RAM_SIZE)) - WriteValueAtSoftwareAddress(Ram_Z80 + address - 0xA00000, value, size, true); - else if(SegaCD_Started && IsInRange(address, 0x020000, SEGACD_RAM_PRG_SIZE)) - WriteValueAtSoftwareAddress(Ram_Prg + address - 0x020000, value, size, true); - else if(SegaCD_Started && IsInRange(address, 0x200000, SEGACD_1M_RAM_SIZE)) - WriteValueAtSoftwareAddress(((Ram_Word_State & 0x2) ? Ram_Word_1M : Ram_Word_2M) + address - 0x200000, value, size, true); - else if(_32X_Started && IsInRange(address, 0x06000000, _32X_RAM_SIZE)) - WriteValueAtSoftwareAddress(_32X_Ram + address - 0x06000000, value, size, false);*/ -// else return false; -// if(!hookless) // a script that calls e.g. memory.writebyte() should trigger write hooks -// CallRegisteredLuaMemHook(address, size, value, LUAMEMHOOK_WRITE); - return true; -} -bool WriteValueAtHardwareROMAddress(unsigned int address, unsigned int value, unsigned int size) -{ - if(IsInRange(address, 0x0, Rom_Size)) - WriteValueAtSoftwareAddress(Rom_Data + address, value, size, true); - else return false; - return true; -} -bool WriteValueAtHardwareAddress(unsigned int address, unsigned int value, unsigned int size, bool hookless=false) -{ - return WriteValueAtHardwareRAMAddress(address, value, size, hookless) || - WriteValueAtHardwareROMAddress(address, value, size); -} -bool IsHardwareRAMAddressValid(unsigned int address) -{ - if((address & ~0xFFFFFF) == ~0xFFFFFF) - address &= 0xFFFFFF; -// if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) -// return true; -// if(IsInRange(address, 0xA00000, Z80_RAM_SIZE)) -// return true; - - return true; //TODO -/* if(SegaCD_Started && IsInRange(address, 0x020000, SEGACD_RAM_PRG_SIZE)) TODO - return true; - if(SegaCD_Started && IsInRange(address, 0x200000, SEGACD_1M_RAM_SIZE)) - return true; - if(_32X_Started && IsInRange(address, 0x06000000, _32X_RAM_SIZE)) - return true;*/ - return false; -} -bool IsHardwareROMAddressValid(unsigned int address) -{ - return IsInRange(address, 0x0, Rom_Size); -} -bool IsHardwareAddressValid(unsigned int address) -{ - return IsHardwareROMAddressValid(address) || IsHardwareRAMAddressValid(address); -} - - - -int ResultCount=0; -bool AutoSearch=false; -bool AutoSearchAutoRetry=false; -LRESULT CALLBACK PromptWatchNameProc(HWND, UINT, WPARAM, LPARAM); -void UpdatePossibilities(int rs_possible, int regions); - - -void CompactAddrs() -{ - int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; - int prevResultCount = ResultCount; - - CalculateItemIndices(size); - - ResultCount = CALL_WITH_T_SIZE_TYPES(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign); - UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); - - if(ResultCount != prevResultCount) - ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount); -} - -void soft_reset_address_info () -{ - ResetMemoryRegions(); - memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); - CompactAddrs(); -} -void reset_address_info () -{ - SetRamSearchUndoType(RamSearchHWnd, 0); - s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo - memcpy(buffers->s_prevValues, buffers->s_curValues, sizeof(buffers->s_prevValues)); - s_prevValuesNeedUpdate = false; - ResetMemoryRegions(); - if(!RamSearchHWnd) - { - s_activeMemoryRegions.clear(); - ResultCount = 0; - } - else - { - // force s_prevValues to be valid - signal_new_frame(); - s_prevValuesNeedUpdate = true; - signal_new_frame(); - } - memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); - CompactAddrs(); -} - -void signal_new_frame () -{ - CALL_WITH_T_SIZE_TYPES(UpdateRegionsT, rs_type_size,rs_t=='s',noMisalign); -} - - - - - - - -void RefreshRamListSelectedCountControlStatus(HWND hDlg) -{ - static int prevSelCount=-1; - int selCount = ListView_GetSelectedCount(GetDlgItem(hDlg,IDC_RAMLIST)); - if(selCount != prevSelCount) - { - if(selCount < 2 || prevSelCount < 2) - { - EnableWindow(GetDlgItem(hDlg, IDC_C_WATCH), (selCount == 1 && WatchCount < MAX_WATCH_COUNT) ? TRUE : FALSE); - EnableWindow(GetDlgItem(hDlg, IDC_C_ADDCHEAT), (selCount == 1) ? /*TRUE*/FALSE : FALSE); - EnableWindow(GetDlgItem(hDlg, IDC_C_ELIMINATE), (selCount >= 1) ? TRUE : FALSE); - } - prevSelCount = selCount; - } -} - - - - -struct AddrRange -{ - unsigned int addr; - unsigned int size; - unsigned int End() const { return addr + size; } - AddrRange(unsigned int a, unsigned int s) : addr(a),size(s){} -}; - -void signal_new_size () -{ - HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); - - int oldSize = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2; - int newSize = (rs_type_size=='b' || !noMisalign) ? 1 : 2; - bool numberOfItemsChanged = (oldSize != newSize); - - unsigned int itemsPerPage = ListView_GetCountPerPage(lv); - unsigned int oldTopIndex = ListView_GetTopIndex(lv); - unsigned int oldSelectionIndex = ListView_GetSelectionMark(lv); - unsigned int oldTopAddr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldTopIndex); - unsigned int oldSelectionAddr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldSelectionIndex); - - std::vector selHardwareAddrs; - if(numberOfItemsChanged) - { - // store selection ranges - // unfortunately this can take a while if the user has a huge range of items selected -// Clear_Sound_Buffer(); - int selCount = ListView_GetSelectedCount(lv); - int size = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2; - int watchIndex = -1; - for(int i = 0; i < selCount; ++i) - { - watchIndex = ListView_GetNextItem(lv, watchIndex, LVNI_SELECTED); - int addr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, watchIndex); - if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End()) - selHardwareAddrs.back().size += size; - else - selHardwareAddrs.push_back(AddrRange(addr,size)); - } - } - - CompactAddrs(); - - rs_last_type_size = rs_type_size; - rs_last_no_misalign = noMisalign; - - if(numberOfItemsChanged) - { - // restore selection ranges - unsigned int newTopIndex = CALL_WITH_T_SIZE_TYPES(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, oldTopAddr); - unsigned int newBottomIndex = newTopIndex + itemsPerPage - 1; - SendMessage(lv, WM_SETREDRAW, FALSE, 0); - ListView_SetItemState(lv, -1, 0, LVIS_SELECTED|LVIS_FOCUSED); // deselect all - for(unsigned int i = 0; i < selHardwareAddrs.size(); i++) - { - // calculate index ranges of this selection - const AddrRange& range = selHardwareAddrs[i]; - int selRangeTop = CALL_WITH_T_SIZE_TYPES(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, range.addr); - int selRangeBottom = -1; - for(int endAddr = range.End()-1; endAddr >= selRangeTop && selRangeBottom == -1; endAddr--) - selRangeBottom = CALL_WITH_T_SIZE_TYPES(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, endAddr); - if(selRangeBottom == -1) - selRangeBottom = selRangeTop; - if(selRangeTop == -1) - continue; - - // select the entire range at once without deselecting the other ranges - // looks hacky but it works, and the only documentation I found on how to do this was blatantly false and equally hacky anyway - POINT pos; - ListView_EnsureVisible(lv, selRangeTop, 0); - ListView_GetItemPosition(lv, selRangeTop, &pos); - SendMessage(lv, WM_LBUTTONDOWN, MK_LBUTTON|MK_CONTROL, MAKELONG(pos.x,pos.y)); - ListView_EnsureVisible(lv, selRangeBottom, 0); - ListView_GetItemPosition(lv, selRangeBottom, &pos); - SendMessage(lv, WM_LBUTTONDOWN, MK_LBUTTON|MK_CONTROL|MK_SHIFT, MAKELONG(pos.x,pos.y)); - } - - // restore previous scroll position - if(newBottomIndex != -1) - ListView_EnsureVisible(lv, newBottomIndex, 0); - if(newTopIndex != -1) - ListView_EnsureVisible(lv, newTopIndex, 0); - - SendMessage(lv, WM_SETREDRAW, TRUE, 0); - - RefreshRamListSelectedCountControlStatus(RamSearchHWnd); - - EnableWindow(GetDlgItem(RamSearchHWnd,IDC_MISALIGN), rs_type_size != 'b'); - } - else - { - ListView_Update(lv, -1); - } -} - - - - -LRESULT CustomDraw (LPARAM lParam) -{ - LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; - - switch(lplvcd->nmcd.dwDrawStage) - { - case CDDS_PREPAINT : - return CDRF_NOTIFYITEMDRAW; - - case CDDS_ITEMPREPAINT: - { - int rv = CDRF_DODEFAULT; - - if(lplvcd->nmcd.dwItemSpec % 2) - { - // alternate the background color slightly - lplvcd->clrTextBk = RGB(248,248,255); - rv = CDRF_NEWFONT; - } - - if(!IsSatisfied(lplvcd->nmcd.dwItemSpec)) - { - // tint red any items that would be eliminated if a search were to run now - lplvcd->clrText = RGB(192,64,64); - rv = CDRF_NEWFONT; - } - - return rv; - } break; - } - return CDRF_DODEFAULT; -} - -//extern "C" int disableRamSearchUpdate; -void Update_RAM_Search() //keeps RAM values up to date in the search and watch windows -{ - if (!RamSearchHWnd) return; -// if(disableRamSearchUpdate) -// return; - - if (AutoSearch && !ResultCount) - { - if(!AutoSearchAutoRetry) - { -// Clear_Sound_Buffer(); - int answer = MessageBox(RamSearchHWnd,"Choosing Retry will reset the search once and continue autosearching.\nChoose Ignore will reset the search whenever necessary and continue autosearching.\nChoosing Abort will reset the search once and stop autosearching.","Autosearch - out of results.",MB_ABORTRETRYIGNORE|MB_DEFBUTTON2|MB_ICONINFORMATION); - if(answer == IDABORT) - { - SendDlgItemMessage(RamSearchHWnd, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0); - SendMessage(RamSearchHWnd, WM_COMMAND, IDC_C_AUTOSEARCH, 0); - } - if(answer == IDIGNORE) - AutoSearchAutoRetry = true; - } - reset_address_info(); - } - - int prevValuesNeededUpdate = s_prevValuesNeedUpdate; - if (RamSearchHWnd) - { - // update active RAM values - signal_new_frame(); - } - - if (AutoSearch && ResultCount) - { - //Clear_Sound_Buffer(); - if(!rs_val_valid) - rs_val_valid = Set_RS_Val(); - if(rs_val_valid) - prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param); - } - - if(RamSearchHWnd) - { - HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); - if(prevValuesNeededUpdate != s_prevValuesNeedUpdate) - { - // previous values got updated, refresh everything visible - ListView_Update(lv, -1); - } - else - { - // refresh any visible parts of the listview box that changed - static int changes[128]; - int top = ListView_GetTopIndex(lv); - int count = ListView_GetCountPerPage(lv); - int start = -1; - for(int i = top; i <= top+count; i++) - { - int changeNum = CALL_WITH_T_SIZE_TYPES(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, i); //s_numChanges[i]; - int changed = changeNum != changes[i-top]; - if(changed) - changes[i-top] = changeNum; - - if(start == -1) - { - if(i != top+count && changed) - { - start = i; - //somethingChanged = true; - } - } - else - { - if(i == top+count || !changed) - { - ListView_RedrawItems(lv, start, i-1); - start = -1; - } - } - } - } - } - - if(RamWatchHWnd) - { - Update_RAM_Watch(); - } -} - -static int rs_lastPercent = -1; -inline void UpdateRamSearchProgressBar(int percent) -{ - if(rs_lastPercent != percent) - { - rs_lastPercent = percent; - UpdateRamSearchTitleBar(percent); - } -} - -static void SelectEditControl(int controlID) -{ - HWND hEdit = GetDlgItem(RamSearchHWnd,controlID); - SetFocus(hEdit); - SendMessage(hEdit, EM_SETSEL, 0, -1); -} - -static BOOL SelectingByKeyboard() -{ - int a = GetKeyState(VK_LEFT); - int b = GetKeyState(VK_RIGHT); - int c = GetKeyState(VK_UP); - int d = GetKeyState(VK_DOWN); // space and tab are intentionally omitted - return (a | b | c | d) & 0x80; -} - -extern void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths); - -LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - RECT r; - RECT r2; - int dx1, dy1, dx2, dy2; - static int watchIndex=0; - - switch(uMsg) - { - case WM_INITDIALOG: { - RamSearchHWnd = hDlg; -/* if (Full_Screen) - { - while (ShowCursor(false) >= 0); - while (ShowCursor(true) < 0); - }*/ - - GetWindowRect(MainWindow->getHWnd(), &r); - dx1 = (r.right - r.left) / 2; - dy1 = (r.bottom - r.top) / 2; - - GetWindowRect(hDlg, &r2); - dx2 = (r2.right - r2.left) / 2; - dy2 = (r2.bottom - r2.top) / 2; - - // push it away from the main window if we can - const int width = (r.right-r.left); - const int width2 = (r2.right-r2.left); - if(r.left+width2 + width < GetSystemMetrics(SM_CXSCREEN)) - { - r.right += width; - r.left += width; - } - else if((int)r.left - (int)width2 > 0) - { - r.right -= width2; - r.left -= width2; - } - - SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); - switch(rs_o) - { - case '<': - SendDlgItemMessage(hDlg, IDC_LESSTHAN, BM_SETCHECK, BST_CHECKED, 0); - break; - case '>': - SendDlgItemMessage(hDlg, IDC_MORETHAN, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'l': - SendDlgItemMessage(hDlg, IDC_NOMORETHAN, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'm': - SendDlgItemMessage(hDlg, IDC_NOLESSTHAN, BM_SETCHECK, BST_CHECKED, 0); - break; - case '=': - SendDlgItemMessage(hDlg, IDC_EQUALTO, BM_SETCHECK, BST_CHECKED, 0); - break; - case '!': - SendDlgItemMessage(hDlg, IDC_DIFFERENTFROM, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'd': - SendDlgItemMessage(hDlg, IDC_DIFFERENTBY, BM_SETCHECK, BST_CHECKED, 0); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true); - break; - case '%': - SendDlgItemMessage(hDlg, IDC_MODULO, BM_SETCHECK, BST_CHECKED, 0); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true); - break; - } - switch (rs_c) - { - case 'r': - SendDlgItemMessage(hDlg, IDC_PREVIOUSVALUE, BM_SETCHECK, BST_CHECKED, 0); - break; - case 's': - SendDlgItemMessage(hDlg, IDC_SPECIFICVALUE, BM_SETCHECK, BST_CHECKED, 0); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true); - break; - case 'a': - SendDlgItemMessage(hDlg, IDC_SPECIFICADDRESS, BM_SETCHECK, BST_CHECKED, 0); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true); - break; - case 'n': - SendDlgItemMessage(hDlg, IDC_NUMBEROFCHANGES, BM_SETCHECK, BST_CHECKED, 0); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true); - break; - } - switch (rs_t) - { - case 's': - SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'u': - SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'h': - SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0); - break; - } - switch (rs_type_size) - { - case 'b': - SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'w': - SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'd': - SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0); - break; - } - - s_prevValuesNeedUpdate = true; - - SendDlgItemMessage(hDlg,IDC_C_AUTOSEARCH,BM_SETCHECK,AutoSearch?BST_CHECKED:BST_UNCHECKED,0); - //const char* names[5] = {"Address","Value","Previous","Changes","Notes"}; - //int widths[5] = {62,64,64,55,55}; - const char* names[] = {"Address","Value","Previous","Changes"}; - int widths[4] = {68,76,76,68}; - if (!ResultCount) - reset_address_info(); - else - { - signal_new_frame(); - CompactAddrs(); - } - init_list_box(GetDlgItem(hDlg,IDC_RAMLIST),names,4,widths); - //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount); - if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0); -// if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0); - last_rs_possible = -1; - RefreshRamListSelectedCountControlStatus(hDlg); - - // force misalign checkbox to refresh - signal_new_size(); - - // force undo button to refresh - int undoType = s_undoType; - SetRamSearchUndoType(hDlg, -2); - SetRamSearchUndoType(hDlg, undoType); - - // force possibility count to refresh - last_rs_possible--; - UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); - - rs_val_valid = Set_RS_Val(); - - ListView_SetCallbackMask(GetDlgItem(hDlg,IDC_RAMLIST), LVIS_FOCUSED|LVIS_SELECTED); - - return true; - } break; - - case WM_NOTIFY: - { - LPNMHDR lP = (LPNMHDR) lParam; - switch (lP->code) - { - case LVN_ITEMCHANGED: // selection changed event - { - NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lP; - if(pNMListView->uNewState & LVIS_FOCUSED) - { - // disable buttons that we don't have the right number of selected items for - RefreshRamListSelectedCountControlStatus(hDlg); - } - } break; - - case LVN_GETDISPINFO: - { - LV_DISPINFO *Item = (LV_DISPINFO *)lParam; - Item->item.mask = LVIF_TEXT; - Item->item.state = 0; - Item->item.iImage = 0; - const unsigned int iNum = Item->item.iItem; - static char num[11]; - switch (Item->item.iSubItem) - { - case 0: - { - int addr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); - sprintf(num,"%08X",addr); - Item->item.pszText = num; - } return true; - case 1: - { - int i = CALL_WITH_T_SIZE_TYPES(GetCurValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); - const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X")); - switch (rs_type_size) - { - case 'b': - default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; - case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; - case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; - } - Item->item.pszText = num; - } return true; - case 2: - { - int i = CALL_WITH_T_SIZE_TYPES(GetPrevValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); - const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X")); - switch (rs_type_size) - { - case 'b': - default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; - case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; - case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; - } - Item->item.pszText = num; - } return true; - case 3: - { - int i = CALL_WITH_T_SIZE_TYPES(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); - sprintf(num,"%d",i); - - Item->item.pszText = num; - } return true; - //case 4: - // Item->item.pszText = rsaddrs[rsresults[iNum].Index].comment ? rsaddrs[rsresults[iNum].Index].comment : ""; - // return true; - default: - return false; - } - } - - case NM_CUSTOMDRAW: - { - SetWindowLong(hDlg, DWL_MSGRESULT, CustomDraw(lParam)); - return TRUE; - } break; - - //case LVN_ODCACHEHINT: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something. - //{ - // LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam; - // return 0; - //} - //case LVN_ODFINDITEM: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something. - //{ - // LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam; - // return 0; - //} - } - } break; - - case WM_COMMAND: - { - int rv = false; - switch(LOWORD(wParam)) - { - case IDC_SIGNED: - rs_t='s'; - signal_new_size(); - {rv = true; break;} - case IDC_UNSIGNED: - rs_t='u'; - signal_new_size(); - {rv = true; break;} - case IDC_HEX: - rs_t='h'; - signal_new_size(); - {rv = true; break;} - case IDC_1_BYTE: - rs_type_size = 'b'; - signal_new_size(); - {rv = true; break;} - case IDC_2_BYTES: - rs_type_size = 'w'; - signal_new_size(); - {rv = true; break;} - case IDC_4_BYTES: - rs_type_size = 'd'; - signal_new_size(); - {rv = true; break;} - case IDC_MISALIGN: - noMisalign = !noMisalign; - //CompactAddrs(); - signal_new_size(); - {rv = true; break;} -// case IDC_ENDIAN: -// littleEndian = !littleEndian; -// signal_new_size(); - {rv = true; break;} - case IDC_LESSTHAN: - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); - rs_o = '<'; - {rv = true; break;} - case IDC_MORETHAN: - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); - rs_o = '>'; - {rv = true; break;} - case IDC_NOMORETHAN: - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); - rs_o = 'l'; - {rv = true; break;} - case IDC_NOLESSTHAN: - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); - rs_o = 'm'; - {rv = true; break;} - case IDC_EQUALTO: - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); - rs_o = '='; - {rv = true; break;} - case IDC_DIFFERENTFROM: - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); - rs_o = '!'; - {rv = true; break;} - case IDC_DIFFERENTBY: - { - rs_o = 'd'; - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); - if(!SelectingByKeyboard()) - SelectEditControl(IDC_EDIT_DIFFBY); - } {rv = true; break;} - case IDC_MODULO: - { - rs_o = '%'; - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true); - if(!SelectingByKeyboard()) - SelectEditControl(IDC_EDIT_MODBY); - } {rv = true; break;} - case IDC_PREVIOUSVALUE: - rs_c='r'; - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); - {rv = true; break;} - case IDC_SPECIFICVALUE: - { - rs_c = 's'; - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); - if(!SelectingByKeyboard()) - SelectEditControl(IDC_EDIT_COMPAREVALUE); - {rv = true; break;} - } - case IDC_SPECIFICADDRESS: - { - rs_c = 'a'; - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); - if(!SelectingByKeyboard()) - SelectEditControl(IDC_EDIT_COMPAREADDRESS); - } {rv = true; break;} - case IDC_NUMBEROFCHANGES: - { - rs_c = 'n'; - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); - EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); - if(!SelectingByKeyboard()) - SelectEditControl(IDC_EDIT_COMPARECHANGES); - } {rv = true; break;} - case IDC_C_ADDCHEAT: - { -// watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST)); -// Liste_GG[CheatCount].restore = Liste_GG[CheatCount].data = rsresults[watchIndex].cur; -// Liste_GG[CheatCount].addr = rsresults[watchIndex].Address; -// Liste_GG[CheatCount].size = rs_type_size; -// Liste_GG[CheatCount].Type = rs_t; -// Liste_GG[CheatCount].oper = '='; -// Liste_GG[CheatCount].mode = 0; -// DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_EDITCHEAT), hDlg, (DLGPROC) EditCheatProc,(LPARAM) 0); - } - case IDC_C_RESET: - { - RamSearchSaveUndoStateIfNotTooBig(RamSearchHWnd); - int prevNumItems = last_rs_possible; - - soft_reset_address_info(); - - if(prevNumItems == last_rs_possible) - SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo - - ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all - //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount); - ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0); - RefreshRamListSelectedCountControlStatus(hDlg); - {rv = true; break;} - } - case IDC_C_RESET_CHANGES: - memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); - ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); - //SetRamSearchUndoType(hDlg, 0); - {rv = true; break;} - case IDC_C_UNDO: - if(s_undoType>0) - { -// Clear_Sound_Buffer(); - if(s_activeMemoryRegions.size() < tooManyRegionsForUndo) - { - MemoryList tempMemoryList = s_activeMemoryRegions; - s_activeMemoryRegions = s_activeMemoryRegionsBackup; - s_activeMemoryRegionsBackup = tempMemoryList; - SetRamSearchUndoType(hDlg, 3 - s_undoType); - } - else - { - s_activeMemoryRegions = s_activeMemoryRegionsBackup; - SetRamSearchUndoType(hDlg, -1); - } - CompactAddrs(); - ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all - ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0); - RefreshRamListSelectedCountControlStatus(hDlg); - } - {rv = true; break;} - case IDC_C_AUTOSEARCH: - AutoSearch = SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_GETCHECK, 0, 0) != 0; - AutoSearchAutoRetry = false; - if (!AutoSearch) {rv = true; break;} - case IDC_C_SEARCH: - { -// Clear_Sound_Buffer(); - - if(!rs_val_valid && !(rs_val_valid = Set_RS_Val())) - goto invalid_field; - - if(ResultCount) - { - RamSearchSaveUndoStateIfNotTooBig(hDlg); - - prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param); - - RefreshRamListSelectedCountControlStatus(hDlg); - } - - if(!ResultCount) - { - - MessageBox(RamSearchHWnd,"Resetting search.","Out of results.",MB_OK|MB_ICONINFORMATION); - soft_reset_address_info(); - } - - {rv = true; break;} - -invalid_field: - MessageBox(RamSearchHWnd,"Invalid or out-of-bound entered value.","Error",MB_OK|MB_ICONSTOP); - if(AutoSearch) // stop autosearch if it just started - { - SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0); - SendMessage(hDlg, WM_COMMAND, IDC_C_AUTOSEARCH, 0); - } - {rv = true; break;} - } - case IDC_C_WATCH: - { - int watchItemIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST)); - if(watchItemIndex >= 0) - { - AddressWatcher tempWatch; - tempWatch.Address = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex); - tempWatch.Size = rs_type_size; - tempWatch.Type = rs_t; - tempWatch.WrongEndian = 0; //Replace when I get little endian working - tempWatch.comment = NULL; - - bool inserted = InsertWatch(tempWatch, hDlg); - //ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); - - // bring up the ram watch window if it's not already showing so the user knows where the watch went - if(inserted && !RamWatchHWnd) - SendMessage(MainWindow->getHWnd(), WM_COMMAND, ID_RAM_WATCH, 0); - SetForegroundWindow(RamSearchHWnd); - } - {rv = true; break;} - } - - // eliminate all selected items - case IDC_C_ELIMINATE: - { - RamSearchSaveUndoStateIfNotTooBig(hDlg); - - HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST); - int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; - int selCount = ListView_GetSelectedCount(ramListControl); - int watchIndex = -1; - - // time-saving trick #1: - // condense the selected items into an array of address ranges - std::vector selHardwareAddrs; - for(int i = 0, j = 1024; i < selCount; ++i, --j) - { - watchIndex = ListView_GetNextItem(ramListControl, watchIndex, LVNI_SELECTED); - int addr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchIndex); - if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End()) - selHardwareAddrs.back().size += size; - else - selHardwareAddrs.push_back(AddrRange(addr,size)); - - if(!j) UpdateRamSearchProgressBar(i * 50 / selCount), j = 1024; - } - - // now deactivate the ranges - - // time-saving trick #2: - // take advantage of the fact that the listbox items must be in the same order as the regions - MemoryList::iterator iter = s_activeMemoryRegions.begin(); - int numHardwareAddrRanges = selHardwareAddrs.size(); - for(int i = 0, j = 16; i < numHardwareAddrRanges; ++i, --j) - { - int addr = selHardwareAddrs[i].addr; - int size = selHardwareAddrs[i].size; - bool affected = false; - while(iter != s_activeMemoryRegions.end()) - { - MemoryRegion& region = *iter; - int affNow = DeactivateRegion(region, iter, addr, size); - if(affNow) - affected = true; - else if(affected) - break; - if(affNow != 2) - ++iter; - } - - if(!j) UpdateRamSearchProgressBar(50 + (i * 50 / selCount)), j = 16; - } - UpdateRamSearchTitleBar(); - - // careful -- if the above two time-saving tricks aren't working, - // the runtime can absolutely explode (seconds -> hours) when there are lots of regions - - ListView_SetItemState(ramListControl, -1, 0, LVIS_SELECTED); // deselect all - signal_new_size(); - {rv = true; break;} - } - //case IDOK: - case IDCANCEL: -/* if (Full_Screen) - { - while (ShowCursor(true) < 0); - while (ShowCursor(false) >= 0); - }*/ -// DialogsOpen--; - RamSearchHWnd = NULL; - EndDialog(hDlg, true); - {rv = true; break;} - } - - // check refresh for comparison preview color update - // also, update rs_val if needed - bool needRefresh = false; - switch(LOWORD(wParam)) - { - case IDC_LESSTHAN: - case IDC_MORETHAN: - case IDC_NOMORETHAN: - case IDC_NOLESSTHAN: - case IDC_EQUALTO: - case IDC_DIFFERENTFROM: - case IDC_DIFFERENTBY: - case IDC_MODULO: - case IDC_PREVIOUSVALUE: - case IDC_SPECIFICVALUE: - case IDC_SPECIFICADDRESS: - case IDC_NUMBEROFCHANGES: - case IDC_SIGNED: - case IDC_UNSIGNED: - case IDC_HEX: - rs_val_valid = Set_RS_Val(); - needRefresh = true; - break; - case IDC_EDIT_COMPAREVALUE: - case IDC_EDIT_COMPAREADDRESS: - case IDC_EDIT_COMPARECHANGES: - case IDC_EDIT_DIFFBY: - case IDC_EDIT_MODBY: - if(HIWORD(wParam) == EN_CHANGE) - { - rs_val_valid = Set_RS_Val(); - needRefresh = true; - } - break; - } - if(needRefresh) - ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); - - - return rv; - } break; - - case WM_CLOSE: -/* if (Full_Screen) - { - while (ShowCursor(true) < 0); - while (ShowCursor(false) >= 0); - } - DialogsOpen--;*/ - RamSearchHWnd = NULL; - EndDialog(hDlg, true); - return true; - } - - return false; -} - -void UpdateRamSearchTitleBar(int percent) -{ -#define HEADER_STR " RAM Search - " -#define PROGRESS_STR " %d%% ... " -#define STATUS_STR "%d Possibilit%s (%d Region%s)" - - int poss = last_rs_possible; - int regions = last_rs_regions; - if(poss <= 0) - strcpy(Str_Tmp," RAM Search"); - else if(percent <= 0) - sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); - else - sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); - SetWindowText(RamSearchHWnd, Str_Tmp); -} - -void UpdatePossibilities(int rs_possible, int regions) -{ - if(rs_possible != last_rs_possible) - { - last_rs_possible = rs_possible; - last_rs_regions = regions; - UpdateRamSearchTitleBar(); - } -} - -void SetRamSearchUndoType(HWND hDlg, int type) -{ - if(s_undoType != type) - { - if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1)) - SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo")); - if((s_undoType>0)!=(type>0)) - EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0); - s_undoType = type; - } -} - -void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg) -{ - if(s_activeMemoryRegions.size() < tooManyRegionsForUndo) - { - s_activeMemoryRegionsBackup = s_activeMemoryRegions; - SetRamSearchUndoType(hDlg, 1); - } - else - { - SetRamSearchUndoType(hDlg, 0); - } -} +//RamSearch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ +//Authors: Upthorn, Nitsuja, adelikat + +// A few notes about this implementation of a RAM search window: +// +// Speed of update was one of the highest priories. +// This is because I wanted the RAM search window to be able to +// update every single value in RAM every single frame, and +// keep track of the exact number of frames across which each value has changed, +// without causing the emulation to run noticeably slower than normal. +// +// The data representation was changed from one entry per valid address +// to one entry per contiguous range of uneliminated addresses +// which references uniform pools of per-address properties. +// - This saves time when there are many items because +// it minimizes the amount of data that needs to be stored and processed per address. +// - It also saves time when there are few items because +// it ensures that no time is wasted in iterating through +// addresses that have already been eliminated from the search. +// +// The worst-case scenario is when every other item has been +// eliminated from the search, maximizing the number of regions. +// This implementation manages to handle even that pathological case +// acceptably well. In fact, it still updates faster than the previous implementation. +// The time spent setting up or clearing such a large number of regions +// is somewhat horrendous, but it seems reasonable to have poor worst-case speed +// during these sporadic "setup" steps to achieve an all-around faster per-update speed. +// (You can test this case by performing the search: Modulo 2 Is Specific Address 0) + +#include "resource.h" + +#include "common.h" +#include "NDSSystem.h" +#include "ramwatch.h" + +#include "ram_search.h" +#include +#include +#include "ramwatch.h" +#include +#include +#ifdef _WIN32 + #include "BaseTsd.h" + typedef INT_PTR intptr_t; +#else + #include "stdint.h" +#endif + +HWND RamSearchHWnd = NULL; + +extern HWND RamWatchHWnd; + +extern char Str_Tmp[1024]; + +int Rom_Size; //TODO +unsigned char* Rom_Data; //TODO + +struct MemoryRegion +{ + unsigned int hardwareAddress; // hardware address of the start of this region + unsigned int size; // number of bytes to the end of this region + unsigned char* softwareAddress; // pointer to the start of the live emulator source values for this region + BOOL byteSwapped; // true if this is a byte-swapped region of memory + + unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions() + unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false +}; + +static struct Buffers { + unsigned char s_prevValues [MAX_RAM_SIZE+4]; // values at last search or reset + unsigned char s_curValues [MAX_RAM_SIZE+4]; // values at last frame update + unsigned short s_numChanges [MAX_RAM_SIZE+4]; // number of changes of the item starting at this virtual index address + MemoryRegion* s_itemIndexToRegionPointer [MAX_RAM_SIZE+4]; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false +} *buffers = NULL; +static BOOL s_itemIndicesInvalid = true; // if true, the link from listbox items to memory regions (s_itemIndexToRegionPointer) and the link from memory regions to list box items (MemoryRegion::itemIndex) both need to be recalculated +static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled +static unsigned int s_maxItemIndex = 0; // max currently valid item index, the listbox sometimes tries to update things past the end of the list so we need to know this to ignore those attempts + +static const MemoryRegion s_prgRegion = { 0x02000000, 0x400000, (unsigned char*)ARM9Mem.MAIN_MEM, false}; + +/* +static const MemoryRegion s_prgRegion = { 0x020000, SEGACD_RAM_PRG_SIZE, (unsigned char*)Ram_Prg, true}; +static const MemoryRegion s_word1MRegion = { 0x200000, SEGACD_1M_RAM_SIZE, (unsigned char*)Ram_Word_1M, true}; +static const MemoryRegion s_word2MRegion = { 0x200000, SEGACD_2M_RAM_SIZE, (unsigned char*)Ram_Word_2M, true}; +static const MemoryRegion s_z80Region = { 0xA00000, Z80_RAM_SIZE, (unsigned char*)Ram_Z80, true}; +static const MemoryRegion s_68kRegion = { 0xFF0000, _68K_RAM_SIZE, (unsigned char*)Ram_68k, true}; +static const MemoryRegion s_32xRegion = {0x06000000, _32X_RAM_SIZE, (unsigned char*)_32X_Ram, false}; +*/ +// list of contiguous uneliminated memory regions +typedef std::list MemoryList; +static MemoryList s_activeMemoryRegions; + +// for undo support (could be better, but this way was really easy) +static MemoryList s_activeMemoryRegionsBackup; +static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo + +void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg); +static const int tooManyRegionsForUndo = 10000; + +void InitRamSearch() +{ + if(buffers == NULL) + { + buffers = new Buffers; + memset(buffers,0,sizeof(Buffers)); + } +} + +void ResetMemoryRegions() +{ +// Clear_Sound_Buffer(); + + s_activeMemoryRegions.clear(); + + s_activeMemoryRegions.push_back(s_prgRegion); + + /*if(Genesis_Started || _32X_Started || SegaCD_Started) + { + s_activeMemoryRegions.push_back(s_68kRegion); + s_activeMemoryRegions.push_back(s_z80Region); + if(SegaCD_Started) + { + s_activeMemoryRegions.push_back(s_prgRegion); + s_activeMemoryRegions.push_back((Ram_Word_State & 0x2) ? s_word1MRegion : s_word2MRegion); + } + if(_32X_Started) + { + s_activeMemoryRegions.push_back(s_32xRegion); + } + }*/ + + int nextVirtualIndex = 0; + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + region.virtualIndex = nextVirtualIndex; + assert(((intptr_t)region.softwareAddress & 1) == 0 && "somebody need to reimplement ReadValueAtSoftwareAddress()"); + nextVirtualIndex = region.virtualIndex + region.size; + } +// assert(nextVirtualIndex <= MAX_RAM_SIZE); TODO +} + +// eliminates a range of hardware addresses from the search results +// returns 2 if it changed the region and moved the iterator to another region +// returns 1 if it changed the region but didn't move the iterator +// returns 0 if it had no effect +// warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion... +// doing so would be tremendously slow because DeactivateRegion invalidates the index cache +int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, unsigned int hardwareAddress, unsigned int size) +{ + if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size) + { + // region is unaffected + return 0; + } + else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) + { + // erase end of region + region.size = hardwareAddress - region.hardwareAddress; + return 1; + } + else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) + { + // erase start of region + int eraseSize = (hardwareAddress + size) - region.hardwareAddress; + region.hardwareAddress += eraseSize; + region.size -= eraseSize; + region.softwareAddress += eraseSize; + region.virtualIndex += eraseSize; + return 1; + } + else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) + { + // erase entire region + iter = s_activeMemoryRegions.erase(iter); + s_itemIndicesInvalid = TRUE; + return 2; + } + else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) + { + // split region + int eraseSize = (hardwareAddress + size) - region.hardwareAddress; + MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.softwareAddress + eraseSize, region.byteSwapped, region.virtualIndex + eraseSize}; + region.size = hardwareAddress - region.hardwareAddress; + iter = s_activeMemoryRegions.insert(++iter, region2); + s_itemIndicesInvalid = TRUE; + return 2; + } +} + +/* +// eliminates a range of hardware addresses from the search results +// this is a simpler but usually slower interface for the above function +void DeactivateRegion(unsigned int hardwareAddress, unsigned int size) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + if(2 != DeactivateRegion(region, iter, hardwareAddress, size)) + ++iter; + } +} +*/ + +// warning: can be slow +void CalculateItemIndices(int itemSize) +{ + unsigned int itemIndex = 0; + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + region.itemIndex = itemIndex; + int startSkipSize = ((unsigned int)(itemSize - region.hardwareAddress)) % itemSize; + unsigned int start = startSkipSize; + unsigned int end = region.size; + for(unsigned int i = start; i < end; i += itemSize) + buffers->s_itemIndexToRegionPointer[itemIndex++] = ®ion; + } + s_maxItemIndex = itemIndex; + s_itemIndicesInvalid = FALSE; +} + +template +void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr) +{ + if(s_prevValuesNeedUpdate) + memcpy(buffers->s_prevValues + region.virtualIndex, buffers->s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); + + unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + + unsigned char* sourceAddr = region.softwareAddress - region.virtualIndex; + unsigned int indexStart = region.virtualIndex + startSkipSize; + unsigned int indexEnd = region.virtualIndex + region.size; + + if(sizeof(compareType) == 1) + { + for(unsigned int i = indexStart; i < indexEnd; i++) + { + if(buffers->s_curValues[i] != sourceAddr[i^swapXOR]) // if value changed + { + buffers->s_curValues[i] = sourceAddr[i^swapXOR]; // update value + //if(s_numChanges[i] != 0xFFFF) + buffers->s_numChanges[i]++; // increase change count + } + } + } + else // it's more complicated for non-byte sizes because: + { // - more than one byte can affect a given change count entry + // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1 + // - a few of those bytes can be outside the region + + unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType); + unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType); + unsigned int lastIndexToCopy = lastIndexToRead; + if(nextRegionPtr) + { + const MemoryRegion& nextRegion = *nextRegionPtr; + int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType); + unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize; + if(lastIndexToCopy > nextIndexStart) + lastIndexToCopy = nextIndexStart; + } + + unsigned int nextValidChange [sizeof(compareType)]; + for(unsigned int i = 0; i < sizeof(compareType); i++) + nextValidChange[i] = indexStart + i; + + for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++) + { + if(buffers->s_curValues[i] != sourceAddr[i^swapXOR]) // if value of this byte changed + { + if(i < lastIndexToCopy) + buffers->s_curValues[i] = sourceAddr[i^swapXOR]; // update value + for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte + { + if(i >= indexEnd+k) + continue; + int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1); + if(nextValidChange[m]+sizeof(compareType) <= i+sizeof(compareType)) // if we didn't already increase the change count for this entry + { + //if(s_numChanges[i-k] != 0xFFFF) + buffers->s_numChanges[i-k]++; // increase the change count for this entry + nextValidChange[m] = i+sizeof(compareType); // and remember not to increase it again + } + } + } + } + } +} + +template +void UpdateRegionsT() +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();) + { + const MemoryRegion& region = *iter; + ++iter; + const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter; + + if(region.byteSwapped) + UpdateRegionT(region, nextRegion); + else + UpdateRegionT(region, nextRegion); + } + + s_prevValuesNeedUpdate = false; +} + +template +int CountRegionItemsT() +{ + if(sizeof(stepType) == 1) + { + if(s_activeMemoryRegions.empty()) + return 0; + + if(s_itemIndicesInvalid) + CalculateItemIndices(sizeof(stepType)); + + MemoryRegion& lastRegion = s_activeMemoryRegions.back(); + return lastRegion.itemIndex + lastRegion.size; + } + else // the branch above is faster but won't work if the step size isn't 1 + { + int total = 0; + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType); + } + return total; + } +} + +// returns information about the item in the form of a "fake" region +// that has the item in it and nothing else +template +void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion) +{ + if(s_itemIndicesInvalid) + CalculateItemIndices(sizeof(stepType)); + + if(itemIndex >= s_maxItemIndex) + { + memset(&virtualRegion, 0, sizeof(MemoryRegion)); + return; + } + + const MemoryRegion* regionPtr = buffers->s_itemIndexToRegionPointer[itemIndex]; + const MemoryRegion& region = *regionPtr; + + int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType); + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + bytesWithinRegion += startSkipSize; + + virtualRegion.size = sizeof(compareType); + virtualRegion.hardwareAddress = region.hardwareAddress + bytesWithinRegion; + virtualRegion.softwareAddress = region.softwareAddress + bytesWithinRegion; + virtualRegion.virtualIndex = region.virtualIndex + bytesWithinRegion; + virtualRegion.byteSwapped = region.byteSwapped; + virtualRegion.itemIndex = itemIndex; + return; +} + +template +unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex) +{ + MemoryRegion virtualRegion; + ItemIndexToVirtualRegion(itemIndex, virtualRegion); + return virtualRegion.virtualIndex; +} + +template +T ReadBigEndian(const unsigned char* data) +{ + T rv = 0; + for(int i = 0; i < sizeof(T); i++) + { + rv <<= 8; + rv |= *data++; + } + return rv; +} +template<> signed char ReadBigEndian(const unsigned char* data) { return *data; } +template<> unsigned char ReadBigEndian(const unsigned char* data) { return *data; } + + +template +compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex) +{ +// return ReadBigEndian(buffers->s_prevValues + virtualIndex); + return *(compareType*)(buffers->s_prevValues+virtualIndex); +} +template +compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex) +{ +// return ReadBigEndian(buffers->s_curValues + virtualIndex); + return *(compareType*)(buffers->s_curValues+virtualIndex); +} +template +unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex) +{ + unsigned short num = buffers->s_numChanges[virtualIndex]; + //for(unsigned int i = 1; i < sizeof(stepType); i++) + // if(num < s_numChanges[virtualIndex+i]) + // num = s_numChanges[virtualIndex+i]; + return num; +} + +template +compareType GetPrevValueFromItemIndex(unsigned int itemIndex) +{ + int virtualIndex = ItemIndexToVirtualIndex(itemIndex); + return GetPrevValueFromVirtualIndex(virtualIndex); +} +template +compareType GetCurValueFromItemIndex(unsigned int itemIndex) +{ + int virtualIndex = ItemIndexToVirtualIndex(itemIndex); + return GetCurValueFromVirtualIndex(virtualIndex); +} +template +unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex) +{ + int virtualIndex = ItemIndexToVirtualIndex(itemIndex); + return GetNumChangesFromVirtualIndex(virtualIndex); +} +template +unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex) +{ + MemoryRegion virtualRegion; + ItemIndexToVirtualRegion(itemIndex, virtualRegion); + return virtualRegion.hardwareAddress; +} + +// this one might be unreliable, haven't used it much +template +unsigned int HardwareAddressToItemIndex(unsigned int hardwareAddress) +{ + if(s_itemIndicesInvalid) + CalculateItemIndices(sizeof(stepType)); + + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size) + { + int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType); + return region.itemIndex + indexWithinRegion; + } + } + + return -1; +} + + + + +// workaround for a parser error in MSVC that sometimes deletes a comma preceeding a macro +// this macro takes a type and a signed/unsigned modifier, and returns the same type with that modifier whether or not the compiler decides to delete the comma between them +template +struct DummyType { typedef T t; }; +#define COMMAHACK(sign, type) DummyType::t +#ifdef _MSC_VER +#pragma warning(disable : 4114) // disable "same modifier used twice" warning that otherwise would get issued when the compiler bug happens +#endif + +// it's ugly but I can't think of a better way to call these functions that isn't also slower, since +// I need the current values of these arguments to determine which primitive types are used within the function +#define CALL_WITH_T_SIZE_TYPES(functionName, sizeTypeID, isSigned, requireAligned, ...) \ + (sizeTypeID == 'b' \ + ? (isSigned \ + ? functionName(__VA_ARGS__) \ + : functionName(__VA_ARGS__)) \ + : sizeTypeID == 'w' \ + ? (isSigned \ + ? (requireAligned \ + ? functionName(__VA_ARGS__) \ + : functionName(__VA_ARGS__)) \ + : (requireAligned \ + ? functionName(__VA_ARGS__) \ + : functionName(__VA_ARGS__))) \ + : sizeTypeID == 'd' \ + ? (isSigned \ + ? (requireAligned \ + ? functionName(__VA_ARGS__) \ + : functionName(__VA_ARGS__)) \ + : (requireAligned \ + ? functionName(__VA_ARGS__) \ + : functionName(__VA_ARGS__))) \ + : functionName(__VA_ARGS__)) + +// version that takes a forced comparison type +#define CALL_WITH_T_STEP(functionName, sizeTypeID, sign,type, requireAligned, ...) \ + (sizeTypeID == 'b' \ + ? functionName(__VA_ARGS__) \ + : sizeTypeID == 'w' \ + ? (requireAligned \ + ? functionName(__VA_ARGS__) \ + : functionName(__VA_ARGS__)) \ + : sizeTypeID == 'd' \ + ? (requireAligned \ + ? functionName(__VA_ARGS__) \ + : functionName(__VA_ARGS__)) \ + : functionName(__VA_ARGS__)) + + +// basic comparison functions: +template inline bool LessCmp (T x, T y, T i) { return x < y; } +template inline bool MoreCmp (T x, T y, T i) { return x > y; } +template inline bool LessEqualCmp (T x, T y, T i) { return x <= y; } +template inline bool MoreEqualCmp (T x, T y, T i) { return x >= y; } +template inline bool EqualCmp (T x, T y, T i) { return x == y; } +template inline bool UnequalCmp (T x, T y, T i) { return x != y; } +template inline bool DiffByCmp (T x, T y, T p) { return x - y == p || y - x == p; } +template inline bool ModIsCmp (T x, T y, T p) { return p && x % p == y; } + +// compare-to type functions: +template +void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(GetCurValueFromVirtualIndex(i), GetPrevValueFromVirtualIndex(i), param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} +template +void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(GetCurValueFromVirtualIndex(i), value, param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} +template +void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(hwaddr, address, param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} +template +void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(GetNumChangesFromVirtualIndex(i), changes, param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} + +char rs_c='s'; +char rs_o='='; +char rs_t='s'; +int rs_param=0, rs_val=0, rs_val_valid=0; +char rs_type_size = 'b', rs_last_type_size = rs_type_size; +bool noMisalign = true, rs_last_no_misalign = noMisalign; +bool littleEndian = false; +int last_rs_possible = -1; +int last_rs_regions = -1; + +void prune(char c,char o,char t,int v,int p) +{ + // repetition-reducing macros + #define DO_SEARCH(sf) \ + switch (o) \ + { \ + case '<': DO_SEARCH_2(LessCmp,sf); break; \ + case '>': DO_SEARCH_2(MoreCmp,sf); break; \ + case '=': DO_SEARCH_2(EqualCmp,sf); break; \ + case '!': DO_SEARCH_2(UnequalCmp,sf); break; \ + case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \ + case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \ + case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \ + case '%': DO_SEARCH_2(ModIsCmp,sf); break; \ + default: assert(!"Invalid operator for this search type."); break; \ + } + + // perform the search, eliminating nonmatching values + switch (c) + { + #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES(sf, rs_type_size, t, noMisalign, CmpFun,v,p) + case 'r': DO_SEARCH(SearchRelative); break; + case 's': DO_SEARCH(SearchSpecific); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP(sf, rs_type_size, unsigned,int, noMisalign, CmpFun,v,p); + case 'a': DO_SEARCH(SearchAddress); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP(sf, rs_type_size, unsigned,short, noMisalign, CmpFun,v,p); + case 'n': DO_SEARCH(SearchChanges); break; + + default: assert(!"Invalid search comparison type."); break; + } + + s_prevValuesNeedUpdate = true; + + int prevNumItems = last_rs_possible; + + CompactAddrs(); + + if(prevNumItems == last_rs_possible) + { + SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo + } +} + + + + +template +bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param) +{ + return cmpFun(GetCurValueFromItemIndex(itemIndex), GetPrevValueFromItemIndex(itemIndex), param); +} +template +bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param) +{ + return cmpFun(GetCurValueFromItemIndex(itemIndex), value, param); +} +template +bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param) +{ + return cmpFun(GetHardwareAddressFromItemIndex(itemIndex), address, param); +} +template +bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param) +{ + return cmpFun(GetNumChangesFromItemIndex(itemIndex), changes, param); +} + +int ReadControlInt(int controlID, bool forceHex, BOOL& success) +{ + int rv = 0; + BOOL ok = false; + + if(!forceHex) + { + rv = GetDlgItemInt(RamSearchHWnd,controlID,&ok,(rs_t == 's')); + } + + if(!ok) + { + if(GetDlgItemText(RamSearchHWnd,controlID,Str_Tmp,16)) + { + for(int i = 0; Str_Tmp[i]; i++) {if(toupper(Str_Tmp[i]) == 'O') Str_Tmp[i] = '0';} + const char* strPtr = Str_Tmp; + bool negate = false; + while(strPtr[0] == '-') + strPtr++, negate = !negate; + if(strPtr[0] == '+') + strPtr++; + if(strPtr[0] == '0' && tolower(strPtr[1]) == 'x') + strPtr += 2, forceHex = true; + if(strPtr[0] == '$') + strPtr++, forceHex = true; + if(!forceHex) + { + const char* strSearchPtr = strPtr; + while(*strSearchPtr) + { + int c = tolower(*strSearchPtr++); + if(c >= 'a' && c <= 'f') + forceHex = true; + } + } + const char* formatString = forceHex ? "%X" : ((rs_t=='s') ? "%d" : "%u"); + if(sscanf(strPtr, formatString, &rv) > 0) + ok = true; + if(negate) + rv = -rv; + } + } + + success = ok; + return rv; +} + + +bool Set_RS_Val() +{ + BOOL success; + + // update rs_val + switch(rs_c) + { + case 'r': + default: + rs_val = 0; + break; + case 's': + rs_val = ReadControlInt(IDC_EDIT_COMPAREVALUE, rs_t == 'h', success); + if(!success) + return false; + if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) || + (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) || + (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) || + (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535))) + return false; + break; + case 'a': + rs_val = ReadControlInt(IDC_EDIT_COMPAREADDRESS, true, success); + if(!success || rs_val < 0 || rs_val > 0x06040000) + return false; + break; + case 'n': { + rs_val = ReadControlInt(IDC_EDIT_COMPARECHANGES, false, success); + if(!success || rs_val < 0 || rs_val > 0xFFFF) + return false; + } break; + } + + // also update rs_param + switch(rs_o) + { + default: + rs_param = 0; + break; + case 'd': + rs_param = ReadControlInt(IDC_EDIT_DIFFBY, false, success); + if(!success) + return false; + if(rs_param < 0) + rs_param = -rs_param; + break; + case '%': + rs_param = ReadControlInt(IDC_EDIT_MODBY, false, success); + if(!success || rs_param == 0) + return false; + break; + } + + // validate that rs_param fits in the comparison data type + { + int appliedSize = rs_type_size; + int appliedSign = rs_t; + if(rs_c == 'n') + appliedSize = 'w', appliedSign = 'u'; + if(rs_c == 'a') + appliedSize = 'd', appliedSign = 'u'; + if((appliedSize == 'b' && appliedSize == 's' && (rs_param < -128 || rs_param > 127)) || + (appliedSize == 'b' && appliedSize != 's' && (rs_param < 0 || rs_param > 255)) || + (appliedSize == 'w' && appliedSize == 's' && (rs_param < -32768 || rs_param > 32767)) || + (appliedSize == 'w' && appliedSize != 's' && (rs_param < 0 || rs_param > 65535))) + return false; + } + + return true; +} + +bool IsSatisfied(int itemIndex) +{ + if(!rs_val_valid) + return true; + int o = rs_o; + switch (rs_c) + { + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_SIZE_TYPES(sf, rs_type_size,(rs_t=='s'),noMisalign, CmpFun,itemIndex,rs_val,rs_param); + case 'r': DO_SEARCH(CompareRelativeAtItem); break; + case 's': DO_SEARCH(CompareSpecificAtItem); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP(sf, rs_type_size, unsigned,int, noMisalign, CmpFun,itemIndex,rs_val,rs_param); + case 'a': DO_SEARCH(CompareAddressAtItem); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP(sf, rs_type_size, unsigned,short, noMisalign, CmpFun,itemIndex,rs_val,rs_param); + case 'n': DO_SEARCH(CompareChangesAtItem); break; + } + return false; +} + + + +// this is mainly for the RAM watch window +unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size, int byteSwapped = false) +{ + unsigned int value = 0; + if(!byteSwapped) + { + // convert to current endianness + for(unsigned int i = 0; i < size; i++) + { + value <<= 8; + value |= *address++; + } + } + else + { + // byte-swap and convert to current endianness at the same time + for(unsigned int i = 0; i < size; i++) + { + value <<= 8; + value |= *((unsigned char*)((intptr_t)address++^1)); + } + } + return value; +} +void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size, int byteSwapped = false) +{ + if(!byteSwapped) + { + // write as big endian + for(int i = size-1; i >= 0; i--) + { + address[i] = value & 0xFF; + value >>= 8; + } + } + else + { + // byte-swap and write as big endian at the same time + for(int i = size-1; i >= 0; i--) + { + *((unsigned char*)((intptr_t)(address+i)^1)) = value & 0xFF; + value >>= 8; + } + } +} +inline bool IsInRange(unsigned int x, unsigned int min, unsigned int size) +{ + x -= min; + return x < size; +} +unsigned int ReadValueAtHardwareAddress(unsigned int address, unsigned int size) +{ + if((address & ~0xFFFFFF) == ~0xFFFFFF) + address &= 0xFFFFFF; + + + char buf[4]; + MMU_DumpMemBlock(0, address, 4, (u8*)buf); + + u32 val_u32 = *(u32*)buf; + u16 val_u16 = *(u16*)buf; + u8 val_u8 = *(u8*)buf; + + switch (size) + { + case 1: return val_u8; + case 2: return val_u16; + case 4: return val_u32; + } +// if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) +// return ReadValueAtSoftwareAddress(Ram_68k + address - 0xFF0000, size, true); +/* if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) TODO + return ReadValueAtSoftwareAddress(Ram_68k + address - 0xFF0000, size, true); + if(IsInRange(address, 0xA00000, Z80_RAM_SIZE)) + return ReadValueAtSoftwareAddress(Ram_Z80 + address - 0xA00000, size, true); + if(SegaCD_Started && IsInRange(address, 0x020000, SEGACD_RAM_PRG_SIZE)) + return ReadValueAtSoftwareAddress(Ram_Prg + address - 0x020000, size, true); + if(SegaCD_Started && IsInRange(address, 0x200000, SEGACD_1M_RAM_SIZE)) + return ReadValueAtSoftwareAddress(((Ram_Word_State & 0x2) ? Ram_Word_1M : Ram_Word_2M) + address - 0x200000, size, true); + if(IsInRange(address, 0x0, Rom_Size)) + return ReadValueAtSoftwareAddress(Rom_Data + address, size, true); + if(_32X_Started && IsInRange(address, 0x06000000, _32X_RAM_SIZE)) + return ReadValueAtSoftwareAddress(_32X_Ram + address - 0x06000000, size, false);*/ + return 0; +} +bool WriteValueAtHardwareRAMAddress(unsigned int address, unsigned int value, unsigned int size, bool hookless) +{ + if((address & ~0xFFFFFF) == ~0xFFFFFF) + address &= 0xFFFFFF; +/* if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) TODO + WriteValueAtSoftwareAddress(Ram_68k + address - 0xFF0000, value, size, true); + else if(IsInRange(address, 0xA00000, Z80_RAM_SIZE)) + WriteValueAtSoftwareAddress(Ram_Z80 + address - 0xA00000, value, size, true); + else if(SegaCD_Started && IsInRange(address, 0x020000, SEGACD_RAM_PRG_SIZE)) + WriteValueAtSoftwareAddress(Ram_Prg + address - 0x020000, value, size, true); + else if(SegaCD_Started && IsInRange(address, 0x200000, SEGACD_1M_RAM_SIZE)) + WriteValueAtSoftwareAddress(((Ram_Word_State & 0x2) ? Ram_Word_1M : Ram_Word_2M) + address - 0x200000, value, size, true); + else if(_32X_Started && IsInRange(address, 0x06000000, _32X_RAM_SIZE)) + WriteValueAtSoftwareAddress(_32X_Ram + address - 0x06000000, value, size, false);*/ +// else return false; +// if(!hookless) // a script that calls e.g. memory.writebyte() should trigger write hooks +// CallRegisteredLuaMemHook(address, size, value, LUAMEMHOOK_WRITE); + return true; +} +bool WriteValueAtHardwareROMAddress(unsigned int address, unsigned int value, unsigned int size) +{ + if(IsInRange(address, 0x0, Rom_Size)) + WriteValueAtSoftwareAddress(Rom_Data + address, value, size, true); + else return false; + return true; +} +bool WriteValueAtHardwareAddress(unsigned int address, unsigned int value, unsigned int size, bool hookless=false) +{ + return WriteValueAtHardwareRAMAddress(address, value, size, hookless) || + WriteValueAtHardwareROMAddress(address, value, size); +} +bool IsHardwareRAMAddressValid(unsigned int address) +{ + if((address & ~0xFFFFFF) == ~0xFFFFFF) + address &= 0xFFFFFF; +// if(IsInRange(address, 0xFF0000, _68K_RAM_SIZE)) +// return true; +// if(IsInRange(address, 0xA00000, Z80_RAM_SIZE)) +// return true; + + return true; //TODO +/* if(SegaCD_Started && IsInRange(address, 0x020000, SEGACD_RAM_PRG_SIZE)) TODO + return true; + if(SegaCD_Started && IsInRange(address, 0x200000, SEGACD_1M_RAM_SIZE)) + return true; + if(_32X_Started && IsInRange(address, 0x06000000, _32X_RAM_SIZE)) + return true;*/ + return false; +} +bool IsHardwareROMAddressValid(unsigned int address) +{ + return IsInRange(address, 0x0, Rom_Size); +} +bool IsHardwareAddressValid(unsigned int address) +{ + return IsHardwareROMAddressValid(address) || IsHardwareRAMAddressValid(address); +} + + + +int ResultCount=0; +bool AutoSearch=false; +bool AutoSearchAutoRetry=false; +LRESULT CALLBACK PromptWatchNameProc(HWND, UINT, WPARAM, LPARAM); +void UpdatePossibilities(int rs_possible, int regions); + + +void CompactAddrs() +{ + int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; + int prevResultCount = ResultCount; + + CalculateItemIndices(size); + + ResultCount = CALL_WITH_T_SIZE_TYPES(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign); + UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); + + if(ResultCount != prevResultCount) + ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount); +} + +void soft_reset_address_info () +{ + ResetMemoryRegions(); + memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); + CompactAddrs(); +} +void reset_address_info () +{ + SetRamSearchUndoType(RamSearchHWnd, 0); + s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo + memcpy(buffers->s_prevValues, buffers->s_curValues, sizeof(buffers->s_prevValues)); + s_prevValuesNeedUpdate = false; + ResetMemoryRegions(); + if(!RamSearchHWnd) + { + s_activeMemoryRegions.clear(); + ResultCount = 0; + } + else + { + // force s_prevValues to be valid + signal_new_frame(); + s_prevValuesNeedUpdate = true; + signal_new_frame(); + } + memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); + CompactAddrs(); +} + +void signal_new_frame () +{ + CALL_WITH_T_SIZE_TYPES(UpdateRegionsT, rs_type_size,rs_t=='s',noMisalign); +} + + + + + + + +void RefreshRamListSelectedCountControlStatus(HWND hDlg) +{ + static int prevSelCount=-1; + int selCount = ListView_GetSelectedCount(GetDlgItem(hDlg,IDC_RAMLIST)); + if(selCount != prevSelCount) + { + if(selCount < 2 || prevSelCount < 2) + { + EnableWindow(GetDlgItem(hDlg, IDC_C_WATCH), (selCount == 1 && WatchCount < MAX_WATCH_COUNT) ? TRUE : FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_C_ADDCHEAT), (selCount == 1) ? /*TRUE*/FALSE : FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_C_ELIMINATE), (selCount >= 1) ? TRUE : FALSE); + } + prevSelCount = selCount; + } +} + + + + +struct AddrRange +{ + unsigned int addr; + unsigned int size; + unsigned int End() const { return addr + size; } + AddrRange(unsigned int a, unsigned int s) : addr(a),size(s){} +}; + +void signal_new_size () +{ + HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); + + int oldSize = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2; + int newSize = (rs_type_size=='b' || !noMisalign) ? 1 : 2; + bool numberOfItemsChanged = (oldSize != newSize); + + unsigned int itemsPerPage = ListView_GetCountPerPage(lv); + unsigned int oldTopIndex = ListView_GetTopIndex(lv); + unsigned int oldSelectionIndex = ListView_GetSelectionMark(lv); + unsigned int oldTopAddr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldTopIndex); + unsigned int oldSelectionAddr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldSelectionIndex); + + std::vector selHardwareAddrs; + if(numberOfItemsChanged) + { + // store selection ranges + // unfortunately this can take a while if the user has a huge range of items selected +// Clear_Sound_Buffer(); + int selCount = ListView_GetSelectedCount(lv); + int size = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2; + int watchIndex = -1; + for(int i = 0; i < selCount; ++i) + { + watchIndex = ListView_GetNextItem(lv, watchIndex, LVNI_SELECTED); + int addr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, watchIndex); + if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End()) + selHardwareAddrs.back().size += size; + else + selHardwareAddrs.push_back(AddrRange(addr,size)); + } + } + + CompactAddrs(); + + rs_last_type_size = rs_type_size; + rs_last_no_misalign = noMisalign; + + if(numberOfItemsChanged) + { + // restore selection ranges + unsigned int newTopIndex = CALL_WITH_T_SIZE_TYPES(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, oldTopAddr); + unsigned int newBottomIndex = newTopIndex + itemsPerPage - 1; + SendMessage(lv, WM_SETREDRAW, FALSE, 0); + ListView_SetItemState(lv, -1, 0, LVIS_SELECTED|LVIS_FOCUSED); // deselect all + for(unsigned int i = 0; i < selHardwareAddrs.size(); i++) + { + // calculate index ranges of this selection + const AddrRange& range = selHardwareAddrs[i]; + int selRangeTop = CALL_WITH_T_SIZE_TYPES(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, range.addr); + int selRangeBottom = -1; + for(int endAddr = range.End()-1; endAddr >= selRangeTop && selRangeBottom == -1; endAddr--) + selRangeBottom = CALL_WITH_T_SIZE_TYPES(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, endAddr); + if(selRangeBottom == -1) + selRangeBottom = selRangeTop; + if(selRangeTop == -1) + continue; + + // select the entire range at once without deselecting the other ranges + // looks hacky but it works, and the only documentation I found on how to do this was blatantly false and equally hacky anyway + POINT pos; + ListView_EnsureVisible(lv, selRangeTop, 0); + ListView_GetItemPosition(lv, selRangeTop, &pos); + SendMessage(lv, WM_LBUTTONDOWN, MK_LBUTTON|MK_CONTROL, MAKELONG(pos.x,pos.y)); + ListView_EnsureVisible(lv, selRangeBottom, 0); + ListView_GetItemPosition(lv, selRangeBottom, &pos); + SendMessage(lv, WM_LBUTTONDOWN, MK_LBUTTON|MK_CONTROL|MK_SHIFT, MAKELONG(pos.x,pos.y)); + } + + // restore previous scroll position + if(newBottomIndex != -1) + ListView_EnsureVisible(lv, newBottomIndex, 0); + if(newTopIndex != -1) + ListView_EnsureVisible(lv, newTopIndex, 0); + + SendMessage(lv, WM_SETREDRAW, TRUE, 0); + + RefreshRamListSelectedCountControlStatus(RamSearchHWnd); + + EnableWindow(GetDlgItem(RamSearchHWnd,IDC_MISALIGN), rs_type_size != 'b'); + } + else + { + ListView_Update(lv, -1); + } +} + + + + +LRESULT CustomDraw (LPARAM lParam) +{ + LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; + + switch(lplvcd->nmcd.dwDrawStage) + { + case CDDS_PREPAINT : + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: + { + int rv = CDRF_DODEFAULT; + + if(lplvcd->nmcd.dwItemSpec % 2) + { + // alternate the background color slightly + lplvcd->clrTextBk = RGB(248,248,255); + rv = CDRF_NEWFONT; + } + + if(!IsSatisfied(lplvcd->nmcd.dwItemSpec)) + { + // tint red any items that would be eliminated if a search were to run now + lplvcd->clrText = RGB(192,64,64); + rv = CDRF_NEWFONT; + } + + return rv; + } break; + } + return CDRF_DODEFAULT; +} + +//extern "C" int disableRamSearchUpdate; +void Update_RAM_Search() //keeps RAM values up to date in the search and watch windows +{ + if (!RamSearchHWnd) return; +// if(disableRamSearchUpdate) +// return; + + if (AutoSearch && !ResultCount) + { + if(!AutoSearchAutoRetry) + { +// Clear_Sound_Buffer(); + int answer = MessageBox(RamSearchHWnd,"Choosing Retry will reset the search once and continue autosearching.\nChoose Ignore will reset the search whenever necessary and continue autosearching.\nChoosing Abort will reset the search once and stop autosearching.","Autosearch - out of results.",MB_ABORTRETRYIGNORE|MB_DEFBUTTON2|MB_ICONINFORMATION); + if(answer == IDABORT) + { + SendDlgItemMessage(RamSearchHWnd, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0); + SendMessage(RamSearchHWnd, WM_COMMAND, IDC_C_AUTOSEARCH, 0); + } + if(answer == IDIGNORE) + AutoSearchAutoRetry = true; + } + reset_address_info(); + } + + int prevValuesNeededUpdate = s_prevValuesNeedUpdate; + if (RamSearchHWnd) + { + // update active RAM values + signal_new_frame(); + } + + if (AutoSearch && ResultCount) + { + //Clear_Sound_Buffer(); + if(!rs_val_valid) + rs_val_valid = Set_RS_Val(); + if(rs_val_valid) + prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param); + } + + if(RamSearchHWnd) + { + HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); + if(prevValuesNeededUpdate != s_prevValuesNeedUpdate) + { + // previous values got updated, refresh everything visible + ListView_Update(lv, -1); + } + else + { + // refresh any visible parts of the listview box that changed + static int changes[128]; + int top = ListView_GetTopIndex(lv); + int count = ListView_GetCountPerPage(lv); + int start = -1; + for(int i = top; i <= top+count; i++) + { + int changeNum = CALL_WITH_T_SIZE_TYPES(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, i); //s_numChanges[i]; + int changed = changeNum != changes[i-top]; + if(changed) + changes[i-top] = changeNum; + + if(start == -1) + { + if(i != top+count && changed) + { + start = i; + //somethingChanged = true; + } + } + else + { + if(i == top+count || !changed) + { + ListView_RedrawItems(lv, start, i-1); + start = -1; + } + } + } + } + } + + if(RamWatchHWnd) + { + Update_RAM_Watch(); + } +} + +static int rs_lastPercent = -1; +inline void UpdateRamSearchProgressBar(int percent) +{ + if(rs_lastPercent != percent) + { + rs_lastPercent = percent; + UpdateRamSearchTitleBar(percent); + } +} + +static void SelectEditControl(int controlID) +{ + HWND hEdit = GetDlgItem(RamSearchHWnd,controlID); + SetFocus(hEdit); + SendMessage(hEdit, EM_SETSEL, 0, -1); +} + +static BOOL SelectingByKeyboard() +{ + int a = GetKeyState(VK_LEFT); + int b = GetKeyState(VK_RIGHT); + int c = GetKeyState(VK_UP); + int d = GetKeyState(VK_DOWN); // space and tab are intentionally omitted + return (a | b | c | d) & 0x80; +} + +extern void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths); + +LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RECT r; + RECT r2; + int dx1, dy1, dx2, dy2; + static int watchIndex=0; + + switch(uMsg) + { + case WM_INITDIALOG: { + RamSearchHWnd = hDlg; +/* if (Full_Screen) + { + while (ShowCursor(false) >= 0); + while (ShowCursor(true) < 0); + }*/ + + GetWindowRect(MainWindow->getHWnd(), &r); + dx1 = (r.right - r.left) / 2; + dy1 = (r.bottom - r.top) / 2; + + GetWindowRect(hDlg, &r2); + dx2 = (r2.right - r2.left) / 2; + dy2 = (r2.bottom - r2.top) / 2; + + // push it away from the main window if we can + const int width = (r.right-r.left); + const int width2 = (r2.right-r2.left); + if(r.left+width2 + width < GetSystemMetrics(SM_CXSCREEN)) + { + r.right += width; + r.left += width; + } + else if((int)r.left - (int)width2 > 0) + { + r.right -= width2; + r.left -= width2; + } + + SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + switch(rs_o) + { + case '<': + SendDlgItemMessage(hDlg, IDC_LESSTHAN, BM_SETCHECK, BST_CHECKED, 0); + break; + case '>': + SendDlgItemMessage(hDlg, IDC_MORETHAN, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'l': + SendDlgItemMessage(hDlg, IDC_NOMORETHAN, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'm': + SendDlgItemMessage(hDlg, IDC_NOLESSTHAN, BM_SETCHECK, BST_CHECKED, 0); + break; + case '=': + SendDlgItemMessage(hDlg, IDC_EQUALTO, BM_SETCHECK, BST_CHECKED, 0); + break; + case '!': + SendDlgItemMessage(hDlg, IDC_DIFFERENTFROM, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'd': + SendDlgItemMessage(hDlg, IDC_DIFFERENTBY, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true); + break; + case '%': + SendDlgItemMessage(hDlg, IDC_MODULO, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true); + break; + } + switch (rs_c) + { + case 'r': + SendDlgItemMessage(hDlg, IDC_PREVIOUSVALUE, BM_SETCHECK, BST_CHECKED, 0); + break; + case 's': + SendDlgItemMessage(hDlg, IDC_SPECIFICVALUE, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true); + break; + case 'a': + SendDlgItemMessage(hDlg, IDC_SPECIFICADDRESS, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true); + break; + case 'n': + SendDlgItemMessage(hDlg, IDC_NUMBEROFCHANGES, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true); + break; + } + switch (rs_t) + { + case 's': + SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'u': + SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'h': + SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0); + break; + } + switch (rs_type_size) + { + case 'b': + SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'w': + SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'd': + SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0); + break; + } + + s_prevValuesNeedUpdate = true; + + SendDlgItemMessage(hDlg,IDC_C_AUTOSEARCH,BM_SETCHECK,AutoSearch?BST_CHECKED:BST_UNCHECKED,0); + //const char* names[5] = {"Address","Value","Previous","Changes","Notes"}; + //int widths[5] = {62,64,64,55,55}; + const char* names[] = {"Address","Value","Previous","Changes"}; + int widths[4] = {68,76,76,68}; + if (!ResultCount) + reset_address_info(); + else + { + signal_new_frame(); + CompactAddrs(); + } + init_list_box(GetDlgItem(hDlg,IDC_RAMLIST),names,4,widths); + //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount); + if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0); +// if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0); + last_rs_possible = -1; + RefreshRamListSelectedCountControlStatus(hDlg); + + // force misalign checkbox to refresh + signal_new_size(); + + // force undo button to refresh + int undoType = s_undoType; + SetRamSearchUndoType(hDlg, -2); + SetRamSearchUndoType(hDlg, undoType); + + // force possibility count to refresh + last_rs_possible--; + UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); + + rs_val_valid = Set_RS_Val(); + + ListView_SetCallbackMask(GetDlgItem(hDlg,IDC_RAMLIST), LVIS_FOCUSED|LVIS_SELECTED); + + return true; + } break; + + case WM_NOTIFY: + { + LPNMHDR lP = (LPNMHDR) lParam; + switch (lP->code) + { + case LVN_ITEMCHANGED: // selection changed event + { + NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lP; + if(pNMListView->uNewState & LVIS_FOCUSED) + { + // disable buttons that we don't have the right number of selected items for + RefreshRamListSelectedCountControlStatus(hDlg); + } + } break; + + case LVN_GETDISPINFO: + { + LV_DISPINFO *Item = (LV_DISPINFO *)lParam; + Item->item.mask = LVIF_TEXT; + Item->item.state = 0; + Item->item.iImage = 0; + const unsigned int iNum = Item->item.iItem; + static char num[11]; + switch (Item->item.iSubItem) + { + case 0: + { + int addr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); + sprintf(num,"%08X",addr); + Item->item.pszText = num; + } return true; + case 1: + { + int i = CALL_WITH_T_SIZE_TYPES(GetCurValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); + const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X")); + switch (rs_type_size) + { + case 'b': + default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; + case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; + case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; + } + Item->item.pszText = num; + } return true; + case 2: + { + int i = CALL_WITH_T_SIZE_TYPES(GetPrevValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); + const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X")); + switch (rs_type_size) + { + case 'b': + default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; + case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; + case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; + } + Item->item.pszText = num; + } return true; + case 3: + { + int i = CALL_WITH_T_SIZE_TYPES(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); + sprintf(num,"%d",i); + + Item->item.pszText = num; + } return true; + //case 4: + // Item->item.pszText = rsaddrs[rsresults[iNum].Index].comment ? rsaddrs[rsresults[iNum].Index].comment : ""; + // return true; + default: + return false; + } + } + + case NM_CUSTOMDRAW: + { + SetWindowLong(hDlg, DWL_MSGRESULT, CustomDraw(lParam)); + return TRUE; + } break; + + //case LVN_ODCACHEHINT: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something. + //{ + // LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam; + // return 0; + //} + //case LVN_ODFINDITEM: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something. + //{ + // LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam; + // return 0; + //} + } + } break; + + case WM_COMMAND: + { + int rv = false; + switch(LOWORD(wParam)) + { + case IDC_SIGNED: + rs_t='s'; + signal_new_size(); + {rv = true; break;} + case IDC_UNSIGNED: + rs_t='u'; + signal_new_size(); + {rv = true; break;} + case IDC_HEX: + rs_t='h'; + signal_new_size(); + {rv = true; break;} + case IDC_1_BYTE: + rs_type_size = 'b'; + signal_new_size(); + {rv = true; break;} + case IDC_2_BYTES: + rs_type_size = 'w'; + signal_new_size(); + {rv = true; break;} + case IDC_4_BYTES: + rs_type_size = 'd'; + signal_new_size(); + {rv = true; break;} + case IDC_MISALIGN: + noMisalign = !noMisalign; + //CompactAddrs(); + signal_new_size(); + {rv = true; break;} +// case IDC_ENDIAN: +// littleEndian = !littleEndian; +// signal_new_size(); + {rv = true; break;} + case IDC_LESSTHAN: + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); + rs_o = '<'; + {rv = true; break;} + case IDC_MORETHAN: + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); + rs_o = '>'; + {rv = true; break;} + case IDC_NOMORETHAN: + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); + rs_o = 'l'; + {rv = true; break;} + case IDC_NOLESSTHAN: + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); + rs_o = 'm'; + {rv = true; break;} + case IDC_EQUALTO: + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); + rs_o = '='; + {rv = true; break;} + case IDC_DIFFERENTFROM: + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); + rs_o = '!'; + {rv = true; break;} + case IDC_DIFFERENTBY: + { + rs_o = 'd'; + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); + if(!SelectingByKeyboard()) + SelectEditControl(IDC_EDIT_DIFFBY); + } {rv = true; break;} + case IDC_MODULO: + { + rs_o = '%'; + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true); + if(!SelectingByKeyboard()) + SelectEditControl(IDC_EDIT_MODBY); + } {rv = true; break;} + case IDC_PREVIOUSVALUE: + rs_c='r'; + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); + {rv = true; break;} + case IDC_SPECIFICVALUE: + { + rs_c = 's'; + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); + if(!SelectingByKeyboard()) + SelectEditControl(IDC_EDIT_COMPAREVALUE); + {rv = true; break;} + } + case IDC_SPECIFICADDRESS: + { + rs_c = 'a'; + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); + if(!SelectingByKeyboard()) + SelectEditControl(IDC_EDIT_COMPAREADDRESS); + } {rv = true; break;} + case IDC_NUMBEROFCHANGES: + { + rs_c = 'n'; + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); + EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); + if(!SelectingByKeyboard()) + SelectEditControl(IDC_EDIT_COMPARECHANGES); + } {rv = true; break;} + case IDC_C_ADDCHEAT: + { +// watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST)); +// Liste_GG[CheatCount].restore = Liste_GG[CheatCount].data = rsresults[watchIndex].cur; +// Liste_GG[CheatCount].addr = rsresults[watchIndex].Address; +// Liste_GG[CheatCount].size = rs_type_size; +// Liste_GG[CheatCount].Type = rs_t; +// Liste_GG[CheatCount].oper = '='; +// Liste_GG[CheatCount].mode = 0; +// DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_EDITCHEAT), hDlg, (DLGPROC) EditCheatProc,(LPARAM) 0); + } + case IDC_C_RESET: + { + RamSearchSaveUndoStateIfNotTooBig(RamSearchHWnd); + int prevNumItems = last_rs_possible; + + soft_reset_address_info(); + + if(prevNumItems == last_rs_possible) + SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo + + ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all + //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount); + ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0); + RefreshRamListSelectedCountControlStatus(hDlg); + {rv = true; break;} + } + case IDC_C_RESET_CHANGES: + memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); + ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); + //SetRamSearchUndoType(hDlg, 0); + {rv = true; break;} + case IDC_C_UNDO: + if(s_undoType>0) + { +// Clear_Sound_Buffer(); + if(s_activeMemoryRegions.size() < tooManyRegionsForUndo) + { + MemoryList tempMemoryList = s_activeMemoryRegions; + s_activeMemoryRegions = s_activeMemoryRegionsBackup; + s_activeMemoryRegionsBackup = tempMemoryList; + SetRamSearchUndoType(hDlg, 3 - s_undoType); + } + else + { + s_activeMemoryRegions = s_activeMemoryRegionsBackup; + SetRamSearchUndoType(hDlg, -1); + } + CompactAddrs(); + ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all + ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0); + RefreshRamListSelectedCountControlStatus(hDlg); + } + {rv = true; break;} + case IDC_C_AUTOSEARCH: + AutoSearch = SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_GETCHECK, 0, 0) != 0; + AutoSearchAutoRetry = false; + if (!AutoSearch) {rv = true; break;} + case IDC_C_SEARCH: + { +// Clear_Sound_Buffer(); + + if(!rs_val_valid && !(rs_val_valid = Set_RS_Val())) + goto invalid_field; + + if(ResultCount) + { + RamSearchSaveUndoStateIfNotTooBig(hDlg); + + prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param); + + RefreshRamListSelectedCountControlStatus(hDlg); + } + + if(!ResultCount) + { + + MessageBox(RamSearchHWnd,"Resetting search.","Out of results.",MB_OK|MB_ICONINFORMATION); + soft_reset_address_info(); + } + + {rv = true; break;} + +invalid_field: + MessageBox(RamSearchHWnd,"Invalid or out-of-bound entered value.","Error",MB_OK|MB_ICONSTOP); + if(AutoSearch) // stop autosearch if it just started + { + SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0); + SendMessage(hDlg, WM_COMMAND, IDC_C_AUTOSEARCH, 0); + } + {rv = true; break;} + } + case IDC_C_WATCH: + { + int watchItemIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST)); + if(watchItemIndex >= 0) + { + AddressWatcher tempWatch; + tempWatch.Address = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex); + tempWatch.Size = rs_type_size; + tempWatch.Type = rs_t; + tempWatch.WrongEndian = 0; //Replace when I get little endian working + tempWatch.comment = NULL; + + bool inserted = InsertWatch(tempWatch, hDlg); + //ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); + + // bring up the ram watch window if it's not already showing so the user knows where the watch went + if(inserted && !RamWatchHWnd) + SendMessage(MainWindow->getHWnd(), WM_COMMAND, ID_RAM_WATCH, 0); + SetForegroundWindow(RamSearchHWnd); + } + {rv = true; break;} + } + + // eliminate all selected items + case IDC_C_ELIMINATE: + { + RamSearchSaveUndoStateIfNotTooBig(hDlg); + + HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST); + int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; + int selCount = ListView_GetSelectedCount(ramListControl); + int watchIndex = -1; + + // time-saving trick #1: + // condense the selected items into an array of address ranges + std::vector selHardwareAddrs; + for(int i = 0, j = 1024; i < selCount; ++i, --j) + { + watchIndex = ListView_GetNextItem(ramListControl, watchIndex, LVNI_SELECTED); + int addr = CALL_WITH_T_SIZE_TYPES(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchIndex); + if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End()) + selHardwareAddrs.back().size += size; + else + selHardwareAddrs.push_back(AddrRange(addr,size)); + + if(!j) UpdateRamSearchProgressBar(i * 50 / selCount), j = 1024; + } + + // now deactivate the ranges + + // time-saving trick #2: + // take advantage of the fact that the listbox items must be in the same order as the regions + MemoryList::iterator iter = s_activeMemoryRegions.begin(); + int numHardwareAddrRanges = selHardwareAddrs.size(); + for(int i = 0, j = 16; i < numHardwareAddrRanges; ++i, --j) + { + int addr = selHardwareAddrs[i].addr; + int size = selHardwareAddrs[i].size; + bool affected = false; + while(iter != s_activeMemoryRegions.end()) + { + MemoryRegion& region = *iter; + int affNow = DeactivateRegion(region, iter, addr, size); + if(affNow) + affected = true; + else if(affected) + break; + if(affNow != 2) + ++iter; + } + + if(!j) UpdateRamSearchProgressBar(50 + (i * 50 / selCount)), j = 16; + } + UpdateRamSearchTitleBar(); + + // careful -- if the above two time-saving tricks aren't working, + // the runtime can absolutely explode (seconds -> hours) when there are lots of regions + + ListView_SetItemState(ramListControl, -1, 0, LVIS_SELECTED); // deselect all + signal_new_size(); + {rv = true; break;} + } + //case IDOK: + case IDCANCEL: +/* if (Full_Screen) + { + while (ShowCursor(true) < 0); + while (ShowCursor(false) >= 0); + }*/ +// DialogsOpen--; + RamSearchHWnd = NULL; + EndDialog(hDlg, true); + {rv = true; break;} + } + + // check refresh for comparison preview color update + // also, update rs_val if needed + bool needRefresh = false; + switch(LOWORD(wParam)) + { + case IDC_LESSTHAN: + case IDC_MORETHAN: + case IDC_NOMORETHAN: + case IDC_NOLESSTHAN: + case IDC_EQUALTO: + case IDC_DIFFERENTFROM: + case IDC_DIFFERENTBY: + case IDC_MODULO: + case IDC_PREVIOUSVALUE: + case IDC_SPECIFICVALUE: + case IDC_SPECIFICADDRESS: + case IDC_NUMBEROFCHANGES: + case IDC_SIGNED: + case IDC_UNSIGNED: + case IDC_HEX: + rs_val_valid = Set_RS_Val(); + needRefresh = true; + break; + case IDC_EDIT_COMPAREVALUE: + case IDC_EDIT_COMPAREADDRESS: + case IDC_EDIT_COMPARECHANGES: + case IDC_EDIT_DIFFBY: + case IDC_EDIT_MODBY: + if(HIWORD(wParam) == EN_CHANGE) + { + rs_val_valid = Set_RS_Val(); + needRefresh = true; + } + break; + } + if(needRefresh) + ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); + + + return rv; + } break; + + case WM_CLOSE: +/* if (Full_Screen) + { + while (ShowCursor(true) < 0); + while (ShowCursor(false) >= 0); + } + DialogsOpen--;*/ + RamSearchHWnd = NULL; + EndDialog(hDlg, true); + return true; + } + + return false; +} + +void UpdateRamSearchTitleBar(int percent) +{ +#define HEADER_STR " RAM Search - " +#define PROGRESS_STR " %d%% ... " +#define STATUS_STR "%d Possibilit%s (%d Region%s)" + + int poss = last_rs_possible; + int regions = last_rs_regions; + if(poss <= 0) + strcpy(Str_Tmp," RAM Search"); + else if(percent <= 0) + sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); + else + sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); + SetWindowText(RamSearchHWnd, Str_Tmp); +} + +void UpdatePossibilities(int rs_possible, int regions) +{ + if(rs_possible != last_rs_possible) + { + last_rs_possible = rs_possible; + last_rs_regions = regions; + UpdateRamSearchTitleBar(); + } +} + +void SetRamSearchUndoType(HWND hDlg, int type) +{ + if(s_undoType != type) + { + if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1)) + SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo")); + if((s_undoType>0)!=(type>0)) + EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0); + s_undoType = type; + } +} + +void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg) +{ + if(s_activeMemoryRegions.size() < tooManyRegionsForUndo) + { + s_activeMemoryRegionsBackup = s_activeMemoryRegions; + SetRamSearchUndoType(hDlg, 1); + } + else + { + SetRamSearchUndoType(hDlg, 0); + } +} diff --git a/desmume/src/windows/ram_search.h b/desmume/src/windows/ram_search.h index 7d1cd6091..e349b34dc 100644 --- a/desmume/src/windows/ram_search.h +++ b/desmume/src/windows/ram_search.h @@ -1,52 +1,52 @@ -//RamSearch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ -//Authors: Upthorn, Nitsuja, adelikat - -#ifndef RAM_SEARCH_H -#define RAM_SEARCH_H - - -//64k in Ram_68k[], 8k in Ram_Z80[] -//#define _68K_RAM_SIZE 64*1024 -//#define Z80_RAM_SIZE 8*1024 -/*#define SRAM_SIZE (((SRAM_End - SRAM_Start) > 2) ? SRAM_End - SRAM_Start : 0) -#define BRAM_SIZE ((8 << BRAM_Ex_Size) * 1024)*/ -//#define GENESIS_RAM_SIZE (_68K_RAM_SIZE + Z80_RAM_SIZE) - -//_32X_Ram[] -//#define _32X_RAM_SIZE 256*1024 - -//512k in Ram_Prg, 256k in Ram_Word_1M and Ram_Word_2M -//(docs say 6Mbit of ram, but I'm not sure what's used when) -//#define SEGACD_RAM_PRG_SIZE 512*1024 -//#define SEGACD_1M_RAM_SIZE 256*1024 -//#define SEGACD_2M_RAM_SIZE 256*1024 -//#define SEGACD_RAM_SIZE (SEGACD_RAM_PRG_SIZE + SEGACD_2M_RAM_SIZE) - - -//#define MAX_RAM_SIZE (0x112000) -//#define MAX_RAM_SIZE (0xD2000) -#define MAX_RAM_SIZE (0x400000) - -extern char rs_type_size; -extern int ResultCount; - -unsigned int sizeConv(unsigned int index,char size, char *prevSize = &rs_type_size, bool usePrev = false); -unsigned int GetRamValue(unsigned int Addr,char Size); -void prune(char Search, char Operater, char Type, int Value, int OperatorParameter); -void CompactAddrs(); -void reset_address_info(); -void signal_new_frame(); -void signal_new_size(); -void UpdateRamSearchTitleBar(int percent = 0); -void Update_RAM_Search(); -void SetRamSearchUndoType(HWND hDlg, int type); -unsigned int ReadValueAtHardwareAddress(unsigned int address, unsigned int size); -bool WriteValueAtHardwareRAMAddress(unsigned int address, unsigned int value, unsigned int size, bool hookless=false); -bool IsHardwareRAMAddressValid(unsigned int address); -extern int curr_ram_size; -extern bool noMisalign; -extern bool littleEndian; - - -#endif - +//RamSearch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ +//Authors: Upthorn, Nitsuja, adelikat + +#ifndef RAM_SEARCH_H +#define RAM_SEARCH_H + + +//64k in Ram_68k[], 8k in Ram_Z80[] +//#define _68K_RAM_SIZE 64*1024 +//#define Z80_RAM_SIZE 8*1024 +/*#define SRAM_SIZE (((SRAM_End - SRAM_Start) > 2) ? SRAM_End - SRAM_Start : 0) +#define BRAM_SIZE ((8 << BRAM_Ex_Size) * 1024)*/ +//#define GENESIS_RAM_SIZE (_68K_RAM_SIZE + Z80_RAM_SIZE) + +//_32X_Ram[] +//#define _32X_RAM_SIZE 256*1024 + +//512k in Ram_Prg, 256k in Ram_Word_1M and Ram_Word_2M +//(docs say 6Mbit of ram, but I'm not sure what's used when) +//#define SEGACD_RAM_PRG_SIZE 512*1024 +//#define SEGACD_1M_RAM_SIZE 256*1024 +//#define SEGACD_2M_RAM_SIZE 256*1024 +//#define SEGACD_RAM_SIZE (SEGACD_RAM_PRG_SIZE + SEGACD_2M_RAM_SIZE) + + +//#define MAX_RAM_SIZE (0x112000) +//#define MAX_RAM_SIZE (0xD2000) +#define MAX_RAM_SIZE (0x400000) + +extern char rs_type_size; +extern int ResultCount; + +unsigned int sizeConv(unsigned int index,char size, char *prevSize = &rs_type_size, bool usePrev = false); +unsigned int GetRamValue(unsigned int Addr,char Size); +void prune(char Search, char Operater, char Type, int Value, int OperatorParameter); +void CompactAddrs(); +void reset_address_info(); +void signal_new_frame(); +void signal_new_size(); +void UpdateRamSearchTitleBar(int percent = 0); +void Update_RAM_Search(); +void SetRamSearchUndoType(HWND hDlg, int type); +unsigned int ReadValueAtHardwareAddress(unsigned int address, unsigned int size); +bool WriteValueAtHardwareRAMAddress(unsigned int address, unsigned int value, unsigned int size, bool hookless=false); +bool IsHardwareRAMAddressValid(unsigned int address); +extern int curr_ram_size; +extern bool noMisalign; +extern bool littleEndian; + + +#endif + diff --git a/desmume/src/windows/ramwatch.cpp b/desmume/src/windows/ramwatch.cpp index 7a8cbd4ba..341f90814 100644 --- a/desmume/src/windows/ramwatch.cpp +++ b/desmume/src/windows/ramwatch.cpp @@ -1,1072 +1,1072 @@ -//RamWatch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ -//Authors: Upthorn, Nitsuja, adelikat - -//#include "main.h" -#include "resource.h" -#include "common.h" -#include "NDSSystem.h" -#include "ramwatch.h" -#include "ram_search.h" -#include -#include -#include -#include - -HWND RamWatchHWnd = NULL; - -#define MESSAGEBOXPARENT (RamWatchHWnd ? RamWatchHWnd : MainWindow->getHWnd()) - -char Str_Tmp[1024]; -std::string Rom_Name; - -static HMENU ramwatchmenu; -static HMENU rwrecentmenu; -static HACCEL RamWatchAccels = NULL; -char rw_recent_files[MAX_RECENT_WATCHES][1024]; -char Watch_Dir[1024]=""; -const unsigned int RW_MENU_FIRST_RECENT_FILE = 600; -bool RWfileChanged = false; //Keeps track of whether the current watch file has been changed, if so, ramwatch will prompt to save changes -bool AutoRWLoad = false; //Keeps track of whether Auto-load is checked -bool RWSaveWindowPos = false; //Keeps track of whether Save Window position is checked -char currentWatch[1024]; -int ramw_x, ramw_y; //Used to store ramwatch dialog window positions -AddressWatcher rswatches[MAX_WATCH_COUNT]; -int WatchCount=0; - -bool QuickSaveWatches(); -bool ResetWatches(); - -unsigned int GetCurrentValue(AddressWatcher& watch) -{ - char buf[4]; - MMU_DumpMemBlock(0, watch.Address, 4, (u8*)buf); - - u32 val_u32 = *(u32*)buf; - u16 val_u16 = *(u16*)buf; - u8 val_u8 = *(u8*)buf; - - switch (watch.Size) - { - case 0x62: return val_u8; - case 0x77: return val_u16; - case 0x64: return val_u32; - default: return 0; - } -// return ReadValueAtHardwareAddress(watch.Address, watch.Size == 'd' ? 4 : watch.Size == 'w' ? 2 : 1); -} - -bool IsSameWatch(const AddressWatcher& l, const AddressWatcher& r) -{ - return ((l.Address == r.Address) && (l.Size == r.Size) && (l.Type == r.Type)/* && (l.WrongEndian == r.WrongEndian)*/); -} - -bool VerifyWatchNotAlreadyAdded(const AddressWatcher& watch) -{ - for (int j = 0; j < WatchCount; j++) - { - if (IsSameWatch(rswatches[j], watch)) - { - if(RamWatchHWnd) - SetForegroundWindow(RamWatchHWnd); - return false; - } - } - return true; -} - - -bool InsertWatch(const AddressWatcher& Watch, char *Comment) -{ - if(!VerifyWatchNotAlreadyAdded(Watch)) - return false; - - if(WatchCount >= MAX_WATCH_COUNT) - return false; - - int i = WatchCount++; - AddressWatcher& NewWatch = rswatches[i]; - NewWatch = Watch; - //if (NewWatch.comment) free(NewWatch.comment); - NewWatch.comment = (char *) malloc(strlen(Comment)+2); - NewWatch.CurValue = GetCurrentValue(NewWatch); - strcpy(NewWatch.comment, Comment); - ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); - RWfileChanged=true; - - return true; -} - -LRESULT CALLBACK PromptWatchNameProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //Gets the description of a watched address -{ - RECT r; - RECT r2; - int dx1, dy1, dx2, dy2; - - switch(uMsg) - { - case WM_INITDIALOG: - GetWindowRect(MainWindow->getHWnd(), &r); - dx1 = (r.right - r.left) / 2; - dy1 = (r.bottom - r.top) / 2; - - GetWindowRect(hDlg, &r2); - dx2 = (r2.right - r2.left) / 2; - dy2 = (r2.bottom - r2.top) / 2; - - SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); - strcpy(Str_Tmp,"Enter a name for this RAM address."); - //SendDlgItemMessage(hDlg,IDC_PROMPT_TEXT,WM_SETTEXT,0,(LPARAM)Str_Tmp); - strcpy(Str_Tmp,""); - //SendDlgItemMessage(hDlg,IDC_PROMPT_TEXT2,WM_SETTEXT,0,(LPARAM)Str_Tmp); - return true; - break; - - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDOK: - { - GetDlgItemText(hDlg,IDC_PROMPT_EDIT,Str_Tmp,80); - InsertWatch(rswatches[WatchCount],Str_Tmp); - EndDialog(hDlg, true); - return true; - break; - } - case IDCANCEL: - - EndDialog(hDlg, false); - return false; - break; - } - break; - - case WM_CLOSE: - EndDialog(hDlg, false); - return false; - break; - } - - return false; -} - -bool InsertWatch(const AddressWatcher& Watch, HWND parent) -{ - if(!VerifyWatchNotAlreadyAdded(Watch)) - return false; - - if(!parent) - parent = RamWatchHWnd; - if(!parent) - parent = MainWindow->getHWnd(); - - int prevWatchCount = WatchCount; - - rswatches[WatchCount] = Watch; - rswatches[WatchCount].CurValue = GetCurrentValue(rswatches[WatchCount]); - DialogBox(hAppInst, MAKEINTRESOURCE(IDD_PROMPT), parent, (DLGPROC) PromptWatchNameProc); - - return WatchCount > prevWatchCount; -} - -void Update_RAM_Watch() -{ - if (!RamWatchHWnd) return; - - // update cached values and detect changes to displayed listview items - BOOL watchChanged[MAX_WATCH_COUNT] = {0}; - for(int i = 0; i < WatchCount; i++) - { - unsigned int prevCurValue = rswatches[i].CurValue; - unsigned int newCurValue = GetCurrentValue(rswatches[i]); - if(prevCurValue != newCurValue) - { - rswatches[i].CurValue = newCurValue; - watchChanged[i] = TRUE; - } - } - - // refresh any visible parts of the listview box that changed - HWND lv = GetDlgItem(RamWatchHWnd,IDC_WATCHLIST); - int top = ListView_GetTopIndex(lv); - int bottom = top + ListView_GetCountPerPage(lv) + 1; // +1 is so we will update a partially-displayed last item - if(top < 0) top = 0; - if(bottom > WatchCount) bottom = WatchCount; - int start = -1; - for(int i = top; i <= bottom; i++) - { - if(start == -1) - { - if(i != bottom && watchChanged[i]) - { - start = i; - //somethingChanged = true; - } - } - else - { - if(i == bottom || !watchChanged[i]) - { - ListView_RedrawItems(lv, start, i-1); - start = -1; - } - } - } -} - -bool AskSave() -{ - //This function asks to save changes if the watch file contents have changed - //returns false only if a save was attempted but failed or was cancelled - if (RWfileChanged) - { - HWND Hwnd = MainWindow->getHWnd(); - int answer = MessageBox(Hwnd, "Save Changes?", "Ram Watch", MB_YESNOCANCEL); - if(answer == IDYES) - if(!QuickSaveWatches()) - return false; - return (answer != IDCANCEL); - } - return true; -} - - -void UpdateRW_RMenu(HMENU menu, unsigned int mitem, unsigned int baseid) -{ - MENUITEMINFO moo; - int x; - - moo.cbSize = sizeof(moo); - moo.fMask = MIIM_SUBMENU | MIIM_STATE; - - GetMenuItemInfo(GetSubMenu(ramwatchmenu, 0), mitem, FALSE, &moo); - moo.hSubMenu = menu; - moo.fState = strlen(rw_recent_files[0]) ? MFS_ENABLED : MFS_GRAYED; - - SetMenuItemInfo(GetSubMenu(ramwatchmenu, 0), mitem, FALSE, &moo); - - // Remove all recent files submenus - for(x = 0; x < MAX_RECENT_WATCHES; x++) - { - RemoveMenu(menu, baseid + x, MF_BYCOMMAND); - } - - // Recreate the menus - for(x = MAX_RECENT_WATCHES - 1; x >= 0; x--) - { - char tmp[128 + 5]; - - // Skip empty strings - if(!strlen(rw_recent_files[x])) - { - continue; - } - - moo.cbSize = sizeof(moo); - moo.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE; - - // Fill in the menu text. - if(strlen(rw_recent_files[x]) < 128) - { - sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, rw_recent_files[x]); - } - else - { - sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, rw_recent_files[x] + strlen( rw_recent_files[x] ) - 127); - } - - // Insert the menu item - moo.cch = strlen(tmp); - moo.fType = 0; - moo.wID = baseid + x; - moo.dwTypeData = tmp; - InsertMenuItem(menu, 0, 1, &moo); - } -} - -void UpdateRWRecentArray(const char* addString, unsigned int arrayLen, HMENU menu, unsigned int menuItem, unsigned int baseId) -{ - // Try to find out if the filename is already in the recent files list. - for(unsigned int x = 0; x < arrayLen; x++) - { - if(strlen(rw_recent_files[x])) - { - if(!strcmp(rw_recent_files[x], addString)) // Item is already in list. - { - // If the filename is in the file list don't add it again. - // Move it up in the list instead. - - int y; - char tmp[1024]; - - // Save pointer. - strcpy(tmp,rw_recent_files[x]); - - for(y = x; y; y--) - { - // Move items down. - strcpy(rw_recent_files[y],rw_recent_files[y - 1]); - } - - // Put item on top. - strcpy(rw_recent_files[0],tmp); - - // Update the recent files menu - UpdateRW_RMenu(menu, menuItem, baseId); - - return; - } - } - } - - // The filename wasn't found in the list. That means we need to add it. - - // Move the other items down. - for(unsigned int x = arrayLen - 1; x; x--) - { - strcpy(rw_recent_files[x],rw_recent_files[x - 1]); - } - - // Add the new item. - strcpy(rw_recent_files[0], addString); - - // Update the recent files menu - UpdateRW_RMenu(menu, menuItem, baseId); -} - - -void RWAddRecentFile(const char *filename) -{ - UpdateRWRecentArray(filename, MAX_RECENT_WATCHES, rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE); -} - -void OpenRWRecentFile(int memwRFileNumber) -{ - if(!ResetWatches()) - return; - - int rnum = memwRFileNumber; - if ((unsigned int)rnum >= MAX_RECENT_WATCHES) - return; //just in case - - char* x; - - while(true) - { - x = rw_recent_files[rnum]; - if (!*x) - return; //If no recent files exist just return. Useful for Load last file on startup (or if something goes screwy) - - if (rnum) //Change order of recent files if not most recent - { - RWAddRecentFile(x); - rnum = 0; - } - else - { - break; - } - } - - strcpy(currentWatch,x); - strcpy(Str_Tmp,currentWatch); - - //loadwatches here - FILE *WatchFile = fopen(Str_Tmp,"rb"); - if (!WatchFile) - { - int answer = MessageBox(MESSAGEBOXPARENT,"Error opening file.","ERROR",MB_OKCANCEL); - if (answer == IDOK) - { - rw_recent_files[rnum][0] = '\0'; //Clear file from list - if (rnum) //Update the ramwatch list - RWAddRecentFile(rw_recent_files[0]); - else - RWAddRecentFile(rw_recent_files[1]); - } - return; - } - const char DELIM = '\t'; - AddressWatcher Temp; - char mode; - fgets(Str_Tmp,1024,WatchFile); - sscanf(Str_Tmp,"%c%*s",&mode); - int WatchAdd; - fgets(Str_Tmp,1024,WatchFile); - sscanf(Str_Tmp,"%d%*s",&WatchAdd); - WatchAdd+=WatchCount; - for (int i = WatchCount; i < WatchAdd; i++) - { - while (i < 0) - i++; - do { - fgets(Str_Tmp,1024,WatchFile); - } while (Str_Tmp[0] == '\n'); - sscanf(Str_Tmp,"%*05X%*c%08X%*c%c%*c%c%*c%d",&(Temp.Address),&(Temp.Size),&(Temp.Type),&(Temp.WrongEndian)); - Temp.WrongEndian = 0; - char *Comment = strrchr(Str_Tmp,DELIM) + 1; - *strrchr(Comment,'\n') = '\0'; - InsertWatch(Temp,Comment); - } - - fclose(WatchFile); - if (RamWatchHWnd) - ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); - RWfileChanged=false; - return; -} - -char Gens_Path[64]= "M:\\"; //TODO - -int Change_File_S(char *Dest, char *Dir, char *Titre, char *Filter, char *Ext, HWND hwnd) -{ - OPENFILENAME ofn; - - SetCurrentDirectory(Gens_Path); - - if (!strcmp(Dest, "")) - { - strcpy(Dest, "default."); - strcat(Dest, Ext); - } - - memset(&ofn, 0, sizeof(OPENFILENAME)); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hwnd; - ofn.hInstance = hAppInst; - ofn.lpstrFile = Dest; - ofn.nMaxFile = 2047; - ofn.lpstrFilter = Filter; - ofn.nFilterIndex = 1; - ofn.lpstrInitialDir = Dir; - ofn.lpstrTitle = Titre; - ofn.lpstrDefExt = Ext; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; - - if (GetSaveFileName(&ofn)) return 1; - - return 0; -} - - -bool Save_Watches() -{ - Rom_Name = GetRomName(); - strncpy(Str_Tmp,Rom_Name.c_str(),512); - strcat(Str_Tmp,".wch"); - if(Change_File_S(Str_Tmp, Gens_Path, "Save Watches", "GENs Watchlist\0*.wch\0All Files\0*.*\0\0", "wch", RamWatchHWnd)) - { - FILE *WatchFile = fopen(Str_Tmp,"r+b"); - if (!WatchFile) WatchFile = fopen(Str_Tmp,"w+b"); - fputc('\n',WatchFile); - strcpy(currentWatch,Str_Tmp); - RWAddRecentFile(currentWatch); - sprintf(Str_Tmp,"%d\n",WatchCount); - fputs(Str_Tmp,WatchFile); - const char DELIM = '\t'; - for (int i = 0; i < WatchCount; i++) - { - sprintf(Str_Tmp,"%05X%c%08X%c%c%c%c%c%d%c%s\n",i,DELIM,rswatches[i].Address,DELIM,rswatches[i].Size,DELIM,rswatches[i].Type,DELIM,rswatches[i].WrongEndian,DELIM,rswatches[i].comment); - fputs(Str_Tmp,WatchFile); - } - - fclose(WatchFile); - RWfileChanged=false; - return true; - } - return false; -} - -bool QuickSaveWatches() -{ -if (RWfileChanged==false) return true; //If file has not changed, no need to save changes -if (currentWatch[0] == NULL) //If there is no currently loaded file, run to Save as and then return - { - return Save_Watches(); - } - - strcpy(Str_Tmp,currentWatch); - FILE *WatchFile = fopen(Str_Tmp,"r+b"); - if (!WatchFile) WatchFile = fopen(Str_Tmp,"w+b"); - fputc('\n',WatchFile); - sprintf(Str_Tmp,"%d\n",WatchCount); - fputs(Str_Tmp,WatchFile); - const char DELIM = '\t'; - for (int i = 0; i < WatchCount; i++) - { - sprintf(Str_Tmp,"%05X%c%08X%c%c%c%c%c%d%c%s\n",i,DELIM,rswatches[i].Address,DELIM,rswatches[i].Size,DELIM,rswatches[i].Type,DELIM,rswatches[i].WrongEndian,DELIM,rswatches[i].comment); - fputs(Str_Tmp,WatchFile); - } - fclose(WatchFile); - RWfileChanged=false; - return true; -} - -bool Load_Watches(bool clear, const char* filename) -{ - const char DELIM = '\t'; - FILE* WatchFile = fopen(filename,"rb"); - if (!WatchFile) - { - MessageBox(MESSAGEBOXPARENT,"Error opening file.","ERROR",MB_OK); - return false; - } - if(clear) - { - if(!ResetWatches()) - { - fclose(WatchFile); - return false; - } - } - strcpy(currentWatch,filename); - RWAddRecentFile(currentWatch); - AddressWatcher Temp; - char mode; - fgets(Str_Tmp,1024,WatchFile); - sscanf(Str_Tmp,"%c%*s",&mode); - int WatchAdd; - fgets(Str_Tmp,1024,WatchFile); - sscanf(Str_Tmp,"%d%*s",&WatchAdd); - WatchAdd+=WatchCount; - for (int i = WatchCount; i < WatchAdd; i++) - { - while (i < 0) - i++; - do { - fgets(Str_Tmp,1024,WatchFile); - } while (Str_Tmp[0] == '\n'); - sscanf(Str_Tmp,"%*05X%*c%08X%*c%c%*c%c%*c%d",&(Temp.Address),&(Temp.Size),&(Temp.Type),&(Temp.WrongEndian)); - Temp.WrongEndian = 0; - char *Comment = strrchr(Str_Tmp,DELIM) + 1; - *strrchr(Comment,'\n') = '\0'; - InsertWatch(Temp,Comment); - } - - fclose(WatchFile); - if (RamWatchHWnd) - ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); - RWfileChanged=false; - return true; -} - - - -int Change_File_L(char *Dest, char *Dir, char *Titre, char *Filter, char *Ext, HWND hwnd) -{ - OPENFILENAME ofn; - - SetCurrentDirectory(Gens_Path); - - if (!strcmp(Dest, "")) - { - strcpy(Dest, "default."); - strcat(Dest, Ext); - } - - memset(&ofn, 0, sizeof(OPENFILENAME)); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hwnd; - ofn.hInstance = hAppInst; - ofn.lpstrFile = Dest; - ofn.nMaxFile = 2047; - ofn.lpstrFilter = Filter; - ofn.nFilterIndex = 1; - ofn.lpstrInitialDir = Dir; - ofn.lpstrTitle = Titre; - ofn.lpstrDefExt = Ext; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - if (GetOpenFileName(&ofn)) return 1; - - return 0; -} - -bool Load_Watches(bool clear) -{ - Rom_Name = GetRomName(); - strncpy(Str_Tmp,Rom_Name.c_str(),512); - strcat(Str_Tmp,".wch"); - if(Change_File_L(Str_Tmp, Watch_Dir, "Load Watches", "GENs Watchlist\0*.wch\0All Files\0*.*\0\0", "wch", RamWatchHWnd)) - { - return Load_Watches(clear, Str_Tmp); - } - return false; -} - -bool ResetWatches() -{ - if(!AskSave()) - return false; - for (;WatchCount>=0;WatchCount--) - { - free(rswatches[WatchCount].comment); - rswatches[WatchCount].comment = NULL; - } - WatchCount++; - if (RamWatchHWnd) - ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); - RWfileChanged = false; - currentWatch[0] = NULL; - return true; -} - -void RemoveWatch(int watchIndex) -{ - free(rswatches[watchIndex].comment); - rswatches[watchIndex].comment = NULL; - for (int i = watchIndex; i <= WatchCount; i++) - rswatches[i] = rswatches[i+1]; - WatchCount--; -} - -LRESULT CALLBACK EditWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //Gets info for a RAM Watch, and then inserts it into the Watch List -{ - RECT r; - RECT r2; - int dx1, dy1, dx2, dy2; - static int index; - static char s,t = s = 0; - - switch(uMsg) - { - case WM_INITDIALOG: - GetWindowRect(MainWindow->getHWnd(), &r); - dx1 = (r.right - r.left) / 2; - dy1 = (r.bottom - r.top) / 2; - - GetWindowRect(hDlg, &r2); - dx2 = (r2.right - r2.left) / 2; - dy2 = (r2.bottom - r2.top) / 2; - - SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); - index = (int)lParam; - sprintf(Str_Tmp,"%08X",rswatches[index].Address); - SetDlgItemText(hDlg,IDC_EDIT_COMPAREADDRESS,Str_Tmp); - if (rswatches[index].comment != NULL) - SetDlgItemText(hDlg,IDC_PROMPT_EDIT,rswatches[index].comment); - s = rswatches[index].Size; - t = rswatches[index].Type; - switch (s) - { - case 'b': - SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'w': - SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'd': - SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0); - break; - default: - s = 0; - break; - } - switch (t) - { - case 's': - SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'u': - SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0); - break; - case 'h': - SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0); - break; - default: - t = 0; - break; - } - - return true; - break; - - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDC_SIGNED: - t='s'; - return true; - case IDC_UNSIGNED: - t='u'; - return true; - case IDC_HEX: - t='h'; - return true; - case IDC_1_BYTE: - s = 'b'; - return true; - case IDC_2_BYTES: - s = 'w'; - return true; - case IDC_4_BYTES: - s = 'd'; - return true; - case IDOK: - { - if (s && t) - { - AddressWatcher Temp; - Temp.Size = s; - Temp.Type = t; - Temp.WrongEndian = false; //replace this when I get little endian working properly - GetDlgItemText(hDlg,IDC_EDIT_COMPAREADDRESS,Str_Tmp,1024); - char *addrstr = Str_Tmp; - if (strlen(Str_Tmp) > 8) addrstr = &(Str_Tmp[strlen(Str_Tmp) - 9]); - for(int i = 0; addrstr[i]; i++) {if(toupper(addrstr[i]) == 'O') addrstr[i] = '0';} - sscanf(addrstr,"%08X",&(Temp.Address)); - - if((Temp.Address & ~0xFFFFFF) == ~0xFFFFFF) - Temp.Address &= 0xFFFFFF; - - if(IsHardwareRAMAddressValid(Temp.Address)) - { - GetDlgItemText(hDlg,IDC_PROMPT_EDIT,Str_Tmp,80); - if (index < WatchCount) RemoveWatch(index); - InsertWatch(Temp,Str_Tmp); - if(RamWatchHWnd) - { - ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); - } - EndDialog(hDlg, true); - } - else - { - MessageBox(hDlg,"Invalid Address","ERROR",MB_OK); - } - } - else - { - strcpy(Str_Tmp,"Error:"); - if (!s) - strcat(Str_Tmp," Size must be specified."); - if (!t) - strcat(Str_Tmp," Type must be specified."); - MessageBox(hDlg,Str_Tmp,"ERROR",MB_OK); - } - RWfileChanged=true; - return true; - break; - } - case IDCANCEL: - EndDialog(hDlg, false); - return false; - break; - } - break; - - case WM_CLOSE: - EndDialog(hDlg, false); - return false; - break; - } - - return false; -} - -void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths) //initializes the ram search and/or ram watch listbox -{ - LVCOLUMN Col; - Col.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; - Col.fmt = LVCFMT_CENTER; - for (int i = 0; i < numColumns; i++) - { - Col.iOrder = i; - Col.iSubItem = i; - Col.pszText = (LPSTR)(Strs[i]); - Col.cx = columnWidths[i]; - ListView_InsertColumn(Box,i,&Col); - } - - ListView_SetExtendedListViewStyle(Box, LVS_EX_FULLROWSELECT); -} - -LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - RECT r; - RECT r2; - int dx1, dy1, dx2, dy2; - static int watchIndex=0; - - Update_RAM_Watch(); - - switch(uMsg) - { - case WM_MOVE: { - RECT wrect; - GetWindowRect(hDlg,&wrect); - ramw_x = wrect.left; - ramw_y = wrect.top; - break; - }; - - case WM_INITDIALOG: { - GetWindowRect(MainWindow->getHWnd(), &r); //Ramwatch window - dx1 = (r.right - r.left) / 2; - dy1 = (r.bottom - r.top) / 2; - - GetWindowRect(hDlg, &r2); // Gens window - dx2 = (r2.right - r2.left) / 2; - dy2 = (r2.bottom - r2.top) / 2; - - - // push it away from the main window if we can - const int width = (r.right-r.left); - const int height = (r.bottom - r.top); - const int width2 = (r2.right-r2.left); - if(r.left+width2 + width < GetSystemMetrics(SM_CXSCREEN)) - { - r.right += width; - r.left += width; - } - else if((int)r.left - (int)width2 > 0) - { - r.right -= width2; - r.left -= width2; - } - - //----------------------------------------------------------------------------------- - //If user has Save Window Pos selected, override default positioning - if (RWSaveWindowPos) - { - //If ramwindow is for some reason completely off screen, use default instead - if (ramw_x > (-width*2) || ramw_x < (width*2 + GetSystemMetrics(SM_CYSCREEN)) ) - r.left = ramw_x; //This also ignores cases of windows -32000 error codes - //If ramwindow is for some reason completely off screen, use default instead - if (ramw_y > (0-height*2) ||ramw_y < (height*2 + GetSystemMetrics(SM_CYSCREEN)) ) - r.top = ramw_y; //This also ignores cases of windows -32000 error codes - } - //------------------------------------------------------------------------------------- - SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); - - ramwatchmenu=GetMenu(hDlg); - rwrecentmenu=CreateMenu(); - UpdateRW_RMenu(rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE); - - const char* names[3] = {"Address","Value","Notes"}; - int widths[3] = {62,64,64+51+53}; - init_list_box(GetDlgItem(hDlg,IDC_WATCHLIST),names,3,widths); -/* if (!ResultCount) //TODO what do these do - reset_address_info(); - else - signal_new_frame();*/ - ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); -// if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0); -// if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0); - - RamWatchAccels = LoadAccelerators(hAppInst, MAKEINTRESOURCE(IDR_ACCELERATOR1)); - - // due to some bug in windows, the arrow button width from the resource gets ignored, so we have to set it here - SetWindowPos(GetDlgItem(hDlg,ID_WATCHES_UPDOWN), 0,0,0, 30,60, SWP_NOMOVE); - Update_RAM_Watch(); - DragAcceptFiles(hDlg, TRUE); - - return true; - break; - } - - case WM_INITMENU: - CheckMenuItem(ramwatchmenu, RAMMENU_FILE_AUTOLOAD, AutoRWLoad ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(ramwatchmenu, RAMMENU_FILE_SAVEWINDOW, RWSaveWindowPos ? MF_CHECKED : MF_UNCHECKED); - break; - - case WM_MENUSELECT: - case WM_ENTERSIZEMOVE: - break; - - case WM_NOTIFY: - { - LPNMHDR lP = (LPNMHDR) lParam; - switch (lP->code) - { - case LVN_GETDISPINFO: - { - LV_DISPINFO *Item = (LV_DISPINFO *)lParam; - Item->item.mask = LVIF_TEXT; - Item->item.state = 0; - Item->item.iImage = 0; - const unsigned int iNum = Item->item.iItem; - static char num[11]; - switch (Item->item.iSubItem) - { - case 0: - sprintf(num,"%08X",rswatches[iNum].Address); - Item->item.pszText = num; - return true; - case 1: { - int i = rswatches[iNum].CurValue; - int t = rswatches[iNum].Type; - int size = rswatches[iNum].Size; - const char* formatString = ((t=='s') ? "%d" : (t=='u') ? "%u" : (size=='d' ? "%08X" : size=='w' ? "%04X" : "%02X")); - switch (size) - { - case 'b': - default: sprintf(num, formatString, t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; - case 'w': sprintf(num, formatString, t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; - case 'd': sprintf(num, formatString, t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; - } - - Item->item.pszText = num; - } return true; - case 2: - Item->item.pszText = rswatches[iNum].comment ? rswatches[iNum].comment : ""; - return true; - - default: - return false; - } - } - case LVN_ODFINDITEM: - { - // disable search by keyboard typing, - // because it interferes with some of the accelerators - // and it isn't very useful here anyway - SetWindowLong(hDlg, DWL_MSGRESULT, ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST))); - return 1; - } - } - break; - } - - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case RAMMENU_FILE_SAVE: - QuickSaveWatches(); - break; - - case RAMMENU_FILE_SAVEAS: - return Save_Watches(); - case RAMMENU_FILE_OPEN: - return Load_Watches(true); - case RAMMENU_FILE_APPEND: - return Load_Watches(false); - case RAMMENU_FILE_NEW: - ResetWatches(); - return true; - case IDC_C_WATCH_REMOVE: - watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); - RemoveWatch(watchIndex); - ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); - RWfileChanged=true; - SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); - return true; - case IDC_C_WATCH_EDIT: - watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); - DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) watchIndex); - SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); - return true; - case IDC_C_WATCH: - rswatches[WatchCount].Address = rswatches[WatchCount].WrongEndian = 0; - rswatches[WatchCount].Size = 'b'; - rswatches[WatchCount].Type = 's'; - DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) WatchCount); - SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); - return true; - case IDC_C_WATCH_DUPLICATE: - watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); - rswatches[WatchCount].Address = rswatches[watchIndex].Address; - rswatches[WatchCount].WrongEndian = rswatches[watchIndex].WrongEndian; - rswatches[WatchCount].Size = rswatches[watchIndex].Size; - rswatches[WatchCount].Type = rswatches[watchIndex].Type; - DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) WatchCount); - SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); - return true; - case IDC_C_WATCH_UP: - { - watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); - if (watchIndex == 0 || watchIndex == -1) - return true; - void *tmp = malloc(sizeof(AddressWatcher)); - memcpy(tmp,&(rswatches[watchIndex]),sizeof(AddressWatcher)); - memcpy(&(rswatches[watchIndex]),&(rswatches[watchIndex - 1]),sizeof(AddressWatcher)); - memcpy(&(rswatches[watchIndex - 1]),tmp,sizeof(AddressWatcher)); - free(tmp); - ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex-1); - ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex-1,LVIS_FOCUSED|LVIS_SELECTED,LVIS_FOCUSED|LVIS_SELECTED); - ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); - RWfileChanged=true; - return true; - } - case IDC_C_WATCH_DOWN: - { - watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); - if (watchIndex >= WatchCount - 1 || watchIndex == -1) - return true; - void *tmp = malloc(sizeof(AddressWatcher)); - memcpy(tmp,&(rswatches[watchIndex]),sizeof(AddressWatcher)); - memcpy(&(rswatches[watchIndex]),&(rswatches[watchIndex + 1]),sizeof(AddressWatcher)); - memcpy(&(rswatches[watchIndex + 1]),tmp,sizeof(AddressWatcher)); - free(tmp); - ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex+1); - ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex+1,LVIS_FOCUSED|LVIS_SELECTED,LVIS_FOCUSED|LVIS_SELECTED); - ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); - RWfileChanged=true; - return true; - } - case ID_WATCHES_UPDOWN: - { - int delta = ((LPNMUPDOWN)lParam)->iDelta; - SendMessage(hDlg, WM_COMMAND, delta<0 ? IDC_C_WATCH_UP : IDC_C_WATCH_DOWN,0); - break; - } - case RAMMENU_FILE_AUTOLOAD: - { - AutoRWLoad ^= 1; - CheckMenuItem(ramwatchmenu, RAMMENU_FILE_AUTOLOAD, AutoRWLoad ? MF_CHECKED : MF_UNCHECKED); - break; - } - case RAMMENU_FILE_SAVEWINDOW: - { - RWSaveWindowPos ^=1; - CheckMenuItem(ramwatchmenu, RAMMENU_FILE_SAVEWINDOW, RWSaveWindowPos ? MF_CHECKED : MF_UNCHECKED); - break; - } - case IDC_C_ADDCHEAT: - { - watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)) | (1 << 24); -// DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITCHEAT), hDlg, (DLGPROC) EditCheatProc,(LPARAM) searchIndex); //TODO: made a IDD_EDITCHEAT dialog, and EditCheatProc (are they in GENS?) and integrate into cheats system - break; - } - case IDCANCEL: - RamWatchHWnd = NULL; - DragAcceptFiles(hDlg, FALSE); - EndDialog(hDlg, true); - return true; - default: - if (LOWORD(wParam) >= RW_MENU_FIRST_RECENT_FILE && LOWORD(wParam) < RW_MENU_FIRST_RECENT_FILE+MAX_RECENT_WATCHES) - OpenRWRecentFile(LOWORD(wParam) - RW_MENU_FIRST_RECENT_FILE); - } - break; - - case WM_KEYDOWN: // handle accelerator keys - { - SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); - MSG msg; - msg.hwnd = hDlg; - msg.message = uMsg; - msg.wParam = wParam; - msg.lParam = lParam; - if(RamWatchAccels && TranslateAccelerator(hDlg, RamWatchAccels, &msg)) - return true; - } break; - - case WM_CLOSE: - RamWatchHWnd = NULL; - DragAcceptFiles(hDlg, FALSE); - EndDialog(hDlg, true); - return true; - - case WM_DROPFILES: - { - HDROP hDrop = (HDROP)wParam; - DragQueryFile(hDrop, 0, Str_Tmp, 1024); - DragFinish(hDrop); - return Load_Watches(true, Str_Tmp); - } break; - } - - return false; -} - +//RamWatch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ +//Authors: Upthorn, Nitsuja, adelikat + +//#include "main.h" +#include "resource.h" +#include "common.h" +#include "NDSSystem.h" +#include "ramwatch.h" +#include "ram_search.h" +#include +#include +#include +#include + +HWND RamWatchHWnd = NULL; + +#define MESSAGEBOXPARENT (RamWatchHWnd ? RamWatchHWnd : MainWindow->getHWnd()) + +char Str_Tmp[1024]; +std::string Rom_Name; + +static HMENU ramwatchmenu; +static HMENU rwrecentmenu; +static HACCEL RamWatchAccels = NULL; +char rw_recent_files[MAX_RECENT_WATCHES][1024]; +char Watch_Dir[1024]=""; +const unsigned int RW_MENU_FIRST_RECENT_FILE = 600; +bool RWfileChanged = false; //Keeps track of whether the current watch file has been changed, if so, ramwatch will prompt to save changes +bool AutoRWLoad = false; //Keeps track of whether Auto-load is checked +bool RWSaveWindowPos = false; //Keeps track of whether Save Window position is checked +char currentWatch[1024]; +int ramw_x, ramw_y; //Used to store ramwatch dialog window positions +AddressWatcher rswatches[MAX_WATCH_COUNT]; +int WatchCount=0; + +bool QuickSaveWatches(); +bool ResetWatches(); + +unsigned int GetCurrentValue(AddressWatcher& watch) +{ + char buf[4]; + MMU_DumpMemBlock(0, watch.Address, 4, (u8*)buf); + + u32 val_u32 = *(u32*)buf; + u16 val_u16 = *(u16*)buf; + u8 val_u8 = *(u8*)buf; + + switch (watch.Size) + { + case 0x62: return val_u8; + case 0x77: return val_u16; + case 0x64: return val_u32; + default: return 0; + } +// return ReadValueAtHardwareAddress(watch.Address, watch.Size == 'd' ? 4 : watch.Size == 'w' ? 2 : 1); +} + +bool IsSameWatch(const AddressWatcher& l, const AddressWatcher& r) +{ + return ((l.Address == r.Address) && (l.Size == r.Size) && (l.Type == r.Type)/* && (l.WrongEndian == r.WrongEndian)*/); +} + +bool VerifyWatchNotAlreadyAdded(const AddressWatcher& watch) +{ + for (int j = 0; j < WatchCount; j++) + { + if (IsSameWatch(rswatches[j], watch)) + { + if(RamWatchHWnd) + SetForegroundWindow(RamWatchHWnd); + return false; + } + } + return true; +} + + +bool InsertWatch(const AddressWatcher& Watch, char *Comment) +{ + if(!VerifyWatchNotAlreadyAdded(Watch)) + return false; + + if(WatchCount >= MAX_WATCH_COUNT) + return false; + + int i = WatchCount++; + AddressWatcher& NewWatch = rswatches[i]; + NewWatch = Watch; + //if (NewWatch.comment) free(NewWatch.comment); + NewWatch.comment = (char *) malloc(strlen(Comment)+2); + NewWatch.CurValue = GetCurrentValue(NewWatch); + strcpy(NewWatch.comment, Comment); + ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); + RWfileChanged=true; + + return true; +} + +LRESULT CALLBACK PromptWatchNameProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //Gets the description of a watched address +{ + RECT r; + RECT r2; + int dx1, dy1, dx2, dy2; + + switch(uMsg) + { + case WM_INITDIALOG: + GetWindowRect(MainWindow->getHWnd(), &r); + dx1 = (r.right - r.left) / 2; + dy1 = (r.bottom - r.top) / 2; + + GetWindowRect(hDlg, &r2); + dx2 = (r2.right - r2.left) / 2; + dy2 = (r2.bottom - r2.top) / 2; + + SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + strcpy(Str_Tmp,"Enter a name for this RAM address."); + //SendDlgItemMessage(hDlg,IDC_PROMPT_TEXT,WM_SETTEXT,0,(LPARAM)Str_Tmp); + strcpy(Str_Tmp,""); + //SendDlgItemMessage(hDlg,IDC_PROMPT_TEXT2,WM_SETTEXT,0,(LPARAM)Str_Tmp); + return true; + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + { + GetDlgItemText(hDlg,IDC_PROMPT_EDIT,Str_Tmp,80); + InsertWatch(rswatches[WatchCount],Str_Tmp); + EndDialog(hDlg, true); + return true; + break; + } + case IDCANCEL: + + EndDialog(hDlg, false); + return false; + break; + } + break; + + case WM_CLOSE: + EndDialog(hDlg, false); + return false; + break; + } + + return false; +} + +bool InsertWatch(const AddressWatcher& Watch, HWND parent) +{ + if(!VerifyWatchNotAlreadyAdded(Watch)) + return false; + + if(!parent) + parent = RamWatchHWnd; + if(!parent) + parent = MainWindow->getHWnd(); + + int prevWatchCount = WatchCount; + + rswatches[WatchCount] = Watch; + rswatches[WatchCount].CurValue = GetCurrentValue(rswatches[WatchCount]); + DialogBox(hAppInst, MAKEINTRESOURCE(IDD_PROMPT), parent, (DLGPROC) PromptWatchNameProc); + + return WatchCount > prevWatchCount; +} + +void Update_RAM_Watch() +{ + if (!RamWatchHWnd) return; + + // update cached values and detect changes to displayed listview items + BOOL watchChanged[MAX_WATCH_COUNT] = {0}; + for(int i = 0; i < WatchCount; i++) + { + unsigned int prevCurValue = rswatches[i].CurValue; + unsigned int newCurValue = GetCurrentValue(rswatches[i]); + if(prevCurValue != newCurValue) + { + rswatches[i].CurValue = newCurValue; + watchChanged[i] = TRUE; + } + } + + // refresh any visible parts of the listview box that changed + HWND lv = GetDlgItem(RamWatchHWnd,IDC_WATCHLIST); + int top = ListView_GetTopIndex(lv); + int bottom = top + ListView_GetCountPerPage(lv) + 1; // +1 is so we will update a partially-displayed last item + if(top < 0) top = 0; + if(bottom > WatchCount) bottom = WatchCount; + int start = -1; + for(int i = top; i <= bottom; i++) + { + if(start == -1) + { + if(i != bottom && watchChanged[i]) + { + start = i; + //somethingChanged = true; + } + } + else + { + if(i == bottom || !watchChanged[i]) + { + ListView_RedrawItems(lv, start, i-1); + start = -1; + } + } + } +} + +bool AskSave() +{ + //This function asks to save changes if the watch file contents have changed + //returns false only if a save was attempted but failed or was cancelled + if (RWfileChanged) + { + HWND Hwnd = MainWindow->getHWnd(); + int answer = MessageBox(Hwnd, "Save Changes?", "Ram Watch", MB_YESNOCANCEL); + if(answer == IDYES) + if(!QuickSaveWatches()) + return false; + return (answer != IDCANCEL); + } + return true; +} + + +void UpdateRW_RMenu(HMENU menu, unsigned int mitem, unsigned int baseid) +{ + MENUITEMINFO moo; + int x; + + moo.cbSize = sizeof(moo); + moo.fMask = MIIM_SUBMENU | MIIM_STATE; + + GetMenuItemInfo(GetSubMenu(ramwatchmenu, 0), mitem, FALSE, &moo); + moo.hSubMenu = menu; + moo.fState = strlen(rw_recent_files[0]) ? MFS_ENABLED : MFS_GRAYED; + + SetMenuItemInfo(GetSubMenu(ramwatchmenu, 0), mitem, FALSE, &moo); + + // Remove all recent files submenus + for(x = 0; x < MAX_RECENT_WATCHES; x++) + { + RemoveMenu(menu, baseid + x, MF_BYCOMMAND); + } + + // Recreate the menus + for(x = MAX_RECENT_WATCHES - 1; x >= 0; x--) + { + char tmp[128 + 5]; + + // Skip empty strings + if(!strlen(rw_recent_files[x])) + { + continue; + } + + moo.cbSize = sizeof(moo); + moo.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE; + + // Fill in the menu text. + if(strlen(rw_recent_files[x]) < 128) + { + sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, rw_recent_files[x]); + } + else + { + sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, rw_recent_files[x] + strlen( rw_recent_files[x] ) - 127); + } + + // Insert the menu item + moo.cch = strlen(tmp); + moo.fType = 0; + moo.wID = baseid + x; + moo.dwTypeData = tmp; + InsertMenuItem(menu, 0, 1, &moo); + } +} + +void UpdateRWRecentArray(const char* addString, unsigned int arrayLen, HMENU menu, unsigned int menuItem, unsigned int baseId) +{ + // Try to find out if the filename is already in the recent files list. + for(unsigned int x = 0; x < arrayLen; x++) + { + if(strlen(rw_recent_files[x])) + { + if(!strcmp(rw_recent_files[x], addString)) // Item is already in list. + { + // If the filename is in the file list don't add it again. + // Move it up in the list instead. + + int y; + char tmp[1024]; + + // Save pointer. + strcpy(tmp,rw_recent_files[x]); + + for(y = x; y; y--) + { + // Move items down. + strcpy(rw_recent_files[y],rw_recent_files[y - 1]); + } + + // Put item on top. + strcpy(rw_recent_files[0],tmp); + + // Update the recent files menu + UpdateRW_RMenu(menu, menuItem, baseId); + + return; + } + } + } + + // The filename wasn't found in the list. That means we need to add it. + + // Move the other items down. + for(unsigned int x = arrayLen - 1; x; x--) + { + strcpy(rw_recent_files[x],rw_recent_files[x - 1]); + } + + // Add the new item. + strcpy(rw_recent_files[0], addString); + + // Update the recent files menu + UpdateRW_RMenu(menu, menuItem, baseId); +} + + +void RWAddRecentFile(const char *filename) +{ + UpdateRWRecentArray(filename, MAX_RECENT_WATCHES, rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE); +} + +void OpenRWRecentFile(int memwRFileNumber) +{ + if(!ResetWatches()) + return; + + int rnum = memwRFileNumber; + if ((unsigned int)rnum >= MAX_RECENT_WATCHES) + return; //just in case + + char* x; + + while(true) + { + x = rw_recent_files[rnum]; + if (!*x) + return; //If no recent files exist just return. Useful for Load last file on startup (or if something goes screwy) + + if (rnum) //Change order of recent files if not most recent + { + RWAddRecentFile(x); + rnum = 0; + } + else + { + break; + } + } + + strcpy(currentWatch,x); + strcpy(Str_Tmp,currentWatch); + + //loadwatches here + FILE *WatchFile = fopen(Str_Tmp,"rb"); + if (!WatchFile) + { + int answer = MessageBox(MESSAGEBOXPARENT,"Error opening file.","ERROR",MB_OKCANCEL); + if (answer == IDOK) + { + rw_recent_files[rnum][0] = '\0'; //Clear file from list + if (rnum) //Update the ramwatch list + RWAddRecentFile(rw_recent_files[0]); + else + RWAddRecentFile(rw_recent_files[1]); + } + return; + } + const char DELIM = '\t'; + AddressWatcher Temp; + char mode; + fgets(Str_Tmp,1024,WatchFile); + sscanf(Str_Tmp,"%c%*s",&mode); + int WatchAdd; + fgets(Str_Tmp,1024,WatchFile); + sscanf(Str_Tmp,"%d%*s",&WatchAdd); + WatchAdd+=WatchCount; + for (int i = WatchCount; i < WatchAdd; i++) + { + while (i < 0) + i++; + do { + fgets(Str_Tmp,1024,WatchFile); + } while (Str_Tmp[0] == '\n'); + sscanf(Str_Tmp,"%*05X%*c%08X%*c%c%*c%c%*c%d",&(Temp.Address),&(Temp.Size),&(Temp.Type),&(Temp.WrongEndian)); + Temp.WrongEndian = 0; + char *Comment = strrchr(Str_Tmp,DELIM) + 1; + *strrchr(Comment,'\n') = '\0'; + InsertWatch(Temp,Comment); + } + + fclose(WatchFile); + if (RamWatchHWnd) + ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); + RWfileChanged=false; + return; +} + +char Gens_Path[64]= "M:\\"; //TODO + +int Change_File_S(char *Dest, char *Dir, char *Titre, char *Filter, char *Ext, HWND hwnd) +{ + OPENFILENAME ofn; + + SetCurrentDirectory(Gens_Path); + + if (!strcmp(Dest, "")) + { + strcpy(Dest, "default."); + strcat(Dest, Ext); + } + + memset(&ofn, 0, sizeof(OPENFILENAME)); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwnd; + ofn.hInstance = hAppInst; + ofn.lpstrFile = Dest; + ofn.nMaxFile = 2047; + ofn.lpstrFilter = Filter; + ofn.nFilterIndex = 1; + ofn.lpstrInitialDir = Dir; + ofn.lpstrTitle = Titre; + ofn.lpstrDefExt = Ext; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + + if (GetSaveFileName(&ofn)) return 1; + + return 0; +} + + +bool Save_Watches() +{ + Rom_Name = GetRomName(); + strncpy(Str_Tmp,Rom_Name.c_str(),512); + strcat(Str_Tmp,".wch"); + if(Change_File_S(Str_Tmp, Gens_Path, "Save Watches", "GENs Watchlist\0*.wch\0All Files\0*.*\0\0", "wch", RamWatchHWnd)) + { + FILE *WatchFile = fopen(Str_Tmp,"r+b"); + if (!WatchFile) WatchFile = fopen(Str_Tmp,"w+b"); + fputc('\n',WatchFile); + strcpy(currentWatch,Str_Tmp); + RWAddRecentFile(currentWatch); + sprintf(Str_Tmp,"%d\n",WatchCount); + fputs(Str_Tmp,WatchFile); + const char DELIM = '\t'; + for (int i = 0; i < WatchCount; i++) + { + sprintf(Str_Tmp,"%05X%c%08X%c%c%c%c%c%d%c%s\n",i,DELIM,rswatches[i].Address,DELIM,rswatches[i].Size,DELIM,rswatches[i].Type,DELIM,rswatches[i].WrongEndian,DELIM,rswatches[i].comment); + fputs(Str_Tmp,WatchFile); + } + + fclose(WatchFile); + RWfileChanged=false; + return true; + } + return false; +} + +bool QuickSaveWatches() +{ +if (RWfileChanged==false) return true; //If file has not changed, no need to save changes +if (currentWatch[0] == NULL) //If there is no currently loaded file, run to Save as and then return + { + return Save_Watches(); + } + + strcpy(Str_Tmp,currentWatch); + FILE *WatchFile = fopen(Str_Tmp,"r+b"); + if (!WatchFile) WatchFile = fopen(Str_Tmp,"w+b"); + fputc('\n',WatchFile); + sprintf(Str_Tmp,"%d\n",WatchCount); + fputs(Str_Tmp,WatchFile); + const char DELIM = '\t'; + for (int i = 0; i < WatchCount; i++) + { + sprintf(Str_Tmp,"%05X%c%08X%c%c%c%c%c%d%c%s\n",i,DELIM,rswatches[i].Address,DELIM,rswatches[i].Size,DELIM,rswatches[i].Type,DELIM,rswatches[i].WrongEndian,DELIM,rswatches[i].comment); + fputs(Str_Tmp,WatchFile); + } + fclose(WatchFile); + RWfileChanged=false; + return true; +} + +bool Load_Watches(bool clear, const char* filename) +{ + const char DELIM = '\t'; + FILE* WatchFile = fopen(filename,"rb"); + if (!WatchFile) + { + MessageBox(MESSAGEBOXPARENT,"Error opening file.","ERROR",MB_OK); + return false; + } + if(clear) + { + if(!ResetWatches()) + { + fclose(WatchFile); + return false; + } + } + strcpy(currentWatch,filename); + RWAddRecentFile(currentWatch); + AddressWatcher Temp; + char mode; + fgets(Str_Tmp,1024,WatchFile); + sscanf(Str_Tmp,"%c%*s",&mode); + int WatchAdd; + fgets(Str_Tmp,1024,WatchFile); + sscanf(Str_Tmp,"%d%*s",&WatchAdd); + WatchAdd+=WatchCount; + for (int i = WatchCount; i < WatchAdd; i++) + { + while (i < 0) + i++; + do { + fgets(Str_Tmp,1024,WatchFile); + } while (Str_Tmp[0] == '\n'); + sscanf(Str_Tmp,"%*05X%*c%08X%*c%c%*c%c%*c%d",&(Temp.Address),&(Temp.Size),&(Temp.Type),&(Temp.WrongEndian)); + Temp.WrongEndian = 0; + char *Comment = strrchr(Str_Tmp,DELIM) + 1; + *strrchr(Comment,'\n') = '\0'; + InsertWatch(Temp,Comment); + } + + fclose(WatchFile); + if (RamWatchHWnd) + ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); + RWfileChanged=false; + return true; +} + + + +int Change_File_L(char *Dest, char *Dir, char *Titre, char *Filter, char *Ext, HWND hwnd) +{ + OPENFILENAME ofn; + + SetCurrentDirectory(Gens_Path); + + if (!strcmp(Dest, "")) + { + strcpy(Dest, "default."); + strcat(Dest, Ext); + } + + memset(&ofn, 0, sizeof(OPENFILENAME)); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwnd; + ofn.hInstance = hAppInst; + ofn.lpstrFile = Dest; + ofn.nMaxFile = 2047; + ofn.lpstrFilter = Filter; + ofn.nFilterIndex = 1; + ofn.lpstrInitialDir = Dir; + ofn.lpstrTitle = Titre; + ofn.lpstrDefExt = Ext; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + if (GetOpenFileName(&ofn)) return 1; + + return 0; +} + +bool Load_Watches(bool clear) +{ + Rom_Name = GetRomName(); + strncpy(Str_Tmp,Rom_Name.c_str(),512); + strcat(Str_Tmp,".wch"); + if(Change_File_L(Str_Tmp, Watch_Dir, "Load Watches", "GENs Watchlist\0*.wch\0All Files\0*.*\0\0", "wch", RamWatchHWnd)) + { + return Load_Watches(clear, Str_Tmp); + } + return false; +} + +bool ResetWatches() +{ + if(!AskSave()) + return false; + for (;WatchCount>=0;WatchCount--) + { + free(rswatches[WatchCount].comment); + rswatches[WatchCount].comment = NULL; + } + WatchCount++; + if (RamWatchHWnd) + ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); + RWfileChanged = false; + currentWatch[0] = NULL; + return true; +} + +void RemoveWatch(int watchIndex) +{ + free(rswatches[watchIndex].comment); + rswatches[watchIndex].comment = NULL; + for (int i = watchIndex; i <= WatchCount; i++) + rswatches[i] = rswatches[i+1]; + WatchCount--; +} + +LRESULT CALLBACK EditWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //Gets info for a RAM Watch, and then inserts it into the Watch List +{ + RECT r; + RECT r2; + int dx1, dy1, dx2, dy2; + static int index; + static char s,t = s = 0; + + switch(uMsg) + { + case WM_INITDIALOG: + GetWindowRect(MainWindow->getHWnd(), &r); + dx1 = (r.right - r.left) / 2; + dy1 = (r.bottom - r.top) / 2; + + GetWindowRect(hDlg, &r2); + dx2 = (r2.right - r2.left) / 2; + dy2 = (r2.bottom - r2.top) / 2; + + SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + index = (int)lParam; + sprintf(Str_Tmp,"%08X",rswatches[index].Address); + SetDlgItemText(hDlg,IDC_EDIT_COMPAREADDRESS,Str_Tmp); + if (rswatches[index].comment != NULL) + SetDlgItemText(hDlg,IDC_PROMPT_EDIT,rswatches[index].comment); + s = rswatches[index].Size; + t = rswatches[index].Type; + switch (s) + { + case 'b': + SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'w': + SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'd': + SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0); + break; + default: + s = 0; + break; + } + switch (t) + { + case 's': + SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'u': + SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0); + break; + case 'h': + SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0); + break; + default: + t = 0; + break; + } + + return true; + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_SIGNED: + t='s'; + return true; + case IDC_UNSIGNED: + t='u'; + return true; + case IDC_HEX: + t='h'; + return true; + case IDC_1_BYTE: + s = 'b'; + return true; + case IDC_2_BYTES: + s = 'w'; + return true; + case IDC_4_BYTES: + s = 'd'; + return true; + case IDOK: + { + if (s && t) + { + AddressWatcher Temp; + Temp.Size = s; + Temp.Type = t; + Temp.WrongEndian = false; //replace this when I get little endian working properly + GetDlgItemText(hDlg,IDC_EDIT_COMPAREADDRESS,Str_Tmp,1024); + char *addrstr = Str_Tmp; + if (strlen(Str_Tmp) > 8) addrstr = &(Str_Tmp[strlen(Str_Tmp) - 9]); + for(int i = 0; addrstr[i]; i++) {if(toupper(addrstr[i]) == 'O') addrstr[i] = '0';} + sscanf(addrstr,"%08X",&(Temp.Address)); + + if((Temp.Address & ~0xFFFFFF) == ~0xFFFFFF) + Temp.Address &= 0xFFFFFF; + + if(IsHardwareRAMAddressValid(Temp.Address)) + { + GetDlgItemText(hDlg,IDC_PROMPT_EDIT,Str_Tmp,80); + if (index < WatchCount) RemoveWatch(index); + InsertWatch(Temp,Str_Tmp); + if(RamWatchHWnd) + { + ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount); + } + EndDialog(hDlg, true); + } + else + { + MessageBox(hDlg,"Invalid Address","ERROR",MB_OK); + } + } + else + { + strcpy(Str_Tmp,"Error:"); + if (!s) + strcat(Str_Tmp," Size must be specified."); + if (!t) + strcat(Str_Tmp," Type must be specified."); + MessageBox(hDlg,Str_Tmp,"ERROR",MB_OK); + } + RWfileChanged=true; + return true; + break; + } + case IDCANCEL: + EndDialog(hDlg, false); + return false; + break; + } + break; + + case WM_CLOSE: + EndDialog(hDlg, false); + return false; + break; + } + + return false; +} + +void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths) //initializes the ram search and/or ram watch listbox +{ + LVCOLUMN Col; + Col.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; + Col.fmt = LVCFMT_CENTER; + for (int i = 0; i < numColumns; i++) + { + Col.iOrder = i; + Col.iSubItem = i; + Col.pszText = (LPSTR)(Strs[i]); + Col.cx = columnWidths[i]; + ListView_InsertColumn(Box,i,&Col); + } + + ListView_SetExtendedListViewStyle(Box, LVS_EX_FULLROWSELECT); +} + +LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RECT r; + RECT r2; + int dx1, dy1, dx2, dy2; + static int watchIndex=0; + + Update_RAM_Watch(); + + switch(uMsg) + { + case WM_MOVE: { + RECT wrect; + GetWindowRect(hDlg,&wrect); + ramw_x = wrect.left; + ramw_y = wrect.top; + break; + }; + + case WM_INITDIALOG: { + GetWindowRect(MainWindow->getHWnd(), &r); //Ramwatch window + dx1 = (r.right - r.left) / 2; + dy1 = (r.bottom - r.top) / 2; + + GetWindowRect(hDlg, &r2); // Gens window + dx2 = (r2.right - r2.left) / 2; + dy2 = (r2.bottom - r2.top) / 2; + + + // push it away from the main window if we can + const int width = (r.right-r.left); + const int height = (r.bottom - r.top); + const int width2 = (r2.right-r2.left); + if(r.left+width2 + width < GetSystemMetrics(SM_CXSCREEN)) + { + r.right += width; + r.left += width; + } + else if((int)r.left - (int)width2 > 0) + { + r.right -= width2; + r.left -= width2; + } + + //----------------------------------------------------------------------------------- + //If user has Save Window Pos selected, override default positioning + if (RWSaveWindowPos) + { + //If ramwindow is for some reason completely off screen, use default instead + if (ramw_x > (-width*2) || ramw_x < (width*2 + GetSystemMetrics(SM_CYSCREEN)) ) + r.left = ramw_x; //This also ignores cases of windows -32000 error codes + //If ramwindow is for some reason completely off screen, use default instead + if (ramw_y > (0-height*2) ||ramw_y < (height*2 + GetSystemMetrics(SM_CYSCREEN)) ) + r.top = ramw_y; //This also ignores cases of windows -32000 error codes + } + //------------------------------------------------------------------------------------- + SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + + ramwatchmenu=GetMenu(hDlg); + rwrecentmenu=CreateMenu(); + UpdateRW_RMenu(rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE); + + const char* names[3] = {"Address","Value","Notes"}; + int widths[3] = {62,64,64+51+53}; + init_list_box(GetDlgItem(hDlg,IDC_WATCHLIST),names,3,widths); +/* if (!ResultCount) //TODO what do these do + reset_address_info(); + else + signal_new_frame();*/ + ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); +// if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0); +// if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0); + + RamWatchAccels = LoadAccelerators(hAppInst, MAKEINTRESOURCE(IDR_ACCELERATOR1)); + + // due to some bug in windows, the arrow button width from the resource gets ignored, so we have to set it here + SetWindowPos(GetDlgItem(hDlg,ID_WATCHES_UPDOWN), 0,0,0, 30,60, SWP_NOMOVE); + Update_RAM_Watch(); + DragAcceptFiles(hDlg, TRUE); + + return true; + break; + } + + case WM_INITMENU: + CheckMenuItem(ramwatchmenu, RAMMENU_FILE_AUTOLOAD, AutoRWLoad ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(ramwatchmenu, RAMMENU_FILE_SAVEWINDOW, RWSaveWindowPos ? MF_CHECKED : MF_UNCHECKED); + break; + + case WM_MENUSELECT: + case WM_ENTERSIZEMOVE: + break; + + case WM_NOTIFY: + { + LPNMHDR lP = (LPNMHDR) lParam; + switch (lP->code) + { + case LVN_GETDISPINFO: + { + LV_DISPINFO *Item = (LV_DISPINFO *)lParam; + Item->item.mask = LVIF_TEXT; + Item->item.state = 0; + Item->item.iImage = 0; + const unsigned int iNum = Item->item.iItem; + static char num[11]; + switch (Item->item.iSubItem) + { + case 0: + sprintf(num,"%08X",rswatches[iNum].Address); + Item->item.pszText = num; + return true; + case 1: { + int i = rswatches[iNum].CurValue; + int t = rswatches[iNum].Type; + int size = rswatches[iNum].Size; + const char* formatString = ((t=='s') ? "%d" : (t=='u') ? "%u" : (size=='d' ? "%08X" : size=='w' ? "%04X" : "%02X")); + switch (size) + { + case 'b': + default: sprintf(num, formatString, t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; + case 'w': sprintf(num, formatString, t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; + case 'd': sprintf(num, formatString, t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; + } + + Item->item.pszText = num; + } return true; + case 2: + Item->item.pszText = rswatches[iNum].comment ? rswatches[iNum].comment : ""; + return true; + + default: + return false; + } + } + case LVN_ODFINDITEM: + { + // disable search by keyboard typing, + // because it interferes with some of the accelerators + // and it isn't very useful here anyway + SetWindowLong(hDlg, DWL_MSGRESULT, ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST))); + return 1; + } + } + break; + } + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case RAMMENU_FILE_SAVE: + QuickSaveWatches(); + break; + + case RAMMENU_FILE_SAVEAS: + return Save_Watches(); + case RAMMENU_FILE_OPEN: + return Load_Watches(true); + case RAMMENU_FILE_APPEND: + return Load_Watches(false); + case RAMMENU_FILE_NEW: + ResetWatches(); + return true; + case IDC_C_WATCH_REMOVE: + watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); + RemoveWatch(watchIndex); + ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); + RWfileChanged=true; + SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); + return true; + case IDC_C_WATCH_EDIT: + watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); + DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) watchIndex); + SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); + return true; + case IDC_C_WATCH: + rswatches[WatchCount].Address = rswatches[WatchCount].WrongEndian = 0; + rswatches[WatchCount].Size = 'b'; + rswatches[WatchCount].Type = 's'; + DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) WatchCount); + SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); + return true; + case IDC_C_WATCH_DUPLICATE: + watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); + rswatches[WatchCount].Address = rswatches[watchIndex].Address; + rswatches[WatchCount].WrongEndian = rswatches[watchIndex].WrongEndian; + rswatches[WatchCount].Size = rswatches[watchIndex].Size; + rswatches[WatchCount].Type = rswatches[watchIndex].Type; + DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) WatchCount); + SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); + return true; + case IDC_C_WATCH_UP: + { + watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); + if (watchIndex == 0 || watchIndex == -1) + return true; + void *tmp = malloc(sizeof(AddressWatcher)); + memcpy(tmp,&(rswatches[watchIndex]),sizeof(AddressWatcher)); + memcpy(&(rswatches[watchIndex]),&(rswatches[watchIndex - 1]),sizeof(AddressWatcher)); + memcpy(&(rswatches[watchIndex - 1]),tmp,sizeof(AddressWatcher)); + free(tmp); + ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex-1); + ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex-1,LVIS_FOCUSED|LVIS_SELECTED,LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); + RWfileChanged=true; + return true; + } + case IDC_C_WATCH_DOWN: + { + watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)); + if (watchIndex >= WatchCount - 1 || watchIndex == -1) + return true; + void *tmp = malloc(sizeof(AddressWatcher)); + memcpy(tmp,&(rswatches[watchIndex]),sizeof(AddressWatcher)); + memcpy(&(rswatches[watchIndex]),&(rswatches[watchIndex + 1]),sizeof(AddressWatcher)); + memcpy(&(rswatches[watchIndex + 1]),tmp,sizeof(AddressWatcher)); + free(tmp); + ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex+1); + ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex+1,LVIS_FOCUSED|LVIS_SELECTED,LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount); + RWfileChanged=true; + return true; + } + case ID_WATCHES_UPDOWN: + { + int delta = ((LPNMUPDOWN)lParam)->iDelta; + SendMessage(hDlg, WM_COMMAND, delta<0 ? IDC_C_WATCH_UP : IDC_C_WATCH_DOWN,0); + break; + } + case RAMMENU_FILE_AUTOLOAD: + { + AutoRWLoad ^= 1; + CheckMenuItem(ramwatchmenu, RAMMENU_FILE_AUTOLOAD, AutoRWLoad ? MF_CHECKED : MF_UNCHECKED); + break; + } + case RAMMENU_FILE_SAVEWINDOW: + { + RWSaveWindowPos ^=1; + CheckMenuItem(ramwatchmenu, RAMMENU_FILE_SAVEWINDOW, RWSaveWindowPos ? MF_CHECKED : MF_UNCHECKED); + break; + } + case IDC_C_ADDCHEAT: + { + watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)) | (1 << 24); +// DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_EDITCHEAT), hDlg, (DLGPROC) EditCheatProc,(LPARAM) searchIndex); //TODO: made a IDD_EDITCHEAT dialog, and EditCheatProc (are they in GENS?) and integrate into cheats system + break; + } + case IDCANCEL: + RamWatchHWnd = NULL; + DragAcceptFiles(hDlg, FALSE); + EndDialog(hDlg, true); + return true; + default: + if (LOWORD(wParam) >= RW_MENU_FIRST_RECENT_FILE && LOWORD(wParam) < RW_MENU_FIRST_RECENT_FILE+MAX_RECENT_WATCHES) + OpenRWRecentFile(LOWORD(wParam) - RW_MENU_FIRST_RECENT_FILE); + } + break; + + case WM_KEYDOWN: // handle accelerator keys + { + SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST)); + MSG msg; + msg.hwnd = hDlg; + msg.message = uMsg; + msg.wParam = wParam; + msg.lParam = lParam; + if(RamWatchAccels && TranslateAccelerator(hDlg, RamWatchAccels, &msg)) + return true; + } break; + + case WM_CLOSE: + RamWatchHWnd = NULL; + DragAcceptFiles(hDlg, FALSE); + EndDialog(hDlg, true); + return true; + + case WM_DROPFILES: + { + HDROP hDrop = (HDROP)wParam; + DragQueryFile(hDrop, 0, Str_Tmp, 1024); + DragFinish(hDrop); + return Load_Watches(true, Str_Tmp); + } break; + } + + return false; +} + diff --git a/desmume/src/windows/ramwatch.h b/desmume/src/windows/ramwatch.h index 0272b8ebb..385223b6b 100644 --- a/desmume/src/windows/ramwatch.h +++ b/desmume/src/windows/ramwatch.h @@ -1,42 +1,42 @@ -//RamWatch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ -//Authors: Upthorn, Nitsuja, adelikat - -#ifndef RAMWATCH_H -#define RAMWATCH_H -#include "windows.h" -bool ResetWatches(); -void OpenRWRecentFile(int memwRFileNumber); -extern bool AutoRWLoad; -extern bool RWSaveWindowPos; -#define MAX_RECENT_WATCHES 5 -extern char rw_recent_files[MAX_RECENT_WATCHES][1024]; -extern bool AskSave(); -extern int ramw_x; -extern int ramw_y; -extern bool RWfileChanged; - -// AddressWatcher is self-contained now -struct AddressWatcher -{ - unsigned int Address; // hardware address - char Size; - char Type; - char* comment; // NULL means no comment, non-NULL means allocated comment - bool WrongEndian; - unsigned int CurValue; -}; -#define MAX_WATCH_COUNT 256 -extern AddressWatcher rswatches[MAX_WATCH_COUNT]; -extern int WatchCount; // number of valid items in rswatches - -extern char Watch_Dir[1024]; - -bool InsertWatch(const AddressWatcher& Watch, char *Comment); -bool InsertWatch(const AddressWatcher& Watch, HWND parent=NULL); // asks user for comment -void Update_RAM_Watch(); -bool Load_Watches(bool clear, const char* filename); - -LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -extern HWND RamWatchHWnd; - -#endif +//RamWatch dialog was copied and adapted from GENS11: http://code.google.com/p/gens-rerecording/ +//Authors: Upthorn, Nitsuja, adelikat + +#ifndef RAMWATCH_H +#define RAMWATCH_H +#include "windows.h" +bool ResetWatches(); +void OpenRWRecentFile(int memwRFileNumber); +extern bool AutoRWLoad; +extern bool RWSaveWindowPos; +#define MAX_RECENT_WATCHES 5 +extern char rw_recent_files[MAX_RECENT_WATCHES][1024]; +extern bool AskSave(); +extern int ramw_x; +extern int ramw_y; +extern bool RWfileChanged; + +// AddressWatcher is self-contained now +struct AddressWatcher +{ + unsigned int Address; // hardware address + char Size; + char Type; + char* comment; // NULL means no comment, non-NULL means allocated comment + bool WrongEndian; + unsigned int CurValue; +}; +#define MAX_WATCH_COUNT 256 +extern AddressWatcher rswatches[MAX_WATCH_COUNT]; +extern int WatchCount; // number of valid items in rswatches + +extern char Watch_Dir[1024]; + +bool InsertWatch(const AddressWatcher& Watch, char *Comment); +bool InsertWatch(const AddressWatcher& Watch, HWND parent=NULL); // asks user for comment +void Update_RAM_Watch(); +bool Load_Watches(bool clear, const char* filename); + +LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +extern HWND RamWatchHWnd; + +#endif diff --git a/desmume/src/windows/replay.cpp b/desmume/src/windows/replay.cpp index 1b0008e95..e39bbb23e 100644 --- a/desmume/src/windows/replay.cpp +++ b/desmume/src/windows/replay.cpp @@ -1,157 +1,157 @@ -#include -#include "resource.h" -#include "replay.h" -#include "common.h" -#include "main.h" -#include "movie.h" -#include "utils/xstring.h" - -bool replayreadonly=1; - -//adelikat: TODO: put this in one of the header files -template -inline std::wstring GetDlgItemTextW(HWND hDlg, int nIDDlgItem) { - wchar_t buf[BUFSIZE]; - GetDlgItemTextW(hDlg, nIDDlgItem, buf, BUFSIZE); - return buf; -} - -template -inline std::string GetDlgItemText(HWND hDlg, int nIDDlgItem) { - char buf[BUFSIZE]; - GetDlgItemText(hDlg, nIDDlgItem, buf, BUFSIZE); - return buf; -} - - -char playfilename[MAX_PATH] = ""; - -//Replay movie dialog -BOOL CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - OPENFILENAME ofn; - char szChoice[MAX_PATH]={0}; - char filename[MAX_PATH] = ""; - - switch(uMsg) - { - case WM_INITDIALOG: - SendDlgItemMessage(hwndDlg, IDC_CHECK_READONLY, BM_SETCHECK, replayreadonly?BST_CHECKED:BST_UNCHECKED, 0); - return FALSE; - - case WM_COMMAND: - int wID = LOWORD(wParam); - switch(wID) - { - case ID_BROWSE: - - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = MainWindow->getHWnd(); - ofn.lpstrFilter = "Desmume Movie File (*.dsm)\0*.dsm\0All files(*.*)\0*.*\0\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = filename; - ofn.lpstrTitle = "Replay Movie from File"; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrDefExt = "dsm"; - GetOpenFileName(&ofn); - strcpy(playfilename, filename); - SetDlgItemText(hwndDlg, PM_FILENAME, playfilename); - return true; - - case IDC_CHECK_READONLY: - replayreadonly ^= 1; - return true; - - case IDOK: - FCEUI_LoadMovie(playfilename, replayreadonly, false, 80000); - ZeroMemory(&playfilename, sizeof(playfilename)); - EndDialog(hwndDlg, 0); - return true; - - case IDCANCEL: - ZeroMemory(&playfilename, sizeof(playfilename)); - EndDialog(hwndDlg, 0); - return true; - } - } - - return false; -} - -//Record movie dialog -static BOOL CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - static struct CreateMovieParameters* p = NULL; - std::wstring author = L""; - switch(uMsg) - { - case WM_INITDIALOG: - - return false; - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDOK: { - author = GetDlgItemTextW<500>(hwndDlg,IDC_EDIT_AUTHOR); - std::string fname = GetDlgItemText(hwndDlg,IDC_EDIT_FILENAME); - FCEUI_SaveMovie(fname.c_str(), author); - EndDialog(hwndDlg, 0); - return true; - } - - case IDCANCEL: - EndDialog(hwndDlg, 0); - return true; - - case IDC_BUTTON_BROWSEFILE: - { - OPENFILENAME ofn; - char szChoice[MAX_PATH]={0}; - char recordfilename[MAX_PATH]; - - // browse button - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = MainWindow->getHWnd(); - ofn.lpstrFilter = "Desmume Movie File (*.dsm)\0*.dsm\0All files(*.*)\0*.*\0\0"; - ofn.lpstrFile = szChoice; - ofn.lpstrTitle = "Record a new movie"; - ofn.lpstrDefExt = "dsm"; - ofn.nMaxFile = MAX_PATH; - ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; - GetSaveFileName(&ofn); - strcpy(recordfilename, szChoice); - SetDlgItemText(hwndDlg, IDC_EDIT_FILENAME, recordfilename); - //if(GetSaveFileName(&ofn)) - // UpdateRecordDialogPath(hwndDlg,szChoice); - - return true; - } - - } - - } - - return false; -} - - -//Show the play movie dialog and play a movie -void Replay_LoadMovie() -{ - char* fn = (char*)DialogBoxParam(hAppInst, "IDD_REPLAYINP", MainWindow->getHWnd(), ReplayDialogProc, false); - - if(fn) - { - FCEUI_LoadMovie(fn, movie_readonly, false, 100000); - - free(fn); - } -} - -//Show the record movie dialog and record a movie. -void MovieRecordTo() -{ - DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_RECORDMOVIE), MainWindow->getHWnd(), RecordDialogProc, (LPARAM)0); -} +#include +#include "resource.h" +#include "replay.h" +#include "common.h" +#include "main.h" +#include "movie.h" +#include "utils/xstring.h" + +bool replayreadonly=1; + +//adelikat: TODO: put this in one of the header files +template +inline std::wstring GetDlgItemTextW(HWND hDlg, int nIDDlgItem) { + wchar_t buf[BUFSIZE]; + GetDlgItemTextW(hDlg, nIDDlgItem, buf, BUFSIZE); + return buf; +} + +template +inline std::string GetDlgItemText(HWND hDlg, int nIDDlgItem) { + char buf[BUFSIZE]; + GetDlgItemText(hDlg, nIDDlgItem, buf, BUFSIZE); + return buf; +} + + +char playfilename[MAX_PATH] = ""; + +//Replay movie dialog +BOOL CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + OPENFILENAME ofn; + char szChoice[MAX_PATH]={0}; + char filename[MAX_PATH] = ""; + + switch(uMsg) + { + case WM_INITDIALOG: + SendDlgItemMessage(hwndDlg, IDC_CHECK_READONLY, BM_SETCHECK, replayreadonly?BST_CHECKED:BST_UNCHECKED, 0); + return FALSE; + + case WM_COMMAND: + int wID = LOWORD(wParam); + switch(wID) + { + case ID_BROWSE: + + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = MainWindow->getHWnd(); + ofn.lpstrFilter = "Desmume Movie File (*.dsm)\0*.dsm\0All files(*.*)\0*.*\0\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = filename; + ofn.lpstrTitle = "Replay Movie from File"; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrDefExt = "dsm"; + GetOpenFileName(&ofn); + strcpy(playfilename, filename); + SetDlgItemText(hwndDlg, PM_FILENAME, playfilename); + return true; + + case IDC_CHECK_READONLY: + replayreadonly ^= 1; + return true; + + case IDOK: + FCEUI_LoadMovie(playfilename, replayreadonly, false, 80000); + ZeroMemory(&playfilename, sizeof(playfilename)); + EndDialog(hwndDlg, 0); + return true; + + case IDCANCEL: + ZeroMemory(&playfilename, sizeof(playfilename)); + EndDialog(hwndDlg, 0); + return true; + } + } + + return false; +} + +//Record movie dialog +static BOOL CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static struct CreateMovieParameters* p = NULL; + std::wstring author = L""; + switch(uMsg) + { + case WM_INITDIALOG: + + return false; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: { + author = GetDlgItemTextW<500>(hwndDlg,IDC_EDIT_AUTHOR); + std::string fname = GetDlgItemText(hwndDlg,IDC_EDIT_FILENAME); + FCEUI_SaveMovie(fname.c_str(), author); + EndDialog(hwndDlg, 0); + return true; + } + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return true; + + case IDC_BUTTON_BROWSEFILE: + { + OPENFILENAME ofn; + char szChoice[MAX_PATH]={0}; + char recordfilename[MAX_PATH]; + + // browse button + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = MainWindow->getHWnd(); + ofn.lpstrFilter = "Desmume Movie File (*.dsm)\0*.dsm\0All files(*.*)\0*.*\0\0"; + ofn.lpstrFile = szChoice; + ofn.lpstrTitle = "Record a new movie"; + ofn.lpstrDefExt = "dsm"; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + GetSaveFileName(&ofn); + strcpy(recordfilename, szChoice); + SetDlgItemText(hwndDlg, IDC_EDIT_FILENAME, recordfilename); + //if(GetSaveFileName(&ofn)) + // UpdateRecordDialogPath(hwndDlg,szChoice); + + return true; + } + + } + + } + + return false; +} + + +//Show the play movie dialog and play a movie +void Replay_LoadMovie() +{ + char* fn = (char*)DialogBoxParam(hAppInst, "IDD_REPLAYINP", MainWindow->getHWnd(), ReplayDialogProc, false); + + if(fn) + { + FCEUI_LoadMovie(fn, movie_readonly, false, 100000); + + free(fn); + } +} + +//Show the record movie dialog and record a movie. +void MovieRecordTo() +{ + DialogBoxParam(hAppInst, MAKEINTRESOURCE(IDD_RECORDMOVIE), MainWindow->getHWnd(), RecordDialogProc, (LPARAM)0); +} diff --git a/desmume/src/windows/replay.h b/desmume/src/windows/replay.h index 6a0880b94..d721b31b5 100644 --- a/desmume/src/windows/replay.h +++ b/desmume/src/windows/replay.h @@ -1,2 +1,2 @@ -void Replay_LoadMovie(); -void MovieRecordTo(); +void Replay_LoadMovie(); +void MovieRecordTo();