Ticket #1492: hotkeys2.patch

File hotkeys2.patch, 15.5 KB (added by picobyte, 12 years ago)

incremental patch, fixes some issues and improves behavior

  • binaries/data/config/default.cfg

    commit ab24419fee2fd86ba4cfcec2d85f86c67a526e4a
    Author: Roel Kluin <roel.kluin@gmail.com>
    Date:   Sun Jun 10 21:37:36 2012 +0200
    
        Separate function initBuildingPlacementView()
        Building placement is now shown immediately, not after mouse movement.
        User can use the same several hotkey more times, e.g. for training.
        Or for iterate over the possible options using hotkeys, changing the
        Formation or Stance of the selected units or choosing different buildings
        during placement.
        
        setting inputState = INPUT_PRESELECTEDACTION for build and garrison
        alters mouse left/rightclick behavior.
        
        Formation fix: don't allow hotkey if selection is only one unit
        
        Add forwardslash as hotkey to reset action hotkey
        
        Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
    
    diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg
    index 0f1220e..1f7c35c 100644
    a b hotkey.selection.group.action.9 = "Shift+K"  
    202202hotkey.selection.group.action.10 = "Shift+L"
    203203hotkey.selection.group.action.11 = Colon
    204204hotkey.selection.group.action.12 = DoubleQuote
     205hotkey.selection.group.reset.action = ForwardSlash
    205206
    206207; > SESSION CONTROLS
    207208hotkey.session.kill = Delete                ; Destroy selected units
  • binaries/data/mods/public/gui/session/input.js

    diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js
    index 1888087..8775bb3 100644
    a b const ACTION_STANCE = 32;  
    2222const ACTION_BARTER = 64;
    2323const ACTION_TRADER =128;
    2424var preSelectedAction = ACTION_NONE;
     25
     26// N.B. reset this after selecting different units or buildings
    2527var _optionsOfpreSelected = [];
    2628
    2729const INPUT_NORMAL = 0;
    function updateBuildingPlacementPreview()  
    144146    return false;
    145147}
    146148
     149function initBuildingPlacementView(ev)
     150{
     151    if (placementSupport.mode === "wall")
     152    {
     153        // Including only the on-screen towers in the next snap candidate list is sufficient here, since the user is
     154        // still selecting a starting point (which must necessarily be on-screen). (The update of the snap entities
     155        // itself happens in the call to updateBuildingPlacementPreview below).
     156        placementSupport.wallSnapEntitiesIncludeOffscreen = false;
     157    }
     158    else
     159    {
     160        var snapData = Engine.GuiInterfaceCall("GetFoundationSnapData", {
     161            "template": placementSupport.template,
     162            "x": placementSupport.position.x,
     163            "z": placementSupport.position.z,
     164        });
     165        if (snapData)
     166        {
     167            placementSupport.angle = snapData.angle;
     168            placementSupport.position.x = snapData.x;
     169            placementSupport.position.z = snapData.z;
     170        }
     171    }
     172    updateBuildingPlacementPreview(); // includes an update of the snap entity candidates
     173}
     174
    147175function findGatherType(gatherer, supply)
    148176{
    149177    if (!gatherer || !supply)
    function findGatherType(gatherer, supply)  
    155183    return undefined;
    156184}
    157185
     186function resetPreselectedAction()
     187{
     188    placementSupport.Reset();
     189    inputState = INPUT_NORMAL;
     190    _optionsOfpreSelected = [];
     191
     192}
     193
    158194function getActionInfo(action, target)
    159195{
    160196    var selection = g_Selection.toList();
    function determineAction(x, y, fromMinimap)  
    449485            break;
    450486        }
    451487    }
    452     else if (Engine.HotkeyIsPressed("session.garrison"))
     488    else if (Engine.HotkeyIsPressed("session.garrison") || preSelectedAction == ACTION_GARRISON)
    453489    {
    454490        if (getActionInfo("garrison", target).possible)
    455491            return {"type": "garrison", "cursor": "action-garrison", "target": target};
    function handleInputBeforeGui(ev, hoveredObject)  
    755791                var queued = Engine.HotkeyIsPressed("session.queue");
    756792                if (tryPlaceBuilding(queued))
    757793                {
    758                     if (queued) {
     794                    if (queued)
    759795                        inputState = INPUT_BUILDING_PLACEMENT;
    760                     } else {
    761                         inputState = INPUT_NORMAL;
    762                         _optionsOfpreSelected = [];
    763                     }
     796                    else
     797                        resetPreselectedAction();
    764798                }
    765799                else
    766800                {
    function handleInputBeforeGui(ev, hoveredObject)  
    774808            if (ev.button == SDL_BUTTON_RIGHT)
    775809            {
    776810                // Cancel building
    777                 placementSupport.Reset();
    778                 inputState = INPUT_NORMAL;
    779                 _optionsOfpreSelected = [];
     811                resetPreselectedAction();
    780812                return true;
    781813            }
    782814            break;
    function handleInputAfterGui(ev)  
    9981030            return false;
    9991031
    10001032        case "mousebuttondown":
     1033            _optionsOfpreSelected = [];
    10011034            if (ev.button == SDL_BUTTON_LEFT)
    10021035            {
    10031036                dragStart = [ ev.x, ev.y ];
    function handleInputAfterGui(ev)  
    10141047            break;
    10151048
    10161049        case "hotkeydown":
    1017             if (ev.hotkey.indexOf("selection.group.") == 0)
     1050            if (ev.hotkey && ev.hotkey.indexOf("selection.group.") == 0)
    10181051            {
     1052                var sptr = ev.hotkey.split(".");
    10191053                var now = new Date();
    1020                 if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey))
    1021                 {
    1022                     if (ev.hotkey.indexOf("selection.group.select.") == 0)
    1023                     {
    1024                         var sptr = ev.hotkey.split(".");
    1025                         performGroup("snap", sptr[3]);
    1026                     }
     1054                if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey) && ev.hotkey.indexOf("selection.group.select.") == 0) {
     1055                    performGroup("snap", sptr[3], ev);
    10271056                }
    10281057                else
    10291058                {
    1030                     var sptr = ev.hotkey.split(".");
    1031                     performGroup(sptr[2], sptr[3]);
     1059                    performGroup(sptr[2], sptr[3], ev);
    10321060
    10331061                    doublePressTimer = now.getTime();
    10341062                    prevHotkey = ev.hotkey;
    function handleInputAfterGui(ev)  
    10451073            if (ev.button == SDL_BUTTON_LEFT && preSelectedAction != ACTION_NONE)
    10461074            {
    10471075                var action = determineAction(ev.x, ev.y);
     1076                resetPreselectedAction();
    10481077                if (!action)
    10491078                    break;
    1050                 preSelectedAction = ACTION_NONE;
    1051                 inputState = INPUT_NORMAL;
    1052                 _optionsOfpreSelected = [];
    10531079                return doAction(action, ev);
    10541080            }
    10551081            else if (ev.button == SDL_BUTTON_RIGHT && preSelectedAction != ACTION_NONE)
    10561082            {
    1057                 preSelectedAction = ACTION_NONE;
    1058                 inputState = INPUT_NORMAL;
    1059                 _optionsOfpreSelected = [];
     1083                resetPreselectedAction();
    10601084                break;
    10611085            }
    1062             // else
    10631086        case "hotkeydown":
    1064             if (!ev.hotkey)
    1065                 break;
    1066 
    1067             if (ev.hotkey.indexOf("selection.group.action.") == 0)
     1087            if (ev.hotkey && ev.hotkey.indexOf("selection.group.action.") == 0)
    10681088            {
    10691089                var sptr = ev.hotkey.split(".");
    10701090                performGroup(sptr[2], sptr[3]);
    function handleInputAfterGui(ev)  
    10741094            // Slight hack: If selection is empty, reset the input state
    10751095            if (g_Selection.toList().length == 0)
    10761096            {
    1077                 preSelectedAction = ACTION_NONE;
    1078                 inputState = INPUT_NORMAL;
    1079                 _optionsOfpreSelected = [];
     1097                resetPreselectedAction();
    10801098                break;
    10811099            }
    10821100        }
    function handleInputAfterGui(ev)  
    11081126                {
    11091127                    g_Selection.reset();
    11101128                    resetEntitySearch();
    1111                     inputState = INPUT_NORMAL;
    1112                     _optionsOfpreSelected = [];
     1129                    resetPreselectedAction();
    11131130                    return true;
    11141131                }
    11151132
    function handleInputAfterGui(ev)  
    11831200                    g_Selection.reset();
    11841201                    g_Selection.addList(ents);
    11851202                }
    1186 
    1187                 inputState = INPUT_NORMAL;
    1188                 _optionsOfpreSelected = [];
     1203                resetPreselectedAction();
    11891204                return true;
    11901205            }
    11911206            break;
    function handleInputAfterGui(ev)  
    11961211        switch (ev.type)
    11971212        {
    11981213        case "mousemotion":
    1199            
    12001214            placementSupport.position = Engine.GetTerrainAtScreenPoint(ev.x, ev.y);
    1201            
    1202             if (placementSupport.mode === "wall")
    1203             {
    1204                 // Including only the on-screen towers in the next snap candidate list is sufficient here, since the user is
    1205                 // still selecting a starting point (which must necessarily be on-screen). (The update of the snap entities
    1206                 // itself happens in the call to updateBuildingPlacementPreview below).
    1207                 placementSupport.wallSnapEntitiesIncludeOffscreen = false;
    1208             }
    1209             else
    1210             {
    1211                 var snapData = Engine.GuiInterfaceCall("GetFoundationSnapData", {
    1212                     "template": placementSupport.template,
    1213                     "x": placementSupport.position.x,
    1214                     "z": placementSupport.position.z,
    1215                 });
    1216                 if (snapData)
    1217                 {
    1218                     placementSupport.angle = snapData.angle;
    1219                     placementSupport.position.x = snapData.x;
    1220                     placementSupport.position.z = snapData.z;
    1221                 }
    1222             }
    1223 
    1224             updateBuildingPlacementPreview(); // includes an update of the snap entity candidates
     1215            initBuildingPlacementView(ev);
    12251216            return false; // continue processing mouse motion
    12261217
    12271218        case "mousebuttondown":
    function handleInputAfterGui(ev)  
    12381229                else
    12391230                {
    12401231                    placementSupport.position = Engine.GetTerrainAtScreenPoint(ev.x, ev.y);
    1241                     dragStart = [ ev.x, ev.y ];
    1242                     inputState = INPUT_BUILDING_CLICK;
     1232                    dragStart = [ ev.x, ev.y ];
     1233                    inputState = INPUT_BUILDING_CLICK;
     1234                    _optionsOfpreSelected = [];
    12431235                }
    12441236                return true;
    12451237            }
    function handleInputAfterGui(ev)  
    12471239            {
    12481240                // Cancel building
    12491241                placementSupport.Reset();
    1250                 inputState = INPUT_NORMAL;
    1251                 preSelectedAction = ACTION_NONE;
    1252                  _optionsOfpreSelected = [];
     1242                resetPreselectedAction();
    12531243                return true;
    12541244            }
    12551245            break;
    function handleInputAfterGui(ev)  
    12681258                placementSupport.angle -= rotation_step;
    12691259                updateBuildingPlacementPreview();
    12701260                break;
     1261            default:
     1262                if (ev.hotkey.indexOf("selection.group.action.") == 0)
     1263                {   // can switch buildings
     1264                    var sptr = ev.hotkey.split(".");
     1265                    performGroup(sptr[2], sptr[3], ev);
     1266                }
    12711267            }
    12721268            break;
    12731269
    function getActionForSelection(player, selection)  
    16181614        switch (preSelectedAction)
    16191615        {
    16201616        case ACTION_GARRISON:
    1621             if (state.buildEntities || (hasClass(state, "Unit") && !hasClass(state, "Animal") && !state.garrisonHolder))
     1617            if (state.buildEntities || (hasClass(state, "Unit") && !hasClass(state, "Animal") && !state.garrisonHolder)) {
     1618                inputState = INPUT_PRESELECTEDACTION;
    16221619                ret.push(ent);
     1620            }
    16231621            break;
    16241622        case ACTION_BUILD:
    1625             if (state.buildEntities && state.buildEntities.length)
     1623            if (state.buildEntities && state.buildEntities.length) {
     1624                inputState = INPUT_PRESELECTEDACTION;
    16261625                return state.buildEntities;
     1626            }
    16271627            break;
    16281628        case ACTION_TRAIN:
    16291629            if (state.production && state.production.entities.length)
    function getActionForSelection(player, selection)  
    16381638            if (!hasClass(state, "Unit") || hasClass(state, "Animal") || state.garrisonHolder)
    16391639                break;
    16401640
    1641             if (preSelectedAction == ACTION_FORMATION) {
    1642                 return Engine.GuiInterfaceCall("GetAvailableFormations");
    1643             } else { // FIXME:
     1641            if (preSelectedAction == STANCE)
    16441642                return ["violent", "aggressive", "passive", "defensive", "standground"];
    1645             }
     1643            if (ret.length) // minimimum is 2 units for formation to be enabled
     1644                return Engine.GuiInterfaceCall("GetAvailableFormations");
     1645            ret.push(1);
    16461646            break;
    16471647        case ACTION_BARTER:
    16481648            if (state.barterMarket)
    function getActionForSelection(player, selection)  
    16601660}
    16611661
    16621662// Performs the specified group
    1663 function performGroup(action, nr)
     1663function performGroup(action, nr, ev)
    16641664{
    16651665    switch (action)
    16661666    {
    function performGroup(action, nr)  
    16981698            var actions = getActionForSelection(player, selection);
    16991699            if (!actions || !actions.length) {
    17001700                preSelectedAction = ACTION_NONE;
    1701                 _optionsOfpreSelected = [];
    17021701                break;
    17031702            }
    17041703
    function performGroup(action, nr)  
    17071706            else if (preSelectedAction == ACTION_TRADER)
    17081707                setupUnitTradingPanel(state, selection);
    17091708
    1710             inputState = INPUT_PRESELECTEDACTION;
    17111709            _optionsOfpreSelected = actions;
    17121710        }
    17131711        else
    function performGroup(action, nr)  
    17351733            {
    17361734            case ACTION_BUILD:
    17371735                var tmpl = GetTemplateData(lst);
    1738                 if (tmpl.requiredTechnology && !Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology))
    1739                     break;
    1740 
    1741                 startBuildingPlacement(lst);
    1742                 inputState = INPUT_BUILDING_PLACEMENT;
    1743                 preSelectedAction = ACTION_NONE;
    1744                 return;
     1736                if (!tmpl.requiredTechnology || Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology)) {
     1737                    // N.B. sets inputState = INPUT_BUILDING_PLACEMENT:
     1738                    startBuildingPlacement(lst);
     1739                    placementSupport.position = Engine.GetTerrainAtScreenPoint(mouseX, mouseY);
     1740                    initBuildingPlacementView(ev);
     1741                }
     1742                break;
    17451743            case ACTION_TRAIN:
    17461744                var tmpl = GetTemplateData(lst);
    17471745                if (!tmpl.requiredTechnology || Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology)) {
    function performGroup(action, nr)  
    17531751                g_Selection.reset();
    17541752                lst.splice(nr, lst.length - nr)
    17551753                g_Selection.addList(lst);
     1754                inputState = INPUT_PRESELECTEDACTION;
    17561755                break;
    17571756            case ACTION_UNGARRISON:
    1758                 if (lst.length != 1 || nr == 0) {
     1757                if (lst.length > 1 || nr == 0) {
     1758                    if (lst.length != 1)   // TODO: uload all from all
     1759                        lst = lst[nr]; // selected buildings
     1760                    else
     1761                        lst = lst[0];
     1762                    // FIXME: follow when ungarrisoning all
    17591763                    var state = GetEntityState(lst);
    1760                     var gents = state.garrisonHolder.entities
    1761                     unloadAll(lst[nr]);
    1762                     // TODO: follow when ungarrisoning all
    1763                     //var gents = g_Selection.toList();
    1764         //          Engine.CameraFollow(gents[0]);
     1764                    var gents = state.garrisonHolder.entities;
     1765                    unloadAll(lst);
     1766                    Engine.CameraFollow(0);
     1767                    g_Selection.reset();
     1768                    g_Selection.addList(gents);
     1769                    Engine.CameraFollow(gents[0]);
    17651770                } else {
    17661771                    lst = lst[0];
    17671772                    var state = GetEntityState(lst);
    function performGroup(action, nr)  
    17881793            case ACTION_TRADER: //TODO
    17891794                break;
    17901795            }
    1791             inputState = INPUT_NORMAL;
    1792             _optionsOfpreSelected = [];
    17931796        }
     1797        break;
     1798    case "reset":
     1799        resetPreselectedAction();
     1800        break;
    17941801    }
    17951802}
    17961803
    function resetEntitySearch()  
    18371844
    18381845function findEntity(classes, mode)
    18391846{
     1847    var player = Engine.GetPlayerID();
    18401848    // Cycle through idling classes before giving up
    18411849    for (var i = 0; i <= classes.length; ++i)
    18421850    {
    function findEntity(classes, mode)  
    18441852        var newEntity = Engine.GuiInterfaceCall("FindEntity", data);
    18451853        if (newEntity && newEntity != lastEntity)
    18461854        {
     1855            if (!getActionForSelection(player, [newEntity]).length)
     1856                resetPreselectedAction();
     1857
    18471858            lastEntity = newEntity;
    18481859            g_Selection.reset();
    18491860            g_Selection.addList([lastEntity]);
  • binaries/data/mods/public/gui/session/input.js

    commit 5656cbab54bcd160f89a6b6681f6329f8b4d15aa
    Author: Roel Kluin <roel.kluin@gmail.com>
    Date:   Sun Jun 10 12:24:03 2012 +0200
    
        was too much indented (no semantic change)
        
        Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
    
    diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js
    index 7da7546..1888087 100644
    a b function handleInputAfterGui(ev)  
    10141014            break;
    10151015
    10161016        case "hotkeydown":
    1017                 if (ev.hotkey.indexOf("selection.group.") == 0)
     1017            if (ev.hotkey.indexOf("selection.group.") == 0)
     1018            {
     1019                var now = new Date();
     1020                if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey))
    10181021                {
    1019                     var now = new Date();
    1020                     if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey))
    1021                     {
    1022                         if (ev.hotkey.indexOf("selection.group.select.") == 0)
    1023                         {
    1024                             var sptr = ev.hotkey.split(".");
    1025                             performGroup("snap", sptr[3]);
    1026                         }
    1027                     }
    1028                     else
     1022                    if (ev.hotkey.indexOf("selection.group.select.") == 0)
    10291023                    {
    10301024                        var sptr = ev.hotkey.split(".");
    1031                         performGroup(sptr[2], sptr[3]);
    1032 
    1033                         doublePressTimer = now.getTime();
    1034                         prevHotkey = ev.hotkey;
     1025                        performGroup("snap", sptr[3]);
    10351026                    }
    10361027                }
    1037                 break;
     1028                else
     1029                {
     1030                    var sptr = ev.hotkey.split(".");
     1031                    performGroup(sptr[2], sptr[3]);
     1032
     1033                    doublePressTimer = now.getTime();
     1034                    prevHotkey = ev.hotkey;
     1035                }
     1036            }
     1037            break;
    10381038        }
    10391039        break;
    10401040