00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038
00039 #include "stratagus.h"
00040 #include "video.h"
00041 #include "sound.h"
00042 #include "sound_server.h"
00043 #include "unittype.h"
00044 #include "player.h"
00045 #include "unit.h"
00046 #include "interface.h"
00047 #include "cursor.h"
00048 #include "ui.h"
00049 #include "menus.h"
00050 #include "script.h"
00051 #include "map.h"
00052 #include "minimap.h"
00053 #include "network.h"
00054 #include "font.h"
00055 #include "results.h"
00056 #include "video.h"
00057 #include "iolib.h"
00058 #include "replay.h"
00059 #include "ai.h"
00060 #include "widgets.h"
00061 #include "particle.h"
00062
00063
00064
00065
00066
00068 #define SCROLL_UP 15
00070 #define SCROLL_DOWN (Video.Height - 16)
00072 #define SCROLL_LEFT 15
00074 #define SCROLL_RIGHT (Video.Width - 16)
00075
00076
00077
00078
00079
00080 static int SavedMapPositionX[3];
00081 static int SavedMapPositionY[3];
00082 static char Input[80];
00083 static int InputIndex;
00084 static char InputStatusLine[99];
00085 std::string DefaultGroupKeys = "0123456789`";
00086 std::string UiGroupKeys = DefaultGroupKeys;
00087 bool GameRunning;
00088 bool GamePaused;
00089 bool GameObserve;
00090 char SkipGameCycle;
00091 char BigMapMode;
00092 enum _iface_state_ InterfaceState;
00093 bool GodMode;
00094 enum _key_state_ KeyState;
00095
00096
00097
00098
00099
00103 static void ShowInput(void)
00104 {
00105 char *input;
00106
00107 sprintf_s(InputStatusLine, sizeof(InputStatusLine), _("MESSAGE:%s~!_"), Input);
00108 input = InputStatusLine;
00109
00110 while (UI.StatusLine.Font->Width(input) > UI.StatusLine.Width) {
00111 ++input;
00112 }
00113 KeyState = KeyStateCommand;
00114 UI.StatusLine.Clear();
00115 UI.StatusLine.Set(input);
00116 KeyState = KeyStateInput;
00117 }
00118
00122 static void UiBeginInput(void)
00123 {
00124 KeyState = KeyStateInput;
00125 Input[0] = '\0';
00126 InputIndex = 0;
00127 ClearCosts();
00128 ShowInput();
00129 }
00130
00131
00132
00133
00134
00138 static void UiUnselectAll(void)
00139 {
00140 UnSelectAll();
00141 NetworkSendSelection(NULL, 0);
00142 SelectionChanged();
00143 }
00144
00153 static void UiCenterOnGroup(unsigned group)
00154 {
00155 CUnit **units;
00156 int n;
00157 int x;
00158 int y;
00159
00160 n = GetNumberUnitsOfGroup(group);
00161 if (n--) {
00162 units = GetUnitsOfGroup(group);
00163
00164
00165 x = units[n]->X;
00166 y = units[n]->Y;
00167 while (n--) {
00168 x += (units[n]->X - x) / 2;
00169 y += (units[n]->Y - y) / 2;
00170 }
00171 UI.SelectedViewport->Center(x, y, TileSizeX / 2, TileSizeY / 2);
00172 }
00173 }
00174
00180 static void UiSelectGroup(unsigned group)
00181 {
00182 SelectGroup(group);
00183 SelectionChanged();
00184 }
00185
00191 static void UiAddGroupToSelection(unsigned group)
00192 {
00193 CUnit **units;
00194 int n;
00195
00196 if (!(n = GetNumberUnitsOfGroup(group))) {
00197 return;
00198 }
00199
00200
00201
00202
00203 if (NumUnits && Selected[0]->Type->Building) {
00204 return;
00205 }
00206
00207 units = GetUnitsOfGroup(group);
00208 if (units[0]->Type->Building) {
00209 return;
00210 }
00211
00212 while (n--) {
00213 if (!units[n]->Removed) {
00214 SelectUnit(units[n]);
00215 }
00216 }
00217
00218 SelectionChanged();
00219 }
00220
00226 static void UiDefineGroup(unsigned group)
00227 {
00228 SetGroup(Selected, NumSelected, group);
00229 }
00230
00236 static void UiAddToGroup(unsigned group)
00237 {
00238 AddToGroup(Selected, NumSelected, group);
00239 }
00240
00244 static void UiToggleSound(void)
00245 {
00246 if (SoundEnabled()) {
00247 if (IsEffectsEnabled()) {
00248 SetEffectsEnabled(false);
00249 SetMusicEnabled(false);
00250 } else {
00251 SetEffectsEnabled(true);
00252 SetMusicEnabled(true);
00253 CheckMusicFinished(true);
00254 }
00255 }
00256
00257 if (SoundEnabled()) {
00258 if (IsEffectsEnabled()) {
00259 UI.StatusLine.Set(_("Sound is on."));
00260 } else {
00261 UI.StatusLine.Set(_("Sound is off."));
00262 }
00263 }
00264 }
00265
00269 static void UiToggleMusic(void)
00270 {
00271 static int vol;
00272 if (SoundEnabled()) {
00273 if (GetMusicVolume()) {
00274 vol = GetMusicVolume();
00275 SetMusicVolume(0);
00276 UI.StatusLine.Set(_("Music is off."));
00277 } else {
00278 SetMusicVolume(vol);
00279 UI.StatusLine.Set(_("Music is on."));
00280 }
00281 }
00282 }
00283
00287 void UiTogglePause(void)
00288 {
00289 if (!IsNetworkGame()) {
00290 GamePaused = !GamePaused;
00291 if (GamePaused) {
00292 UI.StatusLine.Set(_("Game Paused"));
00293 } else {
00294 UI.StatusLine.Set(_("Game Resumed"));
00295 }
00296 }
00297 }
00298
00304 static void UiToggleBigMap(void)
00305 {
00306 static int mapx;
00307 static int mapy;
00308 static int mapex;
00309 static int mapey;
00310
00311 BigMapMode ^= 1;
00312 if (BigMapMode) {
00313 mapx = UI.MapArea.X;
00314 mapy = UI.MapArea.Y;
00315 mapex = UI.MapArea.EndX;
00316 mapey = UI.MapArea.EndY;
00317
00318 UI.MapArea.X = 0;
00319 UI.MapArea.Y = 0;
00320 UI.MapArea.EndX = Video.Width - 1;
00321 UI.MapArea.EndY = Video.Height - 1;
00322
00323 SetViewportMode(UI.ViewportMode);
00324
00325 UI.StatusLine.Set(_("Big map enabled"));
00326 } else {
00327 UI.MapArea.X = mapx;
00328 UI.MapArea.Y = mapy;
00329 UI.MapArea.EndX = mapex;
00330 UI.MapArea.EndY = mapey;
00331
00332 SetViewportMode(UI.ViewportMode);
00333
00334 UI.StatusLine.Set(_("Returning to old map"));
00335 }
00336 }
00337
00341 static void UiIncreaseGameSpeed(void)
00342 {
00343 if (FastForwardCycle >= GameCycle) {
00344 return;
00345 }
00346 VideoSyncSpeed += 10;
00347 SetVideoSync();
00348 UI.StatusLine.Set(_("Faster"));
00349 }
00350
00354 static void UiDecreaseGameSpeed(void)
00355 {
00356 if (FastForwardCycle >= GameCycle) {
00357 return;
00358 }
00359 if (VideoSyncSpeed <= 10) {
00360 if (VideoSyncSpeed > 1) {
00361 --VideoSyncSpeed;
00362 }
00363 } else {
00364 VideoSyncSpeed -= 10;
00365 }
00366 SetVideoSync();
00367 UI.StatusLine.Set(_("Slower"));
00368 }
00369
00376 static void UiCenterOnSelected(void)
00377 {
00378 int x;
00379 int y;
00380 int n;
00381
00382 if ((n = NumSelected)) {
00383 x = Selected[--n]->X;
00384 y = Selected[n]->Y;
00385 while (n--) {
00386 x += (Selected[n]->X - x) / 2;
00387 y += (Selected[n]->Y - y) / 2;
00388 }
00389 UI.SelectedViewport->Center(x, y, TileSizeX / 2, TileSizeY / 2);
00390 }
00391 }
00392
00398 static void UiSaveMapPosition(unsigned position)
00399 {
00400 SavedMapPositionX[position] = UI.SelectedViewport->MapX;
00401 SavedMapPositionY[position] = UI.SelectedViewport->MapY;
00402 }
00403
00409 static void UiRecallMapPosition(unsigned position)
00410 {
00411 UI.SelectedViewport->Set(
00412 SavedMapPositionX[position], SavedMapPositionY[position], TileSizeX / 2, TileSizeY / 2);
00413 }
00414
00418 static void UiToggleTerrain(void)
00419 {
00420 UI.Minimap.WithTerrain ^= 1;
00421 if (UI.Minimap.WithTerrain) {
00422 UI.StatusLine.Set(_("Terrain displayed."));
00423 } else {
00424 UI.StatusLine.Set(_("Terrain hidden."));
00425 }
00426 }
00427
00431 static void UiFindIdleWorker(void)
00432 {
00433 CUnit *unit;
00434
00435 unit = FindIdleWorker(ThisPlayer);
00436 if (unit != NoUnitP) {
00437 SelectSingleUnit(unit);
00438 UI.StatusLine.Clear();
00439 ClearCosts();
00440 CurrentButtonLevel = 0;
00441 PlayUnitSound(Selected[0], VoiceSelected);
00442 SelectionChanged();
00443 UI.SelectedViewport->Center(unit->X, unit->Y, TileSizeX / 2, TileSizeY / 2);
00444 }
00445 }
00446
00450 static void UiToggleGrabMouse(void)
00451 {
00452 DebugPrint("%x\n" _C_ KeyModifiers);
00453 ToggleGrabMouse(0);
00454 UI.StatusLine.Set(_("Grab mouse toggled."));
00455 }
00456
00460 static void UiTrackUnit(void)
00461 {
00462 if (UI.SelectedViewport->Unit == Selected[0]) {
00463 UI.SelectedViewport->Unit = NULL;
00464 } else {
00465 UI.SelectedViewport->Unit = Selected[0];
00466 }
00467 }
00468
00472 bool HandleCommandKey(int key)
00473 {
00474 bool ret;
00475 int base = lua_gettop(Lua);
00476
00477 lua_pushstring(Lua, "HandleCommandKey");
00478 lua_gettable(Lua, LUA_GLOBALSINDEX);
00479 if (!lua_isfunction(Lua, -1)) {
00480 DebugPrint("No HandleCommandKey function in lua.\n");
00481 return false;
00482 }
00483 lua_pushstring(Lua, SdlKey2Str(key));
00484 lua_pushboolean(Lua, (KeyModifiers & ModifierControl));
00485 lua_pushboolean(Lua, (KeyModifiers & ModifierAlt));
00486 lua_pushboolean(Lua, (KeyModifiers & ModifierShift));
00487 LuaCall(4, 0);
00488 if (lua_gettop(Lua) - base == 1) {
00489 ret = LuaToBoolean(Lua, base + 1);
00490 lua_pop(Lua, 1);
00491 } else {
00492 LuaError(Lua, "HandleCommandKey must return a boolean");
00493 ret = false;
00494 }
00495 return ret;
00496 }
00497
00505 static bool CommandKey(int key)
00506 {
00507 size_t p;
00508
00509
00510 if ((p = UiGroupKeys.find(key)) != std::string::npos) {
00511 key = '0' + p;
00512 if (key > '9') {
00513 key = SDLK_BACKQUOTE;
00514 }
00515 }
00516
00517 switch (key) {
00518
00519 case SDLK_RETURN:
00520 case SDLK_KP_ENTER:
00521 UiBeginInput();
00522 return true;
00523
00524
00525 case SDLK_CARET:
00526 case SDLK_BACKQUOTE:
00527 UiUnselectAll();
00528 break;
00529
00530
00531 case '0': case '1': case '2':
00532 case '3': case '4': case '5':
00533 case '6': case '7': case '8':
00534 case '9':
00535 if (KeyModifiers & ModifierShift) {
00536 if (KeyModifiers & (ModifierAlt | ModifierDoublePress)) {
00537 UiCenterOnGroup(key - '0');
00538 } else if (KeyModifiers & ModifierControl) {
00539 UiAddToGroup(key - '0');
00540 } else {
00541 UiAddGroupToSelection(key - '0');
00542 }
00543 } else {
00544 if (KeyModifiers & (ModifierAlt | ModifierDoublePress)) {
00545 UiCenterOnGroup(key - '0');
00546 } else if (KeyModifiers & ModifierControl) {
00547 UiDefineGroup(key - '0');
00548 } else {
00549 UiSelectGroup(key - '0');
00550 }
00551 }
00552 break;
00553
00554 case SDLK_F2:
00555 case SDLK_F3:
00556 case SDLK_F4:
00557 if (KeyModifiers & ModifierShift) {
00558 UiSaveMapPosition(key - SDLK_F2);
00559 } else {
00560 UiRecallMapPosition(key - SDLK_F2);
00561 }
00562 break;
00563
00564 case SDLK_SPACE:
00565 CenterOnMessage();
00566 break;
00567
00568 case SDLK_EQUALS:
00569 case SDLK_KP_PLUS:
00570 UiIncreaseGameSpeed();
00571 break;
00572
00573 case SDLK_MINUS:
00574 case SDLK_KP_MINUS:
00575 UiDecreaseGameSpeed();
00576 break;
00577
00578 case 'b':
00579 if (!(KeyModifiers & (ModifierAlt | ModifierControl))) {
00580 break;
00581 }
00582 UiToggleBigMap();
00583 break;
00584
00585 case 'c':
00586 UiCenterOnSelected();
00587 break;
00588
00589 case 'f':
00590 if (!(KeyModifiers & (ModifierAlt | ModifierControl))) {
00591 break;
00592 }
00593 ToggleFullScreen();
00594 SavePreferences();
00595 break;
00596
00597 case 'g':
00598 if (!(KeyModifiers & (ModifierAlt | ModifierControl))) {
00599 break;
00600 }
00601 UiToggleGrabMouse();
00602 break;
00603
00604 case 'i':
00605 if (!(KeyModifiers & (ModifierAlt | ModifierControl))) {
00606 break;
00607 }
00608
00609 case SDLK_PERIOD:
00610 UiFindIdleWorker();
00611 break;
00612
00613 case 'm':
00614 if (KeyModifiers & ModifierControl) {
00615 UiToggleMusic();
00616 SavePreferences();
00617 break;
00618 }
00619 break;
00620
00621 case 'p':
00622 if (!(KeyModifiers & (ModifierAlt | ModifierControl))) {
00623 break;
00624 }
00625
00626 case SDLK_PAUSE:
00627 UiTogglePause();
00628 break;
00629
00630 case 's':
00631 if (KeyModifiers & ModifierControl) {
00632 UiToggleSound();
00633 SavePreferences();
00634 break;
00635 }
00636 break;
00637
00638 case 't':
00639 if (!(KeyModifiers & (ModifierAlt | ModifierControl))) {
00640 break;
00641 }
00642 UiTrackUnit();
00643 break;
00644
00645 case 'v':
00646 if (KeyModifiers & ModifierControl) {
00647 CycleViewportMode(-1);
00648 } else if (KeyModifiers & ModifierAlt) {
00649 CycleViewportMode(1);
00650 }
00651 break;
00652
00653 case SDLK_TAB:
00654
00655
00656 if (KeyModifiers & ModifierAlt) {
00657 break;
00658 }
00659 UiToggleTerrain();
00660 break;
00661
00662 case SDLK_UP:
00663 case SDLK_KP8:
00664 KeyScrollState |= ScrollUp;
00665 break;
00666 case SDLK_DOWN:
00667 case SDLK_KP2:
00668 KeyScrollState |= ScrollDown;
00669 break;
00670 case SDLK_LEFT:
00671 case SDLK_KP4:
00672 KeyScrollState |= ScrollLeft;
00673 break;
00674 case SDLK_RIGHT:
00675 case SDLK_KP6:
00676 KeyScrollState |= ScrollRight;
00677 break;
00678
00679 default:
00680 if (HandleCommandKey(key)) {
00681 break;
00682 }
00683 return false;
00684 }
00685 return true;
00686 }
00687
00693 int HandleCheats(const std::string &input)
00694 {
00695 int ret;
00696
00697 #ifdef DEBUG
00698 if (input == "ai me") {
00699 if (ThisPlayer->AiEnabled) {
00700
00701
00702
00703 #if 0
00704 ThisPlayer->AiEnabled = 0;
00705 ThisPlayer->Type = PlayerPerson;
00706 SetMessage("AI is off, Normal Player");
00707 #else
00708 SetMessage("Cannot disable 'ai me' cheat");
00709 #endif
00710 } else {
00711 ThisPlayer->AiEnabled = 1;
00712 ThisPlayer->Type = PlayerComputer;
00713 if (!ThisPlayer->Ai) {
00714 AiInit(ThisPlayer);
00715 }
00716 SetMessage("I'm the BORG, resistance is futile!");
00717 }
00718 return 1;
00719 }
00720 #endif
00721 int base = lua_gettop(Lua);
00722 lua_pushstring(Lua, "HandleCheats");
00723 lua_gettable(Lua, LUA_GLOBALSINDEX);
00724 if (!lua_isfunction(Lua, -1)) {
00725 DebugPrint("No HandleCheats function in lua.\n");
00726 return 0;
00727 }
00728 lua_pushstring(Lua, input.c_str());
00729 LuaCall(1, 0, false);
00730 if (lua_gettop(Lua) - base == 1) {
00731 ret = LuaToBoolean(Lua, -1);
00732 lua_pop(Lua, 1);
00733 } else {
00734 DebugPrint("HandleCheats must return a boolean");
00735 ret = 0;
00736 }
00737 return ret;
00738 }
00739
00746 static int InputKey(int key)
00747 {
00748 char ChatMessage[sizeof(Input) + 40];
00749 int i;
00750 char *namestart;
00751 char *p;
00752 char *q;
00753
00754 switch (key) {
00755 case SDLK_RETURN:
00756 case SDLK_KP_ENTER:
00757
00758 for (p = q = Input; *p;) {
00759 if (*p == '~') {
00760 ++p;
00761 }
00762 *q++ = *p++;
00763 }
00764 *q = '\0';
00765 #ifdef DEBUG
00766 if (Input[0] == '-') {
00767 if (!GameObserve && !GamePaused) {
00768 CommandLog("input", NoUnitP, FlushCommands, -1, -1, NoUnitP, Input, -1);
00769 CclCommand(Input + 1, false);
00770 }
00771 } else
00772 #endif
00773 if (!IsNetworkGame()) {
00774 if (!GameObserve && !GamePaused) {
00775 if (HandleCheats(Input)) {
00776 CommandLog("input", NoUnitP, FlushCommands, -1, -1, NoUnitP, Input, -1);
00777 }
00778 }
00779 }
00780
00781
00782 #ifdef DEBUG
00783 if (strncmp(Input, "ffw ", 4) == 0) {
00784 #else
00785 if (strncmp(Input, "ffw ", 4) == 0 && ReplayGameType != ReplayNone) {
00786 #endif
00787 FastForwardCycle = atoi(&Input[4]);
00788 }
00789
00790 if (Input[0]) {
00791
00792 for (p = Input; *p; ++p) {
00793 if (*p == '~') {
00794 q = p + strlen(p);
00795 q[1] = '\0';
00796 while (q > p) {
00797 *q = *(q - 1);
00798 --q;
00799 }
00800 ++p;
00801 }
00802 }
00803 sprintf_s(ChatMessage, sizeof(ChatMessage), "~%s~<%s>~> %s",
00804 PlayerColorNames[ThisPlayer->Index].c_str(),
00805 ThisPlayer->Name.c_str(), Input);
00806
00807 NetworkChatMessage(ChatMessage);
00808 }
00809
00810 case SDLK_ESCAPE:
00811 KeyState = KeyStateCommand;
00812 UI.StatusLine.Clear();
00813 return 1;
00814
00815 case SDLK_BACKSPACE:
00816 if (InputIndex) {
00817 if (Input[InputIndex - 1] == '~') {
00818 Input[--InputIndex] = '\0';
00819 }
00820 InputIndex = UTF8GetPrev(Input, InputIndex);
00821 if (InputIndex >= 0) {
00822 Input[InputIndex] = '\0';
00823 ShowInput();
00824 }
00825 }
00826 return 1;
00827
00828 case SDLK_TAB:
00829 namestart = strrchr(Input, ' ');
00830 if (namestart) {
00831 ++namestart;
00832 } else {
00833 namestart = Input;
00834 }
00835 if (!strlen(namestart)) {
00836 return 1;
00837 }
00838 for (i = 0; i < PlayerMax; ++i) {
00839 if (Players[i].Type != PlayerPerson) {
00840 continue;
00841 }
00842 if (!strncasecmp(namestart, Players[i].Name.c_str(), strlen(namestart))) {
00843 InputIndex += strlen(Players[i].Name.c_str()) - strlen(namestart);
00844 strcpy_s(namestart, sizeof(Input) - (namestart - Input), Players[i].Name.c_str());
00845 if (namestart == Input) {
00846 InputIndex += 2;
00847 strcat_s(namestart, sizeof(Input) - (namestart - Input), ": ");
00848 }
00849 ShowInput();
00850 }
00851 }
00852 return 1;
00853
00854 default:
00855 if (key >= ' ') {
00856 gcn::Key k(key);
00857 std::string kstr = k.toString();
00858 if (key == '~') {
00859 if (InputIndex < (int)sizeof(Input) - 2) {
00860 Input[InputIndex++] = key;
00861 Input[InputIndex++] = key;
00862 Input[InputIndex] = '\0';
00863 ShowInput();
00864 }
00865 } else if (InputIndex < (int)(sizeof(Input) - kstr.size())) {
00866 for (size_t i = 0; i < kstr.size(); ++i) {
00867 Input[InputIndex++] = kstr[i];
00868 }
00869 Input[InputIndex] = '\0';
00870 ShowInput();
00871 }
00872 return 1;
00873 }
00874 break;
00875 }
00876 return 0;
00877 }
00878
00882 static void Screenshot(void)
00883 {
00884 CFile fd;
00885 char filename[30];
00886 int i;
00887
00888 for (i = 1; i <= 99; ++i) {
00889
00890 sprintf_s(filename, sizeof(filename), "screen%02d.png", i);
00891 if (fd.open(filename, CL_OPEN_READ) == -1) {
00892 break;
00893 }
00894 fd.close();
00895 }
00896 SaveScreenshotPNG(filename);
00897 }
00898
00907 int HandleKeyModifiersDown(unsigned key, unsigned keychar)
00908 {
00909 switch (key) {
00910 case SDLK_LSHIFT:
00911 case SDLK_RSHIFT:
00912 KeyModifiers |= ModifierShift;
00913 return 1;
00914 case SDLK_LCTRL:
00915 case SDLK_RCTRL:
00916 KeyModifiers |= ModifierControl;
00917 return 1;
00918 case SDLK_LALT:
00919 case SDLK_RALT:
00920 case SDLK_LMETA:
00921 case SDLK_RMETA:
00922 KeyModifiers |= ModifierAlt;
00923
00924 if (InterfaceState == IfaceStateNormal) {
00925 SelectedUnitChanged();
00926 }
00927 return 1;
00928 case SDLK_LSUPER:
00929 case SDLK_RSUPER:
00930 KeyModifiers |= ModifierSuper;
00931 return 1;
00932 case SDLK_SYSREQ:
00933 case SDLK_PRINT:
00934 Screenshot();
00935 if (GameRunning) {
00936 SetMessage(_("Screenshot made."));
00937 }
00938 return 1;
00939 default:
00940 break;
00941 }
00942 return 0;
00943 }
00944
00953 int HandleKeyModifiersUp(unsigned key, unsigned keychar)
00954 {
00955 switch (key) {
00956 case SDLK_LSHIFT:
00957 case SDLK_RSHIFT:
00958 KeyModifiers &= ~ModifierShift;
00959 return 1;
00960 case SDLK_LCTRL:
00961 case SDLK_RCTRL:
00962 KeyModifiers &= ~ModifierControl;
00963 return 1;
00964 case SDLK_LALT:
00965 case SDLK_RALT:
00966 case SDLK_LMETA:
00967 case SDLK_RMETA:
00968 KeyModifiers &= ~ModifierAlt;
00969
00970 if (InterfaceState == IfaceStateNormal) {
00971 SelectedUnitChanged();
00972 }
00973 return 1;
00974 case SDLK_LSUPER:
00975 case SDLK_RSUPER:
00976 KeyModifiers &= ~ModifierSuper;
00977 return 1;
00978 }
00979 return 0;
00980 }
00981
00985 static bool IsKeyPad(unsigned key, unsigned *kp)
00986 {
00987 if (key >= SDLK_KP0 && key <= SDLK_KP9) {
00988 *kp = SDLK_0 + (key - SDLK_KP0);
00989 } else if (key == SDLK_KP_PERIOD) {
00990 *kp = SDLK_PERIOD;
00991 } else if (key == SDLK_KP_DIVIDE) {
00992 *kp = SDLK_SLASH;
00993 } else if (key == SDLK_KP_MULTIPLY) {
00994 *kp = SDLK_ASTERISK;
00995 } else if (key == SDLK_KP_MINUS) {
00996 *kp = SDLK_MINUS;
00997 } else if (key == SDLK_KP_PLUS) {
00998 *kp = SDLK_PLUS;
00999 } else if (key == SDLK_KP_ENTER) {
01000 *kp = SDLK_RETURN;
01001 } else if (key == SDLK_KP_EQUALS) {
01002 *kp = SDLK_EQUALS;
01003 } else {
01004 *kp = SDLK_UNKNOWN;
01005 return false;
01006 }
01007 return true;
01008 }
01009
01016 void HandleKeyDown(unsigned key, unsigned keychar)
01017 {
01018 if (HandleKeyModifiersDown(key, keychar)) {
01019 return;
01020 }
01021
01022
01023
01024
01025 unsigned kp = 0;
01026 if (KeyState == KeyStateInput && (keychar || IsKeyPad(key, &kp))) {
01027 InputKey(kp ? kp : keychar);
01028 } else {
01029
01030 if (!(KeyModifiers & (ModifierControl | ModifierAlt |
01031 ModifierSuper))) {
01032 if (!GameObserve && !GamePaused) {
01033 if (UI.ButtonPanel.DoKey(key)) {
01034 return;
01035 }
01036 }
01037 }
01038 CommandKey(key);
01039 }
01040 }
01041
01048 void HandleKeyUp(unsigned key, unsigned keychar)
01049 {
01050 if (HandleKeyModifiersUp(key, keychar)) {
01051 return;
01052 }
01053
01054 switch (key) {
01055 case SDLK_UP:
01056 case SDLK_KP8:
01057 KeyScrollState &= ~ScrollUp;
01058 break;
01059 case SDLK_DOWN:
01060 case SDLK_KP2:
01061 KeyScrollState &= ~ScrollDown;
01062 break;
01063 case SDLK_LEFT:
01064 case SDLK_KP4:
01065 KeyScrollState &= ~ScrollLeft;
01066 break;
01067 case SDLK_RIGHT:
01068 case SDLK_KP6:
01069 KeyScrollState &= ~ScrollRight;
01070 break;
01071 default:
01072 break;
01073 }
01074 }
01075
01082 void HandleKeyRepeat(unsigned key, unsigned keychar)
01083 {
01084 if (KeyState == KeyStateInput && keychar) {
01085 InputKey(keychar);
01086 }
01087 }
01088
01097 int HandleMouseScrollArea(int x, int y)
01098 {
01099 if (x < SCROLL_LEFT) {
01100 if (y < SCROLL_UP) {
01101 CursorOn = CursorOnScrollLeftUp;
01102 MouseScrollState = ScrollLeftUp;
01103 GameCursor = UI.ArrowNW.Cursor;
01104 } else if (y > SCROLL_DOWN) {
01105 CursorOn = CursorOnScrollLeftDown;
01106 MouseScrollState = ScrollLeftDown;
01107 GameCursor = UI.ArrowSW.Cursor;
01108 } else {
01109 CursorOn = CursorOnScrollLeft;
01110 MouseScrollState = ScrollLeft;
01111 GameCursor = UI.ArrowW.Cursor;
01112 }
01113 } else if (x > SCROLL_RIGHT) {
01114 if (y < SCROLL_UP) {
01115 CursorOn = CursorOnScrollRightUp;
01116 MouseScrollState = ScrollRightUp;
01117 GameCursor = UI.ArrowNE.Cursor;
01118 } else if (y > SCROLL_DOWN) {
01119 CursorOn = CursorOnScrollRightDown;
01120 MouseScrollState = ScrollRightDown;
01121 GameCursor = UI.ArrowSE.Cursor;
01122 } else {
01123 CursorOn = CursorOnScrollRight;
01124 MouseScrollState = ScrollRight;
01125 GameCursor = UI.ArrowE.Cursor;
01126 }
01127 } else if (y < SCROLL_UP) {
01128 CursorOn = CursorOnScrollUp;
01129 MouseScrollState = ScrollUp;
01130 GameCursor = UI.ArrowN.Cursor;
01131 } else if (y > SCROLL_DOWN) {
01132 CursorOn = CursorOnScrollDown;
01133 MouseScrollState = ScrollDown;
01134 GameCursor = UI.ArrowS.Cursor;
01135 } else {
01136 return 0;
01137 }
01138 return 1;
01139 }
01140
01147 void HandleCursorMove(int *x, int *y)
01148 {
01149
01150
01151
01152 if (*x < 0) {
01153 *x = 0;
01154 } else if (*x >= Video.Width) {
01155 *x = Video.Width - 1;
01156 }
01157 if (*y < 0) {
01158 *y = 0;
01159 } else if (*y >= Video.Height) {
01160 *y = Video.Height - 1;
01161 }
01162
01163 CursorX = *x;
01164 CursorY = *y;
01165 }
01166
01173 void HandleMouseMove(int x, int y)
01174 {
01175 HandleCursorMove(&x, &y);
01176 UIHandleMouseMove(x, y);
01177 }
01178
01184 void HandleButtonDown(unsigned button)
01185 {
01186 UIHandleButtonDown(button);
01187 }
01188
01197 void HandleButtonUp(unsigned button)
01198 {
01199 UIHandleButtonUp(button);
01200 }
01201
01202
01203
01204
01205
01206 int DoubleClickDelay = 300;
01207 int HoldClickDelay = 1000;
01208
01209 static enum {
01210 InitialMouseState,
01211 ClickedMouseState,
01212 } MouseState;
01213
01214 static int MouseX;
01215 static int MouseY;
01216 static unsigned LastMouseButton;
01217 static unsigned StartMouseTicks;
01218 static unsigned LastMouseTicks;
01219
01231 void InputMouseButtonPress(const EventCallback *callbacks,
01232 unsigned ticks, unsigned button)
01233 {
01234
01235
01236
01237 if (!(MouseButtons & (1 << button))) {
01238 MouseButtons |= (1 << button);
01239
01240
01241
01242 if (MouseState == ClickedMouseState && button == LastMouseButton &&
01243 ticks < StartMouseTicks + DoubleClickDelay) {
01244 MouseButtons |= (1 << button) << MouseDoubleShift;
01245 button |= button << MouseDoubleShift;
01246 } else {
01247 MouseState = InitialMouseState;
01248 StartMouseTicks = ticks;
01249 LastMouseButton = button;
01250 }
01251 }
01252 LastMouseTicks = ticks;
01253
01254 callbacks->ButtonPressed(button);
01255 }
01256
01264 void InputMouseButtonRelease(const EventCallback *callbacks,
01265 unsigned ticks, unsigned button)
01266 {
01267 unsigned mask;
01268
01269
01270
01271
01272 if (button == LastMouseButton && MouseState == InitialMouseState) {
01273 MouseState = ClickedMouseState;
01274 } else {
01275 LastMouseButton = 0;
01276 MouseState = InitialMouseState;
01277 }
01278 LastMouseTicks = ticks;
01279
01280 mask = 0;
01281 if (MouseButtons & ((1 << button) << MouseDoubleShift)) {
01282 mask |= button << MouseDoubleShift;
01283 }
01284 if (MouseButtons & ((1 << button) << MouseDragShift)) {
01285 mask |= button << MouseDragShift;
01286 }
01287 if (MouseButtons & ((1 << button) << MouseHoldShift)) {
01288 mask |= button << MouseHoldShift;
01289 }
01290 MouseButtons &= ~(0x01010101 << button);
01291
01292 callbacks->ButtonReleased(button | mask);
01293 }
01294
01303 void InputMouseMove(const EventCallback *callbacks,
01304 unsigned ticks, int x, int y)
01305 {
01306
01307 if (MouseX != x || MouseY != y) {
01308 MouseState = InitialMouseState;
01309 LastMouseTicks = ticks;
01310 MouseX = x;
01311 MouseY = y;
01312 }
01313 callbacks->MouseMoved(x, y);
01314 }
01315
01323 void InputMouseExit(const EventCallback *callbacks, unsigned ticks)
01324 {
01325
01326
01327 callbacks->MouseExit();
01328 }
01329
01336 void InputMouseTimeout(const EventCallback *callbacks, unsigned ticks)
01337 {
01338 if (MouseButtons & (1 << LastMouseButton)) {
01339 if (ticks > StartMouseTicks + DoubleClickDelay) {
01340 MouseState = InitialMouseState;
01341 }
01342 if (ticks > LastMouseTicks + HoldClickDelay) {
01343 LastMouseTicks = ticks;
01344 MouseButtons |= (1 << LastMouseButton) << MouseHoldShift;
01345 callbacks->ButtonPressed(LastMouseButton |
01346 (LastMouseButton << MouseHoldShift));
01347 }
01348 }
01349 }
01350
01351
01352 static int HoldKeyDelay = 250;
01353 static int HoldKeyAdditionalDelay = 50;
01354
01355 static unsigned LastIKey;
01356 static unsigned LastIKeyChar;
01357 static unsigned LastKeyTicks;
01358 static unsigned DoubleKey;
01359
01368 void InputKeyButtonPress(const EventCallback *callbacks,
01369 unsigned ticks, unsigned ikey, unsigned ikeychar)
01370 {
01371 if (!LastIKey && DoubleKey == ikey &&
01372 ticks < LastKeyTicks + DoubleClickDelay) {
01373 KeyModifiers |= ModifierDoublePress;
01374 }
01375 DoubleKey = ikey;
01376 LastIKey = ikey;
01377 LastIKeyChar = ikeychar;
01378 LastKeyTicks = ticks;
01379 callbacks->KeyPressed(ikey, ikeychar);
01380 KeyModifiers &= ~ModifierDoublePress;
01381 }
01382
01391 void InputKeyButtonRelease(const EventCallback *callbacks,
01392 unsigned ticks, unsigned ikey, unsigned ikeychar)
01393 {
01394 if (ikey == LastIKey) {
01395 LastIKey = 0;
01396 }
01397 LastKeyTicks = ticks;
01398 callbacks->KeyReleased(ikey, ikeychar);
01399 }
01400
01407 void InputKeyTimeout(const EventCallback *callbacks, unsigned ticks)
01408 {
01409 if (LastIKey && ticks > LastKeyTicks + HoldKeyDelay) {
01410 LastKeyTicks = ticks - (HoldKeyDelay - HoldKeyAdditionalDelay);
01411 callbacks->KeyRepeated(LastIKey, LastIKeyChar);
01412 }
01413 }
01414
01418 int GetDoubleClickDelay(void)
01419 {
01420 return DoubleClickDelay;
01421 }
01422
01428 void SetDoubleClickDelay(int delay)
01429 {
01430 DoubleClickDelay = delay;
01431 }
01432
01436 int GetHoldClickDelay(void)
01437 {
01438 return HoldClickDelay;
01439 }
01440
01446 void SetHoldClickDelay(int delay)
01447 {
01448 HoldClickDelay = delay;
01449 }
01450