1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/system.h"
24 #include "common/events.h"
25 #include "common/file.h"
26
27 #include "sci/sci.h"
28 #include "sci/event.h"
29 #include "sci/console.h"
30 #include "sci/engine/state.h"
31 #include "sci/engine/kernel.h"
32 #ifdef ENABLE_SCI32
33 #include "sci/graphics/cursor32.h"
34 #include "sci/graphics/frameout.h"
35 #endif
36 #include "sci/graphics/screen.h"
37
38 namespace Sci {
39
40 struct ScancodeRow {
41 int offset;
42 const char *keys;
43 };
44
45 static const ScancodeRow scancodeAltifyRows[] = {
46 { 0x10, "QWERTYUIOP[]" },
47 { 0x1e, "ASDFGHJKL;'\\" },
48 { 0x2c, "ZXCVBNM,./" }
49 };
50
51 static const byte codePageMap88591ToDOS[0x80] = {
52 '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x8x
53 '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x9x
54 '?', 0xad, 0x9b, 0x9c, '?', 0x9d, '?', 0x9e, '?', '?', 0xa6, 0xae, 0xaa, '?', '?', '?', // 0xAx
55 '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 0xa7, 0xaf, 0xac, 0xab, '?', 0xa8, // 0xBx
56 '?', '?', '?', '?', 0x8e, 0x8f, 0x92, 0x80, '?', 0x90, '?', '?', '?', '?', '?', '?', // 0xCx
57 '?', 0xa5, '?', '?', '?', '?', 0x99, '?', '?', '?', '?', '?', 0x9a, '?', '?', 0xe1, // 0xDx
58 0x85, 0xa0, 0x83, '?', 0x84, 0x86, 0x91, 0x87, 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, // 0xEx
59 '?', 0xa4, 0x95, 0xa2, 0x93, '?', 0x94, '?', '?', 0x97, 0xa3, 0x96, 0x81, '?', '?', 0x98 // 0xFx
60 };
61
62 struct SciKeyConversion {
63 Common::KeyCode scummVMKey;
64 int sciKeyNumlockOff;
65 int sciKeyNumlockOn;
66 };
67
68 // Translation table for UTF16->Win1250 (Polish encoding)
69 // Covers characters 0x80-0xFF.
70 // '0x0' means end of list, 0x1 means 'unused'
71 static const uint16 UTF16toWin1250[] = {
72 0x20ac, 0x0001, 0x201a, 0x0001, 0x201e, 0x2026, 0x2020, 0x2021, // 0x80
73 0x0001, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
74 0x0001, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, // 0x90
75 0x0001, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
76 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7, // 0xa0
77 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
78 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // 0xb0
79 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
80 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, // 0xc0
81 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
82 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, // 0xd0
83 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
84 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, // 0xe0
85 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
86 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, // 0xf0
87 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
88 0
89 };
90
91 // Table for transferring Alt+<Key> into Polish symbols
92 // Note, that 'A' and 'S' are swapped with lowercase. This is due to the fact
93 // that we use Alt+a for aspect ratio correction and Alt+s for screenshot saving
94 // and we do that in the SDL backend. There are no words starting with 'A' and
95 // very few starting with S, thus, this is a viable compromise
96 static const byte PolishAltifytoWin1250[] = {
97 'e', 0xea, 'o', 0xf3, 'a', 0xa5, 's', 0x8c, 'l', 0xb3, 'z', 0xbf, 'x', 0x9f, 'c', 0xe6, 'n', 0xF1,
98 'E', 0xca, 'O', 0xd3, 'A', 0xb9, 'S', 0x9c, 'L', 0xa3, 'Z', 0xaf, 'X', 0x8f, 'C', 0xc6, 'N', 0xD1,
99 0
100 };
101
102 static const SciKeyConversion keyMappings[] = {
103 { Common::KEYCODE_UP , kSciKeyUp , kSciKeyUp },
104 { Common::KEYCODE_DOWN , kSciKeyDown , kSciKeyDown },
105 { Common::KEYCODE_RIGHT , kSciKeyRight , kSciKeyRight },
106 { Common::KEYCODE_LEFT , kSciKeyLeft , kSciKeyLeft },
107 { Common::KEYCODE_INSERT , kSciKeyInsert , kSciKeyInsert },
108 { Common::KEYCODE_HOME , kSciKeyHome , kSciKeyHome },
109 { Common::KEYCODE_END , kSciKeyEnd , kSciKeyEnd },
110 { Common::KEYCODE_PAGEUP , kSciKeyPageUp , kSciKeyPageUp },
111 { Common::KEYCODE_PAGEDOWN , kSciKeyPageDown , kSciKeyPageDown },
112 { Common::KEYCODE_DELETE , kSciKeyDelete , kSciKeyDelete },
113 { Common::KEYCODE_KP0 , kSciKeyInsert , '0' },
114 { Common::KEYCODE_KP1 , kSciKeyEnd , '1' },
115 { Common::KEYCODE_KP2 , kSciKeyDown , '2' },
116 { Common::KEYCODE_KP3 , kSciKeyPageDown , '3' },
117 { Common::KEYCODE_KP4 , kSciKeyLeft , '4' },
118 { Common::KEYCODE_KP5 , kSciKeyCenter , '5' },
119 { Common::KEYCODE_KP6 , kSciKeyRight , '6' },
120 { Common::KEYCODE_KP7 , kSciKeyHome , '7' },
121 { Common::KEYCODE_KP8 , kSciKeyUp , '8' },
122 { Common::KEYCODE_KP9 , kSciKeyPageUp , '9' },
123 { Common::KEYCODE_KP_PERIOD , kSciKeyDelete , '.' },
124 { Common::KEYCODE_KP_ENTER , kSciKeyEnter , kSciKeyEnter },
125 { Common::KEYCODE_KP_PLUS , '+' , '+' },
126 { Common::KEYCODE_KP_MINUS , '-' , '-' },
127 { Common::KEYCODE_KP_MULTIPLY , '*' , '*' },
128 { Common::KEYCODE_KP_DIVIDE , '/' , '/' }
129 };
130
131 struct MouseEventConversion {
132 Common::EventType commonType;
133 SciEventType sciType;
134 };
135
136 static const MouseEventConversion mouseEventMappings[] = {
137 { Common::EVENT_LBUTTONDOWN , kSciEventMousePress },
138 { Common::EVENT_RBUTTONDOWN , kSciEventMousePress },
139 { Common::EVENT_MBUTTONDOWN , kSciEventMousePress },
140 { Common::EVENT_LBUTTONUP , kSciEventMouseRelease },
141 { Common::EVENT_RBUTTONUP , kSciEventMouseRelease },
142 { Common::EVENT_MBUTTONUP , kSciEventMouseRelease }
143 };
144
EventManager(bool fontIsExtended)145 EventManager::EventManager(bool fontIsExtended) :
146 _fontIsExtended(fontIsExtended)
147 #ifdef ENABLE_SCI32
148 , _hotRectanglesActive(false)
149 #endif
150 {}
151
~EventManager()152 EventManager::~EventManager() {
153 }
154
155 /**
156 * Calculates the IBM keyboard alt-key scancode of a printable character.
157 */
altify(char ch)158 static int altify(char ch) {
159 if (g_sci->getLanguage() == Common::PL_POL) {
160 const byte *p = PolishAltifytoWin1250;
161
162 while (*p) {
163 if ((byte)ch == *p)
164 return *(p + 1);
165
166 p += 2;
167 }
168 }
169
170 const char c = toupper(ch);
171
172 for (int row = 0; row < ARRAYSIZE(scancodeAltifyRows); ++row) {
173 const char *keys = scancodeAltifyRows[row].keys;
174 int offset = scancodeAltifyRows[row].offset;
175
176 while (*keys) {
177 if (*keys == c)
178 return offset << 8;
179
180 ++offset;
181 ++keys;
182 }
183 }
184
185 return ch;
186 }
187
getScummVMEvent()188 SciEvent EventManager::getScummVMEvent() {
189 #ifdef ENABLE_SCI32
190 SciEvent input = { kSciEventNone, kSciKeyModNone, 0, Common::Point(), Common::Point(), -1 };
191 SciEvent noEvent = { kSciEventNone, kSciKeyModNone, 0, Common::Point(), Common::Point(), -1 };
192 #else
193 SciEvent input = { kSciEventNone, kSciKeyModNone, 0, Common::Point() };
194 SciEvent noEvent = { kSciEventNone, kSciKeyModNone, 0, Common::Point() };
195 #endif
196
197 Common::EventManager *em = g_system->getEventManager();
198 Common::Event ev;
199
200 // SCI does not generate separate events for mouse movement (it puts the
201 // current mouse position on every event, including non-mouse events), so
202 // skip past all mousemove events in the event queue
203 bool found;
204 do {
205 found = em->pollEvent(ev);
206 } while (found && ev.type == Common::EVENT_MOUSEMOVE);
207
208 Common::Point mousePos = em->getMousePos();
209
210 #if ENABLE_SCI32
211 if (getSciVersion() >= SCI_VERSION_2) {
212 const GfxFrameout *gfxFrameout = g_sci->_gfxFrameout;
213
214 // This will clamp `mousePos` according to the restricted zone,
215 // so any cursor or screen item associated with the mouse position
216 // does not bounce when it hits the edge (or ignore the edge)
217 g_sci->_gfxCursor32->deviceMoved(mousePos);
218
219 Common::Point mousePosSci = mousePos;
220 mulru(mousePosSci, Ratio(gfxFrameout->getScriptWidth(), gfxFrameout->getScreenWidth()), Ratio(gfxFrameout->getScriptHeight(), gfxFrameout->getScreenHeight()));
221 noEvent.mousePosSci = input.mousePosSci = mousePosSci;
222
223 if (_hotRectanglesActive) {
224 checkHotRectangles(mousePosSci);
225 }
226 } else {
227 #endif
228 g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x);
229 #if ENABLE_SCI32
230 }
231 #endif
232
233 noEvent.mousePos = input.mousePos = mousePos;
234
235 if (!found || ev.type == Common::EVENT_MOUSEMOVE) {
236 int modifiers = em->getModifierState();
237 if (modifiers & Common::KBD_ALT)
238 noEvent.modifiers |= kSciKeyModAlt;
239 if (modifiers & Common::KBD_CTRL)
240 noEvent.modifiers |= kSciKeyModCtrl;
241 if (modifiers & Common::KBD_SHIFT)
242 noEvent.modifiers |= kSciKeyModShift;
243
244 return noEvent;
245 }
246 if (ev.type == Common::EVENT_QUIT || ev.type == Common::EVENT_RETURN_TO_LAUNCHER) {
247 input.type = kSciEventQuit;
248 return input;
249 }
250
251 int scummVMKeyFlags;
252
253 switch (ev.type) {
254 case Common::EVENT_KEYDOWN:
255 case Common::EVENT_KEYUP:
256 // Use keyboard modifiers directly in case this is a keyboard event
257 scummVMKeyFlags = ev.kbd.flags;
258 break;
259 default:
260 // Otherwise get them from EventManager
261 scummVMKeyFlags = em->getModifierState();
262 break;
263 }
264
265 // Caps lock and scroll lock are not handled here because we already
266 // handle upper case keys elsewhere, and scroll lock doesn't seem to
267 // ever be used
268 input.modifiers = kSciKeyModNone;
269 if (scummVMKeyFlags & Common::KBD_ALT)
270 input.modifiers |= kSciKeyModAlt;
271 if (scummVMKeyFlags & Common::KBD_CTRL)
272 input.modifiers |= kSciKeyModCtrl;
273 if (scummVMKeyFlags & Common::KBD_SHIFT)
274 input.modifiers |= kSciKeyModShift;
275
276 // Handle mouse events
277 for (int i = 0; i < ARRAYSIZE(mouseEventMappings); i++) {
278 if (mouseEventMappings[i].commonType == ev.type) {
279 input.type = mouseEventMappings[i].sciType;
280 // Sierra passed keyboard modifiers for mouse events, too.
281
282 // Sierra also set certain modifiers within their mouse interrupt handler
283 // This whole thing was probably meant for people using a mouse, that only featured 1 button
284 // So the user was able to press Ctrl and click the mouse button to create a right click.
285 switch (ev.type) {
286 case Common::EVENT_RBUTTONDOWN: // right button
287 case Common::EVENT_RBUTTONUP:
288 input.modifiers |= kSciKeyModShift; // this value was hardcoded in the mouse interrupt handler
289 break;
290 case Common::EVENT_MBUTTONDOWN: // middle button
291 case Common::EVENT_MBUTTONUP:
292 input.modifiers |= kSciKeyModCtrl; // this value was hardcoded in the mouse interrupt handler
293 break;
294 default:
295 break;
296 }
297 return input;
298 }
299 }
300
301 // Handle keyboard events for the rest of the function
302 if (ev.type != Common::EVENT_KEYDOWN && ev.type != Common::EVENT_KEYUP) {
303 return noEvent;
304 }
305
306 // The IBM keyboard driver prior to SCI1.1 only sent keydown events to the
307 // interpreter
308 if (ev.type != Common::EVENT_KEYDOWN && getSciVersion() < SCI_VERSION_1_1) {
309 return noEvent;
310 }
311
312 const Common::KeyCode scummVMKeycode = ev.kbd.keycode;
313
314 input.character = ev.kbd.ascii;
315
316 if (scummVMKeycode >= Common::KEYCODE_KP0 && scummVMKeycode <= Common::KEYCODE_KP9 && !(scummVMKeyFlags & Common::KBD_NUM)) {
317 // TODO: Leaky abstractions from SDL should not be handled in game
318 // engines!
319 // SDL may provide a character value for numpad keys even if numlock is
320 // turned off, but arrow/navigation keys won't get mapped below if a
321 // character value is provided
322 input.character = 0;
323 }
324
325 if (input.character && input.character <= 0xFF) {
326 // Extended characters need to be converted to the old to DOS CP850/437
327 // character sets for multilingual games
328 if (input.character >= 0x80 && input.character <= 0xFF) {
329 // SSCI accepted all input scan codes, regardless of locale, and
330 // just didn't display any characters that were missing from fonts
331 // used by text input controls. We intentionally filter them out
332 // entirely for non-multilingual games here instead, so we can have
333 // better error detection for bugs in the text controls
334 if (!_fontIsExtended) {
335 return noEvent;
336 }
337
338 input.character = codePageMap88591ToDOS[input.character & 0x7f];
339 }
340
341 if (scummVMKeycode == Common::KEYCODE_TAB) {
342 input.character = kSciKeyTab;
343 if (scummVMKeyFlags & Common::KBD_SHIFT)
344 input.character = kSciKeyShiftTab;
345 }
346
347 if (scummVMKeycode == Common::KEYCODE_DELETE)
348 input.character = kSciKeyDelete;
349 } else if (scummVMKeycode >= Common::KEYCODE_F1 && scummVMKeycode <= Common::KEYCODE_F10) {
350 if (scummVMKeyFlags & Common::KBD_SHIFT)
351 input.character = kSciKeyShiftF1 + ((scummVMKeycode - Common::KEYCODE_F1) << 8);
352 else
353 input.character = kSciKeyF1 + ((scummVMKeycode - Common::KEYCODE_F1) << 8);
354 } else {
355 // Arrow keys, numpad keys, etc.
356 for (int i = 0; i < ARRAYSIZE(keyMappings); i++) {
357 if (keyMappings[i].scummVMKey == scummVMKeycode) {
358 const bool numlockOn = (ev.kbd.flags & Common::KBD_NUM);
359 input.character = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff;
360 break;
361 }
362 }
363
364 if (g_sci->getLanguage() == Common::RU_RUS) {
365 // Convert UTF16 to CP866
366 if (input.character >= 0x400 && input.character <= 0x4ff) {
367 if (input.character >= 0x440)
368 input.character = input.character - 0x410 + 0xb0;
369 else
370 input.character = input.character - 0x410 + 0x80;
371 }
372 } else if (g_sci->getLanguage() == Common::PL_POL) {
373 for (int i = 0; UTF16toWin1250[i]; i++)
374 if (UTF16toWin1250[i] == input.character) {
375 input.character = 0x80 + i;
376 break;
377 }
378 } else if (g_sci->getLanguage() == Common::HE_ISR) {
379 if (input.character >= 0x05d0 && input.character <= 0x05ea)
380 // convert to WIN-1255
381 input.character = input.character - 0x05d0 + 0xe0;
382 }
383 }
384
385 // TODO: Leaky abstractions from SDL should not be handled in game engines!
386 // When Ctrl and Alt are pressed together with a printable key, SDL1 on
387 // Linux will give us a control character instead of the printable
388 // character we need to convert to an alt scancode
389 if ((scummVMKeyFlags & Common::KBD_ALT) && input.character > 0 && input.character < 27)
390 input.character += 96; // 0x01 -> 'a'
391
392 if (scummVMKeyFlags & Common::KBD_ALT) {
393 input.character = altify(input.character & 0xFF);
394 } else if ((scummVMKeyFlags & Common::KBD_NON_STICKY) == Common::KBD_CTRL && input.character >= 'a' && input.character <= 'z') {
395 // In SSCI, Ctrl+<key> generates ASCII control characters, but the
396 // backends usually give us a printable character + Ctrl flag, so
397 // convert this combo back into what is expected by game scripts
398 input.character -= 96;
399 }
400
401 // In SCI1.1, if only a modifier key is pressed, the IBM keyboard driver
402 // sends an event the same as if a key had been released
403 if (getSciVersion() != SCI_VERSION_1_1 && !input.character) {
404 return noEvent;
405 } else if (!input.character || ev.type == Common::EVENT_KEYUP) {
406 input.type = kSciEventKeyUp;
407
408 // SCI32 includes the released key character code in keyup messages, but
409 // the IBM keyboard driver in SCI1.1 sends a special character value
410 // instead. This is necessary to prevent at least Island of Dr Brain
411 // from processing keyup events as though they were keydown events in
412 // the word search puzzle
413 if (getSciVersion() == SCI_VERSION_1_1) {
414 input.character = 0x8000;
415 }
416 } else {
417 input.type = kSciEventKeyDown;
418 }
419
420 return input;
421 }
422
updateScreen()423 void EventManager::updateScreen() {
424 // Update the screen here, since it's called very often.
425 // Throttle the screen update rate to 60fps.
426 EngineState *s = g_sci->getEngineState();
427 if (g_system->getMillis() - s->_screenUpdateTime >= 1000 / 60) {
428 g_system->updateScreen();
429 s->_screenUpdateTime = g_system->getMillis();
430 // Throttle the checking of shouldQuit() to 60fps as well, since
431 // Engine::shouldQuit() invokes 2 virtual functions
432 // (EventManager::shouldQuit() and EventManager::shouldReturnToLauncher()),
433 // which is very expensive to invoke constantly without any
434 // throttling at all.
435 if (g_engine->shouldQuit())
436 s->abortScriptProcessing = kAbortQuitGame;
437 }
438 }
439
getSciEvent(SciEventType mask)440 SciEvent EventManager::getSciEvent(SciEventType mask) {
441 #ifdef ENABLE_SCI32
442 SciEvent event = { kSciEventNone, kSciKeyModNone, 0, Common::Point(), Common::Point(), -1 };
443 #else
444 SciEvent event = { kSciEventNone, kSciKeyModNone, 0, Common::Point() };
445 #endif
446
447 if (getSciVersion() < SCI_VERSION_2) {
448 updateScreen();
449 }
450
451 // Get all queued events from graphics driver
452 do {
453 event = getScummVMEvent();
454 if (event.type != kSciEventNone)
455 _events.push_back(event);
456 } while (event.type != kSciEventNone);
457
458 // Search for matching event in queue
459 Common::List<SciEvent>::iterator iter = _events.begin();
460 while (iter != _events.end() && !(iter->type & mask))
461 ++iter;
462
463 if (iter != _events.end()) {
464 // Event found
465 event = *iter;
466
467 // If not peeking at the queue, remove the event
468 if (!(mask & kSciEventPeek))
469 _events.erase(iter);
470 } else {
471 // No event found: we must return a kSciEventNone event.
472
473 // Because event.type is kSciEventNone already here,
474 // there is no need to change it.
475 }
476
477 return event;
478 }
479
flushEvents()480 void EventManager::flushEvents() {
481 Common::EventManager *em = g_system->getEventManager();
482 Common::Event event;
483 while (em->pollEvent(event)) {}
484 _events.clear();
485 }
486
487 #ifdef ENABLE_SCI32
setHotRectanglesActive(const bool active)488 void EventManager::setHotRectanglesActive(const bool active) {
489 _hotRectanglesActive = active;
490 }
491
setHotRectangles(const Common::Array<Common::Rect> & rects)492 void EventManager::setHotRectangles(const Common::Array<Common::Rect> &rects) {
493 _hotRects = rects;
494 _activeRectIndex = -1;
495 }
496
checkHotRectangles(const Common::Point & mousePosition)497 void EventManager::checkHotRectangles(const Common::Point &mousePosition) {
498 int lastActiveRectIndex = _activeRectIndex;
499 _activeRectIndex = -1;
500
501 for (int16 i = 0; i < (int16)_hotRects.size(); ++i) {
502 if (_hotRects[i].contains(mousePosition)) {
503 _activeRectIndex = i;
504 if (i != lastActiveRectIndex) {
505 SciEvent hotRectEvent;
506 hotRectEvent.type = kSciEventHotRectangle;
507 hotRectEvent.hotRectangleIndex = i;
508 _events.push_front(hotRectEvent);
509 break;
510 }
511
512 lastActiveRectIndex = _activeRectIndex;
513 }
514 }
515
516 if (lastActiveRectIndex != _activeRectIndex && lastActiveRectIndex != -1) {
517 _activeRectIndex = -1;
518 SciEvent hotRectEvent;
519 hotRectEvent.type = kSciEventHotRectangle;
520 hotRectEvent.hotRectangleIndex = -1;
521 _events.push_front(hotRectEvent);
522 }
523 }
524 #endif
525
526 } // End of namespace Sci
527