From 41a4ee009f764a5cf31b513413005d7e34d6f8b3 Mon Sep 17 00:00:00 2001 From: rogerman Date: Thu, 4 Apr 2013 01:21:21 +0000 Subject: [PATCH] Cocoa Port: - New feature: Users can now save and restore their favorite input settings as an "Input Profile". This feature may be accessed in the Input section in DeSmuME > Preferences. --- .../project.pbxproj | 12 + .../project.pbxproj | 10 + desmume/src/cocoa/DefaultKeyMappings.plist | 673 ++--- desmume/src/cocoa/DefaultUserPrefs.plist | Bin 4943 -> 4974 bytes desmume/src/cocoa/cocoa_globals.h | 2 + .../English.lproj/MainMenu.strings | Bin 260224 -> 267714 bytes .../translations/English.lproj/MainMenu.xib | 2154 +++++++++++++++-- .../src/cocoa/userinterface/InputManager.h | 9 +- .../src/cocoa/userinterface/InputManager.mm | 106 +- .../userinterface/InputProfileController.h | 39 + .../userinterface/InputProfileController.mm | 238 ++ .../src/cocoa/userinterface/appDelegate.mm | 2 + .../src/cocoa/userinterface/inputPrefsView.h | 53 +- .../src/cocoa/userinterface/inputPrefsView.mm | 398 ++- 14 files changed, 3065 insertions(+), 631 deletions(-) create mode 100644 desmume/src/cocoa/userinterface/InputProfileController.h create mode 100644 desmume/src/cocoa/userinterface/InputProfileController.mm diff --git a/desmume/src/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj b/desmume/src/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj index cddce86fc..c3ac93eee 100644 --- a/desmume/src/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj +++ b/desmume/src/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj @@ -52,6 +52,10 @@ AB0F29C714BE7213009ABC6F /* Icon_RotateCW_420x420.png in Resources */ = {isa = PBXBuildFile; fileRef = AB0F29A314BE7213009ABC6F /* Icon_RotateCW_420x420.png */; }; AB0F29C814BE7213009ABC6F /* Icon_ShowHUD_420x420.png in Resources */ = {isa = PBXBuildFile; fileRef = AB0F29A414BE7213009ABC6F /* Icon_ShowHUD_420x420.png */; }; AB0F29C914BE7213009ABC6F /* Icon_Speaker_420x420.png in Resources */ = {isa = PBXBuildFile; fileRef = AB0F29A514BE7213009ABC6F /* Icon_Speaker_420x420.png */; }; + AB213D45170CB141006DDB0F /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB213D44170CB141006DDB0F /* InputProfileController.mm */; }; + AB213D46170CB141006DDB0F /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB213D44170CB141006DDB0F /* InputProfileController.mm */; }; + AB213D47170CB141006DDB0F /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB213D44170CB141006DDB0F /* InputProfileController.mm */; }; + AB213D48170CB141006DDB0F /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB213D44170CB141006DDB0F /* InputProfileController.mm */; }; AB2F3B7D15CF9C6000858373 /* KeyNames.plist in Resources */ = {isa = PBXBuildFile; fileRef = AB02475B13886BF300E9F9AB /* KeyNames.plist */; }; AB2F3B7E15CF9C6000858373 /* DefaultKeyMappings.plist in Resources */ = {isa = PBXBuildFile; fileRef = ABC719E1138CB25E002827A9 /* DefaultKeyMappings.plist */; }; AB2F3B7F15CF9C6000858373 /* DefaultUserPrefs.plist in Resources */ = {isa = PBXBuildFile; fileRef = ABBC0F8C1394B1AA0028B6BD /* DefaultUserPrefs.plist */; }; @@ -925,6 +929,8 @@ AB0F29A314BE7213009ABC6F /* Icon_RotateCW_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_RotateCW_420x420.png; path = images/Icon_RotateCW_420x420.png; sourceTree = ""; }; AB0F29A414BE7213009ABC6F /* Icon_ShowHUD_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_ShowHUD_420x420.png; path = images/Icon_ShowHUD_420x420.png; sourceTree = ""; }; AB0F29A514BE7213009ABC6F /* Icon_Speaker_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_Speaker_420x420.png; path = images/Icon_Speaker_420x420.png; sourceTree = ""; }; + AB213D43170CB141006DDB0F /* InputProfileController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputProfileController.h; sourceTree = ""; }; + AB213D44170CB141006DDB0F /* InputProfileController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputProfileController.mm; sourceTree = ""; }; AB2F3C4515CF9C6000858373 /* DeSmuME (PPC).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DeSmuME (PPC).app"; sourceTree = BUILT_PRODUCTS_DIR; }; AB2F56EE1704C86900E28885 /* utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utilities.h; sourceTree = ""; }; AB2F56EF1704C86900E28885 /* utilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utilities.c; sourceTree = ""; }; @@ -1494,6 +1500,7 @@ AB6A187A16C9951C00384EED /* EmuControllerDelegate.h */, AB5A795616D5A56000ED84B7 /* InputManager.h */, AB3ACB6E14C2361100D7D192 /* inputPrefsView.h */, + AB213D43170CB141006DDB0F /* InputProfileController.h */, AB3ACB7014C2361100D7D192 /* preferencesWindowDelegate.h */, ABA0356E169127BB00817C69 /* troubleshootingWindowDelegate.h */, AB3ACB6714C2361100D7D192 /* appDelegate.mm */, @@ -1502,6 +1509,7 @@ AB6A187B16C9951C00384EED /* EmuControllerDelegate.mm */, AB5A795716D5A56000ED84B7 /* InputManager.mm */, AB3ACB6F14C2361100D7D192 /* inputPrefsView.mm */, + AB213D44170CB141006DDB0F /* InputProfileController.mm */, AB3ACB7114C2361100D7D192 /* preferencesWindowDelegate.mm */, ABA0356F169127C000817C69 /* troubleshootingWindowDelegate.mm */, ); @@ -2650,6 +2658,7 @@ AB4C4C5116F55C64002E07CD /* TDStretch.cpp in Sources */, AB4C4C5216F55C64002E07CD /* WavFile.cpp in Sources */, AB2F56F11704C86900E28885 /* utilities.c in Sources */, + AB213D46170CB141006DDB0F /* InputProfileController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2807,6 +2816,7 @@ AB4C4C4716F55C64002E07CD /* TDStretch.cpp in Sources */, AB4C4C4816F55C64002E07CD /* WavFile.cpp in Sources */, AB2F56F01704C86900E28885 /* utilities.c in Sources */, + AB213D48170CB141006DDB0F /* InputProfileController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2964,6 +2974,7 @@ AB4C4C6516F55C64002E07CD /* TDStretch.cpp in Sources */, AB4C4C6616F55C64002E07CD /* WavFile.cpp in Sources */, AB2F56F31704C86900E28885 /* utilities.c in Sources */, + AB213D45170CB141006DDB0F /* InputProfileController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3091,6 +3102,7 @@ AB4C4C5B16F55C64002E07CD /* TDStretch.cpp in Sources */, AB4C4C5C16F55C64002E07CD /* WavFile.cpp in Sources */, AB2F56F21704C86900E28885 /* utilities.c in Sources */, + AB213D47170CB141006DDB0F /* InputProfileController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/desmume/src/cocoa/DeSmuME (XCode 4).xcodeproj/project.pbxproj b/desmume/src/cocoa/DeSmuME (XCode 4).xcodeproj/project.pbxproj index fd6db9ab6..5e5f6e865 100644 --- a/desmume/src/cocoa/DeSmuME (XCode 4).xcodeproj/project.pbxproj +++ b/desmume/src/cocoa/DeSmuME (XCode 4).xcodeproj/project.pbxproj @@ -10,6 +10,9 @@ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; AB00E87B14205EAE00DE561F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AB00E87914205EAE00DE561F /* InfoPlist.strings */; }; AB00E87E14205EBC00DE561F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB00E87C14205EBC00DE561F /* MainMenu.xib */; }; + AB01005E170D07B000D70FBE /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB01005D170D07B000D70FBE /* InputProfileController.mm */; }; + AB01005F170D07B000D70FBE /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB01005D170D07B000D70FBE /* InputProfileController.mm */; }; + AB010060170D07B000D70FBE /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB01005D170D07B000D70FBE /* InputProfileController.mm */; }; AB02475C13886BF300E9F9AB /* KeyNames.plist in Resources */ = {isa = PBXBuildFile; fileRef = AB02475B13886BF300E9F9AB /* KeyNames.plist */; }; AB0F290214BE6E68009ABC6F /* Icon_Execute_420x420.png in Resources */ = {isa = PBXBuildFile; fileRef = AB0F28FE14BE6E68009ABC6F /* Icon_Execute_420x420.png */; }; AB0F290314BE6E68009ABC6F /* Icon_Pause_420x420.png in Resources */ = {isa = PBXBuildFile; fileRef = AB0F28FF14BE6E68009ABC6F /* Icon_Pause_420x420.png */; }; @@ -630,6 +633,8 @@ AB00E87A14205EAE00DE561F /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = translations/English.lproj/InfoPlist.strings; sourceTree = ""; }; AB00E87D14205EBC00DE561F /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = translations/English.lproj/MainMenu.xib; sourceTree = ""; }; AB00E89114205ECC00DE561F /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; lineEnding = 0; name = English; path = translations/English.lproj/Localizable.strings; sourceTree = ""; }; + AB01005C170D07AF00D70FBE /* InputProfileController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputProfileController.h; sourceTree = ""; }; + AB01005D170D07B000D70FBE /* InputProfileController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputProfileController.mm; sourceTree = ""; }; AB02475B13886BF300E9F9AB /* KeyNames.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = KeyNames.plist; sourceTree = ""; }; AB02791814415E4C0075E58C /* Info (Debug).plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info (Debug).plist"; sourceTree = ""; }; AB0A0D1914AACA9600E83E91 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; @@ -1243,6 +1248,7 @@ AB3A655C16CC5416001F5D4A /* EmuControllerDelegate.h */, AB29B32F16D4BEBF000EF671 /* InputManager.h */, AB3ACB6E14C2361100D7D192 /* inputPrefsView.h */, + AB01005C170D07AF00D70FBE /* InputProfileController.h */, AB3ACB7014C2361100D7D192 /* preferencesWindowDelegate.h */, ABF2B9F81690412A000FF7C0 /* troubleshootingWindowDelegate.h */, AB3ACB6714C2361100D7D192 /* appDelegate.mm */, @@ -1251,6 +1257,7 @@ AB3A655D16CC5421001F5D4A /* EmuControllerDelegate.mm */, AB29B33016D4BEBF000EF671 /* InputManager.mm */, AB3ACB6F14C2361100D7D192 /* inputPrefsView.mm */, + AB01005D170D07B000D70FBE /* InputProfileController.mm */, AB3ACB7114C2361100D7D192 /* preferencesWindowDelegate.mm */, ABF2B9FA16904133000FF7C0 /* troubleshootingWindowDelegate.mm */, ); @@ -2247,6 +2254,7 @@ AB8967DA16D2ED0700F826F1 /* DisplayWindowController.mm in Sources */, AB29B33216D4BEBF000EF671 /* InputManager.mm in Sources */, AB82445C1704AE9A00B8EE20 /* utilities.c in Sources */, + AB01005F170D07B000D70FBE /* InputProfileController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2405,6 +2413,7 @@ AB8967D916D2ED0700F826F1 /* DisplayWindowController.mm in Sources */, AB29B33116D4BEBF000EF671 /* InputManager.mm in Sources */, AB82445B1704AE9A00B8EE20 /* utilities.c in Sources */, + AB01005E170D07B000D70FBE /* InputProfileController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2551,6 +2560,7 @@ AB68A0DD16B139BC00DE0546 /* OGLRender_3_2.cpp in Sources */, AB3A656316CC5438001F5D4A /* cocoa_GPU.mm in Sources */, AB82445D1704AE9A00B8EE20 /* utilities.c in Sources */, + AB010060170D07B000D70FBE /* InputProfileController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/desmume/src/cocoa/DefaultKeyMappings.plist b/desmume/src/cocoa/DefaultKeyMappings.plist index 725c32d73..587512753 100644 --- a/desmume/src/cocoa/DefaultKeyMappings.plist +++ b/desmume/src/cocoa/DefaultKeyMappings.plist @@ -32,313 +32,374 @@ Enable/Disable Cheats Enable/Disable GPU State - DefaultInputMappings - - Up - + DefaultInputProfiles + + + Name + Default + IsDefaultType + + Mappings - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 126 - elementName - Up Arrow + Up + + + deviceInfoSummary + Keyboard: Up Arrow + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 126 + elementName + Up Arrow + + + Down + + + deviceInfoSummary + Keyboard: Down Arrow + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 125 + elementName + Down Arrow + + + Left + + + deviceInfoSummary + Keyboard: Left Arrow + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 123 + elementName + Left Arrow + + + Right + + + deviceInfoSummary + Keyboard: Right Arrow + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 124 + elementName + Right Arrow + + + A + + + deviceInfoSummary + Keyboard: X + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 7 + elementName + X + + + B + + + deviceInfoSummary + Keyboard: Z + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 6 + elementName + Z + + + X + + + deviceInfoSummary + Keyboard: S + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 1 + elementName + S + + + Y + + + deviceInfoSummary + Keyboard: A + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 0 + elementName + A + + + L + + + deviceInfoSummary + Keyboard: Q + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 12 + elementName + Q + + + R + + + deviceInfoSummary + Keyboard: W + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 13 + elementName + W + + + Start + + + deviceInfoSummary + Keyboard: Return + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 36 + elementName + Return + + + Select + + + deviceInfoSummary + Keyboard: Tab + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 48 + elementName + Tab + + + Touch + + + deviceInfoSummary + Keyboard: Primary Button + deviceCode + NSEventMouse + deviceName + Mouse + elementCode + 0 + elementName + Primary Button + inputSettingsSummary + Use Device Coordinates + useInputForIntCoord + + + + Microphone + + + deviceInfoSummary + Keyboard: ` (Accent) + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 50 + elementName + ` (Accent) + inputSettingsSummary + Internal Noise Samples + intValue1 + 1 + + + Lid + + + deviceInfoSummary + Keyboard: Delete (Backspace) + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 51 + elementName + Delete (Backspace) + + + Debug + + + deviceInfoSummary + Keyboard: \ + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 42 + elementName + \ + + + HUD + + + deviceInfoSummary + Keyboard: H + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 4 + elementName + H + + + Execute/Pause + + + deviceInfoSummary + Keyboard: Forward Delete + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 117 + elementName + Forward Delete + + + Reset + + + deviceInfoSummary + Keyboard: Page Down + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 121 + elementName + Page Down + + + Mute/Unmute + + + deviceInfoSummary + Keyboard: Numpad Clear + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 71 + elementName + Numpad Clear + + + Load State Slot + + Save State Slot + + Copy Screen + + Set Speed + + + deviceInfoSummary + Keyboard: - + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 27 + elementName + - + inputSettingsSummary + 0.50x Speed + floatValue0 + 0.5 + + + deviceInfoSummary + Keyboard: = + deviceCode + NSEventKeyboard + deviceName + Keyboard + elementCode + 24 + elementName + = + inputSettingsSummary + 2.00x Speed + floatValue0 + 2 + + + Enable/Disable Speed Limiter + + Enable/Disable Auto Frame Skip + + Enable/Disable Cheats + + Enable/Disable GPU State + - - Down - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 125 - elementName - Down Arrow - - - Left - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 123 - elementName - Left Arrow - - - Right - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 124 - elementName - Right Arrow - - - A - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 7 - elementName - X - - - B - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 6 - elementName - Z - - - X - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 1 - elementName - S - - - Y - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 0 - elementName - A - - - L - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 12 - elementName - Q - - - R - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 13 - elementName - W - - - Start - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 36 - elementName - Return - - - Select - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 48 - elementName - Tab - - - Touch - - - deviceCode - NSEventMouse - deviceName - Mouse - elementCode - 0 - elementName - Primary Button - useInputForIntCoord - - - - Microphone - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 50 - elementName - ` (Accent) - intValue1 - 1 - - - Lid - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 51 - elementName - Delete (Backspace) - - - Debug - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 42 - elementName - \ - - - HUD - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 4 - elementName - H - - - Execute/Pause - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 117 - elementName - Forward Delete - - - Reset - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 121 - elementName - Page Down - - - Mute/Unmute - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 71 - elementName - Numpad Clear - - - Load State Slot - - Save State Slot - - Copy Screen - - Set Speed - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 27 - elementName - - - floatValue0 - 0.5 - - - deviceCode - NSEventKeyboard - deviceName - Keyboard - elementCode - 24 - elementName - = - floatValue0 - 2 - - - Enable/Disable Speed Limiter - - Enable/Disable Auto Frame Skip - - Enable/Disable Cheats - - Enable/Disable GPU State - - + + diff --git a/desmume/src/cocoa/DefaultUserPrefs.plist b/desmume/src/cocoa/DefaultUserPrefs.plist index 41e50bdc3e251a998e84959beb782148607f067b..8f9d802fd2ab9f77525116e0d32faec9bab2a3e8 100644 GIT binary patch delta 1747 zcmYk53shBA8pr?Nx%ZyOKCkWdCeTCC)RGJ(wIB=g9SI5D(Nf3m;&Dit%LUQ1-A6aB8*p+WTAU`+fiKzxG~x zzc=)&p=v>SxTG>Va^z8-zEO=;jm218hYV!?wlZ<8Gczz5Q+je)JuJiJxyW;5rdyTesCv~I^s8>N!?KV;(?dLPixnxdDn?BT<;23#lFIzj7k}6<1o~!0%45+` zFn@tnlv`0&ToSe_oA-L27vdFS`ZWv6C;o;vaR49VQ=Gx~*g;;> zojt)>11W_@VMqL^I3zwy8dNp0tb9>&u&~0iA|akQIg(!xwnj{H%$=A#HFrjGFq$8= z=1yK{6~?00h}`^GrInXGGiZga!swiw?%a$>sT1;M%?eu4$E#) zzi=G?#%Jin=Qx2coRT{2*1rG6Nu0u$_zGV; z&-OIF>B*0ckJl6ZXKnls|3??T#jW@b=iIJ8>H){{2OB@)C!EL61R@e#_=rC6g8ByX z*(8!gGAYDJCC#NlBhhczWD=)7TPXk=|tdY{) zb&yS$(qI}wL+LWQoQAoy!c6jCVbgHBl2T~|jifZX%0=&({rin>r!jOjT|?=VLDwRa zu0sc1AOG2$7cb@`t4@;Oe3#KQp61XZdXTo$9y%xpLO)@QFkL7V76_Y!W}!{^!sGQM zct&|{^n^SS&ni!&r`6NpIqhZM6mO1qp10P!)w|of&)eZW=i|NszI5MoU(~nEx5d}& zJK#I$`&#si1H|#-Y;le_R}6`Fi1Wk}@y;soPhwas6(eGqIA5$3qhd_FOI#=}5*Le0 z#Jk0%VvTrC@=CH~NPVOPDM{)tjgzKH#ZpvSAT5<(K5w<#*+(Hu;!*T<(;+6hYCI zBxSIYs@$MVQl=`mDMd<|vP7v-)+-IlQ_41Fx6-1#uN+ZMC})|EDNJLRuwiU8yMaw( zIV{BTSrLn|YPOa=%o;yZ*&Z~-=sHUi?YMMGhy;+@ArCMsa zTA?miSE{w@W9l>NPIZs^wt7H4svcK6)hdE?WJzbxuPuFMbf7B!Td_AhK&^PLJ`Zm2;Z_!)z z{rX}3gnmY^I&UaOz!++z7*`mn#yDe|G1Dk8N{uq3+E`}P7@Lhoqse&1XfaxiL&g!K z!#HMqWBg>wX22X^jy9*5S>{bRGY5?7Gb4~&8Vn>2&M7SkWcMyCdMM7HTO0_4 zVwHA$V54MBnH(;m{z^>G5&l3h&R-M=j2}86@L({r=NKsl6y}VN^9OT+fjECbVKB3o ze?b2Dtn|RR(!8+xbEbv+|7&QSa&xF&xixZ1EecVDsVGJXg5d#6F%8p0?bTf0LpC19 zOgw^Fn2j>b3AY=pPNA>WC||jaM==kNVLle%aa1@IueJ3(X=5Rt!XiA4#aM!89Gb7S z@h!FSESBLpJdfpg0WUgqN{jccu<-gHL;dwA-%1;A;7z=Rx3LQE;9ZAa z)!Rf=<9!<+U^UiYEyke+A2wlf=n2CY#*b`#j8Cv0pW-uYz~@eK2aoY>vhf8rV++2- zR&2vp4i)ie-wqo)u?t^gH}+sJzHvz736WJ*)v#^U;vl}oAsogLeCKey(Ke>)6&%Cq zTGZhO9LJCN2`6w8KjT#RPMq02)L^t~egG*MzG^j2`Hzh&xQc7Ij$s6%CTyItS!CC$YVz3RB}NLVq>)bC$xgPSe5Oqn36j)| zeAJvGn&^RuYKpX}B}Gv*-9$0eiejD2Rx7GS_>FCBYD?`Xo)RdLZlPNpT_~b`x7pNz zI@0abiIOOpQXD!dT1R%Sr8}t$-9=p~mAWB~y5mFY5sH=*Lgg~4>=dq1Y&eoe!>N=O z(@I)T2k4s1=Sp$)ca3osyOy}#ckOhYaKqi)o#ak;XS*l5=eaB0TigfTzk8&ovuBW} z$TQDV>3PSq#Z%|G;PrZ2d%Ji?dh@-HdY60GdN+7$y?-+=yM^7$da~ZE4;#n^vHRIz zmRZJzFh3j0ve%OEFvV1a605XV z`YFSdsme@cj#92HRhB6)C{@ZDWuJ0DIjqzv7nRGZP-D~tHCgSU_Em?da9P2H~UQje;q)j!nhnyy7?iP~-2?b|SZXUtocn98<_u}{Q2Y7ZFAI%H-Og^7K!&mT1zM9wYkN9?O^EzJ7FBo2< zr4eJaGGdK5BgIHFGK`_d7^A?LZOk>wjRnR_#+ycsvC-IN95fCYM~!nvgUL*v+1hMx zb}{cYdznMc;pRwlk~!ThHy4@9&DYFz=6Z93xyL+Wo;1rE%qx~^L}o|SJEShK7OYpGRbt+F;*`>k5*kafoTOF$T+rHB?CL?@9Xl0|2cE(VKiktd2p zP|OzEDPB-IMVj_w$nI@VrWBjqiA^zAu6H4~On8kSReGA*r7`ilV-@Nyp z=brPN=RPNz-uBJ=`O!0QhJPZWe`4~w*oli_s6@}4u;#g0h>fyg)-SJ`tHF!*AA|#Z zXde(xbk7T0?%MJ*c{NkhVp8~6qx6~`IrPsO(Hn$1y$?gvq7vOJq8yXY!lN1-&s`K- zWkKG~oB*Tk8e7Nt?udKsqOjrA1yM=p`!O^t>cJ=D6OK$wLl7G9@~oJmq+&}v^IFC~ zcjDxSydVE=1&<(j8GOuG+as?YDnidSKA_et*gGfOgt&0Up|`O-q zaAt*@@!JT5TtPNMpCNXNx!D*o>}GB3IB`A7`dEaGVH}`ENBh)aR9@;iaF+gW6khs~ zw_)^Es26?gB!=fi1@*&+=`V#tJxEGJdJ-l$iGaM5YO_*p$7QOjVmmD}KPzV~l*j|D zfm!KU^ET?FBF*9i8^o9sx}>MfgsX?3O3{UIkQ=;xm3Cs!Q7~bs3!1QJUL2r|7Y=6{ z(kxT9B6P1pJ4SCp0lxhvx8gudxHaeT0s|xXmlL0UkK6E!mj%hG5ws8xl(7r8%ZsjHQb5rQkg6<<9s(=oSvV-v&YCv<#dd4+H|(M+_mK(6@71z7`zFccx{L)bs4}Az}O6Tsh2h!xxn3+yai1SVfI3{)N081 z2U?OU*Z44Z`BbhEDn2VT&2WwmMQspO>nVW&(+EOKi>t(?4XhvCD&*YRRmE2@f& z!vg=Z0cyo}pbg)OYBTQJ4Yj&1Xv6qva5y5w YES + @@ -2957,24 +2958,214 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA 268 YES - + - {{197, 15}, {247, 17}} + 268 + {{97, 463}, {96, 17}} - YES - - 605158976 - 171971584 - Click this area to map mouse input. - - LucidaGrande-Bold + + 68288064 + 71304192 + Saved Profiles: + + + + + + + + + 268 + {{195, 457}, {265, 26}} + + YES + + -2076049856 + 2048 + + + 109199615 + 129 + + + 400 + 75 + + + New... + + 2147483647 + 1 + + NSImage + NSActionTemplate + + + + _popUpItemAction: + -1 + + + YES + + InputConfigurationMenu + + YES + + + YES + YES + + + 2147483647 + + + _popUpItemAction: + + + + + YES + + + 1 + 1 + YES + YES + 2 + + + + + 268 + {{462, 457}, {116, 26}} + + YES + + -2076049856 + 134219776 + + + -2038284033 + 129 + + LucidaGrande 13 16 - - - + + + 400 + 75 + + + YES + Actions + + 1048576 + 2147483647 + 1 + + + + _popUpItemAction: + + + YES + + OtherViews + + YES + + + + View + + 2147483647 + + + _popUpItemAction: + + + + + Apply + + 2147483647 + + + _popUpItemAction: + + + + + YES + YES + + + 2147483647 + + + _popUpItemAction: + + + + + YES + Rename + + 2147483647 + + + _popUpItemAction: + + + + + YES + Save + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + YES + YES + + + 2147483647 + + + _popUpItemAction: + + + + + YES + Delete + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + YES + + + YES + 1 + YES + YES + 2 @@ -2990,16 +3181,14 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA 256 - {638, 437} + {640, 394} - YES 256 - {638, 17} + {640, 17} - @@ -3007,7 +3196,6 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA -2147483392 {{584, 0}, {16, 17}} - YES @@ -3195,9 +3383,8 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA YES - {{1, 17}, {638, 437}} + {{1, 17}, {640, 394}} - @@ -3208,7 +3395,6 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA -2147483392 {{584, 17}, {15, 102}} - _doScroller: 0.96411483253588515 @@ -3218,7 +3404,6 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA -2147483392 {{1, 420}, {624, 15}} - 1 _doScroller: @@ -3231,9 +3416,8 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA YES - {{1, 0}, {638, 17}} + {{1, 0}, {640, 17}} - @@ -3241,9 +3425,8 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA - {{0, 42}, {640, 455}} + {{-1, 37}, {642, 412}} - 562 @@ -3253,10 +3436,28 @@ aGVhdHMuZ2JhdGVtcC5uZXQvA QSAAAEEgAABBmAAAQZgAAA + + + {{197, 12}, {247, 17}} + + YES + + 605158976 + 171971584 + Click this area to map mouse input. + + LucidaGrande-Bold + 13 + 16 + + + + + + - {640, 497} + {640, 495} - InputPrefsView @@ -6820,6 +7021,462 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA PreferencesWindowDelegate + + 9 + 2 + {{235, 426}, {620, 442}} + 1685586944 + Input Profile + NSWindow + + {1.79769e+308, 1.79769e+308} + {620, 180} + + + 256 + + YES + + + 274 + + YES + + + 2304 + + YES + + + 256 + {620, 304} + + + YES + + + 256 + {620, 17} + + + + + + + -2147483392 + {{584, 0}, {16, 17}} + + + + + YES + + InputCommandIconColumn + 35 + 16 + 3.4028234663852886e+38 + + 75628096 + 2048 + + + + + + + 67239424 + 33685504 + + 0 + 3 + 0 + NO + + + + + InputCommandTagColumn + 181 + 16 + 1000 + + 75628096 + 2048 + Command + + + 3 + MC4zMzMzMzI5ODU2AA + + + + + 67239488 + 272761856 + Text + + + + + + 3 + YES + + + + InputDeviceColumn + 222 + 10 + 3.4028234663852886e+38 + + 75628096 + 2048 + Input Device + + + + + + 69336641 + 137216 + Text Cell + + + + + + 3 + YES + + + + InputSettingsSummaryColumn + 151 + 10 + 3.4028234663852886e+38 + + 75628096 + 2048 + Input Settings Summary + + + + + + 69336641 + 137216 + Text Cell + + + + + + 3 + YES + + + + 3 + 2 + + + 17 + 1386217472 + + + 0 + 15 + 0 + NO + 0 + NO + + + {{1, 17}, {620, 304}} + + + + + + 4 + + + + -2147483392 + {{584, 17}, {15, 102}} + + + + _doScroller: + 0.95844875346260383 + + + + -2147483392 + {{1, 325}, {599, 15}} + + + 1 + + _doScroller: + 0.99667221297836939 + + + + 2304 + + YES + + + {{1, 0}, {620, 17}} + + + + + + 4 + + + + {{-1, 60}, {622, 322}} + + + + 562 + + + + + + QSAAAEEgAABBmAAAQZgAAA + + + + 268 + {{19, 419}, {72, 14}} + + + YES + + 68288064 + 272761856 + Profile Name + + + + + + + + + 289 + {{510, 12}, {96, 32}} + + + YES + + 67239424 + 134217728 + Close + + + -2038284033 + 129 + + DQ + 200 + 25 + + + + + 266 + {{20, 396}, {392, 22}} + + + YES + + -1804468671 + 272630784 + + + + YES + + + + + + + 292 + {{14, 12}, {236, 32}} + + + YES + + 67239424 + 134217728 + Apply to Current Configuration + + + -2038284033 + 129 + + + 200 + 25 + + + + + 265 + {{510, 390}, {96, 32}} + + + YES + + 67239424 + 134217728 + Next + + + -2038284033 + 129 + + + 200 + 25 + + + + + 265 + {{414, 390}, {96, 32}} + + + YES + + 67239424 + 134217728 + Previous + + + -2038284033 + 129 + + + 200 + 25 + + + + + 292 + {{250, 12}, {96, 32}} + + + YES + + 67239424 + 134217728 + Delete + + + -2038284033 + 129 + + + 200 + 25 + + + + {620, 442} + + + + {{0, 0}, {1920, 1178}} + {620, 202} + {1.79769e+308, 1.79769e+308} + + + 1 + 2 + {{235, 444}, {452, 115}} + 1685586944 + Input Profile Rename + NSWindow + + + + 256 + + YES + + + 266 + {{20, 48}, {412, 22}} + + + YES + + -1804468671 + 272630784 + + + + YES + + + + + + + 268 + {{342, 12}, {96, 32}} + + + 1 + YES + + 67239424 + 134217728 + OK + + + -2038284033 + 129 + + DQ + 200 + 25 + + + + + 268 + {{17, 78}, {215, 17}} + + + YES + + 68288064 + 272630784 + Enter a new name for this profile: + + + + + + + + {452, 115} + + + + {{0, 0}, {1920, 1178}} + {1.79769e+308, 1.79769e+308} + 1 2 @@ -10146,7 +10803,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA NO - + cheatType YES compare: @@ -10188,6 +10845,10 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 1 + + YES + + 4 15 0 @@ -10429,11 +11090,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 68288064 272630784 Type: - - LucidaGrande - 13 - 16 - + @@ -11816,10 +12473,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA -2033434369 160 - - NSImage - NSActionTemplate - + 400 @@ -12724,7 +13378,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA -2033434369 160 - + 400 @@ -14490,7 +15144,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {1.79769e+308, 1.79769e+308} - + 256 YES @@ -14509,6 +15163,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{15, 77}, {206, 18}} + YES -2080244224 @@ -14531,6 +15186,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{15, 57}, {134, 18}} + YES -2080244224 @@ -14553,6 +15209,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{15, 37}, {80, 18}} + YES -2080244224 @@ -14575,6 +15232,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{185, 12}, {45, 19}} + YES -1804468671 @@ -14655,6 +15313,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{15, 14}, {165, 14}} + YES 68288064 @@ -14669,10 +15328,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {{1, 1}, {248, 103}} + {{17, 241}, {250, 119}} + {0, 0} 67239424 @@ -14696,6 +15357,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{65, 18}, {154, 19}} + YES -2080244224 @@ -14726,6 +15388,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{18, 14}, {107, 58}} + YES 3 1 @@ -14930,10 +15593,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {{1, 1}, {248, 82}} + {{17, 442}, {250, 98}} + {0, 0} 67239424 @@ -14967,6 +15632,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{18, 14}, {120, 98}} + YES 5 1 @@ -15231,10 +15897,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {{1, 1}, {248, 122}} + {{17, 41}, {250, 138}} + {0, 0} 67239424 @@ -15268,6 +15936,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{15, 32}, {113, 18}} + YES -2080244224 @@ -15290,6 +15959,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{15, 12}, {108, 18}} + YES -2080244224 @@ -15310,10 +15980,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {{1, 1}, {248, 58}} + {{17, 364}, {250, 74}} + {0, 0} 67239424 @@ -15347,6 +16019,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 {{16, 12}, {192, 18}} + YES 67239424 @@ -15367,10 +16040,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {{1, 1}, {248, 38}} + {{17, 183}, {250, 54}} + {0, 0} 67239424 @@ -15391,6 +16066,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {284, 560} + + {{0, 0}, {1920, 1178}} {1.79769e+308, 1.79769e+308} @@ -19741,6 +20418,16 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES + + + YES + Name + IsDefaultType + Mappings + + YES + + YES @@ -27648,14 +28335,6 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 7165 - - - inputPrefOutlineView - - - - 7166 - removeInput: @@ -28162,6 +28841,358 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 7495 + + + enabled: selection.IsDefaultType + + + + + + enabled: selection.IsDefaultType + enabled + selection.IsDefaultType + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 7674 + + + + enabled: selection.IsDefaultType + + + + + + enabled: selection.IsDefaultType + enabled + selection.IsDefaultType + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 7676 + + + + enabled: selection.IsDefaultType + + + + + + enabled: selection.IsDefaultType + enabled + selection.IsDefaultType + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 7678 + + + + value: selection.Name + + + + + + value: selection.Name + value + selection.Name + 2 + + + 7680 + + + + enabled: selection.IsDefaultType + + + + + + enabled: selection.IsDefaultType + enabled + selection.IsDefaultType + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 7682 + + + + inputProfileController + + + + 7685 + + + + inputProfileMenu + + + + 7686 + + + + inputProfileSheet + + + + 7687 + + + + profileApply: + + + + 7688 + + + + profileRename: + + + + 7689 + + + + profileSave: + + + + 7690 + + + + profileView: + + + + 7691 + + + + profileDelete: + + + + 7692 + + + + profileNew: + + + + 7693 + + + + closeProfileSheet: + + + + 7696 + + + + profileDelete: + + + + 7697 + + + + profileApply: + + + + 7698 + + + + inputProfileNextButton + + + + 7700 + + + + inputProfilePreviousButton + + + + 7701 + + + + profileSelect: + + + + 7702 + + + + profileSelect: + + + + 7703 + + + + enabled: selection.IsDefaultType + + + + + + enabled: selection.IsDefaultType + enabled + selection.IsDefaultType + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 7705 + + + + delegate + + + + 7706 + + + + value: selection.Name + + + + + + value: selection.Name + value + selection.Name + 2 + + + 7718 + + + + enabled: selection.IsDefaultType + + + + + + enabled: selection.IsDefaultType + enabled + selection.IsDefaultType + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 7719 + + + + delegate + + + + 7720 + + + + inputProfileRenameSheet + + + + 7731 + + + + closeProfileRenameSheet: + + + + 7732 + + + + inputPrefOutlineView + + + + 7734 + + + + inputManager + + + + 7741 + + + + dataSource + + + + 7742 + + + + delegate + + + + 7743 + + + + profileOutlineView + + + + 7744 + @@ -37270,122 +38301,15 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - + + + + Input Preferences View - - 7128 - - - YES - - - - - - - - - 7132 - - - - - 7131 - - - - - 7130 - - - YES - - - - - - - - - - 7129 - - - - - 7137 - - - YES - - - - - - 7136 - - - YES - - - - - - 7135 - - - YES - - - - - - 7134 - - - YES - - - - - - 7133 - - - YES - - - - - - 7142 - - - - - 7141 - - - - - 7140 - - - - - 7139 - - - - - 7138 - - - 7168 @@ -38534,6 +39458,528 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA + + 7515 + + + YES + + + + + + 7516 + + + YES + + + + + + + + + + + + + 7517 + + + YES + + + + + + + + + 7521 + + + + + 7520 + + + + + 7519 + + + YES + + + + + + + + + 7518 + + + + + 7526 + + + YES + + + + + + 7525 + + + YES + + + + + + 7522 + + + YES + + + + + + 7531 + + + + + 7528 + + + + + 7537 + + + YES + + + + + + 7540 + + + + + 7541 + + + YES + + + + + + 7542 + + + + + 7543 + + + YES + + + + + + 7544 + + + + + 7545 + + + YES + + + + + + 7546 + + + + + 7551 + + + YES + + + + + + 7552 + + + + + 7553 + + + YES + + + + + + 7554 + + + + + 7555 + + + YES + + + + + + 7556 + + + + + 7583 + + + YES + + + + + + 7584 + + + + + 7128 + + + YES + + + + + + + + + 7132 + + + + + 7131 + + + + + 7130 + + + YES + + + + + + + + + + 7129 + + + + + 7137 + + + YES + + + + + + 7136 + + + YES + + + + + + 7135 + + + YES + + + + + + 7134 + + + YES + + + + + + 7133 + + + YES + + + + + + 7142 + + + + + 7141 + + + + + 7140 + + + + + 7139 + + + + + 7138 + + + + + 7594 + + + YES + + + + + + 7595 + + + YES + + + + + + 7596 + + + YES + + + + + + + + + + + + + 7597 + + + + + 7598 + + + + + 7599 + + + + + 7601 + + + + + 7602 + + + + + 7603 + + + + + 7600 + + + + + 7604 + + + + + 7605 + + + YES + + + + + + 7606 + + + YES + + + + + + 7607 + + + YES + + + + + + + 7610 + + + + + 7612 + + + + + 7624 + + + YES + + + + + + 7625 + + + + + 7666 + + + Input Profile Controller + + + 7707 + + + YES + + + + + + 7708 + + + YES + + + + + + + + 7715 + + + YES + + + + + + 7716 + + + + + 7725 + + + YES + + + + + + 7726 + + + + + 7729 + + + YES + + + + + + 7730 + + + + + 7740 + + + @@ -40441,6 +41887,86 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 7489.IBPluginDependency 75.IBPluginDependency 75.ImportedFromIB2 + 7515.IBEditorWindowLastContentRect + 7515.IBPluginDependency + 7515.IBWindowTemplateEditedContentRect + 7515.NSWindowTemplate.visibleAtLaunch + 7515.windowTemplate.hasMinSize + 7515.windowTemplate.minSize + 7516.IBPluginDependency + 7517.IBPluginDependency + 7517.IBViewBoundsToFrameTransform + 7518.IBPluginDependency + 7519.IBPluginDependency + 7520.IBPluginDependency + 7521.IBPluginDependency + 7526.IBPluginDependency + 7540.IBPluginDependency + 7541.IBPluginDependency + 7541.IBViewBoundsToFrameTransform + 7542.IBPluginDependency + 7543.IBPluginDependency + 7543.IBViewBoundsToFrameTransform + 7544.IBPluginDependency + 7545.IBPluginDependency + 7545.IBViewBoundsToFrameTransform + 7546.IBPluginDependency + 7551.IBPluginDependency + 7551.IBViewBoundsToFrameTransform + 7552.IBPluginDependency + 7553.IBPluginDependency + 7553.IBViewBoundsToFrameTransform + 7554.IBPluginDependency + 7555.IBPluginDependency + 7556.IBPluginDependency + 7583.IBPluginDependency + 7584.IBPluginDependency + 7594.IBPluginDependency + 7594.IBViewBoundsToFrameTransform + 7595.IBPluginDependency + 7596.IBEditorWindowLastContentRect + 7596.IBPluginDependency + 7597.IBPluginDependency + 7598.IBAttributePlaceholdersKey + 7598.IBPluginDependency + 7599.IBAttributePlaceholdersKey + 7599.IBPluginDependency + 7600.IBAttributePlaceholdersKey + 7600.IBPluginDependency + 7601.IBAttributePlaceholdersKey + 7601.IBPluginDependency + 7602.IBPluginDependency + 7603.IBPluginDependency + 7604.IBAttributePlaceholdersKey + 7604.IBPluginDependency + 7605.IBPluginDependency + 7605.IBViewBoundsToFrameTransform + 7606.IBPluginDependency + 7607.IBEditorWindowLastContentRect + 7607.IBPluginDependency + 7610.IBAttributePlaceholdersKey + 7610.IBPluginDependency + 7612.IBPluginDependency + 7624.IBPluginDependency + 7624.IBViewBoundsToFrameTransform + 7625.IBPluginDependency + 7666.CustomClassName + 7666.IBPluginDependency + 7707.IBEditorWindowLastContentRect + 7707.IBPluginDependency + 7707.IBWindowTemplateEditedContentRect + 7707.NSWindowTemplate.visibleAtLaunch + 7708.IBPluginDependency + 7715.IBPluginDependency + 7715.IBViewBoundsToFrameTransform + 7716.IBPluginDependency + 7725.IBPluginDependency + 7725.IBViewBoundsToFrameTransform + 7726.IBPluginDependency + 7729.IBPluginDependency + 7729.IBViewBoundsToFrameTransform + 7730.IBPluginDependency + 7740.IBPluginDependency 783.IBPluginDependency 784.IBEditorWindowLastContentRect 784.IBPluginDependency @@ -41590,9 +43116,9 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA AUGoAABDXwAAA - {{915, 238}, {640, 480}} + {{967, 130}, {640, 480}} com.apple.InterfaceBuilder.CocoaPlugin - {{915, 238}, {640, 480}} + {{967, 130}, {640, 480}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -42620,7 +44146,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA P4AAAL+AAABC3gAAw9EAAA com.apple.InterfaceBuilder.CocoaPlugin - {{1302, 582}, {209, 71}} + {{1354, 474}, {209, 71}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -43727,12 +45253,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{707, 309}, {640, 497}} + {{984, 92}, {640, 495}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - P4AAAL+AAAAAAAAAw/eAAA + P4AAAL+AAAC/gAAAw9+AAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -43748,7 +45274,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - P4AAAL+AAABDHQAAwegAAA + P4AAAL+AAABDogAAwhAAAA com.apple.InterfaceBuilder.CocoaPlugin {{1237, 579}, {350, 263}} @@ -44111,6 +45637,152 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + {{997, 160}, {620, 442}} + com.apple.InterfaceBuilder.CocoaPlugin + {{997, 160}, {620, 442}} + + + {620, 180} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAAC/gAAAw9iAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBmAAAw/IAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD/wAAwigAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBoAAAw+qAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBYAAAwigAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABEBIAAw+uAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD5wAAw/CAAA + + com.apple.InterfaceBuilder.CocoaPlugin + {{1435, 432}, {136, 143}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Saves the current configuration to the selected profile. + + + com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Deletes the selected profile. + + + com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Replaces the current configuration with the selected profile. + + + com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Renames the selected profile. + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Shows the selected profile. + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDQwAAw/CAAA + + com.apple.InterfaceBuilder.CocoaPlugin + {{1168, 542}, {265, 33}} + com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Creates a new profile using the current configuration. + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCQAAAw/EAAA + + com.apple.InterfaceBuilder.CocoaPlugin + InputProfileController + com.apple.InterfaceBuilder.CocoaPlugin + {{853, 403}, {452, 115}} + com.apple.InterfaceBuilder.CocoaPlugin + {{853, 403}, {452, 115}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABByAAAwoYAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDqwAAwoAAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBiAAAwwwAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{1234, 903}, {136, 163}} com.apple.InterfaceBuilder.CocoaPlugin @@ -44449,7 +46121,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - 7495 + 7744 @@ -45568,13 +47240,11 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES emuControl hidInputTarget - inputPrefsOutlineView YES EmuControllerDelegate id - NSOutlineView @@ -45583,7 +47253,6 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES emuControl hidInputTarget - inputPrefsOutlineView YES @@ -45595,10 +47264,6 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA hidInputTarget id - - inputPrefsOutlineView - NSOutlineView - @@ -45614,7 +47279,16 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES changeSpeed: + closeProfileRenameSheet: + closeProfileSheet: closeSettingsSheet: + profileApply: + profileDelete: + profileNew: + profileRename: + profileSave: + profileSelect: + profileView: removeInput: setInputAdd: showSettingsSheet: @@ -45626,6 +47300,15 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA id id id + id + id + id + id + id + id + id + id + id @@ -45633,7 +47316,16 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES changeSpeed: + closeProfileRenameSheet: + closeProfileSheet: closeSettingsSheet: + profileApply: + profileDelete: + profileNew: + profileRename: + profileSave: + profileSelect: + profileView: removeInput: setInputAdd: showSettingsSheet: @@ -45644,10 +47336,46 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA changeSpeed: id + + closeProfileRenameSheet: + id + + + closeProfileSheet: + id + closeSettingsSheet: id + + profileApply: + id + + + profileDelete: + id + + + profileNew: + id + + + profileRename: + id + + + profileSave: + id + + + profileSelect: + id + + + profileView: + id + removeInput: id @@ -45668,6 +47396,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES inputManager inputPrefOutlineView + inputProfileController + inputProfileMenu + inputProfileNextButton + inputProfilePreviousButton + inputProfileRenameSheet + inputProfileSheet inputSettingsController inputSettingsGPUState inputSettingsLoadStateSlot @@ -45681,6 +47415,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES InputManager NSOutlineView + InputProfileController + NSPopUpButton + NSButton + NSButton + NSWindow + NSWindow NSObjectController NSWindow NSWindow @@ -45697,6 +47437,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES inputManager inputPrefOutlineView + inputProfileController + inputProfileMenu + inputProfileNextButton + inputProfilePreviousButton + inputProfileRenameSheet + inputProfileSheet inputSettingsController inputSettingsGPUState inputSettingsLoadStateSlot @@ -45716,6 +47462,30 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA inputPrefOutlineView NSOutlineView + + inputProfileController + InputProfileController + + + inputProfileMenu + NSPopUpButton + + + inputProfileNextButton + NSButton + + + inputProfilePreviousButton + NSButton + + + inputProfileRenameSheet + NSWindow + + + inputProfileSheet + NSWindow + inputSettingsController NSObjectController @@ -45755,6 +47525,46 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA userinterface/inputPrefsView.h + + InputProfileController + NSObjectController + + YES + + YES + inputManager + profileOutlineView + + + YES + InputManager + NSOutlineView + + + + YES + + YES + inputManager + profileOutlineView + + + YES + + inputManager + InputManager + + + profileOutlineView + NSOutlineView + + + + + IBProjectSource + userinterface/InputProfileController.h + + PreferencesWindowDelegate NSObject diff --git a/desmume/src/cocoa/userinterface/InputManager.h b/desmume/src/cocoa/userinterface/InputManager.h index 92a32497e..703f80975 100644 --- a/desmume/src/cocoa/userinterface/InputManager.h +++ b/desmume/src/cocoa/userinterface/InputManager.h @@ -147,6 +147,8 @@ void HandleDeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSen id hidInputTarget; InputHIDManager *hidManager; NSMutableDictionary *inputMappings; + NSArray *commandTagList; + NSDictionary *commandIcon; InputCommandMap commandMap; CommandAttributesMap defaultCommandAttributes; @@ -155,9 +157,11 @@ void HandleDeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSen @property (readonly) IBOutlet EmuControllerDelegate *emuControl; @property (retain) id hidInputTarget; -@property (retain) NSMutableDictionary *inputMappings; +@property (readonly) NSMutableDictionary *inputMappings; +@property (readonly) NSArray *commandTagList; +@property (readonly) NSDictionary *commandIcon; -- (void) addMappingsUsingUserDefaults; +- (void) setMappingsWithMappings:(NSDictionary *)mappings; - (void) addMappingUsingDeviceInfoDictionary:(NSDictionary *)deviceDict commandAttributes:(const CommandAttributes *)cmdAttr; - (void) addMappingUsingInputAttributes:(const InputAttributes *)inputAttr commandAttributes:(const CommandAttributes *)cmdAttr; - (void) addMappingUsingInputList:(const InputAttributesList *)inputList commandAttributes:(const CommandAttributes *)cmdAttr; @@ -173,6 +177,7 @@ void HandleDeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSen - (BOOL) dispatchCommandUsingIBAction:(const SEL)theSelector sender:(id)sender; - (void) writeDefaultsInputMappings; +- (NSString *) commandTagFromInputList:(NSArray *)inputList; - (SEL) selectorOfCommandTag:(const char *)commandTag; - (CommandAttributes) defaultCommandAttributesForCommandTag:(const char *)commandTag; diff --git a/desmume/src/cocoa/userinterface/InputManager.mm b/desmume/src/cocoa/userinterface/InputManager.mm index 04f5656a2..f29b6f612 100644 --- a/desmume/src/cocoa/userinterface/InputManager.mm +++ b/desmume/src/cocoa/userinterface/InputManager.mm @@ -788,6 +788,8 @@ void HandleDeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSen @synthesize emuControl; @dynamic hidInputTarget; @synthesize inputMappings; +@synthesize commandTagList; +@synthesize commandIcon; static std::tr1::unordered_map keyboardNameTable; // Key = Key code, Value = Key name @@ -812,7 +814,33 @@ static std::tr1::unordered_map keyboardNameTable; / } hidManager = [[InputHIDManager alloc] initWithInputManager:self]; - inputMappings = [[NSMutableDictionary dictionaryWithCapacity:128] retain]; + inputMappings = [[NSMutableDictionary alloc] initWithCapacity:128]; + commandTagList = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultKeyMappings" ofType:@"plist"]] valueForKey:@"CommandTagList"]; + + // Initialize the icons associated with each command. + commandIcon = [[NSDictionary alloc] initWithObjectsAndKeys: + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonSelect_420x420" ofType:@"png"]] autorelease], @"UNKNOWN COMMAND", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowUp_420x420" ofType:@"png"]] autorelease], @"Up", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowDown_420x420" ofType:@"png"]] autorelease], @"Down", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowLeft_420x420" ofType:@"png"]] autorelease], @"Left", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowRight_420x420" ofType:@"png"]] autorelease], @"Right", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonA_420x420" ofType:@"png"]] autorelease], @"A", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonB_420x420" ofType:@"png"]] autorelease], @"B", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonX_420x420" ofType:@"png"]] autorelease], @"X", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonY_420x420" ofType:@"png"]] autorelease], @"Y", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonL_420x420" ofType:@"png"]] autorelease], @"L", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonR_420x420" ofType:@"png"]] autorelease], @"R", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonStart_420x420" ofType:@"png"]] autorelease], @"Start", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonSelect_420x420" ofType:@"png"]] autorelease], @"Select", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Microphone_420x420" ofType:@"png"]] autorelease], @"Microphone", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ShowHUD_420x420" ofType:@"png"]] autorelease], @"HUD", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Execute_420x420" ofType:@"png"]] autorelease], @"Execute", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Pause_420x420" ofType:@"png"]] autorelease], @"Pause", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Execute_420x420" ofType:@"png"]] autorelease], @"Execute/Pause", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Reset_420x420" ofType:@"png"]] autorelease], @"Reset", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonSelect_420x420" ofType:@"png"]] autorelease], @"Touch", + [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_VolumeMute_16x16" ofType:@"png"]] autorelease], @"Mute/Unmute", + nil]; // Initialize the selectors used for each command tag. (Do this in code rather than in an external file.) commandSelector["Up"] = @selector(cmdUpdateDSController:); @@ -921,7 +949,7 @@ static std::tr1::unordered_map keyboardNameTable; / [self addMappingForIBAction:@selector(reset:) commandAttributes:&cmdReset]; [self addMappingForIBAction:@selector(toggleGPUState:) commandAttributes:&cmdToggleGPUState]; - [self addMappingsUsingUserDefaults]; + [self setMappingsWithMappings:[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"Input_ControllerMappings"]]; return self; } @@ -929,7 +957,9 @@ static std::tr1::unordered_map keyboardNameTable; / - (void)dealloc { [hidManager release]; - [self setInputMappings:nil]; + [inputMappings release]; + [commandTagList release]; + [commandIcon release]; [super dealloc]; } @@ -948,54 +978,26 @@ static std::tr1::unordered_map keyboardNameTable; / #pragma mark Class Methods -- (void) addMappingsUsingUserDefaults +- (void) setMappingsWithMappings:(NSDictionary *)mappings { - // Check to see if the DefaultKeyMappings.plist files exists. - NSDictionary *defaultKeyMappingsDict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultKeyMappings" ofType:@"plist"]]; - if (defaultKeyMappingsDict == nil) + if (mappings == nil || commandTagList == nil) { return; } - NSDictionary *defaultMappings = [defaultKeyMappingsDict valueForKey:@"DefaultInputMappings"]; - if (defaultMappings == nil) - { - return; - } - - NSArray *commandTagList = [defaultKeyMappingsDict valueForKey:@"CommandTagList"]; - if (commandTagList == nil) - { - return; - } - - // At this point, we need to check every key in the user's preference file and make sure that all the keys - // exist. The keys that must exist are all listed in the DefaultKeyMappings.plist file. - BOOL userMappingsDidChange = NO; - NSMutableDictionary *tempUserMappings = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"Input_ControllerMappings"]]; - + // Add the input mappings, filling in missing data as needed. for (NSString *commandTag in commandTagList) { - if ([tempUserMappings objectForKey:commandTag] == nil) + NSArray *deviceInfoList = (NSArray *)[mappings valueForKey:commandTag]; + + if ([[self inputMappings] valueForKey:commandTag] == nil) { - [tempUserMappings setValue:[defaultMappings valueForKey:commandTag] forKey:commandTag]; - userMappingsDidChange = YES; + [[self inputMappings] setObject:[NSMutableArray arrayWithCapacity:4] forKey:commandTag]; + } + else + { + [self removeAllMappingsForCommandTag:[commandTag cStringUsingEncoding:NSUTF8StringEncoding]]; } - } - - // If we had to add a missing key, then we need to copy our temporary dictionary back to the - // user's preferences file. - if (userMappingsDidChange) - { - [[NSUserDefaults standardUserDefaults] setObject:tempUserMappings forKey:@"Input_ControllerMappings"]; - } - - // Finally, add all the input mappings per user defaults. - NSDictionary *userMappings = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"Input_ControllerMappings"]; - for (NSString *commandTag in commandTagList) - { - NSArray *deviceInfoList = (NSArray *)[userMappings valueForKey:commandTag]; - [[self inputMappings] setObject:[NSMutableArray arrayWithCapacity:2] forKey:commandTag]; for(NSDictionary *deviceInfo in deviceInfoList) { @@ -1266,6 +1268,26 @@ static std::tr1::unordered_map keyboardNameTable; / [[NSUserDefaults standardUserDefaults] setObject:[self inputMappings] forKey:@"Input_ControllerMappings"]; } +- (NSString *) commandTagFromInputList:(NSArray *)inputList +{ + NSString *commandTag = nil; + if (inputList == nil) + { + return commandTag; + } + + for (NSString *tag in inputMappings) + { + if (inputList == [inputMappings valueForKey:tag]) + { + commandTag = tag; + break; + } + } + + return commandTag; +} + - (SEL) selectorOfCommandTag:(const char *)commandTag { return commandSelector[commandTag]; diff --git a/desmume/src/cocoa/userinterface/InputProfileController.h b/desmume/src/cocoa/userinterface/InputProfileController.h new file mode 100644 index 000000000..aeb7b48a8 --- /dev/null +++ b/desmume/src/cocoa/userinterface/InputProfileController.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2013 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#import +#import "InputManager.h" + + +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 +@interface InputProfileController : NSObjectController +#else +@interface InputProfileController : NSObjectController +#endif +{ + NSObject *dummyObject; + InputManager *inputManager; + NSOutlineView *profileOutlineView; +} + +@property (readonly) IBOutlet NSObject *dummyObject; +@property (readonly) IBOutlet InputManager *inputManager; +@property (readonly) IBOutlet NSOutlineView *profileOutlineView; + +- (NSString *) commandTagFromInputList:(NSArray *)inputList; + +@end diff --git a/desmume/src/cocoa/userinterface/InputProfileController.mm b/desmume/src/cocoa/userinterface/InputProfileController.mm new file mode 100644 index 000000000..fe079f0d7 --- /dev/null +++ b/desmume/src/cocoa/userinterface/InputProfileController.mm @@ -0,0 +1,238 @@ +/* + Copyright (C) 2013 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#import "InputProfileController.h" +#import "cocoa_globals.h" + + +@implementation InputProfileController + +@synthesize dummyObject; +@synthesize inputManager; +@synthesize profileOutlineView; + +- (id)init +{ + self = [super init]; + if (self == nil) + { + return self; + } + + return self; +} + +- (void)dealloc +{ + [super dealloc]; +} + +- (NSString *) commandTagFromInputList:(NSArray *)inputList +{ + NSDictionary *mappings = [(NSDictionary *)[self content] valueForKey:@"Mappings"]; + NSString *commandTag = nil; + if (inputList == nil) + { + return commandTag; + } + + for (NSString *tag in mappings) + { + if (inputList == [mappings valueForKey:tag]) + { + commandTag = tag; + break; + } + } + + return commandTag; +} + +#pragma mark NSOutlineViewDelegate Protocol + +- (BOOL)selectionShouldChangeInOutlineView:(NSOutlineView *)outlineView +{ + return NO; +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + if ([(NSString *)[tableColumn identifier] isEqualToString:@"InputCommandTagColumn"]) + { + return YES; + } + + return NO; +} + +- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + NSString *columnID = (NSString *)[tableColumn identifier]; + NSCell *outCell = [tableColumn dataCellForRow:[outlineView rowForItem:item]]; + + if ([columnID isEqualToString:@"InputCommandIconColumn"]) + { + if ([item isKindOfClass:[NSArray class]]) + { + NSString *commandTag = [self commandTagFromInputList:item]; + if (commandTag != nil) + { + NSImage *iconImage = (NSImage *)[[inputManager commandIcon] valueForKey:commandTag]; + if (iconImage == nil) + { + iconImage = (NSImage *)[[inputManager commandIcon] valueForKey:@"UNKNOWN COMMAND"]; + } + + [outCell setImage:iconImage]; + } + else + { + outCell = [[[NSCell alloc] init] autorelease]; + } + } + else + { + outCell = [[[NSCell alloc] init] autorelease]; + } + } + else if ([columnID isEqualToString:@"InputDeviceColumn"]) + { + NSFont *newFont = [[NSFontManager sharedFontManager] fontWithFamily:[[outCell font] familyName] + traits:([item isKindOfClass:[NSArray class]]) ? NSBoldFontMask : 0 + weight:0 + size:[[outCell font] pointSize]]; + [outCell setFont:newFont]; + } + else if ([columnID isEqualToString:@"InputSettingsSummaryColumn"]) + { + NSFont *newFont = [[NSFontManager sharedFontManager] fontWithFamily:[[outCell font] familyName] + traits:([item isKindOfClass:[NSArray class]]) ? NSBoldFontMask : 0 + weight:0 + size:[[outCell font] pointSize]]; + [outCell setFont:newFont]; + } + + return outCell; +} + +#pragma mark NSOutlineViewDataSource Protocol +- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item +{ + if (item == nil) + { + NSDictionary *mappings = [(NSDictionary *)[self content] valueForKey:@"Mappings"]; + NSString *commandTag = [[inputManager commandTagList] objectAtIndex:index]; + return [mappings valueForKey:commandTag]; + } + else if ([item isKindOfClass:[NSArray class]]) + { + return [(NSArray *)item objectAtIndex:index]; + } + + return nil; +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item +{ + if ([item isKindOfClass:[NSArray class]]) + { + return YES; + } + + return NO; +} + +- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item +{ + NSInteger numberChildren = 0; + + if (item == nil) + { + numberChildren = [[inputManager commandTagList] count]; + } + else if ([item isKindOfClass:[NSArray class]]) + { + numberChildren = [(NSArray *)item count]; + } + + return numberChildren; +} + +- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item +{ + NSString *columnID = (NSString *)[tableColumn identifier]; + + if ([columnID isEqualToString:@"InputCommandIconColumn"]) + { + NSString *commandTag = [self commandTagFromInputList:item]; + if (commandTag != nil) + { + NSImage *iconImage = (NSImage *)[[inputManager commandIcon] valueForKey:commandTag]; + if (iconImage == nil) + { + iconImage = (NSImage *)[[inputManager commandIcon] valueForKey:@"UNKNOWN COMMAND"]; + } + + return iconImage; + } + else + { + return nil; + } + } + else if ([columnID isEqualToString:@"InputCommandTagColumn"]) + { + if ([item isKindOfClass:[NSArray class]]) + { + NSString *tag = [self commandTagFromInputList:item]; + return tag; + } + else + { + return @""; + } + } + else if ([columnID isEqualToString:@"InputDeviceColumn"]) + { + if ([item isKindOfClass:[NSArray class]]) + { + const unsigned long inputCount = (unsigned long)[(NSArray *)item count]; + return [NSString stringWithFormat:(inputCount != 1) ? NSSTRING_INPUTPREF_NUM_INPUTS_MAPPED_PLURAL : NSSTRING_INPUTPREF_NUM_INPUTS_MAPPED, inputCount]; + } + else if ([item isKindOfClass:[NSDictionary class]]) + { + return [item valueForKey:@"deviceInfoSummary"]; + } + + return @""; + } + else if ([columnID isEqualToString:@"InputSettingsSummaryColumn"]) + { + NSString *settingsSummary = @""; + + if ([item isKindOfClass:[NSDictionary class]]) + { + settingsSummary = [item valueForKey:@"inputSettingsSummary"]; + } + + return settingsSummary; + } + + return item; +} + +@end diff --git a/desmume/src/cocoa/userinterface/appDelegate.mm b/desmume/src/cocoa/userinterface/appDelegate.mm index 5cb120751..14ec07bba 100644 --- a/desmume/src/cocoa/userinterface/appDelegate.mm +++ b/desmume/src/cocoa/userinterface/appDelegate.mm @@ -203,6 +203,8 @@ [self setupUserDefaults]; [inputPrefsView initSettingsSheets]; + [inputPrefsView populateInputProfileMenu]; + [[inputPrefsView inputProfileMenu] selectItemAtIndex:0]; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification diff --git a/desmume/src/cocoa/userinterface/inputPrefsView.h b/desmume/src/cocoa/userinterface/inputPrefsView.h index 8469bc7ac..87566584b 100644 --- a/desmume/src/cocoa/userinterface/inputPrefsView.h +++ b/desmume/src/cocoa/userinterface/inputPrefsView.h @@ -19,24 +19,8 @@ #import #import "InputManager.h" -@class CocoaDSController; +@class InputProfileController; -@interface InputPrefProperties : NSObject -{ - NSString *commandTag; - NSImage *icon; - NSWindow *settingsSheet; -} - -@property (retain) NSString *commandTag; -@property (retain) NSImage *icon; -@property (retain) NSWindow *settingsSheet; - -- (id) initWithCommandTag:(NSString *)theCommandTag icon:(NSImage *)theIcon sheet:(NSWindow *)theSheet; - -@end - -#pragma mark - #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 @interface InputPrefsView : NSView @@ -44,10 +28,17 @@ @interface InputPrefsView : NSView #endif { + NSObject *dummyObject; NSWindow *prefWindow; + NSPopUpButton *inputProfileMenu; + NSButton *inputProfilePreviousButton; + NSButton *inputProfileNextButton; NSOutlineView *inputPrefOutlineView; NSObjectController *inputSettingsController; + InputProfileController *inputProfileController; + NSWindow *inputProfileSheet; + NSWindow *inputProfileRenameSheet; NSWindow *inputSettingsMicrophone; NSWindow *inputSettingsTouch; NSWindow *inputSettingsLoadStateSlot; @@ -59,15 +50,23 @@ NSString *configInputTargetID; NSMutableDictionary *configInputList; - NSDictionary *inputPrefProperties; NSDictionary *inputSettingsMappings; - NSArray *commandTagList; + + NSUInteger _defaultProfileListCount; + NSMutableArray *savedProfilesList; } +@property (readonly) IBOutlet NSObject *dummyObject; @property (readonly) IBOutlet NSWindow *prefWindow; +@property (readonly) IBOutlet NSPopUpButton *inputProfileMenu; +@property (readonly) IBOutlet NSButton *inputProfilePreviousButton; +@property (readonly) IBOutlet NSButton *inputProfileNextButton; @property (readonly) IBOutlet NSOutlineView *inputPrefOutlineView; @property (readonly) IBOutlet NSObjectController *inputSettingsController; +@property (readonly) IBOutlet InputProfileController *inputProfileController; +@property (readonly) IBOutlet NSWindow *inputProfileSheet; +@property (readonly) IBOutlet NSWindow *inputProfileRenameSheet; @property (readonly) IBOutlet NSWindow *inputSettingsMicrophone; @property (readonly) IBOutlet NSWindow *inputSettingsTouch; @property (readonly) IBOutlet NSWindow *inputSettingsLoadStateSlot; @@ -79,13 +78,17 @@ @property (retain) NSString *configInputTargetID; - (void) initSettingsSheets; -- (NSString *) commandTagFromInputList:(NSArray *)inputList; +- (void) populateInputProfileMenu; - (BOOL) handleKeyboardEvent:(NSEvent *)theEvent keyPressed:(BOOL)keyPressed; - (BOOL) handleMouseButtonEvent:(NSEvent *)mouseEvent buttonPressed:(BOOL)buttonPressed; - (BOOL) addMappingUsingInputAttributes:(const InputAttributes *)inputAttr commandTag:(NSString *)commandTag; - (void) setMappingUsingDeviceInfoDictionary:(NSMutableDictionary *)deviceInfo; +- (BOOL) doesProfileNameExist:(NSString *)profileName; +- (void) updateSelectedProfileName; - (void) didEndSettingsSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo; +- (void) didEndProfileSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo; +- (void) didEndProfileRenameSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo; - (IBAction) setInputAdd:(id)sender; - (IBAction) removeInput:(id)sender; @@ -93,4 +96,14 @@ - (IBAction) showSettingsSheet:(id)sender; - (IBAction) closeSettingsSheet:(id)sender; +- (IBAction) profileNew:(id)sender; +- (IBAction) profileView:(id)sender; +- (IBAction) profileApply:(id)sender; +- (IBAction) profileRename:(id)sender; +- (IBAction) profileSave:(id)sender; +- (IBAction) profileDelete:(id)sender; +- (IBAction) profileSelect:(id)sender; +- (IBAction) closeProfileSheet:(id)sender; +- (IBAction) closeProfileRenameSheet:(id)sender; + @end diff --git a/desmume/src/cocoa/userinterface/inputPrefsView.mm b/desmume/src/cocoa/userinterface/inputPrefsView.mm index 3b49d637a..e30150ebe 100644 --- a/desmume/src/cocoa/userinterface/inputPrefsView.mm +++ b/desmume/src/cocoa/userinterface/inputPrefsView.mm @@ -17,114 +17,67 @@ */ #import "inputPrefsView.h" +#import "InputProfileController.h" #import "preferencesWindowDelegate.h" #import "cocoa_globals.h" -#import "cocoa_input.h" #import "cocoa_util.h" #define INPUT_HOLD_TIME 0.1 // Time in seconds to hold a button in its on state when mapping an input. -@implementation InputPrefProperties - -@synthesize commandTag; -@synthesize icon; -@synthesize settingsSheet; - -- (id)init -{ - return [self initWithCommandTag:@"" icon:nil sheet:nil]; -} - -- (id) initWithCommandTag:(NSString *)theCommandTag icon:(NSImage *)theIcon sheet:(NSWindow *)theSheet -{ - self = [super init]; - if (self == nil) - { - return self; - } - - commandTag = [theCommandTag retain]; - icon = [theIcon retain]; - settingsSheet = [theSheet retain]; - - return self; -} - -- (void)dealloc -{ - [self setCommandTag:nil]; - [self setIcon:nil]; - [self setSettingsSheet:nil]; - - [super dealloc]; -} - -@end - - -#pragma mark - @implementation InputPrefsView +@synthesize dummyObject; @synthesize prefWindow; +@synthesize inputProfileMenu; +@synthesize inputProfilePreviousButton; +@synthesize inputProfileNextButton; @synthesize inputPrefOutlineView; @synthesize inputSettingsController; +@synthesize inputProfileController; @synthesize inputSettingsMicrophone; @synthesize inputSettingsTouch; @synthesize inputSettingsLoadStateSlot; @synthesize inputSettingsSaveStateSlot; @synthesize inputSettingsSetSpeedLimit; @synthesize inputSettingsGPUState; +@synthesize inputProfileSheet; +@synthesize inputProfileRenameSheet; @synthesize inputManager; @dynamic configInputTargetID; - (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; + self = [super initWithFrame:frame]; if (self == nil) { return self; } + NSDictionary *defaultKeyMappingsDict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultKeyMappings" ofType:@"plist"]]; + NSArray *defaultProfileList = [defaultKeyMappingsDict valueForKey:@"DefaultInputProfiles"]; + _defaultProfileListCount = [defaultProfileList count]; + + NSArray *userDefaultsSavedProfilesList = (NSArray *)[[NSUserDefaults standardUserDefaults] arrayForKey:@"Input_SavedProfiles"]; + savedProfilesList = [[NSMutableArray alloc] initWithCapacity:32]; + + for (NSDictionary *savedProfile in userDefaultsSavedProfilesList) + { + [savedProfilesList addObject:[NSMutableDictionary dictionaryWithDictionary:savedProfile]]; + } + configInputTargetID = nil; configInputList = [[NSMutableDictionary alloc] initWithCapacity:128]; - - inputPrefProperties = [[NSDictionary alloc] initWithObjectsAndKeys: - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonSelect_420x420" ofType:@"png"]] autorelease], @"UNKNOWN COMMAND", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowUp_420x420" ofType:@"png"]] autorelease], @"Up", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowDown_420x420" ofType:@"png"]] autorelease], @"Down", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowLeft_420x420" ofType:@"png"]] autorelease], @"Left", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ArrowRight_420x420" ofType:@"png"]] autorelease], @"Right", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonA_420x420" ofType:@"png"]] autorelease], @"A", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonB_420x420" ofType:@"png"]] autorelease], @"B", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonX_420x420" ofType:@"png"]] autorelease], @"X", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonY_420x420" ofType:@"png"]] autorelease], @"Y", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonL_420x420" ofType:@"png"]] autorelease], @"L", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonR_420x420" ofType:@"png"]] autorelease], @"R", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonStart_420x420" ofType:@"png"]] autorelease], @"Start", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonSelect_420x420" ofType:@"png"]] autorelease], @"Select", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Microphone_420x420" ofType:@"png"]] autorelease], @"Microphone", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_ShowHUD_420x420" ofType:@"png"]] autorelease], @"HUD", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Execute_420x420" ofType:@"png"]] autorelease], @"Execute", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Pause_420x420" ofType:@"png"]] autorelease], @"Pause", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Execute_420x420" ofType:@"png"]] autorelease], @"Execute/Pause", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_Reset_420x420" ofType:@"png"]] autorelease], @"Reset", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_DSButtonSelect_420x420" ofType:@"png"]] autorelease], @"Touch", - [[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_VolumeMute_16x16" ofType:@"png"]] autorelease], @"Mute/Unmute", - nil]; - - commandTagList = [[[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultKeyMappings" ofType:@"plist"]] valueForKey:@"CommandTagList"] retain]; - + return self; } - (void)dealloc { [configInputList release]; - [inputPrefProperties release]; [inputSettingsMappings release]; - [commandTagList release]; + [savedProfilesList release]; [super dealloc]; } @@ -160,25 +113,70 @@ nil]; } -- (NSString *) commandTagFromInputList:(NSArray *)inputList +- (void) populateInputProfileMenu { - NSString *commandTag = nil; - if (inputList == nil) + NSDictionary *defaultKeyMappingsDict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultKeyMappings" ofType:@"plist"]]; + NSArray *defaultProfileList = [defaultKeyMappingsDict valueForKey:@"DefaultInputProfiles"]; + if (defaultKeyMappingsDict == nil || defaultProfileList == nil) { - return commandTag; + return; } - NSDictionary *inputMappings = [inputManager inputMappings]; - for (NSString *tag in inputMappings) + // We're going to populate this menu from scratch, so remove all existing profile items. + NSMenu *profileMenu = [inputProfileMenu menu]; + NSInteger menuItemCount = [profileMenu numberOfItems] - 2; + for (NSInteger i = 0; i < menuItemCount; i++) { - if (inputList == [inputMappings valueForKey:tag]) + [profileMenu removeItemAtIndex:i]; + } + + // Need this to keep track of profile indexes. + NSInteger profileIndex = 0; + + // Add the menu items for the default profiles. + for (NSUInteger i = 0; i < _defaultProfileListCount; i++) + { + NSDictionary *profileDict = [defaultProfileList objectAtIndex:i]; + NSString *profileName = (NSString *)[profileDict valueForKey:@"Name"]; + NSMenuItem *newProfileMenuItem = [[[NSMenuItem alloc] initWithTitle:profileName + action:@selector(profileSelect:) + keyEquivalent:@""] autorelease]; + [newProfileMenuItem setTag:profileIndex]; + [newProfileMenuItem setTarget:self]; + + [profileMenu insertItem:newProfileMenuItem atIndex:profileIndex]; + profileIndex++; + } + + // Add a separator item in between default profiles and user saved profiles. + [[inputProfileMenu menu] insertItem:[NSMenuItem separatorItem] atIndex:profileIndex]; + + // Add the menu items for the user saved profiles. + if ([savedProfilesList count] < 1) + { + [inputProfileMenu insertItemWithTitle:NSSTRING_INPUTPREF_NO_SAVED_PROFILES atIndex:profileIndex+1]; + NSMenuItem *noSavedConfigItem = [inputProfileMenu itemAtIndex:profileIndex+1]; + [noSavedConfigItem setEnabled:NO]; + } + else + { + for (NSUInteger i = 0; i < [savedProfilesList count]; i++) { - commandTag = tag; - break; + NSDictionary *profileDict = [savedProfilesList objectAtIndex:i]; + NSString *profileName = (NSString *)[profileDict valueForKey:@"Name"]; + NSMenuItem *newProfileMenuItem = [[[NSMenuItem alloc] initWithTitle:profileName + action:@selector(profileSelect:) + keyEquivalent:@""] autorelease]; + [newProfileMenuItem setTag:profileIndex]; + [newProfileMenuItem setTarget:self]; + + [profileMenu insertItem:newProfileMenuItem atIndex:profileIndex+1]; + profileIndex++; } } - return commandTag; + [inputProfileMenu selectItemAtIndex:0]; + [self profileSelect:[inputProfileMenu itemAtIndex:0]]; } - (BOOL) handleKeyboardEvent:(NSEvent *)theEvent keyPressed:(BOOL)keyPressed @@ -257,6 +255,36 @@ [inputManager writeDefaultsInputMappings]; } +- (BOOL) doesProfileNameExist:(NSString *)profileName +{ + BOOL doesExist = NO; + + for (NSMutableDictionary *savedProfile in savedProfilesList) + { + NSString *savedProfileName = (NSString *)[savedProfile valueForKey:@"Name"]; + if ([savedProfileName isEqualToString:profileName]) + { + doesExist = YES; + break; + } + } + + return doesExist; +} + +- (void) updateSelectedProfileName +{ + NSInteger profileID = [inputProfileMenu indexOfSelectedItem]; + NSMutableDictionary *selectedProfile = (NSMutableDictionary *)[inputProfileController content]; + if (profileID < (NSInteger)_defaultProfileListCount || selectedProfile == nil) + { + return; + } + + [[inputProfileMenu selectedItem] setTitle:(NSString *)[selectedProfile valueForKey:@"Name"]]; + [[NSUserDefaults standardUserDefaults] setObject:savedProfilesList forKey:@"Input_SavedProfiles"]; +} + - (void) didEndSettingsSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { [sheet orderOut:self]; @@ -281,6 +309,16 @@ [inputSettingsController setContent:nil]; } +- (void) didEndProfileSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo +{ + [sheet orderOut:self]; +} + +- (void) didEndProfileRenameSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo +{ + [sheet orderOut:self]; +} + #pragma mark InputHIDManagerTarget Protocol - (BOOL) handleHIDQueue:(IOHIDQueueRef)hidQueue { @@ -363,13 +401,13 @@ { if ([item isKindOfClass:[NSArray class]]) { - NSString *commandTag = [self commandTagFromInputList:item]; + NSString *commandTag = [inputManager commandTagFromInputList:item]; if (commandTag != nil) { - NSImage *buttonImage = (NSImage *)[inputPrefProperties valueForKey:commandTag]; + NSImage *buttonImage = (NSImage *)[[inputManager commandIcon] valueForKey:commandTag]; if (buttonImage == nil) { - buttonImage = (NSImage *)[inputPrefProperties valueForKey:@"UNKNOWN COMMAND"]; + buttonImage = (NSImage *)[[inputManager commandIcon] valueForKey:@"UNKNOWN COMMAND"]; } [outCell setTitle:NSLocalizedString(commandTag, nil)]; @@ -405,7 +443,7 @@ { if ([item isKindOfClass:[NSDictionary class]]) { - NSString *commandTag = [self commandTagFromInputList:[outlineView parentForItem:item]]; + NSString *commandTag = [inputManager commandTagFromInputList:[outlineView parentForItem:item]]; NSWindow *theSheet = (NSWindow *)[inputSettingsMappings valueForKey:commandTag]; [outCell setEnabled:(theSheet == nil) ? NO : YES]; } @@ -430,7 +468,7 @@ { if (item == nil) { - NSString *commandTag = [commandTagList objectAtIndex:index]; + NSString *commandTag = [[inputManager commandTagList] objectAtIndex:index]; return [[inputManager inputMappings] valueForKey:commandTag]; } else if ([item isKindOfClass:[NSArray class]]) @@ -457,7 +495,7 @@ if (item == nil) { - numberChildren = [commandTagList count]; + numberChildren = [[inputManager commandTagList] count]; } else if ([item isKindOfClass:[NSArray class]]) { @@ -517,7 +555,7 @@ - (id)outlineView:(NSOutlineView *)outlineView persistentObjectForItem:(id)item { - return [self commandTagFromInputList:item]; + return [inputManager commandTagFromInputList:item]; } - (id)outlineView:(NSOutlineView *)outlineView itemForPersistentObject:(id)object @@ -615,7 +653,7 @@ [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:rowNumber] byExtendingSelection:NO]; NSArray *inputList = (NSArray *)[outlineView itemAtRow:rowNumber]; - [self setConfigInputTargetID:[self commandTagFromInputList:inputList]]; + [self setConfigInputTargetID:[inputManager commandTagFromInputList:inputList]]; [prefWindow makeFirstResponder:self]; } } @@ -650,7 +688,7 @@ const NSInteger rowNumber = [outlineView clickedRow]; NSMutableDictionary *item = (NSMutableDictionary *)[outlineView itemAtRow:rowNumber]; - NSString *commandTag = [self commandTagFromInputList:[outlineView parentForItem:item]]; + NSString *commandTag = [inputManager commandTagFromInputList:[outlineView parentForItem:item]]; NSWindow *theSheet = (NSWindow *)[inputSettingsMappings valueForKey:commandTag]; if (theSheet == nil) @@ -674,4 +712,186 @@ [NSApp endSheet:sheet returnCode:[CocoaDSUtil getIBActionSenderTag:sender]]; } +- (IBAction) profileNew:(id)sender +{ + static NSUInteger untitledCount = 1; + NSString *newProfileName = (untitledCount == 1) ? @"Untitled" : [NSString stringWithFormat:@"Untitled %ld", (unsigned long)untitledCount]; + + while([self doesProfileNameExist:newProfileName]) + { + newProfileName = [NSString stringWithFormat:@"Untitled %ld", (unsigned long)++untitledCount]; + } + + NSMutableDictionary *newProfile = [NSMutableDictionary dictionaryWithObjectsAndKeys: + newProfileName, @"Name", + [NSNumber numberWithBool:NO], @"IsDefaultType", + [[[NSMutableDictionary alloc] initWithDictionary:[inputManager inputMappings] copyItems:YES] autorelease], @"Mappings", + nil]; + + [savedProfilesList addObject:newProfile]; + + NSInteger profileIndex = _defaultProfileListCount + [savedProfilesList count] - 1; + NSMenu *profileMenu = [inputProfileMenu menu]; + NSMenuItem *newProfileMenuItem = [[[NSMenuItem alloc] initWithTitle:newProfileName + action:@selector(profileSelect:) + keyEquivalent:@""] autorelease]; + [newProfileMenuItem setTag:profileIndex]; + [newProfileMenuItem setTarget:self]; + + [profileMenu insertItem:newProfileMenuItem atIndex:profileIndex+1]; + + // Remove the "no items" menu item when the first profile is saved. + if ([savedProfilesList count] == 1) + { + [inputProfileMenu removeItemAtIndex:profileIndex+2]; + } + + [inputProfileMenu selectItemAtIndex:profileIndex+1]; + [self profileSelect:newProfileMenuItem]; + [[NSUserDefaults standardUserDefaults] setObject:savedProfilesList forKey:@"Input_SavedProfiles"]; + + // Give the user a chance to name the new profile. + [self profileRename:nil]; +} + +- (IBAction) profileView:(id)sender +{ + [NSApp beginSheet:inputProfileSheet + modalForWindow:prefWindow + modalDelegate:self + didEndSelector:@selector(didEndProfileSheet:returnCode:contextInfo:) + contextInfo:nil]; +} + +- (IBAction) profileApply:(id)sender +{ + NSMutableDictionary *selectedProfile = (NSMutableDictionary *)[inputProfileController content]; + NSMutableDictionary *profileMappings = (NSMutableDictionary *)[selectedProfile valueForKey:@"Mappings"]; + + if (profileMappings != nil) + { + // Use setMappingsWithMappings: instead of replacing the input mappings + // completely since we need to keep this particular pointer address for + // the inputMappings dictionary. If we don't do this, the outline view + // will desync. + [inputManager setMappingsWithMappings:profileMappings]; + [inputPrefOutlineView reloadData]; + [inputManager writeDefaultsInputMappings]; + } +} + +- (IBAction) profileRename:(id)sender +{ + [NSApp beginSheet:inputProfileRenameSheet + modalForWindow:prefWindow + modalDelegate:self + didEndSelector:@selector(didEndProfileRenameSheet:returnCode:contextInfo:) + contextInfo:nil]; +} + +- (IBAction) profileSave:(id)sender +{ + NSMutableDictionary *selectedProfile = (NSMutableDictionary *)[inputProfileController content]; + if (selectedProfile == nil) + { + return; + } + + [selectedProfile setValue:[[[NSMutableDictionary alloc] initWithDictionary:[inputManager inputMappings] copyItems:YES] autorelease] forKey:@"Mappings"]; + [[NSUserDefaults standardUserDefaults] setObject:savedProfilesList forKey:@"Input_SavedProfiles"]; +} + +- (IBAction) profileDelete:(id)sender +{ + NSMutableDictionary *selectedProfile = (NSMutableDictionary *)[inputProfileController content]; + if (selectedProfile == nil) + { + return; + } + + NSInteger profileIndex = [inputProfileMenu indexOfSelectedItem] - 1; + NSMenu *profileMenu = [inputProfileMenu menu]; + + [profileMenu removeItemAtIndex:[inputProfileMenu indexOfSelectedItem]]; + [savedProfilesList removeObjectAtIndex:(profileIndex - _defaultProfileListCount)]; + [inputProfileMenu selectItemAtIndex:0]; + + // Add the "no items" menu item if there are no profiles saved. + if ([savedProfilesList count] < 1) + { + NSMenuItem *noSavedConfigItem = [[[NSMenuItem alloc] initWithTitle:NSSTRING_INPUTPREF_NO_SAVED_PROFILES + action:NULL + keyEquivalent:@""] autorelease]; + [noSavedConfigItem setEnabled:NO]; + [profileMenu insertItem:noSavedConfigItem atIndex:profileIndex+1]; + } + else // Update the profile indices in the menu tags. + { + for (NSUInteger i = 0; i < [savedProfilesList count]; i++) + { + [[profileMenu itemAtIndex:_defaultProfileListCount+i+1] setTag:_defaultProfileListCount+i]; + } + } + + [self profileSelect:[inputProfileMenu itemAtIndex:0]]; + [[NSUserDefaults standardUserDefaults] setObject:savedProfilesList forKey:@"Input_SavedProfiles"]; +} + +- (IBAction) profileSelect:(id)sender +{ + NSInteger profileID = [CocoaDSUtil getIBActionSenderTag:sender]; + NSArray *profileList = nil; + + if (profileID < 0 || profileID >= (NSInteger)(_defaultProfileListCount + [savedProfilesList count])) + { + return; + } + + if (profileID < (NSInteger)_defaultProfileListCount) // Select one of the default profiles + { + NSDictionary *defaultKeyMappingsDict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultKeyMappings" ofType:@"plist"]]; + profileList = [defaultKeyMappingsDict valueForKey:@"DefaultInputProfiles"]; + } + else // Select one of the saved configs + { + profileList = savedProfilesList; + } + + [inputProfilePreviousButton setTag:profileID-1]; + [inputProfilePreviousButton setEnabled:(profileID > 0) ? YES : NO]; + [inputProfileNextButton setTag:profileID+1]; + [inputProfileNextButton setEnabled:(profileID < ((NSInteger)_defaultProfileListCount + (NSInteger)[savedProfilesList count] - 1)) ? YES : NO]; + + if (![sender isMemberOfClass:[NSMenuItem class]]) + { + [inputProfileMenu selectItemAtIndex:(profileID < (NSInteger)_defaultProfileListCount) ? profileID : profileID+1]; + } + + [inputProfileController setContent:[profileList objectAtIndex:(profileID < (NSInteger)_defaultProfileListCount) ? profileID : (profileID - _defaultProfileListCount)]]; + [[inputProfileController profileOutlineView] reloadData]; + [[inputProfileController profileOutlineView] expandItem:nil expandChildren:YES]; +} + +- (IBAction) closeProfileSheet:(id)sender +{ + NSWindow *sheet = [(NSControl *)sender window]; + [sheet makeFirstResponder:nil]; // Force end of editing of any text fields. + [NSApp endSheet:sheet returnCode:[CocoaDSUtil getIBActionSenderTag:sender]]; +} + +- (IBAction) closeProfileRenameSheet:(id)sender +{ + NSWindow *sheet = [(NSControl *)sender window]; + [sheet makeFirstResponder:nil]; // Force end of editing of any text fields. + [NSApp endSheet:sheet returnCode:[CocoaDSUtil getIBActionSenderTag:sender]]; +} + +#pragma mark NSControl Delegate Methods + +- (void)controlTextDidEndEditing:(NSNotification *)aNotification +{ + // Called when the profile view sheet changes the profile name + [self updateSelectedProfileName]; +} + @end