1 ////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Nestopia - NES/Famicom emulator written in C++
4 //
5 // Copyright (C) 2003-2008 Martin Freij
6 //
7 // This file is part of Nestopia.
8 //
9 // Nestopia is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Nestopia is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Nestopia; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 ////////////////////////////////////////////////////////////////////////////////////////
24 
25 #include "NstIoScreen.hpp"
26 #include "NstResourceString.hpp"
27 #include "NstResourceClipboard.hpp"
28 #include "NstSystemKeyboard.hpp"
29 #include "NstManager.hpp"
30 #include "NstManagerInput.hpp"
31 
32 namespace Nestopia
33 {
34 	namespace Managers
35 	{
Clipboard(Emulator & e,Window::Menu & m)36 		Input::Clipboard::Clipboard(Emulator& e,Window::Menu& m)
37 		:
38 		Manager (e,m),
39 		paste   (false)
40 		{
41 			static const Window::Menu::CmdHandler::Entry<Clipboard> commands[] =
42 			{
43 				{ IDM_MACHINE_EXT_KEYBOARD_PASTE, &Clipboard::OnCmdMachineKeyboardPaste }
44 			};
45 
46 			menu.Commands().Add( this, commands );
47 
48 			static const Window::Menu::PopupHandler::Entry<Clipboard> popups[] =
49 			{
50 				{ Window::Menu::PopupHandler::Pos<IDM_POS_MACHINE,IDM_POS_MACHINE_EXT,IDM_POS_MACHINE_EXT_KEYBOARD>::ID, &Clipboard::OnMenuKeyboard }
51 			};
52 
53 			menu.Popups().Add( this, popups );
54 
55 			HeapString name;
56 			menu[IDM_MACHINE_EXT_KEYBOARD_PASTE].Text() >> name;
57 			menu[IDM_MACHINE_EXT_KEYBOARD_PASTE].Text() << (name << '\t' << System::Keyboard::GetName( VK_F12 ));
58 		}
59 
Clear()60 		void Input::Clipboard::Clear()
61 		{
62 			paste = false;
63 			buffer.Destroy();
64 		}
65 
CanPaste() const66 		bool Input::Clipboard::CanPaste() const
67 		{
68 			return emulator.IsGameOn() && buffer.Empty() && Resource::Clipboard::Available() &&
69 			(
70 				Nes::Input(emulator).IsControllerConnected( Nes::Input::FAMILYKEYBOARD ) ||
71 				Nes::Input(emulator).IsControllerConnected( Nes::Input::SUBORKEYBOARD  )
72 			);
73 		}
74 
Query(const uchar * const NST_RESTRICT keyboard,const Type type)75 		uint Input::Clipboard::Query(const uchar* const NST_RESTRICT keyboard,const Type type)
76 		{
77 			const bool prev = paste;
78 			paste = false;
79 
80 			if (buffer.Empty())
81 			{
82 				if (prev || (keyboard[DIK_F12] & 0x80U))
83 				{
84 					Resource::Clipboard resource;
85 
86 					if (wcstring string = resource)
87 					{
88 						pos = 0;
89 						releasing = 0;
90 						hold = 0;
91 						shifted = false;
92 
93 						bool kana = false;
94 
95 						for (wchar_t p; '\0' != (p = *string); ++string)
96 						{
97 							bool mode = false;
98 
99 							if (p < 32)
100 							{
101 								if (p != '\r')
102 									continue;
103 							}
104 							else if (p >= 'A' && p <= 'Z')
105 							{
106 								p = p - 'A' + 'a';
107 							}
108 							else if (p > 122)
109 							{
110 								if (p == 165) // ''
111 								{
112 									p = '\\';
113 								}
114 								else if (type == SUBOR)
115 								{
116 									if (p > 125)
117 										continue;
118 								}
119 								else if (p > 0xFF00)
120 								{
121 									switch (p)
122 									{
123 										case 0xFF71: p = '1';  break;
124 										case 0xFF72: p = '2';  break;
125 										case 0xFF73: p = '3';  break;
126 										case 0xFF74: p = '4';  break;
127 										case 0xFF75: p = '5';  break;
128 
129 										case 0xFF67: p = '!';  break;
130 										case 0xFF68: p = '\"'; break;
131 										case 0xFF69: p = '#';  break;
132 										case 0xFF6A: p = '$';  break;
133 										case 0xFF6B: p = '%';  break;
134 
135 										case 0xFF6F: p = 'c' | 0x80; break;
136 
137 										case 0xFF76: p = 'q';  break;
138 										case 0xFF77: p = 'w';  break;
139 										case 0xFF78: p = 'e';  break;
140 										case 0xFF79: p = 'r';  break;
141 										case 0xFF7A: p = 't';  break;
142 
143 										case 0xFF9E:
144 
145 											if (buffer.Length())
146 												buffer.Back() |= 0x100;
147 
148 											continue;
149 
150 										case 0xFF9F:
151 
152 											if (buffer.Length())
153 												buffer.Back() |= 0x80;
154 
155 											continue;
156 
157 										case 0xFF7B: p = 'a';  break;
158 										case 0xFF7C: p = 's';  break;
159 										case 0xFF7D: p = 'd';  break;
160 										case 0xFF7E: p = 'f';  break;
161 										case 0xFF7F: p = 'g';  break;
162 
163 										case 0xFF80: p = 'z';  break;
164 										case 0xFF81: p = 'x';  break;
165 										case 0xFF82: p = 'c';  break;
166 										case 0xFF83: p = 'v';  break;
167 										case 0xFF84: p = 'b';  break;
168 
169 										case 0xFF85: p = '6';  break;
170 										case 0xFF86: p = '7';  break;
171 										case 0xFF87: p = '8';  break;
172 										case 0xFF88: p = '9';  break;
173 										case 0xFF89: p = '0';  break;
174 
175 										case 0xFF8A: p = 'y';  break;
176 										case 0xFF8B: p = 'u';  break;
177 										case 0xFF8C: p = 'i';  break;
178 										case 0xFF8D: p = 'o';  break;
179 										case 0xFF8E: p = 'p';  break;
180 
181 										case 0xFF8F: p = 'h';  break;
182 										case 0xFF90: p = 'j';  break;
183 										case 0xFF91: p = 'k';  break;
184 										case 0xFF92: p = 'l';  break;
185 										case 0xFF93: p = ';';  break;
186 
187 										case 0xFF94: p = 'n';  break;
188 										case 0xFF95: p = 'm';  break;
189 										case 0xFF96: p = ',';  break;
190 
191 										case 0xFF6C: p = 'n' | 0x80; break;
192 										case 0xFF6D: p = 'm' | 0x80; break;
193 										case 0xFF6E: p = '<';        break;
194 
195 										case 0xFF97: p = '-';  break;
196 										case 0xFF98: p = '^';  break;
197 										case 0xFF99: p = '\\'; break;
198 										case 0xFF9A: p = '@';  break;
199 										case 0xFF9B: p = '[';  break;
200 
201 										case 0xFF9C: p = '.';  break;
202 										case 0xFF66: p = '-';  break;
203 										case 0xFF9D: p = '\t'; break;
204 
205 										case 0xFF61: p = ']';        break;
206 										case 0xFF62: p = '[' | 0x80; break;
207 										case 0xFF63: p = ']' | 0x80; break;
208 
209 										default: continue;
210 									}
211 
212 									mode = true;
213 								}
214 								else
215 								{
216 									continue;
217 								}
218 							}
219 
220 							if (kana != mode)
221 							{
222 								kana = mode;
223 								buffer << char(0xFF);
224 							}
225 
226 							buffer << (p);
227 						}
228 
229 						if (kana)
230 							buffer << char(0xFF);
231 
232 						if (buffer.Length())
233 							Io::Screen() << Resource::String( IDS_SCREEN_TEXT_PASTE ).Invoke( buffer.Length() );
234 					}
235 				}
236 			}
237 			else
238 			{
239 				if (keyboard[DIK_ESCAPE] & 0x80U)
240 					Clear();
241 			}
242 
243 			return buffer.Length();
244 		}
245 
OnCmdMachineKeyboardPaste(uint)246 		void Input::Clipboard::OnCmdMachineKeyboardPaste(uint)
247 		{
248 			paste = CanPaste();
249 			Resume();
250 		}
251 
OnMenuKeyboard(const Window::Menu::PopupHandler::Param & param)252 		void Input::Clipboard::OnMenuKeyboard(const Window::Menu::PopupHandler::Param& param)
253 		{
254 			param.menu[IDM_MACHINE_EXT_KEYBOARD_PASTE].Enable( !param.show || CanPaste() );
255 		}
256 
257 		#ifdef NST_MSVC_OPTIMIZE
258 		#pragma optimize("t", on)
259 		#endif
260 
operator ++()261 		void Input::Clipboard::operator ++ ()
262 		{
263 			hold = (hold + 1) & 7;
264 
265 			if (!hold)
266 			{
267 				shifted = false;
268 				releasing = 32;
269 
270 				if (++pos == buffer.Length())
271 					Clear();
272 			}
273 		}
274 
275 		#ifdef NST_MSVC_OPTIMIZE
276 		#pragma optimize("", on)
277 		#endif
278 	}
279 }
280